1use std::fmt::{self, Debug, Formatter};
2use std::hash::{Hash};
3use std::marker::{PhantomData};
4
5pub trait AsUsize: Debug + Copy + Hash + Eq {
7 fn as_usize(self) -> usize;
8}
9
10#[derive(Clone)]
13pub struct ArrayMap<K: AsUsize, V>(
14 Box<[V]>,
15 PhantomData<K>,
16);
17
18impl<K: AsUsize, V> ArrayMap<K, V> {
19 pub fn new_with(length: usize, f: impl Fn() -> V) -> Self {
20 (0..length).map(|_| f()).collect()
21 }
22
23 pub fn new(length: usize) -> Self where V: Default {
24 Self::new_with(length, Default::default)
25 }
26
27 pub fn is_empty(&self) -> bool { self.0.len() == 0 }
28
29 pub fn len(&self) -> usize { self.0.len() }
30
31 pub fn iter(&self) -> std::slice::Iter<V> { self.0.iter() }
32
33 pub fn iter_mut(&mut self) -> std::slice::IterMut<V> { self.0.iter_mut() }
34}
35
36impl<K: AsUsize, V: Debug> Debug for ArrayMap<K, V> {
37 fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
38 self.0.fmt(f)
39 }
40}
41
42impl<'a, K: AsUsize, V> IntoIterator for &'a ArrayMap<K, V> {
43 type Item = &'a V;
44 type IntoIter = std::slice::Iter<'a, V>;
45
46 fn into_iter(self) -> Self::IntoIter { self.iter() }
47}
48
49impl<'a, K: AsUsize, V> IntoIterator for &'a mut ArrayMap<K, V> {
50 type Item = &'a mut V;
51 type IntoIter = std::slice::IterMut<'a, V>;
52
53 fn into_iter(self) -> Self::IntoIter { self.iter_mut() }
54}
55
56impl<K: AsUsize, V> FromIterator<V> for ArrayMap<K, V> {
57 fn from_iter<T: IntoIterator<Item=V>>(iter: T) -> Self {
58 ArrayMap(iter.into_iter().collect(), PhantomData)
59 }
60}
61
62impl<K: AsUsize, V> AsRef<[V]> for ArrayMap<K, V> {
63 fn as_ref(&self) -> &[V] { self.0.as_ref() }
64}
65
66impl<K: AsUsize, V> AsMut<[V]> for ArrayMap<K, V> {
67 fn as_mut(&mut self) -> &mut [V] { self.0.as_mut() }
68}
69
70impl<K: AsUsize, V> std::ops::Index<K> for ArrayMap<K, V> {
71 type Output = V;
72
73 fn index(&self, index: K) -> &V {
74 &self.0[index.as_usize()]
75 }
76}
77
78impl<K: AsUsize, V> std::ops::IndexMut<K> for ArrayMap<K, V> {
79 fn index_mut(&mut self, index: K) -> &mut V {
80 &mut self.0[index.as_usize()]
81 }
82}
83
84macro_rules! array_index {
102 (
103 $(#[$struct_attributes: meta])*
104 pub struct $Name: ident(
105 $(#[$field_attributes: meta])*
106 $NonZeroUInt: ty
107 ) {
108 debug_name: $debug_name: expr,
109 UInt: $UInt: ty,
110 }
111 ) => {
112 $(#[$struct_attributes])*
113 #[repr(transparent)]
114 pub struct $Name(
115 $(#[$field_attributes])*
116 $NonZeroUInt
117 );
118
119 impl $Name {
120 #[allow(clippy::missing_safety_doc)] #[allow(dead_code)]
125 pub const unsafe fn new_unchecked(index: $UInt) -> Self {
126 Self(<$NonZeroUInt>::new_unchecked(index + 1))
127 }
128
129 #[allow(dead_code)]
130 pub const fn new(index: $UInt) -> Option<Self> {
131 #[allow(clippy::manual_map)] match <$NonZeroUInt>::new(index.wrapping_add(1)) {
133 Some(index) => Some(Self(index)),
134 None => None,
135 }
136 }
137 }
138
139 impl std::fmt::Debug for $Name {
140 fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
141 use crate::util::AsUsize;
142 write!(f, "{}({:?})", $debug_name, self.as_usize())
143 }
144 }
145
146 impl crate::util::AsUsize for $Name {
147 fn as_usize(self) -> usize {
148 self.0.get() as usize - 1
149 }
150 }
151 }
152}
153
154#[cfg(test)]
157pub mod tests {
158 use super::*;
159
160 use std::num::NonZeroU8;
161
162 #[derive(Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
163 #[repr(transparent)]
164 struct Foo(NonZeroU8);
165
166 impl Foo {
167 fn new(index: u8) -> Self {
168 let index = NonZeroU8::new(index + 1).expect("Not a valid array index");
169 Self(index)
170 }
171 }
172
173 impl std::fmt::Debug for Foo {
174 fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
175 write!(f, "Foo({:?})", self.as_usize())
176 }
177 }
178
179 impl AsUsize for Foo {
180 fn as_usize(self) -> usize {
181 self.0.get() as usize - 1
182 }
183 }
184
185 #[test]
186 fn array_map() {
187 assert_eq!(std::mem::size_of::<Foo>(), 1);
188 assert_eq!(std::mem::size_of::<Option<Foo>>(), 1);
189 let i = Foo::new(1);
190 assert_eq!(i.0.get(), 2);
191 assert_eq!(i.as_usize(), 1);
192 assert_eq!(format!("{:#?}", i), "Foo(1)");
193 let mut a = ArrayMap::new(2);
194 assert_eq!(a.as_ref(), &[false, false]);
195 assert_eq!(a.as_mut(), &[false, false]);
196 a[i] = true;
197 assert_eq!(a.as_ref(), &[false, true]);
198 for (i, r) in a.iter().enumerate() {
199 assert_eq!(*r, i>0);
200 }
201 for r in &mut a {
202 *r = !*r;
203 }
204 assert_eq!(a.as_ref(), &[true, false]);
205 a.as_mut()[1] = true;
206 assert_eq!(a.as_ref(), &[true, true]);
207 }
208}