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, PtrConst, Shape,
5    StructDef, TypeNameOpts, 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        let a = unsafe { $a.get::<Self>() };
66        let b = unsafe { $b.get::<Self>() };
67
68        $(
69            unsafe {
70                let a_ptr = &a.$idx as *const $elems;
71                let b_ptr = &b.$idx as *const $elems;
72
73                let ordering = ($elems::SHAPE.vtable.$cmp.unwrap_unchecked())(
74                    PtrConst::new(a_ptr),
75                    PtrConst::new(b_ptr),
76                );
77
78                if ordering != $eq {
79                    return ordering;
80                }
81            }
82        )+
83
84        $eq
85    }};
86    // Actually generate the trait implementation, and keep the remaining possible elements around
87    {
88        impl ($($elems:ident.$idx:tt,)+),
89        remaining ($($remaining:ident.$remainingidx:tt,)*)
90    } => {
91        unsafe impl<'a $(, $elems)+> Facet<'a> for ($($elems,)+)
92        where
93            $($elems: Facet<'a>,)+
94        {
95            const SHAPE: &'static Shape = &const {
96                Shape::builder()
97                    .id(ConstTypeId::of::<Self>())
98                    .layout(Layout::new::<Self>())
99                    .vtable(&const {
100                        let mut builder = ValueVTable::builder()
101                            .type_name(|f, opts| {
102                                write_type_name_list(f, opts, "(", ", ", ")", &[$($elems::SHAPE),+])
103                            })
104                            .drop_in_place(|data| unsafe { data.drop_in_place::<Self>() })
105                            .marker_traits(
106                                MarkerTraits::all()
107                                    $(.intersection($elems::SHAPE.vtable.marker_traits))+
108                            );
109
110                        let elem_shapes = const { &[$($elems::SHAPE),+] };
111                        if Characteristic::Debug.all(elem_shapes) {
112                            builder = builder.debug(|value, f| {
113                                let value = unsafe { value.get::<Self>() };
114
115                                impl_facet_for_tuple! {
116                                    debug on f {
117                                        $(
118                                            unsafe {
119                                                let ptr = &value.$idx as *const $elems;
120                                                ($elems::SHAPE.vtable.debug.unwrap_unchecked())(
121                                                    PtrConst::new(ptr),
122                                                    f,
123                                                )
124                                            }?;
125                                        )+
126                                    }
127                                }
128                            });
129                        }
130
131                        if Characteristic::Default.all(elem_shapes) {
132                            builder = builder.default_in_place(|dst| {
133                                $(
134                                    unsafe {
135                                        ($elems::SHAPE.vtable.default_in_place.unwrap_unchecked())(
136                                            dst.field_uninit_at(mem::offset_of!(Self, $idx))
137                                        );
138                                    }
139                                )+
140
141                                unsafe { dst.assume_init() }
142                            });
143                        }
144
145                        if Characteristic::Clone.all(elem_shapes) {
146                             builder = builder.clone_into(|src, dst| {
147                                $({
148                                    let offset = mem::offset_of!(Self, $idx);
149                                    unsafe {
150                                        ($elems::SHAPE.vtable.clone_into.unwrap_unchecked())(
151                                            src.field(offset),
152                                            dst.field_uninit_at(offset),
153                                        );
154                                    }
155                                })+
156
157                                unsafe { dst.assume_init() }
158                            });
159                       }
160
161                        if Characteristic::PartialEq.all(elem_shapes) {
162                            builder = builder.eq(|a, b| impl_facet_for_tuple! {
163                                ord on ($($elems.$idx,)+),
164                                eq(a, b),
165                                eq = true
166                            });
167                        }
168
169                        if Characteristic::PartialOrd.all(elem_shapes) {
170                            builder = builder.partial_ord(|a, b| impl_facet_for_tuple! {
171                                ord on ($($elems.$idx,)+),
172                                partial_ord(a, b),
173                                eq = Some(Ordering::Equal)
174                            });
175                        }
176
177                        if Characteristic::Ord.all(elem_shapes) {
178                            builder = builder.ord(|a, b| impl_facet_for_tuple! {
179                                ord on ($($elems.$idx,)+),
180                                ord(a, b),
181                                eq = Ordering::Equal
182                            });
183                        }
184
185                        if Characteristic::Hash.all(elem_shapes) {
186                            builder = builder.hash(|value, hasher_this, hasher_write_fn| {
187                                let value = unsafe { value.get::<Self>() };
188
189                                $(
190                                    unsafe {
191                                        let ptr = &value.$idx as *const $elems;
192
193                                        ($elems::SHAPE.vtable.hash.unwrap_unchecked())(
194                                            PtrConst::new(ptr),
195                                            hasher_this,
196                                            hasher_write_fn,
197                                        );
198                                    }
199                                )+
200                           });
201                        }
202
203                        builder.build()
204                    })
205                    .def(Def::Struct({
206                        StructDef::builder()
207                            .tuple()
208                            .fields(
209                                &const {[
210                                    $(
211                                        Field::builder()
212                                            .name(stringify!($idx))
213                                            .shape(|| shape_of(&|t: &Self| &t.$idx))
214                                            .offset(mem::offset_of!(Self, $idx))
215                                            .flags(FieldFlags::EMPTY)
216                                            .build(),
217                                    )+
218                                ]}
219                            )
220                            .build()
221                    }))
222                    .build()
223            };
224        }
225
226        impl_facet_for_tuple! {
227            continue from ($($elems.$idx,)+),
228            remaining ($($remaining.$remainingidx,)*)
229        }
230    };
231    // The entry point into this macro, all smaller tuple types get implemented as well.
232    { ($first:ident.$firstidx:tt $(, $remaining:ident.$remainingidx:tt)* $(,)?) } => {
233        impl_facet_for_tuple! {
234            impl ($first.$firstidx,),
235            remaining ($($remaining.$remainingidx,)*)
236        }
237    };
238}
239
240impl_facet_for_tuple! {
241    (T0.0, T1.1, T2.2, T3.3, T4.4, T5.5, T6.6, T7.7, T8.8, T9.9, T10.10, T11.11)
242}