facet_core/impls_core/
tuple.rs

1use core::{cmp::Ordering, fmt, mem};
2
3use crate::{
4    Characteristic, Facet, MarkerTraits, Repr, Shape, StructKind, StructType, Type, TypeNameOpts,
5    UserType, VTableView, ValueVTable, types::field_in_type,
6};
7
8#[inline(always)]
9pub fn write_type_name_list(
10    f: &mut fmt::Formatter<'_>,
11    opts: TypeNameOpts,
12    open: &'static str,
13    delimiter: &'static str,
14    close: &'static str,
15    shapes: &'static [&'static Shape],
16) -> fmt::Result {
17    f.pad(open)?;
18    if let Some(opts) = opts.for_children() {
19        for (index, shape) in shapes.iter().enumerate() {
20            if index > 0 {
21                f.pad(delimiter)?;
22            }
23            shape.write_type_name(f, opts)?;
24        }
25    } else {
26        write!(f, "⋯")?;
27    }
28    f.pad(close)?;
29    Ok(())
30}
31
32macro_rules! impl_facet_for_tuple {
33    // Used to implement the next bigger tuple type, by taking the next typename & associated index
34    // out of `remaining`, if it exists.
35    {
36        continue from ($($elems:ident.$idx:tt,)+),
37        remaining ()
38    } => {};
39    {
40        continue from ($($elems:ident.$idx:tt,)+),
41        remaining ($next:ident.$nextidx:tt, $($remaining:ident.$remainingidx:tt,)*)
42    } => {
43        impl_facet_for_tuple! {
44            impl ($($elems.$idx,)+ $next.$nextidx,),
45            remaining ($($remaining.$remainingidx,)*)
46        }
47    };
48    // Handle commas correctly for the debug implementation
49    { debug on $f:ident { $first:stmt; } } => {
50        write!($f, "(")?;
51        $first
52        write!($f, ",)")
53    };
54    { debug on $f:ident { $first:stmt; $($stmt:stmt;)+ } } => {
55        write!($f, "(")?;
56        $first
57        $(
58            write!($f, ", ")?;
59            $stmt
60        )+
61        write!($f, ")")
62    };
63    // Common structure of eq, partial_ord & ord
64    { ord on ($($elems:ident.$idx:tt,)+), $cmp:ident($a:ident, $b:ident), eq = $eq:expr } => {{
65        $(
66            unsafe {
67                let ordering = (<VTableView<$elems>>::of().$cmp().unwrap_unchecked())(
68                    &$a.$idx,
69                    &$b.$idx,
70                );
71
72                if ordering != $eq {
73                    return ordering;
74                }
75            }
76        )+
77
78        $eq
79    }};
80    // Actually generate the trait implementation, and keep the remaining possible elements around
81    {
82        impl ($($elems:ident.$idx:tt,)+),
83        remaining ($($remaining:ident.$remainingidx:tt,)*)
84    } => {
85        unsafe impl<'a $(, $elems)+> Facet<'a> for ($($elems,)+)
86        where
87            $($elems: Facet<'a>,)+
88        {
89            const VTABLE: &'static ValueVTable = &const {
90                ValueVTable::builder::<Self>()
91                    .type_name(|f, opts| {
92                        write_type_name_list(f, opts, "(", ", ", ")", &[$($elems::SHAPE),+])
93                    })
94                    .drop_in_place(|| Some(|data| unsafe { data.drop_in_place::<Self>() }))
95                    .marker_traits(||
96                        MarkerTraits::all()
97                            $(.intersection($elems::SHAPE.vtable.marker_traits()))+
98                    )
99                    .debug(|| {
100                        let elem_shapes = const { &[$($elems::SHAPE),+] };
101                        if Characteristic::Debug.all(elem_shapes) {
102                            Some(|value, f| {
103                                impl_facet_for_tuple! {
104                                    debug on f {
105                                        $(
106                                            (<VTableView<$elems>>::of().debug().unwrap())(
107                                                &value.$idx,
108                                                f,
109                                            )?;
110                                        )+
111                                    }
112                                }
113                            })
114                        } else {
115                            None
116                        }
117                    })
118                    .default_in_place(|| {
119                        let elem_shapes = const { &[$($elems::SHAPE),+] };
120                        if Characteristic::all_default(elem_shapes) {
121                            Some(|mut dst| {
122                                $(
123                                    unsafe {
124                                        (<VTableView<$elems>>::of().default_in_place().unwrap())(
125                                            dst.field_uninit_at(mem::offset_of!(Self, $idx))
126                                        );
127                                    }
128                                )+
129
130                                unsafe { dst.assume_init() }
131                            })
132                        } else {
133                            None
134                        }
135                    })
136                    // .clone_into(|| {
137                    //     let elem_shapes = const { &[$($elems::SHAPE),+] };
138                    //     if Characteristic::Clone.all(elem_shapes) {
139                    //         Some(|src, dst| {
140                    //             $({
141                    //                 let offset = mem::offset_of!(Self, $idx);
142                    //                 unsafe {
143                    //                     (<VTableView<$elems>>::of().clone_into().unwrap())(
144                    //                         src.field(offset),
145                    //                         dst.field_uninit_at(offset),
146                    //                     );
147                    //                 }
148                    //             })+
149
150                    //             unsafe { dst.assume_init() }
151                    //         })
152                    //     } else {
153                    //         None
154                    //     }
155                    // })
156                    .partial_eq(|| {
157                        let elem_shapes = const { &[$($elems::SHAPE),+] };
158                        if Characteristic::all_partial_eq(elem_shapes) {
159                            Some(|a, b| impl_facet_for_tuple! {
160                                ord on ($($elems.$idx,)+),
161                                partial_eq(a, b),
162                                eq = true
163                            })
164                        } else {
165                            None
166                        }
167                    })
168                    .partial_ord(|| {
169                        let elem_shapes = const { &[$($elems::SHAPE),+] };
170                        if Characteristic::all_partial_ord(elem_shapes) {
171                            Some(|a, b| impl_facet_for_tuple! {
172                                ord on ($($elems.$idx,)+),
173                                partial_ord(a, b),
174                                eq = Some(Ordering::Equal)
175                            })
176                        } else {
177                            None
178                        }
179                    })
180                    .ord(|| {
181                        let elem_shapes = const { &[$($elems::SHAPE),+] };
182                        if Characteristic::all_ord(elem_shapes) {
183                            Some(|a, b| impl_facet_for_tuple! {
184                                ord on ($($elems.$idx,)+),
185                                ord(a, b),
186                                eq = Ordering::Equal
187                            })
188                        } else {
189                            None
190                        }
191                    })
192                    .hash(|| {
193                        let elem_shapes = const { &[$($elems::SHAPE),+] };
194                        if Characteristic::all_hash(elem_shapes) {
195                            Some(|value, hasher_this, hasher_write_fn| {
196                                $(
197                                    (<VTableView<$elems>>::of().hash().unwrap())(
198                                        &value.$idx,
199                                        hasher_this,
200                                        hasher_write_fn,
201                                    );
202                                )+
203                            })
204                        } else {
205                            None
206                        }
207                    })
208                    .build()
209            };
210
211            const SHAPE: &'static Shape<'static> = &const {
212                Shape::builder_for_sized::<Self>()
213                    .type_identifier(const {
214                        let fields = [
215                            $(field_in_type!(Self, $idx),)+
216                        ];
217                        if fields.len() == 1 {
218                            "(_)"
219                        } else {
220                            "(⋯)"
221                        }
222                    })
223                    .ty(Type::User(UserType::Struct(StructType {
224                        repr: Repr::default(),
225                        kind: StructKind::Tuple,
226                        fields: &const {[
227                            $(field_in_type!(Self, $idx),)+
228                        ]}
229                    })))
230                    .build()
231            };
232        }
233
234        impl_facet_for_tuple! {
235            continue from ($($elems.$idx,)+),
236            remaining ($($remaining.$remainingidx,)*)
237        }
238    };
239    // The entry point into this macro, all smaller tuple types get implemented as well.
240    { ($first:ident.$firstidx:tt $(, $remaining:ident.$remainingidx:tt)* $(,)?) } => {
241        impl_facet_for_tuple! {
242            impl ($first.$firstidx,),
243            remaining ($($remaining.$remainingidx,)*)
244        }
245    };
246}
247
248#[cfg(feature = "tuples-12")]
249impl_facet_for_tuple! {
250    (T0.0, T1.1, T2.2, T3.3, T4.4, T5.5, T6.6, T7.7, T8.8, T9.9, T10.10, T11.11)
251}
252
253#[cfg(not(feature = "tuples-12"))]
254impl_facet_for_tuple! {
255    (T0.0, T1.1, T2.2, T3.3)
256}