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