facet_core/impls_core/
tuple.rs

1use core::{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    // Actually generate the trait implementation, and keep the remaining possible elements around
55    {
56        impl ($($elems:ident.$idx:tt,)+),
57        remaining ($($remaining:ident.$remainingidx:tt,)*)
58    } => {
59        unsafe impl<'a $(, $elems)+> Facet<'a> for ($($elems,)+)
60        where
61            $($elems: Facet<'a>,)+
62        {
63            const VTABLE: &'static ValueVTable = &const {
64                ValueVTable::builder::<Self>()
65                    .type_name(|f, opts| {
66                        write_type_name_list(f, opts, "(", ", ", ")", &[$($elems::SHAPE),+])
67                    })
68                    .drop_in_place(|| Some(|data| unsafe { data.drop_in_place::<Self>() }))
69                    .marker_traits(||
70                        MarkerTraits::all()
71                            $(.intersection($elems::SHAPE.vtable.marker_traits()))+
72                    )
73                    .default_in_place(|| {
74                        let elem_shapes = const { &[$($elems::SHAPE),+] };
75                        if Characteristic::all_default(elem_shapes) {
76                            Some(|mut dst| {
77                                $(
78                                    unsafe {
79                                        (<VTableView<$elems>>::of().default_in_place().unwrap())(
80                                            dst.field_uninit_at(mem::offset_of!(Self, $idx))
81                                        );
82                                    }
83                                )+
84
85                                unsafe { dst.assume_init() }
86                            })
87                        } else {
88                            None
89                        }
90                    })
91                    .build()
92            };
93
94            const SHAPE: &'static Shape = &const {
95                Shape::builder_for_sized::<Self>()
96                    .type_identifier(const {
97                        let fields = [
98                            $(field_in_type!(Self, $idx),)+
99                        ];
100                        if fields.len() == 1 {
101                            "(_)"
102                        } else {
103                            "(⋯)"
104                        }
105                    })
106                    .ty(Type::User(UserType::Struct(StructType {
107                        repr: Repr::default(),
108                        kind: StructKind::Tuple,
109                        fields: &const {[
110                            $(field_in_type!(Self, $idx),)+
111                        ]}
112                    })))
113                    .build()
114            };
115        }
116
117        impl_facet_for_tuple! {
118            continue from ($($elems.$idx,)+),
119            remaining ($($remaining.$remainingidx,)*)
120        }
121    };
122    // The entry point into this macro, all smaller tuple types get implemented as well.
123    { ($first:ident.$firstidx:tt $(, $remaining:ident.$remainingidx:tt)* $(,)?) } => {
124        impl_facet_for_tuple! {
125            impl ($first.$firstidx,),
126            remaining ($($remaining.$remainingidx,)*)
127        }
128    };
129}
130
131#[cfg(feature = "tuples-12")]
132impl_facet_for_tuple! {
133    (T0.0, T1.1, T2.2, T3.3, T4.4, T5.5, T6.6, T7.7, T8.8, T9.9, T10.10, T11.11)
134}
135
136#[cfg(not(feature = "tuples-12"))]
137impl_facet_for_tuple! {
138    (T0.0, T1.1, T2.2, T3.3)
139}