|
42 | 42 | } |
43 | 43 | } |
44 | 44 |
|
| 45 | +/// A trait for infallibly converting from one nested tuple type to another. |
| 46 | +/// |
| 47 | +/// This mirrors `From` but works element-wise across nested tuple structures. |
| 48 | +/// |
| 49 | +/// Part of the [`tuplities`](https://docs.rs/tuplities/latest/tuplities/) crate. |
| 50 | +pub trait NestedTupleFrom<T>: Sized { |
| 51 | + /// Converts `other` into `Self` by applying `From` element-wise. |
| 52 | + fn nested_tuple_from(other: T) -> Self; |
| 53 | +} |
| 54 | + |
| 55 | +/// A trait for infallibly converting into another nested tuple type. |
| 56 | +/// |
| 57 | +/// Automatically implemented for any type that implements `NestedTupleFrom`. |
| 58 | +pub trait NestedTupleInto<T>: Sized { |
| 59 | + /// Converts `self` into `T` by applying `From` element-wise. |
| 60 | + fn nested_tuple_into(self) -> T; |
| 61 | +} |
| 62 | + |
| 63 | +impl<T, U> NestedTupleInto<U> for T |
| 64 | +where |
| 65 | + U: NestedTupleFrom<T>, |
| 66 | +{ |
| 67 | + #[inline] |
| 68 | + fn nested_tuple_into(self) -> U { |
| 69 | + U::nested_tuple_from(self) |
| 70 | + } |
| 71 | +} |
| 72 | + |
| 73 | +impl NestedTupleFrom<()> for () { |
| 74 | + #[inline] |
| 75 | + fn nested_tuple_from(_other: ()) -> Self {} |
| 76 | +} |
| 77 | + |
| 78 | +impl<Head, OtherHead> NestedTupleFrom<(OtherHead,)> for (Head,) |
| 79 | +where |
| 80 | + Head: From<OtherHead>, |
| 81 | +{ |
| 82 | + #[inline] |
| 83 | + fn nested_tuple_from(other: (OtherHead,)) -> Self { |
| 84 | + let (other_head,) = other; |
| 85 | + (Head::from(other_head),) |
| 86 | + } |
| 87 | +} |
| 88 | + |
| 89 | +impl<Head, Tail, OtherHead, OtherTail> NestedTupleFrom<(OtherHead, OtherTail)> for (Head, Tail) |
| 90 | +where |
| 91 | + Head: From<OtherHead>, |
| 92 | + Tail: NestedTupleFrom<OtherTail>, |
| 93 | +{ |
| 94 | + #[inline] |
| 95 | + fn nested_tuple_from(other: (OtherHead, OtherTail)) -> Self { |
| 96 | + let (other_head, other_tail) = other; |
| 97 | + let head = Head::from(other_head); |
| 98 | + let tail = Tail::nested_tuple_from(other_tail); |
| 99 | + (head, tail) |
| 100 | + } |
| 101 | +} |
| 102 | + |
45 | 103 | impl<E> NestedTupleTryFrom<(), E> for () { |
46 | 104 | #[inline] |
47 | 105 | fn nested_tuple_try_from(_other: ()) -> Result<Self, E> { |
@@ -116,6 +174,41 @@ mod tests { |
116 | 174 | assert_eq!(target, Ok((1u16, (2u16,)))); |
117 | 175 | } |
118 | 176 |
|
| 177 | + #[test] |
| 178 | + fn test_nested_tuple_from_single() { |
| 179 | + let source = (1u8,); |
| 180 | + let target: (u16,) = NestedTupleFrom::nested_tuple_from(source); |
| 181 | + assert_eq!(target, (1u16,)); |
| 182 | + } |
| 183 | + |
| 184 | + #[test] |
| 185 | + fn test_nested_tuple_from_nested() { |
| 186 | + let source = (1u8, (2u8, (3u8,))); |
| 187 | + let target: (u16, (u16, (u16,))) = NestedTupleFrom::nested_tuple_from(source); |
| 188 | + assert_eq!(target, (1u16, (2u16, (3u16,)))); |
| 189 | + } |
| 190 | + |
| 191 | + #[test] |
| 192 | + fn test_nested_tuple_into() { |
| 193 | + let source = (1u8, (2u8,)); |
| 194 | + let target: (u16, (u16,)) = source.nested_tuple_into(); |
| 195 | + assert_eq!(target, (1u16, (2u16,))); |
| 196 | + } |
| 197 | + |
| 198 | + #[test] |
| 199 | + fn test_nested_tuple_from_empty() { |
| 200 | + let source = (); |
| 201 | + let target: () = NestedTupleFrom::nested_tuple_from(source); |
| 202 | + assert_eq!(target, ()); |
| 203 | + } |
| 204 | + |
| 205 | + #[test] |
| 206 | + fn test_nested_tuple_into_empty() { |
| 207 | + let source = (); |
| 208 | + let target: () = source.nested_tuple_into(); |
| 209 | + assert_eq!(target, ()); |
| 210 | + } |
| 211 | + |
119 | 212 | // Note: We avoid using `TryFromIntError` in these tests to improve portability |
120 | 213 | // and to focus on custom error types that do not implement `From<Infallible>`. |
121 | 214 |
|
|
0 commit comments