facet_core/impls_core/
tuple.rs

1use core::{alloc::Layout, cmp::Ordering, fmt, mem};
2
3use crate::{
4    Characteristic, ConstTypeId, Def, Facet, Field, FieldFlags, MarkerTraits, Shape, StructDef,
5    TypeNameOpts, VTableView, ValueVTable, shape_of,
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 SHAPE: &'static Shape = &const {
90                Shape::builder()
91                    .id(ConstTypeId::of::<Self>())
92                    .layout(Layout::new::<Self>())
93                    .vtable(&const {
94                        let mut builder = ValueVTable::builder::<Self>()
95                            .type_name(|f, opts| {
96                                write_type_name_list(f, opts, "(", ", ", ")", &[$($elems::SHAPE),+])
97                            })
98                            .drop_in_place(|data| unsafe { data.drop_in_place::<Self>() })
99                            .marker_traits(
100                                MarkerTraits::all()
101                                    $(.intersection($elems::SHAPE.vtable.marker_traits))+
102                            );
103
104                        let elem_shapes = const { &[$($elems::SHAPE),+] };
105                        if Characteristic::Debug.all(elem_shapes) {
106                            builder = builder.debug(|value, f| {
107                                impl_facet_for_tuple! {
108                                    debug on f {
109                                        $(
110                                            (<VTableView<$elems>>::of().debug().unwrap())(
111                                                &value.$idx,
112                                                f,
113                                            )?;
114                                        )+
115                                    }
116                                }
117                            });
118                        }
119
120                        if Characteristic::Default.all(elem_shapes) {
121                            builder = builder.default_in_place(|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                        }
133
134                    //     if Characteristic::Clone.all(elem_shapes) {
135                    //          builder = builder.clone_into(|src, dst| {
136                    //             $({
137                    //                 let offset = mem::offset_of!(Self, $idx);
138                    //                 unsafe {
139                    //                     (<VTableView<$elems>>::of().clone_into().unwrap())(
140                    //                         src.field(offset),
141                    //                         dst.field_uninit_at(offset),
142                    //                     );
143                    //                 }
144                    //             })+
145
146                    //             unsafe { dst.assume_init() }
147                    //         });
148                    //    }
149
150                        if Characteristic::PartialEq.all(elem_shapes) {
151                            builder = builder.eq(|a, b| impl_facet_for_tuple! {
152                                ord on ($($elems.$idx,)+),
153                                eq(a, b),
154                                eq = true
155                            });
156                        }
157
158                        if Characteristic::PartialOrd.all(elem_shapes) {
159                            builder = builder.partial_ord(|a, b| impl_facet_for_tuple! {
160                                ord on ($($elems.$idx,)+),
161                                partial_ord(a, b),
162                                eq = Some(Ordering::Equal)
163                            });
164                        }
165
166                        if Characteristic::Ord.all(elem_shapes) {
167                            builder = builder.ord(|a, b| impl_facet_for_tuple! {
168                                ord on ($($elems.$idx,)+),
169                                ord(a, b),
170                                eq = Ordering::Equal
171                            });
172                        }
173
174                        if Characteristic::Hash.all(elem_shapes) {
175                            builder = builder.hash(|value, hasher_this, hasher_write_fn| {
176                                $(
177                                    (<VTableView<$elems>>::of().hash().unwrap())(
178                                        &value.$idx,
179                                        hasher_this,
180                                        hasher_write_fn,
181                                    );
182                                )+
183                           });
184                        }
185
186                        builder.build()
187                    })
188                    .def(Def::Struct({
189                        StructDef::builder()
190                            .tuple()
191                            .fields(
192                                &const {[
193                                    $(
194                                        Field::builder()
195                                            .name(stringify!($idx))
196                                            .shape(|| shape_of(&|t: &Self| &t.$idx))
197                                            .offset(mem::offset_of!(Self, $idx))
198                                            .flags(FieldFlags::EMPTY)
199                                            .build(),
200                                    )+
201                                ]}
202                            )
203                            .build()
204                    }))
205                    .build()
206            };
207        }
208
209        impl_facet_for_tuple! {
210            continue from ($($elems.$idx,)+),
211            remaining ($($remaining.$remainingidx,)*)
212        }
213    };
214    // The entry point into this macro, all smaller tuple types get implemented as well.
215    { ($first:ident.$firstidx:tt $(, $remaining:ident.$remainingidx:tt)* $(,)?) } => {
216        impl_facet_for_tuple! {
217            impl ($first.$firstidx,),
218            remaining ($($remaining.$remainingidx,)*)
219        }
220    };
221}
222
223impl_facet_for_tuple! {
224    (T0.0, T1.1, T2.2, T3.3, T4.4, T5.5, T6.6, T7.7, T8.8, T9.9, T10.10, T11.11)
225}