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