tuple_conv/
lib.rs

1//! A simple crate for providing conversions from tuples to vectors and boxed
2//! slices.
3//!
4//! # Small example
5//!
6//! This crate is pretty simple. Here's a trivial example.
7//!
8//! ```rust
9//! # extern crate tuple_conv;
10//! # use tuple_conv::RepeatedTuple;
11//! let t = (0, 1, 2);
12//! let v = t.to_vec();
13//! assert_eq!(v, [0, 1, 2]);
14//! ```
15//!
16//! # Motivation
17//!
18//! The primary motivation for using these tools is for syntactic elegance. In
19//! APIs where a small, but variable number of arguments of a single type is
20//! wanted, it's standard to use a `Vec<T>`. This can become cumbersome for the
21//! user, however - particularly when we have nested types. See, for example:
22//! ```
23//! fn do_something_2d(a: Vec<Vec<i32>>) { /* ... */ }
24//!
25//! do_something_2d(vec![vec![1, 2, 3],
26//!                      vec![4, 5, 6],
27//!                      vec![7, 8, 9]]);
28//! ```
29//! Calling this function is somewhat cumbersome, and can be made cleaner with:
30//! ```
31//! # extern crate tuple_conv;
32//! # use tuple_conv::RepeatedTuple;
33//! fn do_something_2d<T, S>(a: T) where
34//!     T: RepeatedTuple<S>,
35//!     S: RepeatedTuple<i32>,
36//! { /* ... */ }
37//!
38//! do_something_2d(((1, 2, 3),
39//!                  (4, 5, 6),
40//!                  (7, 8, 9)));
41//! ```
42//! Even though it starts to give us flashbacks from LISP, more of our code is
43//! made up of things we actually care about - gone with the `vec` macros
44//! everywhere. The primary benefit is simpler syntax.
45//!
46//! # Typical usage
47//!
48//! Although we can use [`RepeatedTuple`] as a type restriction, this would
49//! usually be replacing a `Vec`, so there's a good chance we'd still like to
50//! allow it. The main usage for this crate is then with the [`TupleOrVec`]
51//! trait - it's implemented for all repeated tuples and for every `Vec`, which
52//! allows us to easily change the public-facing API to allow tuples without
53//! removing any functionality.
54//!
55//! Here's how we'd go about doing that, given a function `foo` that takes some
56//! `Vec`:
57//! ```
58//! fn foo(v: Vec<&str>) {
59//!     /* do stuff */
60//! }
61//!
62//! // a typical way to call `foo`:
63//! foo(vec!["bar", "baz"]);
64//! ```
65//! The first step is to change the function signature to accept tuples:
66//! ```
67//! extern crate tuple_conv;
68//! use tuple_conv::TupleOrVec;
69//!
70//! // ...
71//!
72//! fn foo<V: TupleOrVec<&'static str>>(v: V) {
73//!     /* do stuff */
74//! }
75//! ```
76//! Then, convert the argument
77//! ```
78//! # extern crate tuple_conv;
79//! # use tuple_conv::TupleOrVec;
80//! fn foo<V: TupleOrVec<&'static str>>(v: V) {
81//!     let v = v.as_vec();
82//!     /* do stuff */
83//! }
84//! ```
85//! And now we can call `foo` like this:
86//! ```
87//! # extern crate tuple_conv;
88//! # use tuple_conv::TupleOrVec;
89//! # fn foo<V: TupleOrVec<&'static str>>(v: V) {}
90//! foo(("bar", "baz"));
91//! foo(vec!["baz", "bar"]);
92//! ```
93//! It is, however, worth keeping in mind the implications of large generic
94//! functions implemented for many types. This is discussed in more detail
95//! [below](#performance).
96//!
97//! # Limitations and performance
98//!
99//! ### Limitations
100//!
101//! Because each new tuple is a distinct type, we can only implement for
102//! finitely many tuple lengths. We've chosen to go up to tuples with 64
103//! elements of the same type. If you find yourself needing more (although I
104//! suspect this will be unlikely), the source is **relatively** simple, and
105//! not too difficult to extend.
106//!
107//! Additionally, because of the Rust's visibility rules for public traits,
108//! there isn't a good way to ensure that certain traits aren't implemented by
109//! others - like [`TupleOrVec`] for example. That being said, the trait is
110//! defined such that it *shouldn't* matter.
111//!
112//! ### Performance
113//!
114//! The details of the implementation are such that vectors are constructed in
115//! reverse, and `Vec<_>.reverse()` called, due to a limitation of Rust's macro
116//! system.
117//!
118//! This is not very significant (only ~10% increase with tuples of length 64),
119//! but something worth considering for performance-critical code. For more
120//! detail, pull this repository on [GitHub](add-link.com) and run
121//! `cargo bench`.
122//!
123//! There are two other considerations: time to compile and final binary size.
124//! These should usually be very minor - hardly noticeable. However: if you
125//! are having issues, keep this in mind:  While these both may increase for
126//! functions that are being implemented on many types, it may be possible to
127//! reduce them by using public functions simply as wrappers for your internals
128//! that only take vectors.
129//!
130//! [`RepeatedTuple`]: trait.RepeatedTuple.html
131//! [`TupleOrVec`]: trait.TupleOrVec.html
132
133/// A trait implemented on all tuples composed of a single type.[^1]
134///
135/// The available methods for this trait are what make up the standard way to
136/// use this crate. Importing `RepeatedTuple` allows these methods to be called
137/// directly on types you're working with. This trait can also be used loosely
138/// as a bound specifically for repeated tuples, though there's nothing
139/// stopping someone from implementing it on their own type.
140///
141/// A particularly nice use case of `RepeatedTuple` is ensuring a nice syntax
142/// for your API. Because this is already discussed in the
143/// [crate-level documentation], more examples will not be given here.
144///
145/// ### A few notes:
146///
147/// While this trait **can** be used as a trait bound, you may find it better
148/// to instead use [`TupleOrVec`], as it also encapsulates vectors.
149///
150/// Additionally, while it is true in practice, there is no blanket
151/// implementation of `TupleOrVec` for all `RepeatedTuple`, due to compiler
152/// constraints.
153///
154/// Finally: The typical use case does not recommend or require re-implementing
155/// this trait, but nothing will break if you do.
156///
157/// [^1]: Please note that this is only implemented for tuples up to size 64.
158///     If you need more than 64, please fork this crate or submit a pull
159///     request.
160///
161/// [crate-level documentation]: index.html
162/// [`TupleOrVec`]: trait.TupleOrVec.html
163pub trait RepeatedTuple<E>: Sized {
164    /// Converts a tuple to a boxed slice, with elements in reverse order
165    fn to_boxed_slice_reversed(self) -> Box<[E]>;
166
167    /// Converts a tuple to a boxed slice of its elements
168    fn to_boxed_slice(self) -> Box<[E]> {
169        let mut s = self.to_boxed_slice_reversed();
170        s.reverse();
171        s
172    }
173
174    /// Converts a tuple to a vector, with elements in reverse order
175    fn to_vec_reversed(self) -> Vec<E> {
176        self.to_boxed_slice_reversed().into_vec()
177    }
178
179    /// Converts a tuple to a vector of its elements
180    fn to_vec(self) -> Vec<E> {
181        self.to_boxed_slice().into_vec()
182    }
183}
184
185/// A trait implemented on repeated tuples and vectors.
186///
187/// This trait has already been covered in the [crate-level documentation], so
188/// its coverage here will be brief.
189///
190/// This trait is implemented for all [repeated tuples] and all vectors, and
191/// serves as a drop-in replacement for functions that take vectors as
192/// arguments (albeit with some conversion). Types that were `Vec<T>` should be
193/// converted to generic types that implement `TupleOrVec<T>`.
194///
195/// `TupleOrVec` is not designed with the intent of being implementable, but
196/// there's nothing stopping you from doing so.
197///
198/// [crate-level documentation]: index.html
199/// [repeated tuples]: trait.RepeatedTuple.html
200pub trait TupleOrVec<E> {
201    /// Converts the type to a vec
202    fn as_vec(self) -> Vec<E>;
203}
204
205impl<E> TupleOrVec<E> for Vec<E> {
206    fn as_vec(self) -> Vec<E> {
207        self
208    }
209}
210
211macro_rules! impl_tuple {
212    (
213        $E:ident,
214        ($tup_head:ident, $($tup:ident),+),
215        $idx_head:tt @ $($idx:tt)@+
216    ) => {
217        impl<$E> RepeatedTuple<$E> for ($tup_head, $($tup),+) {
218            fn to_boxed_slice_reversed(self) -> Box<[$E]> {
219                Box::new([self.$idx_head, $(self.$idx),+])
220            }
221        }
222
223        impl<$E> TupleOrVec<$E> for ($tup_head, $($tup),+) {
224            fn as_vec(self) -> Vec<$E> {
225                RepeatedTuple::to_vec(self)
226            }
227        }
228
229        impl_tuple! {
230            $E,
231            ($($tup),+),
232            $($idx)@+
233        }
234    };
235
236    // base case
237    (
238        $E:ident,
239        ($tup:ident),
240        $idx:tt
241    ) => {
242        impl<$E> RepeatedTuple<$E> for ($tup,) {
243            fn to_boxed_slice_reversed(self) -> Box<[$E]> {
244                Box::new([self.$idx])
245            }
246        }
247
248        impl<$E> TupleOrVec<$E> for ($tup,) {
249            fn as_vec(self) -> Vec<$E> {
250                RepeatedTuple::to_vec(self)
251            }
252        }
253    }
254}
255
256impl_tuple! {
257    E,
258
259    (E, E, E, E,
260     E, E, E, E,
261     E, E, E, E,
262     E, E, E, E,
263
264     E, E, E, E,
265     E, E, E, E,
266     E, E, E, E,
267     E, E, E, E,
268
269     E, E, E, E,
270     E, E, E, E,
271     E, E, E, E,
272     E, E, E, E,
273
274     E, E, E, E,
275     E, E, E, E,
276     E, E, E, E,
277     E, E, E, E),
278
279
280    63 @ 62 @ 61 @ 60 @
281    59 @ 58 @ 57 @ 56 @
282    55 @ 54 @ 53 @ 52 @
283    51 @ 50 @ 49 @ 48 @
284
285    47 @ 46 @ 45 @ 44 @
286    43 @ 42 @ 41 @ 40 @
287    39 @ 38 @ 37 @ 36 @
288    35 @ 34 @ 33 @ 32 @
289
290    31 @ 30 @ 29 @ 28 @
291    27 @ 26 @ 25 @ 24 @
292    23 @ 22 @ 21 @ 20 @
293    19 @ 18 @ 17 @ 16 @
294
295    15 @ 14 @ 13 @ 12 @
296    11 @ 10 @  9 @  8 @
297     7 @  6 @  5 @  4 @
298     3 @  2 @  1 @  0
299}
300
301#[cfg(test)]
302mod tests {
303    use crate::RepeatedTuple;
304
305    #[rustfmt::skip]
306    macro_rules! long {
307        (tuple) => {
308            (
309                1, 2, 3, 4, 5, 6, 7, 8,
310                9, 10, 11, 12, 13, 14, 15, 16,
311                17, 18, 19, 20, 21, 22, 23, 24,
312                25, 26, 27, 28, 29, 30, 31, 32,
313                33, 34, 35, 36, 37, 38, 39, 40,
314                41, 42, 43, 44, 45, 46, 47, 48,
315                49, 50, 51, 52, 53, 54, 55, 56,
316                57, 58, 59, 60, 61, 62, 63, 64,
317            )
318        };
319
320        (slice_reversed) => {
321            [
322                64, 63, 62, 61, 60, 59, 58, 57,
323                56, 55, 54, 53, 52, 51, 50, 49,
324                48, 47, 46, 45, 44, 43, 42, 41,
325                40, 39, 38, 37, 36, 35, 34, 33,
326                32, 31, 30, 29, 28, 27, 26, 25,
327                24, 23, 22, 21, 20, 19, 18, 17,
328                16, 15, 14, 13, 12, 11, 10, 9,
329                8, 7, 6, 5, 4, 3, 2, 1,
330            ]
331        };
332    }
333
334    #[test]
335    fn to_boxed_slice_reversed() {
336        let t = (1,);
337        let b = t.to_boxed_slice_reversed();
338        assert!(b == Box::new([1]));
339
340        let t = (1, 2, 3);
341        let b = t.to_boxed_slice_reversed();
342        assert!(b == Box::new([3, 2, 1]));
343
344        let t = long!(tuple);
345        let b = t.to_boxed_slice_reversed();
346        assert!(b == Box::new(long!(slice_reversed)));
347    }
348
349    #[test]
350    fn to_boxed_slice() {
351        let t = (1, 2, 3);
352        let b = t.to_boxed_slice();
353        assert!(b == Box::new([1, 2, 3]));
354    }
355
356    #[test]
357    fn to_vec() {
358        let t = (1, 2, 3);
359        let v = t.to_vec();
360        assert_eq!(v, [1, 2, 3]);
361    }
362
363    #[test]
364    fn to_vec_reversed() {
365        let t = (1, 2, 3);
366        let v = t.to_vec_reversed();
367        assert_eq!(v, [3, 2, 1]);
368    }
369}