1use core::{cmp::Ordering, fmt, mem};
2
3use crate::{
4 Def, Facet, FieldBuilder, HashProxy, OxPtrConst, OxPtrMut, OxRef, PtrConst, PtrMut, Repr,
5 Shape, ShapeBuilder, StructKind, StructType, Type, TypeNameOpts, TypeOpsIndirect, UserType,
6 VTableIndirect,
7};
8
9unsafe fn tuple_debug(
11 ox: OxPtrConst,
12 f: &mut core::fmt::Formatter<'_>,
13) -> Option<core::fmt::Result> {
14 let shape = ox.shape();
15 let ty = match shape.ty {
16 Type::User(UserType::Struct(ref st)) => st,
17 _ => return None,
18 };
19
20 let ptr = ox.ptr();
21 let mut tuple = f.debug_tuple("");
22
23 for field in ty.fields {
24 let field_ptr = unsafe { PtrConst::new(ptr.as_byte_ptr().add(field.offset)) };
25 let field_ox = OxRef::new(field_ptr, field.shape.get());
26 tuple.field(&field_ox);
27 }
28
29 Some(tuple.finish())
30}
31
32unsafe fn tuple_hash(ox: OxPtrConst, hasher: &mut HashProxy<'_>) -> Option<()> {
34 let shape = ox.shape();
35 let ty = match shape.ty {
36 Type::User(UserType::Struct(ref st)) => st,
37 _ => return None,
38 };
39
40 let ptr = ox.ptr();
41
42 for field in ty.fields {
43 let field_ptr = unsafe { PtrConst::new(ptr.as_byte_ptr().add(field.offset)) };
44 let field_shape = field.shape.get();
45 unsafe { field_shape.call_hash(field_ptr, hasher)? };
46 }
47
48 Some(())
49}
50
51unsafe fn tuple_partial_eq(a: OxPtrConst, b: OxPtrConst) -> Option<bool> {
53 let shape = a.shape();
54 let ty = match shape.ty {
55 Type::User(UserType::Struct(ref st)) => st,
56 _ => return None,
57 };
58
59 let a_ptr = a.ptr();
60 let b_ptr = b.ptr();
61
62 for field in ty.fields {
63 let a_field = unsafe { PtrConst::new(a_ptr.as_byte_ptr().add(field.offset)) };
64 let b_field = unsafe { PtrConst::new(b_ptr.as_byte_ptr().add(field.offset)) };
65 let field_shape = field.shape.get();
66 if !unsafe { field_shape.call_partial_eq(a_field, b_field)? } {
67 return Some(false);
68 }
69 }
70
71 Some(true)
72}
73
74unsafe fn tuple_partial_cmp(a: OxPtrConst, b: OxPtrConst) -> Option<Option<Ordering>> {
76 let shape = a.shape();
77 let ty = match shape.ty {
78 Type::User(UserType::Struct(ref st)) => st,
79 _ => return None,
80 };
81
82 let a_ptr = a.ptr();
83 let b_ptr = b.ptr();
84
85 for field in ty.fields {
86 let a_field = unsafe { PtrConst::new(a_ptr.as_byte_ptr().add(field.offset)) };
87 let b_field = unsafe { PtrConst::new(b_ptr.as_byte_ptr().add(field.offset)) };
88 let field_shape = field.shape.get();
89 match unsafe { field_shape.call_partial_cmp(a_field, b_field)? } {
90 Some(Ordering::Equal) => continue,
91 other => return Some(other),
92 }
93 }
94
95 Some(Some(Ordering::Equal))
96}
97
98unsafe fn tuple_cmp(a: OxPtrConst, b: OxPtrConst) -> Option<Ordering> {
100 let shape = a.shape();
101 let ty = match shape.ty {
102 Type::User(UserType::Struct(ref st)) => st,
103 _ => return None,
104 };
105
106 let a_ptr = a.ptr();
107 let b_ptr = b.ptr();
108
109 for field in ty.fields {
110 let a_field = unsafe { PtrConst::new(a_ptr.as_byte_ptr().add(field.offset)) };
111 let b_field = unsafe { PtrConst::new(b_ptr.as_byte_ptr().add(field.offset)) };
112 let field_shape = field.shape.get();
113 match unsafe { field_shape.call_cmp(a_field, b_field)? } {
114 Ordering::Equal => continue,
115 other => return Some(other),
116 }
117 }
118
119 Some(Ordering::Equal)
120}
121
122unsafe fn tuple_drop(ox: OxPtrMut) {
124 let shape = ox.shape();
125 let ty = match shape.ty {
126 Type::User(UserType::Struct(ref st)) => st,
127 _ => return,
128 };
129
130 let ptr = ox.ptr();
131
132 for field in ty.fields {
133 let field_ptr = unsafe { PtrMut::new((ptr.as_byte_ptr() as *mut u8).add(field.offset)) };
134 let field_shape = field.shape.get();
135 unsafe { field_shape.call_drop_in_place(field_ptr) };
136 }
137}
138
139const TUPLE_VTABLE: VTableIndirect = VTableIndirect {
141 display: None,
142 debug: Some(tuple_debug),
143 hash: Some(tuple_hash),
144 invariants: None,
145 parse: None,
146 parse_bytes: None,
147 try_from: None,
148 try_into_inner: None,
149 try_borrow_inner: None,
150 partial_eq: Some(tuple_partial_eq),
151 partial_cmp: Some(tuple_partial_cmp),
152 cmp: Some(tuple_cmp),
153};
154
155static TUPLE_TYPE_OPS: TypeOpsIndirect = TypeOpsIndirect {
157 drop_in_place: tuple_drop,
158 default_in_place: None,
159 clone_into: None,
160 is_truthy: None,
161};
162
163fn tuple_type_name(
165 shape: &'static Shape,
166 f: &mut fmt::Formatter<'_>,
167 opts: TypeNameOpts,
168) -> fmt::Result {
169 let st = match &shape.ty {
170 Type::User(UserType::Struct(st)) if st.kind == StructKind::Tuple => st,
171 _ => return write!(f, "(?)"),
172 };
173
174 write!(f, "(")?;
175 let child_opts = opts.for_children();
177 for (i, field) in st.fields.iter().enumerate() {
178 if i > 0 {
179 write!(f, ", ")?;
180 }
181 if let Some(opts) = child_opts {
182 field.shape.get().write_type_name(f, opts)?;
183 } else {
184 write!(f, "…")?;
185 }
186 }
187 if st.fields.len() == 1 {
189 write!(f, ",")?;
190 }
191 write!(f, ")")?;
192 Ok(())
193}
194
195macro_rules! impl_facet_for_tuple {
196 {
199 continue from ($($elems:ident.$idx:tt,)+),
200 remaining ()
201 } => {};
202 {
203 continue from ($($elems:ident.$idx:tt,)+),
204 remaining ($next:ident.$nextidx:tt, $($remaining:ident.$remainingidx:tt,)*)
205 } => {
206 impl_facet_for_tuple! {
207 impl ($($elems.$idx,)+ $next.$nextidx,),
208 remaining ($($remaining.$remainingidx,)*)
209 }
210 };
211 {
213 impl ($($elems:ident.$idx:tt,)+),
214 remaining ($($remaining:ident.$remainingidx:tt,)*)
215 } => {
216 unsafe impl<'a $(, $elems)+> Facet<'a> for ($($elems,)+)
217 where
218 $($elems: Facet<'a>,)+
219 {
220 const SHAPE: &'static Shape = &const {
221 ShapeBuilder::for_sized::<Self>(
222 if 1 == [$($elems::SHAPE),+].len() {
223 "(_,)"
224 } else {
225 "(…)"
226 }
227 )
228 .type_name(tuple_type_name)
229 .ty(Type::User(UserType::Struct(StructType {
230 repr: Repr::default(),
231 kind: StructKind::Tuple,
232 fields: &const {[
233 $(FieldBuilder::new(stringify!($idx), crate::shape_of::<$elems>, mem::offset_of!(Self, $idx)).build(),)+
234 ]}
235 })))
236 .def(Def::Undefined)
237 .vtable_indirect(&TUPLE_VTABLE)
238 .type_ops_indirect(&TUPLE_TYPE_OPS)
239 .build()
240 };
241 }
242
243 impl_facet_for_tuple! {
244 continue from ($($elems.$idx,)+),
245 remaining ($($remaining.$remainingidx,)*)
246 }
247 };
248 { ($first:ident.$firstidx:tt $(, $remaining:ident.$remainingidx:tt)* $(,)?) } => {
250 impl_facet_for_tuple! {
251 impl ($first.$firstidx,),
252 remaining ($($remaining.$remainingidx,)*)
253 }
254 };
255}
256
257#[cfg(feature = "tuples-12")]
258impl_facet_for_tuple! {
259 (T0.0, T1.1, T2.2, T3.3, T4.4, T5.5, T6.6, T7.7, T8.8, T9.9, T10.10, T11.11)
260}
261
262#[cfg(not(feature = "tuples-12"))]
263impl_facet_for_tuple! {
264 (T0.0, T1.1, T2.2, T3.3)
265}