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 parse_bytes: None,
184 try_from: None,
185 try_into_inner: None,
186 try_borrow_inner: None,
187 partial_eq: Some(slice_partial_eq),
188 partial_cmp: Some(slice_partial_cmp),
189 cmp: Some(slice_cmp),
190};
191
192unsafe impl<'a, T> Facet<'a> for [T]
193where
194 T: Facet<'a>,
195{
196 const SHAPE: &'static Shape = &const {
197 const fn build_type_name<'a, T: Facet<'a>>() -> TypeNameFn {
198 fn type_name_impl<'a, T: Facet<'a>>(
199 _shape: &'static Shape,
200 f: &mut core::fmt::Formatter<'_>,
201 opts: TypeNameOpts,
202 ) -> core::fmt::Result {
203 if let Some(opts) = opts.for_children() {
204 write!(f, "[")?;
205 T::SHAPE.write_type_name(f, opts)?;
206 write!(f, "]")
207 } else {
208 write!(f, "[…]")
209 }
210 }
211 type_name_impl::<T>
212 }
213
214 const fn build_slice_vtable<'a, T: Facet<'a>>() -> SliceVTable {
215 SliceVTable {
216 len: slice_len::<T>,
217 as_ptr: slice_as_ptr::<T>,
218 as_mut_ptr: slice_as_mut_ptr::<T>,
219 }
220 }
221
222 ShapeBuilder::for_unsized::<Self>("[_]")
223 .type_name(build_type_name::<T>())
224 .vtable_indirect(&SLICE_VTABLE)
225 .ty(Type::Sequence(SequenceType::Slice(SliceType {
226 t: T::SHAPE,
227 })))
228 .def(Def::Slice(SliceDef::new(
229 &const { build_slice_vtable::<T>() },
230 T::SHAPE,
231 )))
232 .type_params(&[TypeParam {
233 name: "T",
234 shape: T::SHAPE,
235 }])
236 .type_ops_indirect(
237 &const {
238 TypeOpsIndirect {
239 drop_in_place: slice_drop,
240 default_in_place: None,
241 clone_into: None,
242 is_truthy: Some(slice_truthy::<T>),
243 }
244 },
245 )
246 .build()
247 };
248}