scir/
slice.rs

1//! Slices of bus signals.
2
3use arcstr::ArcStr;
4use std::ops::{Range, RangeFrom, RangeFull, RangeInclusive, RangeTo, RangeToInclusive};
5
6use crate::SignalId;
7use serde::{Deserialize, Serialize};
8
9/// A single bit wire or a portion of a bus signal addressed by name.
10#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
11pub struct NamedSlice {
12    signal: ArcStr,
13    range: Option<SliceRange>,
14}
15
16/// A single bit wire or a single bit of a bus signal addressed by name.
17#[derive(Debug, Clone, Eq, PartialEq, Hash, Ord, PartialOrd, Serialize, Deserialize)]
18pub struct NamedSliceOne {
19    signal: ArcStr,
20    index: Option<usize>,
21}
22
23/// A single bit wire or a portion of a bus signal.
24#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
25pub struct Slice {
26    signal: SignalId,
27    range: Option<SliceRange>,
28}
29
30/// A single bit wire or a single bit of a bus signal.
31#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Ord, PartialOrd, Serialize, Deserialize)]
32pub struct SliceOne {
33    signal: SignalId,
34    index: Option<usize>,
35}
36
37/// A range of bus indices.
38#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
39pub struct SliceRange {
40    pub(crate) start: usize,
41    pub(crate) end: usize,
42}
43
44impl From<Range<usize>> for SliceRange {
45    fn from(value: Range<usize>) -> Self {
46        Self {
47            start: value.start,
48            end: value.end,
49        }
50    }
51}
52
53impl SliceRange {
54    /// Creates a new [`SliceRange`].
55    #[inline]
56    pub fn new(start: usize, end: usize) -> Self {
57        assert!(end > start);
58        Self { start, end }
59    }
60
61    pub(crate) fn from_index(start: usize) -> Self {
62        Self::new(start, start + 1)
63    }
64
65    #[inline]
66    pub(crate) fn with_width(end: usize) -> Self {
67        assert!(end > 0);
68        Self { start: 0, end }
69    }
70
71    /// The width of this slice.
72    #[inline]
73    pub const fn width(&self) -> usize {
74        self.end - self.start
75    }
76
77    /// The start index (inclusive) of this range.
78    #[inline]
79    pub const fn start(&self) -> usize {
80        self.start
81    }
82
83    /// The end index (**exclusive**) of this range.
84    #[inline]
85    pub const fn end(&self) -> usize {
86        self.end
87    }
88
89    /// Iterate over the indices in this slice.
90    #[inline]
91    pub fn indices(&self) -> impl Iterator<Item = usize> {
92        self.start..self.end
93    }
94
95    /// Returns if the this slice contains the given index.
96    #[inline]
97    pub const fn contains(&self, idx: usize) -> bool {
98        idx >= self.start && idx < self.end
99    }
100}
101impl IntoIterator for SliceRange {
102    type Item = usize;
103    type IntoIter = std::ops::Range<usize>;
104    fn into_iter(self) -> Self::IntoIter {
105        self.start..self.end
106    }
107}
108
109impl NamedSlice {
110    /// Creates a new [`NamedSlice`].
111    #[inline]
112    pub fn new(signal: impl Into<ArcStr>) -> Self {
113        Self {
114            signal: signal.into(),
115            range: None,
116        }
117    }
118
119    /// Creates a new [`NamedSlice`] with the given range.
120    #[inline]
121    pub fn with_range(signal: impl Into<ArcStr>, range: impl Into<SliceRange>) -> Self {
122        Self {
123            signal: signal.into(),
124            range: Some(range.into()),
125        }
126    }
127
128    /// The range of indices indexed by this slice.
129    ///
130    /// Returns [`None`] if this slice represents a single bit wire.
131    #[inline]
132    pub fn range(&self) -> Option<SliceRange> {
133        self.range
134    }
135
136    /// The width of this slice.
137    ///
138    /// Returns 1 if this slice represents a single bit wire.
139    #[inline]
140    pub fn width(&self) -> usize {
141        self.range.map(|x| x.width()).unwrap_or(1)
142    }
143
144    /// The name of the signal this slice indexes.
145    #[inline]
146    pub fn signal(&self) -> &ArcStr {
147        &self.signal
148    }
149
150    /// Returns `true` if this signal indexes into a bus.
151    #[inline]
152    pub fn is_bus(&self) -> bool {
153        self.range.is_some()
154    }
155
156    #[inline]
157    fn assert_bus_index(&self) {
158        assert!(
159            self.is_bus(),
160            "attempted to index into a single-bit wire; only buses support indexing"
161        );
162    }
163
164    /// If this slice contains one bit, returns `Some` with a [`SliceOne`].
165    ///
166    /// Otherwise, returns [`None`].
167    pub fn slice_one(self) -> Option<NamedSliceOne> {
168        NamedSliceOne::try_from(self).ok()
169    }
170}
171
172impl IndexOwned<usize> for NamedSlice {
173    type Output = NamedSliceOne;
174    fn index(&self, index: usize) -> Self::Output {
175        self.assert_bus_index();
176        NamedSliceOne::with_index(self.signal.clone(), self.range.unwrap().index(index))
177    }
178}
179
180impl IndexOwned<Range<usize>> for NamedSlice {
181    type Output = Self;
182    fn index(&self, index: Range<usize>) -> Self::Output {
183        self.assert_bus_index();
184        Self::with_range(self.signal.clone(), self.range.unwrap().index(index))
185    }
186}
187
188impl IndexOwned<RangeFrom<usize>> for NamedSlice {
189    type Output = Self;
190    fn index(&self, index: RangeFrom<usize>) -> Self::Output {
191        self.assert_bus_index();
192        Self::with_range(self.signal.clone(), self.range.unwrap().index(index))
193    }
194}
195
196impl IndexOwned<RangeFull> for NamedSlice {
197    type Output = Self;
198    fn index(&self, index: RangeFull) -> Self::Output {
199        self.assert_bus_index();
200        Self::with_range(self.signal.clone(), self.range.unwrap().index(index))
201    }
202}
203
204impl IndexOwned<RangeInclusive<usize>> for NamedSlice {
205    type Output = Self;
206    fn index(&self, index: RangeInclusive<usize>) -> Self::Output {
207        self.assert_bus_index();
208        Self::with_range(self.signal.clone(), self.range.unwrap().index(index))
209    }
210}
211
212impl IndexOwned<RangeTo<usize>> for NamedSlice {
213    type Output = Self;
214    fn index(&self, index: RangeTo<usize>) -> Self::Output {
215        self.assert_bus_index();
216        Self::with_range(self.signal.clone(), self.range.unwrap().index(index))
217    }
218}
219
220impl IndexOwned<RangeToInclusive<usize>> for NamedSlice {
221    type Output = Self;
222    fn index(&self, index: RangeToInclusive<usize>) -> Self::Output {
223        self.assert_bus_index();
224        Self::with_range(self.signal.clone(), self.range.unwrap().index(index))
225    }
226}
227
228impl TryFrom<NamedSlice> for NamedSliceOne {
229    type Error = SliceWidthNotOne;
230    fn try_from(value: NamedSlice) -> Result<Self, Self::Error> {
231        if value.width() == 1 {
232            Ok(Self {
233                signal: value.signal,
234                index: value.range.map(|s| s.start()),
235            })
236        } else {
237            Err(SliceWidthNotOne)
238        }
239    }
240}
241
242impl From<NamedSliceOne> for NamedSlice {
243    fn from(value: NamedSliceOne) -> Self {
244        let range = value.range();
245        Self {
246            signal: value.signal,
247            range,
248        }
249    }
250}
251
252impl NamedSliceOne {
253    /// Creates a new [`NamedSliceOne`].
254    #[inline]
255    pub fn new(signal: impl Into<ArcStr>) -> Self {
256        Self {
257            signal: signal.into(),
258            index: None,
259        }
260    }
261
262    /// Creates a new [`NamedSliceOne`] with the given index.
263    pub fn with_index(signal: ArcStr, index: usize) -> Self {
264        Self {
265            signal,
266            index: Some(index),
267        }
268    }
269
270    /// The range of indices indexed by this slice.
271    ///
272    /// Returns [`None`] if this slice represents a single bit wire.
273    #[inline]
274    pub fn range(&self) -> Option<SliceRange> {
275        self.index.map(SliceRange::from_index)
276    }
277
278    /// The width of this slice.
279    #[inline]
280    pub const fn width(&self) -> usize {
281        1
282    }
283
284    /// The ID of the signal this slice indexes.
285    #[inline]
286    pub fn signal(&self) -> &ArcStr {
287        &self.signal
288    }
289
290    /// Returns `true` if this signal indexes into a bus.
291    #[inline]
292    pub fn is_bus(&self) -> bool {
293        self.index.is_some()
294    }
295
296    /// The index this single-bit slice contains.
297    #[inline]
298    pub fn index(&self) -> Option<usize> {
299        self.index
300    }
301}
302
303impl Slice {
304    #[inline]
305    pub(crate) fn new(signal: SignalId, range: Option<SliceRange>) -> Self {
306        Self { signal, range }
307    }
308
309    /// The range of indices indexed by this slice.
310    ///
311    /// Returns [`None`] if this slice represents a single bit wire.
312    #[inline]
313    pub fn range(&self) -> Option<SliceRange> {
314        self.range
315    }
316
317    /// The width of this slice.
318    ///
319    /// Returns 1 if this slice represents a single bit wire.
320    #[inline]
321    pub fn width(&self) -> usize {
322        self.range.map(|x| x.width()).unwrap_or(1)
323    }
324
325    /// The ID of the signal this slice indexes.
326    #[inline]
327    pub fn signal(&self) -> SignalId {
328        self.signal
329    }
330
331    /// Returns `true` if this signal indexes into a bus.
332    #[inline]
333    pub fn is_bus(&self) -> bool {
334        self.range.is_some()
335    }
336
337    #[inline]
338    fn assert_bus_index(&self) {
339        assert!(
340            self.is_bus(),
341            "attempted to index into a single-bit wire; only buses support indexing"
342        );
343    }
344
345    /// If this slice contains one bit, returns `Some` with a [`SliceOne`].
346    ///
347    /// Otherwise, returns [`None`].
348    pub fn slice_one(&self) -> Option<SliceOne> {
349        SliceOne::try_from(self).ok()
350    }
351}
352
353impl IndexOwned<usize> for Slice {
354    type Output = SliceOne;
355    fn index(&self, index: usize) -> Self::Output {
356        self.assert_bus_index();
357        SliceOne::new(self.signal, Some(self.range.unwrap().index(index)))
358    }
359}
360
361impl IndexOwned<Range<usize>> for Slice {
362    type Output = Self;
363    fn index(&self, index: Range<usize>) -> Self::Output {
364        self.assert_bus_index();
365        Self::new(self.signal, Some(self.range.unwrap().index(index)))
366    }
367}
368
369impl IndexOwned<RangeFrom<usize>> for Slice {
370    type Output = Self;
371    fn index(&self, index: RangeFrom<usize>) -> Self::Output {
372        self.assert_bus_index();
373        Self::new(self.signal, Some(self.range.unwrap().index(index)))
374    }
375}
376
377impl IndexOwned<RangeFull> for Slice {
378    type Output = Self;
379    fn index(&self, index: RangeFull) -> Self::Output {
380        self.assert_bus_index();
381        Self::new(self.signal, Some(self.range.unwrap().index(index)))
382    }
383}
384
385impl IndexOwned<RangeInclusive<usize>> for Slice {
386    type Output = Self;
387    fn index(&self, index: RangeInclusive<usize>) -> Self::Output {
388        self.assert_bus_index();
389        Self::new(self.signal, Some(self.range.unwrap().index(index)))
390    }
391}
392
393impl IndexOwned<RangeTo<usize>> for Slice {
394    type Output = Self;
395    fn index(&self, index: RangeTo<usize>) -> Self::Output {
396        self.assert_bus_index();
397        Self::new(self.signal, Some(self.range.unwrap().index(index)))
398    }
399}
400
401impl IndexOwned<RangeToInclusive<usize>> for Slice {
402    type Output = Self;
403    fn index(&self, index: RangeToInclusive<usize>) -> Self::Output {
404        self.assert_bus_index();
405        Self::new(self.signal, Some(self.range.unwrap().index(index)))
406    }
407}
408
409impl IndexOwned<usize> for SliceRange {
410    type Output = usize;
411    fn index(&self, index: usize) -> Self::Output {
412        let idx = self.start + index;
413        assert!(idx < self.end, "index out of bounds");
414        idx
415    }
416}
417
418impl IndexOwned<Range<usize>> for SliceRange {
419    type Output = Self;
420    fn index(&self, index: Range<usize>) -> Self::Output {
421        assert!(self.start + index.end <= self.end, "index out of bounds");
422        Self::new(self.start + index.start, self.start + index.end)
423    }
424}
425
426impl IndexOwned<RangeFrom<usize>> for SliceRange {
427    type Output = Self;
428    fn index(&self, index: RangeFrom<usize>) -> Self::Output {
429        assert!(self.start + index.start <= self.end, "index out of bounds");
430        Self::new(self.start + index.start, self.end)
431    }
432}
433
434impl IndexOwned<RangeFull> for SliceRange {
435    type Output = Self;
436    fn index(&self, _index: RangeFull) -> Self::Output {
437        *self
438    }
439}
440
441impl IndexOwned<RangeInclusive<usize>> for SliceRange {
442    type Output = Self;
443    fn index(&self, index: RangeInclusive<usize>) -> Self::Output {
444        assert!(self.start + index.end() < self.end, "index out of bounds");
445        Self::new(self.start + index.start(), self.start + index.end() + 1)
446    }
447}
448
449impl IndexOwned<RangeTo<usize>> for SliceRange {
450    type Output = Self;
451    fn index(&self, index: RangeTo<usize>) -> Self::Output {
452        assert!(self.start + index.end <= self.end, "index out of bounds");
453        Self::new(self.start, self.start + index.end)
454    }
455}
456
457impl IndexOwned<RangeToInclusive<usize>> for SliceRange {
458    type Output = Self;
459    fn index(&self, index: RangeToInclusive<usize>) -> Self::Output {
460        assert!(self.start + index.end < self.end, "index out of bounds");
461        Self::new(self.start, self.start + index.end + 1)
462    }
463}
464
465/// A concatenation of multiple slices.
466#[derive(Debug, Clone, Serialize, Deserialize)]
467pub struct Concat {
468    parts: Vec<Slice>,
469}
470
471impl Concat {
472    /// Creates a new concatenation from the given list of slices.
473    #[inline]
474    pub fn new(parts: Vec<Slice>) -> Self {
475        Self { parts }
476    }
477
478    /// The width of this concatenation.
479    ///
480    /// Equal to the sum of the widths of all constituent slices.
481    pub fn width(&self) -> usize {
482        self.parts.iter().map(Slice::width).sum()
483    }
484
485    /// Iterate over the parts of this concatenation.
486    #[inline]
487    pub fn parts(&self) -> impl Iterator<Item = &Slice> {
488        self.parts.iter()
489    }
490}
491
492impl FromIterator<Slice> for Concat {
493    fn from_iter<T: IntoIterator<Item = Slice>>(iter: T) -> Self {
494        let parts = iter.into_iter().collect();
495        Self { parts }
496    }
497}
498
499impl FromIterator<SliceOne> for Concat {
500    fn from_iter<T: IntoIterator<Item = SliceOne>>(iter: T) -> Self {
501        let parts = iter.into_iter().map(|s| s.into()).collect();
502        Self { parts }
503    }
504}
505
506impl From<Vec<Slice>> for Concat {
507    #[inline]
508    fn from(value: Vec<Slice>) -> Self {
509        Self::new(value)
510    }
511}
512
513impl From<Vec<SliceOne>> for Concat {
514    #[inline]
515    fn from(value: Vec<SliceOne>) -> Self {
516        Self::new(
517            value
518                .into_iter()
519                .map(|slice_one| slice_one.into())
520                .collect(),
521        )
522    }
523}
524
525impl From<Slice> for Concat {
526    #[inline]
527    fn from(value: Slice) -> Self {
528        Self { parts: vec![value] }
529    }
530}
531
532impl From<SliceOne> for Concat {
533    #[inline]
534    fn from(value: SliceOne) -> Self {
535        Self {
536            parts: vec![value.into()],
537        }
538    }
539}
540
541impl IndexOwned<usize> for Concat {
542    type Output = SliceOne;
543
544    fn index(&self, mut index: usize) -> Self::Output {
545        for part in self.parts.iter() {
546            let width = part.width();
547            if index < width {
548                return part.slice_one().unwrap_or_else(|| part.index(index));
549            }
550            index -= width;
551        }
552        panic!("index {index} out of bounds for signal");
553    }
554}
555
556/// Index into an object.
557///
558///
559/// Unlike [`std::ops::Index`], allows implementors
560/// to return ownership of data, rather than just a reference.
561pub trait IndexOwned<Idx>
562where
563    Idx: ?Sized,
564{
565    /// The result of the indexing operation.
566    type Output;
567
568    /// Indexes the given object, returning owned data.
569    fn index(&self, index: Idx) -> Self::Output;
570}
571
572/// The error type returned when converting
573/// [`Slice`]s to [`SliceOne`]s.
574#[derive(
575    Copy, Clone, Eq, PartialEq, Debug, Default, Hash, Serialize, Deserialize, thiserror::Error,
576)]
577#[error("slice width is not one")]
578pub struct SliceWidthNotOne;
579
580impl TryFrom<Slice> for SliceOne {
581    type Error = SliceWidthNotOne;
582    fn try_from(value: Slice) -> Result<Self, Self::Error> {
583        if value.width() == 1 {
584            Ok(Self {
585                signal: value.signal,
586                index: value.range.map(|s| s.start()),
587            })
588        } else {
589            Err(SliceWidthNotOne)
590        }
591    }
592}
593
594impl TryFrom<&Slice> for SliceOne {
595    type Error = SliceWidthNotOne;
596    fn try_from(value: &Slice) -> Result<Self, Self::Error> {
597        Self::try_from(*value)
598    }
599}
600
601impl From<SliceOne> for Slice {
602    fn from(value: SliceOne) -> Self {
603        Self {
604            signal: value.signal,
605            range: value.range(),
606        }
607    }
608}
609
610impl From<&SliceOne> for Slice {
611    fn from(value: &SliceOne) -> Self {
612        Self::from(*value)
613    }
614}
615
616impl SliceOne {
617    #[inline]
618    pub(crate) fn new(signal: SignalId, index: Option<usize>) -> Self {
619        Self { signal, index }
620    }
621
622    /// The range of indices indexed by this slice.
623    ///
624    /// Returns [`None`] if this slice represents a single bit wire.
625    #[inline]
626    pub fn range(&self) -> Option<SliceRange> {
627        self.index.map(SliceRange::from_index)
628    }
629
630    /// The width of this slice.
631    #[inline]
632    pub const fn width(&self) -> usize {
633        1
634    }
635
636    /// The ID of the signal this slice indexes.
637    #[inline]
638    pub fn signal(&self) -> SignalId {
639        self.signal
640    }
641
642    /// Returns `true` if this signal indexes into a bus.
643    #[inline]
644    pub fn is_bus(&self) -> bool {
645        self.index.is_some()
646    }
647
648    /// The index this single-bit slice contains.
649    #[inline]
650    pub fn index(&self) -> Option<usize> {
651        self.index
652    }
653}