newtype_array/
lib.rs

1//!# `newtype_array`
2//!
3//!This crate has a single macro, `newtype_arrays`, that will create transparent newtypes for arrays,
4//!and implement standard traits for them. It will be redundant when generic cosntants land, in the
5//!mean time it means you can use large arrays on stable rust.
6//!
7//!# Examples
8//!
9//!```rust
10//!#[macro_use]
11//!extern crate newtype_array;
12//!
13//!use std::collections::HashMap;
14//!
15//!# fn main() {
16//!// Sha385 length
17//!newtype_array!(pub struct Array48(pub 48));
18//!// Sha512 length
19//!newtype_array!(pub struct Array64(pub 64));
20//!
21//!// We've got `Clone` and `PartialEq`/`Eq`
22//!let arr1 = Array48([0u8; 48]);
23//!let arr2 = arr1.clone();
24//!assert_eq!(arr1, arr2);
25//!
26//!// `Hash` is implemented as well
27//!let mut map = HashMap::new();
28//!map.insert(arr1, "hello");
29//!# }
30//!```
31
32// Lifted from rust/src/libcore/array.rs.
33
34#[doc(hidden)]
35#[macro_export(local_inner_macros)]
36macro_rules! __impl_slice_eq1 {
37    ($Lhs: ty, $Rhs: ty) => {
38        __impl_slice_eq1! { $Lhs, $Rhs, Sized }
39    };
40    ($Lhs: ty, $Rhs: ty, $Bound: ident) => {
41        impl<'a, 'b, A: $Bound, B> PartialEq<$Rhs> for $Lhs where A: PartialEq<B> {
42            #[inline]
43            fn eq(&self, other: &$Rhs) -> bool { self[..] == other[..] }
44            #[inline]
45            fn ne(&self, other: &$Rhs) -> bool { self[..] != other[..] }
46        }
47    }
48}
49
50#[doc(hidden)]
51#[macro_export(local_inner_macros)]
52macro_rules! __impl_slice_eq2 {
53    ($Lhs: ty, $Rhs: ty) => {
54        __impl_slice_eq2! { $Lhs, $Rhs, Sized }
55    };
56    ($Lhs: ty, $Rhs: ty, $Bound: ident) => {
57        __impl_slice_eq1!($Lhs, $Rhs, $Bound);
58
59        impl<'a, 'b, A: $Bound, B> PartialEq<$Lhs> for $Rhs where B: PartialEq<A> {
60            #[inline]
61            fn eq(&self, other: &$Lhs) -> bool { self[..] == other[..] }
62            #[inline]
63            fn ne(&self, other: &$Lhs) -> bool { self[..] != other[..] }
64        }
65    }
66}
67
68#[doc(hidden)]
69// macro for implementing n-element array functions and operations
70#[macro_export(local_inner_macros)]
71macro_rules! __array_impls {
72    ($name:ident, $size:expr) => {
73        impl<T> AsRef<[T]> for $name<T> {
74            #[inline]
75            fn as_ref(&self) -> &[T] {
76                &self.0[..]
77            }
78        }
79
80        impl<T> AsMut<[T]> for $name<T> {
81            #[inline]
82            fn as_mut(&mut self) -> &mut [T] {
83                &mut self.0[..]
84            }
85        }
86
87        impl<T> ::std::borrow::Borrow<[T]> for $name<T> {
88            fn borrow(&self) -> &[T] {
89                &self.0
90            }
91        }
92
93        impl<T> ::std::borrow::BorrowMut<[T]> for $name<T> {
94            fn borrow_mut(&mut self) -> &mut [T] {
95                &mut self.0
96            }
97        }
98
99        impl<T: ::std::hash::Hash> ::std::hash::Hash for $name<T> {
100            fn hash<H: ::std::hash::Hasher>(&self, state: &mut H) {
101                ::std::hash::Hash::hash(&self.0[..], state)
102            }
103        }
104
105        impl<T: ::std::fmt::Debug> ::std::fmt::Debug for $name<T> {
106            fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
107                ::std::fmt::Debug::fmt(&&self.0[..], f)
108            }
109        }
110
111        impl<'a, T> IntoIterator for &'a $name<T> {
112            type Item = &'a T;
113            type IntoIter = ::std::slice::Iter<'a, T>;
114
115            fn into_iter(self) -> ::std::slice::Iter<'a, T> {
116                self.0.iter()
117            }
118        }
119
120        impl<'a, T> IntoIterator for &'a mut $name<T> {
121            type Item = &'a mut T;
122            type IntoIter = ::std::slice::IterMut<'a, T>;
123
124            fn into_iter(self) -> ::std::slice::IterMut<'a, T> {
125                self.0.iter_mut()
126            }
127        }
128
129        // NOTE: some less important impls are omitted to reduce code bloat
130        __impl_slice_eq1! { $name<A>, $name<B> }
131        //__impl_slice_eq2! { $name<A>, [B] }
132        //__impl_slice_eq2! { $name<A>, &'b [B] }
133        //__impl_slice_eq2! { $name<A>, &'b mut [B] }
134        // __impl_slice_eq2! { [A; $N], &'b [B; $N] }
135        // __impl_slice_eq2! { [A; $N], &'b mut [B; $N] }
136
137        impl<T:Eq> Eq for $name<T> { }
138
139        impl<T:PartialOrd> PartialOrd for $name<T> {
140            #[inline]
141            fn partial_cmp(&self, other: &$name<T>) -> Option<::std::cmp::Ordering> {
142                PartialOrd::partial_cmp(&&self[..], &&other[..])
143            }
144            #[inline]
145            fn lt(&self, other: &$name<T>) -> bool {
146                PartialOrd::lt(&&self[..], &&other[..])
147            }
148            #[inline]
149            fn le(&self, other: &$name<T>) -> bool {
150                PartialOrd::le(&&self[..], &&other[..])
151            }
152            #[inline]
153            fn ge(&self, other: &$name<T>) -> bool {
154                PartialOrd::ge(&&self[..], &&other[..])
155            }
156            #[inline]
157            fn gt(&self, other: &$name<T>) -> bool {
158                PartialOrd::gt(&&self[..], &&other[..])
159            }
160        }
161
162        impl<T:Ord> Ord for $name<T> {
163            #[inline]
164            fn cmp(&self, other: &$name<T>) -> ::std::cmp::Ordering {
165                Ord::cmp(&&self[..], &&other[..])
166            }
167        }
168
169        // Indexing
170
171        impl<T> ::std::ops::Index<usize> for $name<T> {
172            type Output = T;
173
174            fn index(&self, idx: usize) -> &T {
175                &self.0[idx]
176            }
177        }
178
179        impl<T> ::std::ops::IndexMut<usize> for $name<T> {
180            fn index_mut(&mut self, idx: usize) -> &mut T {
181                &mut self.0[idx]
182            }
183        }
184
185        impl<T> ::std::ops::Index<::std::ops::Range<usize>> for $name<T> {
186            type Output = [T];
187
188            fn index(&self, index: ::std::ops::Range<usize>) -> &[T] {
189                &self.0[index]
190            }
191        }
192
193        impl<T> ::std::ops::IndexMut<::std::ops::Range<usize>> for $name<T> {
194            fn index_mut(&mut self, index: ::std::ops::Range<usize>) -> &mut [T] {
195                &mut self.0[index]
196            }
197        }
198
199        impl<T> ::std::ops::Index<::std::ops::RangeFrom<usize>> for $name<T> {
200            type Output = [T];
201
202            fn index(&self, index: ::std::ops::RangeFrom<usize>) -> &[T] {
203                &self.0[index]
204            }
205        }
206
207        impl<T> ::std::ops::IndexMut<::std::ops::RangeFrom<usize>> for $name<T> {
208            fn index_mut(&mut self, index: ::std::ops::RangeFrom<usize>) -> &mut [T] {
209                &mut self.0[index]
210            }
211        }
212
213        impl<T> ::std::ops::Index<::std::ops::RangeTo<usize>> for $name<T> {
214            type Output = [T];
215
216            fn index(&self, index: ::std::ops::RangeTo<usize>) -> &[T] {
217                &self.0[index]
218            }
219        }
220
221        impl<T> ::std::ops::IndexMut<::std::ops::RangeTo<usize>> for $name<T> {
222            fn index_mut(&mut self, index: ::std::ops::RangeTo<usize>) -> &mut [T] {
223                &mut self.0[index]
224            }
225        }
226
227        impl<T> ::std::ops::Index<::std::ops::RangeInclusive<usize>> for $name<T> {
228            type Output = [T];
229
230            fn index(&self, index: ::std::ops::RangeInclusive<usize>) -> &[T] {
231                &self.0[index]
232            }
233        }
234
235        impl<T> ::std::ops::IndexMut<::std::ops::RangeInclusive<usize>> for $name<T> {
236            fn index_mut(&mut self, index: ::std::ops::RangeInclusive<usize>) -> &mut [T] {
237                &mut self.0[index]
238            }
239        }
240
241        impl<T> ::std::ops::Index<::std::ops::RangeToInclusive<usize>> for $name<T> {
242            type Output = [T];
243
244            fn index(&self, index: ::std::ops::RangeToInclusive<usize>) -> &[T] {
245                &self.0[index]
246            }
247        }
248
249        impl<T> ::std::ops::IndexMut<::std::ops::RangeToInclusive<usize>> for $name<T> {
250            fn index_mut(&mut self, index: ::std::ops::RangeToInclusive<usize>) -> &mut [T] {
251                &mut self.0[index]
252            }
253        }
254        impl<T> ::std::ops::Index<::std::ops::RangeFull> for $name<T> {
255            type Output = [T];
256
257            fn index(&self, index: ::std::ops::RangeFull) -> &[T] {
258                &self.0[index]
259            }
260        }
261
262        impl<T> ::std::ops::IndexMut<::std::ops::RangeFull> for $name<T> {
263            fn index_mut(&mut self, index: ::std::ops::RangeFull) -> &mut [T] {
264                &mut self.0[index]
265            }
266        }
267
268        impl<T> From<[T; $size]> for $name<T> {
269            fn from(from: [T; $size]) -> $name<T> {
270                $name(from)
271            }
272        }
273
274        impl<T> Into<[T; $size]> for $name<T> {
275            fn into(self) -> [T; $size] {
276                self.0
277            }
278        }
279
280        impl<T> AsRef<[T; $size]> for $name<T> {
281            fn as_ref(&self) -> &[T; $size] {
282                &self.0
283            }
284        }
285
286        impl<T: Default + Copy> Default for $name<T> {
287            fn default() -> Self {
288                $name([T::default(); $size])
289            }
290        }
291    }
292}
293
294#[macro_export(local_inner_macros)]
295macro_rules! newtype_array {
296    (pub struct $name:ident(pub $size:expr)) => {
297        /// A newtype around an array. All traits are implemented as you would expect on the raw
298        /// array.
299        #[derive(Copy, Clone)]
300        pub struct $name<T>(pub [T; $size]);
301        __array_impls!($name, $size);
302    };
303    (pub struct $name:ident($size:expr)) => {
304        /// A newtype around an array. All traits are implemented as you would expect on the raw
305        /// array.
306        #[derive(Copy, Clone)]
307        pub struct $name<T>([T; $size]);
308        __array_impls!($name, $size);
309    };
310    (struct $name:ident($size:expr)) => {
311        /// A newtype around an array. All traits are implemented as you would expect on the raw
312        /// array.
313        #[derive(Copy, Clone)]
314        struct $name<T>([T; $size]);
315        __array_impls!($name, $size);
316    }
317}
318
319#[cfg(test)]
320mod tests {
321    use std::collections::HashMap;
322    #[test]
323    fn it_works() {
324
325        // Sha385 length
326        newtype_array!(pub struct Array48(pub 48));
327        // Sha512 length
328        newtype_array!(pub struct Array64(pub 64));
329
330        // We've got `Clone` and `PartialEq`/`Eq`
331        let arr1: Array48<u8> = [0; 48].into();
332        let arr2 = arr1.clone();
333        assert_eq!(arr1, arr2);
334
335        // `Hash` is implemented as well
336        let mut map = HashMap::new();
337        map.insert(arr1, "hello");
338
339        // Check 'Default'
340        let dflt: Array48<u32> = Array48::default();
341        assert_eq!(dflt[0], 0);
342    }
343}