1use crate::{array::Array, primitive::Primitive};
2
3pub trait Tuple: Primitive {
4 const N: usize;
5}
6
7pub trait HomogeneousTuple<Item>: Tuple {
8 type Array: Array<Item = Item>;
9
10 fn into_array(self) -> Self::Array
11 where
12 Self: Sized;
13 fn from_array(array: Self::Array) -> Self;
14}
15
16impl Primitive for () {}
17impl Tuple for () {
18 const N: usize = 0;
19}
20impl<T> HomogeneousTuple<T> for () {
21 type Array = [T; 0];
22
23 fn into_array(self) -> Self::Array
24 where
25 Self: Sized,
26 {
27 []
28 }
29
30 fn from_array(_array: Self::Array) -> Self {
31 #[allow(clippy::unused_unit)]
32 ()
33 }
34}
35
36#[cfg_attr(docsrs, doc(fake_variadic))]
37#[cfg_attr(
38 docsrs,
39 doc = "This trait is implemented for tuples up to 12 items long."
40)]
41impl<T1: ?Sized> Primitive for (T1,) {}
42
43#[cfg_attr(docsrs, doc(fake_variadic))]
44#[cfg_attr(
45 docsrs,
46 doc = "This trait is implemented for tuples up to 12 items long."
47)]
48impl<T1: ?Sized> Tuple for (T1,) {
49 const N: usize = 1;
50}
51
52#[cfg_attr(docsrs, doc(fake_variadic))]
53#[cfg_attr(
54 docsrs,
55 doc = "This trait is implemented for tuples up to 12 items long."
56)]
57impl<T> HomogeneousTuple<T> for (T,) {
58 type Array = [T; 1];
59
60 fn into_array(self) -> Self::Array
61 where
62 Self: Sized,
63 {
64 self.into()
65 }
66
67 fn from_array(array: Self::Array) -> Self {
68 array.into()
69 }
70}
71
72macro_rules! replace_expr {
73 ($_t:tt $sub:tt) => {
74 $sub
75 };
76}
77
78macro_rules! homogeneous_tuple {
79 ($($types:tt),*) => {
80 (
81 $(
82 replace_expr!(
83 ($types)
84 T
85 ),
86 )*
87 )
88 };
89}
90
91macro_rules! impl_tuple {
92 ($n:expr => $($types:tt $i:tt),*; $last:tt $last_i:tt) => {
93 #[cfg_attr(docsrs, doc(hidden))]
94 impl<$($types,)* $last: ?Sized> Primitive for ($($types,)* $last,) {}
95 #[cfg_attr(docsrs, doc(hidden))]
96 impl<$($types,)* $last: ?Sized> Tuple for ($($types,)* $last,) {
97 const N: usize = $n;
98 }
99 #[cfg_attr(docsrs, doc(hidden))]
100 impl<T> HomogeneousTuple<T> for homogeneous_tuple!($($types,)* $last) {
101 type Array = [T; $n];
102
103 fn into_array(self) -> Self::Array
104 where
105 Self: Sized
106 {
107 self.into()
108 }
109
110 fn from_array(array: Self::Array) -> Self {
111 array.into()
112 }
113 }
114 }
115}
116
117impl_tuple!(2 => T1 0; T2 1);
122impl_tuple!(3 => T1 0, T2 1; T3 2);
123impl_tuple!(4 => T1 0, T2 1, T3 2; T4 3);
124impl_tuple!(5 => T1 0, T2 1, T3 2, T4 3; T5 4);
125impl_tuple!(6 => T1 0, T2 1, T3 2, T4 3, T5 4; T6 5);
126impl_tuple!(7 => T1 0, T2 1, T3 2, T4 3, T5 4, T6 5; T7 6);
127impl_tuple!(8 => T1 0, T2 1, T3 2, T4 3, T5 4, T6 5, T7 6; T8 7);
128impl_tuple!(9 => T1 0, T2 1, T3 2, T4 3, T5 4, T6 5, T7 6, T8 7; T9 8);
129impl_tuple!(10 => T1 0, T2 1, T3 2, T4 3, T5 4, T6 5, T7 6, T8 7, T9 8; T10 9);
130impl_tuple!(11 => T1 0, T2 1, T3 2, T4 3, T5 4, T6 5, T7 6, T8 7, T9 8, T10 9; T11 10);
131impl_tuple!(12 => T1 0, T2 1, T3 2, T4 3, T5 4, T6 5, T7 6, T8 7, T9 8, T10 9, T11 10; T12 11);
132
133#[cfg(test)]
134mod test {
135 use super::*;
136 extern crate std;
137 use std::{format, prelude::rust_2021::*, println};
138
139 macro_rules! test_from_array {
140 ($($types:tt),+) => {
141 let arr = std::array::from_fn(|i| format!("{i}"));
142 println!("{arr:?}");
143 let tuple = <($($types,)+)>::from_array(arr.clone());
144 let arr2 = tuple.into_array();
145 println!("{arr2:?}");
146 assert_eq!(arr2, arr);
147 }
148 }
149
150 #[test]
151 fn test_from_array_0() {
152 let arr: [String; 0] = [];
153 #[allow(clippy::let_unit_value)]
154 let tuple = <()>::from_array(arr);
155 let _: [String; 0] = tuple.into_array();
156 }
157
158 #[test]
159 fn test_into_array_change_type_0_elements() {
160 let arr: [String; 0] = [];
161 #[allow(clippy::let_unit_value)]
162 let tuple = <()>::from_array(arr);
163 let _: [u8; 0] = tuple.into_array();
164 }
165
166 #[test]
167 fn test_from_array_1() {
168 test_from_array!(String);
169 }
170
171 #[test]
172 fn test_from_array_2() {
173 test_from_array!(String, String);
174 }
175
176 #[test]
177 fn test_from_array_3() {
178 test_from_array!(String, String, String);
179 }
180
181 #[test]
182 fn test_from_array_12() {
183 test_from_array!(
184 String, String, String, String, String, String, String, String, String, String, String,
185 String
186 );
187 }
188}