pluralize/
lib.rs

1/*!
2The ```Pluralize``` trait exists to offer a single generic trait which can yield an iterator from any
3reference. This allows generic code to be implemented where the plurality of the generic type is
4flexible. This is accomplished by casting the reference of any single primitive into a single
5element array of the same type and calling the appropriate ```.iter()``` function.
6
7In simplest terms if you specify that a generic type has the bounds ```Pluralize< T >``` then that
8type could be a plain old ```T``` or a ```Vec<T>```. In order to make use of this simply call the
9```.puralize( )``` method and iterate in a for loop.
10
11## Limitations
12
13Currently implementation of Pluralize over ```Option<T>``` is locked behind a feature: Options.  
14Currently implementation of the Remover Iterator is locked behind a feature: Remover.
15
16Both of these features are locked because they represent very janky code which could be broken
17by anything which effects memory layout.
18 */
19
20#![feature(ptr_offset_from)]
21
22extern crate cfg_if;
23use cfg_if::cfg_if;
24
25extern crate alloc;
26use alloc::vec::Vec;
27use core::slice::{Iter, IterMut};
28use core::mem::transmute;
29
30pub mod iter;
31pub use iter::{ Adder, AddController };
32
33cfg_if!{ if #[cfg( any( feature = "Remover", feature = "Options" ) )] {
34pub mod jank;
35}}
36cfg_if!{ if #[cfg( feature = "Remover")] {
37pub use iter::{ Remover, RemoveController };
38}
39else if #[cfg( feature = "Options" )] {
40use jank::{ JankIter, JankIterMut };
41use core::marker::PhantomData;
42}}
43
44/// A trait implemented across both collections and single primitives which exposes an iterator
45pub trait Pluralize< T > {
46    fn pluralize<'a>( &'a self ) -> Iter<'a, T>;
47    fn pluralize_mut<'a>( &'a mut self ) -> IterMut<'a, T>;
48}
49
50/// A trait enabling further mutations to Pluralize<> objects through two Controller-Iterator objects
51pub trait PluralizeControlIter<T, P: Pluralize< T >> {
52    fn adder<'a>( &'a mut self ) -> Adder< 'a, T, P >;
53    cfg_if!{ if #[cfg( feature = "Remover" )] {
54    fn remover<'p, 'a:'p>( &'a mut self ) -> Remover< 'p, 'a, T, P >;
55    }}
56}
57
58impl< T, P > PluralizeControlIter<T, P> for P
59where T: Pluralize< T >,
60      P: Pluralize< T >
61{
62    #[inline(always)]
63    fn adder<'a>( &'a mut self ) -> Adder<'a, T, P> {
64        Adder::new( self )
65    }
66    cfg_if!{ if #[cfg(feature = "Remover")] {
67    fn remover<'p, 'a: 'p>( &'p mut self ) -> Remover<'p, 'a, T, P> {
68        Remover::new( self )
69    }
70    }}
71}
72
73impl< T > Pluralize< T > for Vec<T>
74where T: Pluralize< T > /*If T doesn't also Pluralize over T then we aren't using this as a generic,
75    we're just making a complicated call to .iter()*/
76{
77    #[inline(always)]
78    fn pluralize<'a>( &'a self ) -> Iter<'a, T> {
79        self.iter()
80    }
81
82    #[inline(always)]
83    fn pluralize_mut<'a>( &'a mut self ) -> IterMut<'a, T> {
84        self.iter_mut()
85    }
86}
87
88cfg_if!{ if #[cfg( feature = "Options")]{
89impl< T > Pluralize< T > for Option< T >
90where T: Pluralize< T > {
91    #[inline(always)]
92    fn pluralize<'a>( &'a self ) -> Iter<'a, T> {
93        if self.is_none( ) {
94            // Maybe we should switch this. I have a feeling we could easily seg fault by calling
95            // as_slice
96            let ptr = core::ptr::null( );
97            let end = ptr;
98            unsafe {
99                transmute::< JankIter<'a, T>, Iter<'a, T> > (
100                    JankIter {
101                        ptr: ptr,
102                        end: end,
103                        _marker: PhantomData,
104                    }
105                )
106            }
107        } else {
108            self.as_ref( )
109                .unwrap( )
110                .pluralize( )
111        }
112    }
113
114    #[inline(always)]
115    fn pluralize_mut<'a>( &'a mut self ) -> IterMut<'a, T> {
116        if self.is_none( ) {
117            let ptr = core::ptr::null_mut( );
118            let end = ptr;
119            unsafe{
120                transmute::<JankIterMut<'a, T>, IterMut<'a, T>> (
121                    JankIterMut {
122                        ptr: ptr,
123                        end: end,
124                        _marker: PhantomData
125                    }
126                )
127            }
128        } else {
129            self.as_mut( )
130                .unwrap( )
131                .pluralize_mut( )
132        }
133    }
134}
135}}
136
137macro_rules! impl_tuple_pluralize {
138    ($(
139        $Tuple:ident {
140            $($T:ident),+
141        }
142    )+) => {
143        $(
144            impl < $($T,)+ > Pluralize<($($T,)+)>
145                for ($($T,)+)
146            {
147                #[inline(always)]
148                fn pluralize<'a>( &'a self ) -> Iter<'a, ($($T,)+)> {
149                    unsafe{transmute::<&'a($($T,)+), &'a [($($T,)+);1]>(self)}.iter( )
150                }
151                #[inline(always)]
152                fn pluralize_mut<'a>( &'a mut self ) -> IterMut<'a, ($($T,)+)> {
153                    unsafe{transmute::<&'a mut($($T,)+), &'a mut[($($T,)+);1]>(self)}
154                    .iter_mut( )
155                }
156            }
157        )+
158    }
159}
160
161//Should make an equivelent proc_macro, #[derive(Pluralize)] would take care of import gore
162#[macro_export]
163macro_rules! impl_primitive_pluralize {
164    ( $($t:ty), + ) => {
165        $(
166            impl Pluralize<$t> for $t {
167                #[inline(always)]
168                fn pluralize<'a>( &'a self ) -> Iter<'a, $t> {
169                    unsafe{ core::mem::transmute::<&'a $t, &'a [$t;1]>(self)}.iter( )
170                }
171
172                #[inline(always)]
173                fn pluralize_mut<'a>( &'a mut self ) -> IterMut<'a, $t> {
174                    unsafe{ core::mem::transmute::<&'a mut $t, &'a mut[$t;1]>(self)}.iter_mut( )
175                }
176            }
177        )+
178    }
179}
180
181impl_primitive_pluralize!( i8, i16, i32, i64, i128, isize );
182impl_primitive_pluralize!( u8, u16, u32, u64, u128, usize );
183impl_primitive_pluralize!( bool, char, f32, f64 );
184
185impl_tuple_pluralize!{
186    Tuple1{
187        A
188    }
189    Tuple2{
190        A,
191        B
192    }
193    Tuple3{
194        A,
195        B,
196        C
197    }
198    Tuple4{
199        A,
200        B,
201        C,
202        D
203    }
204    Tuple5{
205        A,
206        B,
207        C,
208        D,
209        E
210    }
211    Tuple6{
212        A,
213        B,
214        C,
215        D,
216        E,
217        F
218    }
219    Tuple7{
220        A,
221        B,
222        C,
223        D,
224        E,
225        F,
226        G
227    }
228    Tuple8{
229        A,
230        B,
231        C,
232        D,
233        E,
234        F,
235        G,
236        H
237    }
238    Tuple9{
239        A,
240        B,
241        C,
242        D,
243        E,
244        F,
245        G,
246        H,
247        I
248    }
249    Tuple10{
250        A,
251        B,
252        C,
253        D,
254        E,
255        F,
256        G,
257        H,
258        I,
259        J
260    }
261    Tuple11{
262        A,
263        B,
264        C,
265        D,
266        E,
267        F,
268        G,
269        H,
270        I,
271        J,
272        K
273    }
274    Tuple12{
275        A,
276        B,
277        C,
278        D,
279        E,
280        F,
281        G,
282        H,
283        I,
284        J,
285        K,
286        L
287    }
288}
289
290#[cfg(test)]
291mod tests {
292    use core::mem::transmute;
293
294    #[test]
295    /// Key assumptions made in the design of the Pluralize trait.
296    fn assumption( ) {
297        let primitive:usize = 5;
298        let scarequotes_slice:&[usize;1] = unsafe{ transmute( &primitive ) };
299
300        // A &usize looks the same as a &[usize;1] in terms of memory layout
301        assert_eq!( primitive, scarequotes_slice[0] );
302    }
303
304}