typed_vec.rs
1 /// Implement methods for vectors indexed with typed indices. 2 /// 3 /// We use a lot of indices into arrays: we have arrays indexed by input 4 /// segments, arrays indexed by output segments, arrays indexed by output 5 /// endpoints, and more. To help keep these straight, we wrap indices 6 /// in new types, like `SegIdx`, `OutputSegIdx`, etc., and we wrap `Vec` 7 /// in new types, like `SegVec`, `OutputSegVec`, etc. Then you can only 8 /// use the right index type with the right vector type. 9 /// 10 /// This macro implements a bunch of useful methods on the new-type 11 /// wrappers. It assumes that the index new-type is just a wrapper 12 /// around `usize`. 13 macro_rules! impl_typed_vec { 14 ($vec_name:ident, $idx_name:ident, $dbg_prefix:expr) => { 15 impl std::fmt::Debug for $idx_name { 16 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 17 write!(f, "{}_{}", $dbg_prefix, self.0) 18 } 19 } 20 21 #[allow(dead_code)] 22 impl<T> $vec_name<T> { 23 /// Wraps a plain vector. 24 pub fn from_vec(vec: Vec<T>) -> Self { 25 Self { inner: vec } 26 } 27 28 /// Creates a new vector with capacity for at least `cap` output segments before reallocating. 29 pub fn with_capacity(cap: usize) -> Self { 30 Self { 31 inner: Vec::with_capacity(cap), 32 } 33 } 34 35 /// Returns an iterator over all indices into this vector. 36 pub fn indices(&self) -> impl Iterator<Item = $idx_name> { 37 (0..self.inner.len()).map($idx_name) 38 } 39 40 /// The length of this vector. 41 pub fn len(&self) -> usize { 42 self.inner.len() 43 } 44 45 /// Are we empty? 46 pub fn is_empty(&self) -> bool { 47 self.inner.is_empty() 48 } 49 50 /// Adds a new element, returning its index. 51 pub fn push(&mut self, elt: T) -> $idx_name { 52 self.inner.push(elt); 53 $idx_name(self.len() - 1) 54 } 55 56 /// Returns an iterator over indices and elements. 57 pub fn iter(&self) -> impl Iterator<Item = ($idx_name, &T)> + '_ { 58 self.inner 59 .iter() 60 .enumerate() 61 .map(|(idx, t)| ($idx_name(idx), t)) 62 } 63 64 /// Returns an iterator over indices and mutable elements. 65 pub fn iter_mut(&mut self) -> impl Iterator<Item = ($idx_name, &mut T)> + '_ { 66 self.inner 67 .iter_mut() 68 .enumerate() 69 .map(|(idx, t)| ($idx_name(idx), t)) 70 } 71 } 72 73 #[allow(dead_code)] 74 impl<T: Default> $vec_name<T> { 75 /// Creates a new vector with `size` elements, each initialized with the default value. 76 pub fn with_size(size: usize) -> Self { 77 Self { 78 inner: std::iter::from_fn(|| Some(T::default())) 79 .take(size) 80 .collect(), 81 } 82 } 83 } 84 85 impl<T> Default for $vec_name<T> { 86 fn default() -> Self { 87 Self { inner: Vec::new() } 88 } 89 } 90 91 impl<T> std::ops::Index<$idx_name> for $vec_name<T> { 92 type Output = T; 93 94 fn index(&self, index: $idx_name) -> &Self::Output { 95 &self.inner[index.0] 96 } 97 } 98 99 impl<T> std::ops::IndexMut<$idx_name> for $vec_name<T> { 100 fn index_mut(&mut self, index: $idx_name) -> &mut T { 101 &mut self.inner[index.0] 102 } 103 } 104 105 impl<T: std::fmt::Debug> std::fmt::Debug for $vec_name<T> { 106 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 107 struct Entry<'a, T> { 108 idx: $idx_name, 109 inner: &'a T, 110 } 111 112 impl<T: std::fmt::Debug> std::fmt::Debug for Entry<'_, T> { 113 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 114 write!(f, "{idx:?}: {inner:?}", idx = self.idx, inner = self.inner,) 115 } 116 } 117 118 let mut list = f.debug_list(); 119 for idx in self.indices() { 120 list.entry(&Entry { 121 idx, 122 inner: &self[idx], 123 }); 124 } 125 list.finish() 126 } 127 } 128 }; 129 }