facet_core/impls/core/
array.rs1use core::{cmp::Ordering, fmt};
4
5use crate::{
6 ArrayDef, ArrayVTable, Def, Facet, HashProxy, OxPtrConst, OxPtrMut, OxRef, PtrConst, PtrMut,
7 Shape, ShapeBuilder, Type, TypeNameOpts, TypeOpsIndirect, TypeParam, VTableIndirect,
8};
9
10#[inline]
12fn get_array_def(shape: &'static Shape) -> Option<&'static ArrayDef> {
13 match shape.def {
14 Def::Array(ref def) => Some(def),
15 _ => None,
16 }
17}
18
19fn array_type_name(
21 shape: &'static Shape,
22 f: &mut fmt::Formatter<'_>,
23 opts: TypeNameOpts,
24) -> fmt::Result {
25 let def = match &shape.def {
26 Def::Array(def) => def,
27 _ => return write!(f, "[?; ?]"),
28 };
29
30 if let Some(opts) = opts.for_children() {
31 write!(f, "[")?;
32 def.t.write_type_name(f, opts)?;
33 write!(f, "; {}]", def.n)
34 } else {
35 write!(f, "[…; {}]", def.n)
36 }
37}
38
39unsafe fn array_debug(
41 ox: OxPtrConst,
42 f: &mut core::fmt::Formatter<'_>,
43) -> Option<core::fmt::Result> {
44 let shape = ox.shape();
45 let def = get_array_def(shape)?;
46 let ptr = ox.ptr();
47
48 let mut list = f.debug_list();
49 let slice_ptr = unsafe { (def.vtable.as_ptr)(ptr) };
50 let stride = def.t.layout.sized_layout().ok()?.pad_to_align().size();
51
52 for i in 0..def.n {
53 let elem_ptr = unsafe { PtrConst::new((slice_ptr.as_byte_ptr()).add(i * stride)) };
54 let elem_ox = OxRef::new(elem_ptr, def.t);
55 list.entry(&elem_ox);
56 }
57 Some(list.finish())
58}
59
60unsafe fn array_hash(ox: OxPtrConst, hasher: &mut HashProxy<'_>) -> Option<()> {
62 let shape = ox.shape();
63 let def = get_array_def(shape)?;
64 let ptr = ox.ptr();
65
66 let slice_ptr = unsafe { (def.vtable.as_ptr)(ptr) };
67 let stride = def.t.layout.sized_layout().ok()?.pad_to_align().size();
68
69 for i in 0..def.n {
70 let elem_ptr = unsafe { PtrConst::new((slice_ptr.as_byte_ptr()).add(i * stride)) };
71 unsafe { def.t.call_hash(elem_ptr, hasher)? };
72 }
73 Some(())
74}
75
76unsafe fn array_partial_eq(a: OxPtrConst, b: OxPtrConst) -> Option<bool> {
78 let shape = a.shape();
79 let def = get_array_def(shape)?;
80
81 let a_ptr = unsafe { (def.vtable.as_ptr)(a.ptr()) };
82 let b_ptr = unsafe { (def.vtable.as_ptr)(b.ptr()) };
83 let stride = def.t.layout.sized_layout().ok()?.pad_to_align().size();
84
85 for i in 0..def.n {
86 let a_elem = unsafe { PtrConst::new((a_ptr.as_byte_ptr()).add(i * stride)) };
87 let b_elem = unsafe { PtrConst::new((b_ptr.as_byte_ptr()).add(i * stride)) };
88 if !unsafe { def.t.call_partial_eq(a_elem, b_elem)? } {
89 return Some(false);
90 }
91 }
92 Some(true)
93}
94
95unsafe fn array_partial_cmp(a: OxPtrConst, b: OxPtrConst) -> Option<Option<Ordering>> {
97 let shape = a.shape();
98 let def = get_array_def(shape)?;
99
100 let a_ptr = unsafe { (def.vtable.as_ptr)(a.ptr()) };
101 let b_ptr = unsafe { (def.vtable.as_ptr)(b.ptr()) };
102 let stride = def.t.layout.sized_layout().ok()?.pad_to_align().size();
103
104 for i in 0..def.n {
105 let a_elem = unsafe { PtrConst::new((a_ptr.as_byte_ptr()).add(i * stride)) };
106 let b_elem = unsafe { PtrConst::new((b_ptr.as_byte_ptr()).add(i * stride)) };
107 match unsafe { def.t.call_partial_cmp(a_elem, b_elem)? } {
108 Some(Ordering::Equal) => continue,
109 other => return Some(other),
110 }
111 }
112 Some(Some(Ordering::Equal))
113}
114
115unsafe fn array_cmp(a: OxPtrConst, b: OxPtrConst) -> Option<Ordering> {
117 let shape = a.shape();
118 let def = get_array_def(shape)?;
119
120 let a_ptr = unsafe { (def.vtable.as_ptr)(a.ptr()) };
121 let b_ptr = unsafe { (def.vtable.as_ptr)(b.ptr()) };
122 let stride = def.t.layout.sized_layout().ok()?.pad_to_align().size();
123
124 for i in 0..def.n {
125 let a_elem = unsafe { PtrConst::new((a_ptr.as_byte_ptr()).add(i * stride)) };
126 let b_elem = unsafe { PtrConst::new((b_ptr.as_byte_ptr()).add(i * stride)) };
127 match unsafe { def.t.call_cmp(a_elem, b_elem)? } {
128 Ordering::Equal => continue,
129 other => return Some(other),
130 }
131 }
132 Some(Ordering::Equal)
133}
134
135unsafe fn array_drop(ox: OxPtrMut) {
137 let shape = ox.shape();
138 let Some(def) = get_array_def(shape) else {
139 return;
140 };
141 let ptr = ox.ptr();
142
143 let slice_ptr = unsafe { (def.vtable.as_mut_ptr)(ptr) };
144 let Some(stride) = def
145 .t
146 .layout
147 .sized_layout()
148 .ok()
149 .map(|l| l.pad_to_align().size())
150 else {
151 return;
152 };
153
154 for i in 0..def.n {
155 let elem_ptr = unsafe { PtrMut::new((slice_ptr.as_byte_ptr() as *mut u8).add(i * stride)) };
156 unsafe { def.t.call_drop_in_place(elem_ptr) };
157 }
158}
159
160unsafe fn array_default(ox: OxPtrMut) {
162 let shape = ox.shape();
163 let Some(def) = get_array_def(shape) else {
164 return;
165 };
166 let ptr = ox.ptr();
167
168 let slice_ptr = unsafe { (def.vtable.as_mut_ptr)(ptr) };
169 let Some(stride) = def
170 .t
171 .layout
172 .sized_layout()
173 .ok()
174 .map(|l| l.pad_to_align().size())
175 else {
176 return;
177 };
178
179 for i in 0..def.n {
180 let elem_ptr = unsafe { PtrMut::new((slice_ptr.as_byte_ptr() as *mut u8).add(i * stride)) };
181 if unsafe { def.t.call_default_in_place(elem_ptr) }.is_none() {
182 return;
183 }
184 }
185}
186
187unsafe fn array_clone(src: OxPtrConst, dst: OxPtrMut) {
189 let shape = src.shape();
190 let Some(def) = get_array_def(shape) else {
191 return;
192 };
193
194 let src_ptr = unsafe { (def.vtable.as_ptr)(src.ptr()) };
195 let dst_ptr = unsafe { (def.vtable.as_mut_ptr)(dst.ptr()) };
196 let Some(stride) = def
197 .t
198 .layout
199 .sized_layout()
200 .ok()
201 .map(|l| l.pad_to_align().size())
202 else {
203 return;
204 };
205
206 for i in 0..def.n {
207 let src_elem = unsafe { PtrConst::new((src_ptr.as_byte_ptr()).add(i * stride)) };
208 let dst_elem = unsafe { PtrMut::new((dst_ptr.as_byte_ptr() as *mut u8).add(i * stride)) };
209 if unsafe { def.t.call_clone_into(src_elem, dst_elem) }.is_none() {
210 return;
211 }
212 }
213}
214
215const ARRAY_VTABLE: VTableIndirect = VTableIndirect {
217 display: None,
218 debug: Some(array_debug),
219 hash: Some(array_hash),
220 invariants: None,
221 parse: None,
222 parse_bytes: None,
223 try_from: None,
224 try_into_inner: None,
225 try_borrow_inner: None,
226 partial_eq: Some(array_partial_eq),
227 partial_cmp: Some(array_partial_cmp),
228 cmp: Some(array_cmp),
229};
230
231unsafe fn array_as_ptr<T, const N: usize>(ptr: PtrConst) -> PtrConst {
233 let array = unsafe { ptr.get::<[T; N]>() };
234 PtrConst::new(array.as_ptr() as *const u8)
235}
236
237unsafe fn array_as_mut_ptr<T, const N: usize>(ptr: PtrMut) -> PtrMut {
239 let array = unsafe { ptr.as_mut::<[T; N]>() };
240 PtrMut::new(array.as_mut_ptr() as *mut u8)
241}
242
243unsafe impl<'a, T, const N: usize> Facet<'a> for [T; N]
244where
245 T: Facet<'a>,
246{
247 const SHAPE: &'static Shape = &const {
248 const fn build_array_vtable<T, const N: usize>() -> ArrayVTable {
249 ArrayVTable::builder()
250 .as_ptr(array_as_ptr::<T, N>)
251 .as_mut_ptr(array_as_mut_ptr::<T, N>)
252 .build()
253 }
254
255 ShapeBuilder::for_sized::<[T; N]>("[T; N]")
256 .type_name(array_type_name)
257 .ty(Type::Sequence(crate::SequenceType::Array(
258 crate::ArrayType { t: T::SHAPE, n: N },
259 )))
260 .def(Def::Array(ArrayDef::new(
261 &const { build_array_vtable::<T, N>() },
262 T::SHAPE,
263 N,
264 )))
265 .type_params(&[TypeParam {
266 name: "T",
267 shape: T::SHAPE,
268 }])
269 .vtable_indirect(&ARRAY_VTABLE)
270 .type_ops_indirect(
271 &const {
272 unsafe fn truthy<const N: usize>(_: PtrConst) -> bool {
273 N != 0
274 }
275
276 TypeOpsIndirect {
277 drop_in_place: array_drop,
278 default_in_place: Some(array_default),
279 clone_into: Some(array_clone),
280 is_truthy: Some(truthy::<N>),
281 }
282 },
283 )
284 .build()
285 };
286}