facet_core/impls/core/
slice.rs1use core::cmp::Ordering;
2
3use crate::{OxPtrConst, *};
4
5unsafe fn slice_len<T>(ptr: PtrConst) -> usize {
6 unsafe {
7 let slice = ptr.get::<[T]>();
8 slice.len()
9 }
10}
11
12unsafe fn slice_as_ptr<T>(ptr: PtrConst) -> PtrConst {
13 unsafe {
14 let slice = ptr.get::<[T]>();
15 PtrConst::new(slice.as_ptr())
16 }
17}
18
19unsafe fn slice_as_mut_ptr<T>(ptr: PtrMut) -> PtrMut {
20 unsafe {
21 let slice = ptr.as_mut::<[T]>();
22 PtrMut::new(slice.as_mut_ptr())
23 }
24}
25
26unsafe fn slice_drop(ox: OxPtrMut) {
27 let shape = ox.shape();
28 let Some(def) = get_slice_def(shape) else {
29 return;
30 };
31 let len = unsafe { (def.vtable.len)(ox.ptr().as_const()) };
32 let slice_ptr = unsafe { (def.vtable.as_mut_ptr)(ox.ptr()) };
33 let Some(stride) = def
34 .t
35 .layout
36 .sized_layout()
37 .ok()
38 .map(|l| l.pad_to_align().size())
39 else {
40 return;
41 };
42
43 for i in 0..len {
44 let elem_ptr = unsafe { PtrMut::new((slice_ptr.as_byte_ptr() as *mut u8).add(i * stride)) };
45 unsafe { def.t.call_drop_in_place(elem_ptr) };
46 }
47}
48
49#[inline(always)]
50unsafe fn slice_truthy<T>(ptr: PtrConst) -> bool {
51 !unsafe { ptr.get::<[T]>() }.is_empty()
52}
53
54#[inline]
56fn get_slice_def(shape: &'static Shape) -> Option<&'static SliceDef> {
57 match shape.def {
58 Def::Slice(ref def) => Some(def),
59 _ => None,
60 }
61}
62
63unsafe fn slice_debug(
65 ox: OxPtrConst,
66 f: &mut core::fmt::Formatter<'_>,
67) -> Option<core::fmt::Result> {
68 let shape = ox.shape();
69 let def = get_slice_def(shape)?;
70 let ptr = ox.ptr();
71
72 let len = unsafe { (def.vtable.len)(ptr) };
73 let slice_ptr = unsafe { (def.vtable.as_ptr)(ptr) };
74 let stride = def.t.layout.sized_layout().ok()?.pad_to_align().size();
75
76 let mut list = f.debug_list();
77 for i in 0..len {
78 let elem_ptr = unsafe { PtrConst::new((slice_ptr.raw_ptr()).add(i * stride)) };
79 let elem_ox = OxRef::new(elem_ptr, def.t);
80 list.entry(&elem_ox);
81 }
82 Some(list.finish())
83}
84
85unsafe fn slice_hash(ox: OxPtrConst, hasher: &mut HashProxy<'_>) -> Option<()> {
87 let shape = ox.shape();
88 let def = get_slice_def(shape)?;
89 let ptr = ox.ptr();
90
91 let len = unsafe { (def.vtable.len)(ptr) };
92 let slice_ptr = unsafe { (def.vtable.as_ptr)(ptr) };
93 let stride = def.t.layout.sized_layout().ok()?.pad_to_align().size();
94
95 for i in 0..len {
96 let elem_ptr = unsafe { PtrConst::new((slice_ptr.raw_ptr()).add(i * stride)) };
97 unsafe { def.t.call_hash(elem_ptr, hasher)? };
98 }
99 Some(())
100}
101
102unsafe fn slice_partial_eq(a: OxPtrConst, b: OxPtrConst) -> Option<bool> {
104 let shape = a.shape();
105 let def = get_slice_def(shape)?;
106
107 let a_len = unsafe { (def.vtable.len)(a.ptr()) };
108 let b_len = unsafe { (def.vtable.len)(b.ptr()) };
109
110 if a_len != b_len {
111 return Some(false);
112 }
113
114 let a_ptr = unsafe { (def.vtable.as_ptr)(a.ptr()) };
115 let b_ptr = unsafe { (def.vtable.as_ptr)(b.ptr()) };
116 let stride = def.t.layout.sized_layout().ok()?.pad_to_align().size();
117
118 for i in 0..a_len {
119 let a_elem = unsafe { PtrConst::new((a_ptr.raw_ptr()).add(i * stride)) };
120 let b_elem = unsafe { PtrConst::new((b_ptr.raw_ptr()).add(i * stride)) };
121 if !unsafe { def.t.call_partial_eq(a_elem, b_elem)? } {
122 return Some(false);
123 }
124 }
125 Some(true)
126}
127
128unsafe fn slice_partial_cmp(a: OxPtrConst, b: OxPtrConst) -> Option<Option<Ordering>> {
130 let shape = a.shape();
131 let def = get_slice_def(shape)?;
132
133 let a_len = unsafe { (def.vtable.len)(a.ptr()) };
134 let b_len = unsafe { (def.vtable.len)(b.ptr()) };
135
136 let a_ptr = unsafe { (def.vtable.as_ptr)(a.ptr()) };
137 let b_ptr = unsafe { (def.vtable.as_ptr)(b.ptr()) };
138 let stride = def.t.layout.sized_layout().ok()?.pad_to_align().size();
139
140 let min_len = a_len.min(b_len);
141 for i in 0..min_len {
142 let a_elem = unsafe { PtrConst::new((a_ptr.raw_ptr()).add(i * stride)) };
143 let b_elem = unsafe { PtrConst::new((b_ptr.raw_ptr()).add(i * stride)) };
144 match unsafe { def.t.call_partial_cmp(a_elem, b_elem)? } {
145 Some(Ordering::Equal) => continue,
146 other => return Some(other),
147 }
148 }
149 Some(Some(a_len.cmp(&b_len)))
150}
151
152unsafe fn slice_cmp(a: OxPtrConst, b: OxPtrConst) -> Option<Ordering> {
154 let shape = a.shape();
155 let def = get_slice_def(shape)?;
156
157 let a_len = unsafe { (def.vtable.len)(a.ptr()) };
158 let b_len = unsafe { (def.vtable.len)(b.ptr()) };
159
160 let a_ptr = unsafe { (def.vtable.as_ptr)(a.ptr()) };
161 let b_ptr = unsafe { (def.vtable.as_ptr)(b.ptr()) };
162 let stride = def.t.layout.sized_layout().ok()?.pad_to_align().size();
163
164 let min_len = a_len.min(b_len);
165 for i in 0..min_len {
166 let a_elem = unsafe { PtrConst::new((a_ptr.raw_ptr()).add(i * stride)) };
167 let b_elem = unsafe { PtrConst::new((b_ptr.raw_ptr()).add(i * stride)) };
168 match unsafe { def.t.call_cmp(a_elem, b_elem)? } {
169 Ordering::Equal => continue,
170 other => return Some(other),
171 }
172 }
173 Some(a_len.cmp(&b_len))
174}
175
176const SLICE_VTABLE: VTableIndirect = VTableIndirect {
178 display: None,
179 debug: Some(slice_debug),
180 hash: Some(slice_hash),
181 invariants: None,
182 parse: None,
183 try_from: None,
184 try_into_inner: None,
185 try_borrow_inner: None,
186 partial_eq: Some(slice_partial_eq),
187 partial_cmp: Some(slice_partial_cmp),
188 cmp: Some(slice_cmp),
189};
190
191unsafe impl<'a, T> Facet<'a> for [T]
192where
193 T: Facet<'a>,
194{
195 const SHAPE: &'static Shape = &const {
196 const fn build_type_name<'a, T: Facet<'a>>() -> TypeNameFn {
197 fn type_name_impl<'a, T: Facet<'a>>(
198 _shape: &'static Shape,
199 f: &mut core::fmt::Formatter<'_>,
200 opts: TypeNameOpts,
201 ) -> core::fmt::Result {
202 if let Some(opts) = opts.for_children() {
203 write!(f, "[")?;
204 T::SHAPE.write_type_name(f, opts)?;
205 write!(f, "]")
206 } else {
207 write!(f, "[…]")
208 }
209 }
210 type_name_impl::<T>
211 }
212
213 const fn build_slice_vtable<'a, T: Facet<'a>>() -> SliceVTable {
214 SliceVTable {
215 len: slice_len::<T>,
216 as_ptr: slice_as_ptr::<T>,
217 as_mut_ptr: slice_as_mut_ptr::<T>,
218 }
219 }
220
221 ShapeBuilder::for_unsized::<Self>("[_]")
222 .type_name(build_type_name::<T>())
223 .vtable_indirect(&SLICE_VTABLE)
224 .ty(Type::Sequence(SequenceType::Slice(SliceType {
225 t: T::SHAPE,
226 })))
227 .def(Def::Slice(SliceDef::new(
228 &const { build_slice_vtable::<T>() },
229 T::SHAPE,
230 )))
231 .type_params(&[TypeParam {
232 name: "T",
233 shape: T::SHAPE,
234 }])
235 .type_ops_indirect(
236 &const {
237 TypeOpsIndirect {
238 drop_in_place: slice_drop,
239 default_in_place: None,
240 clone_into: None,
241 is_truthy: Some(slice_truthy::<T>),
242 }
243 },
244 )
245 .build()
246 };
247}