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