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)) };
81 let elem_ox = unsafe { OxRef::new(elem_ptr, def.t) };
82 list.entry(&elem_ox);
83 }
84 Some(list.finish())
85}
86
87unsafe fn slice_hash(ox: OxPtrConst, hasher: &mut HashProxy<'_>) -> Option<()> {
89 let shape = ox.shape();
90 let def = get_slice_def(shape)?;
91 let ptr = ox.ptr();
92
93 let len = unsafe { (def.vtable.len)(ptr) };
94 let slice_ptr = unsafe { (def.vtable.as_ptr)(ptr) };
95 let stride = def.t.layout.sized_layout().ok()?.pad_to_align().size();
96
97 for i in 0..len {
98 let elem_ptr = unsafe { PtrConst::new((slice_ptr.raw_ptr()).add(i * stride)) };
99 unsafe { def.t.call_hash(elem_ptr, hasher)? };
100 }
101 Some(())
102}
103
104unsafe fn slice_partial_eq(a: OxPtrConst, b: OxPtrConst) -> Option<bool> {
106 let shape = a.shape();
107 let def = get_slice_def(shape)?;
108
109 let a_len = unsafe { (def.vtable.len)(a.ptr()) };
110 let b_len = unsafe { (def.vtable.len)(b.ptr()) };
111
112 if a_len != b_len {
113 return Some(false);
114 }
115
116 let a_ptr = unsafe { (def.vtable.as_ptr)(a.ptr()) };
117 let b_ptr = unsafe { (def.vtable.as_ptr)(b.ptr()) };
118 let stride = def.t.layout.sized_layout().ok()?.pad_to_align().size();
119
120 for i in 0..a_len {
121 let a_elem = unsafe { PtrConst::new((a_ptr.raw_ptr()).add(i * stride)) };
122 let b_elem = unsafe { PtrConst::new((b_ptr.raw_ptr()).add(i * stride)) };
123 if !unsafe { def.t.call_partial_eq(a_elem, b_elem)? } {
124 return Some(false);
125 }
126 }
127 Some(true)
128}
129
130unsafe fn slice_partial_cmp(a: OxPtrConst, b: OxPtrConst) -> Option<Option<Ordering>> {
132 let shape = a.shape();
133 let def = get_slice_def(shape)?;
134
135 let a_len = unsafe { (def.vtable.len)(a.ptr()) };
136 let b_len = unsafe { (def.vtable.len)(b.ptr()) };
137
138 let a_ptr = unsafe { (def.vtable.as_ptr)(a.ptr()) };
139 let b_ptr = unsafe { (def.vtable.as_ptr)(b.ptr()) };
140 let stride = def.t.layout.sized_layout().ok()?.pad_to_align().size();
141
142 let min_len = a_len.min(b_len);
143 for i in 0..min_len {
144 let a_elem = unsafe { PtrConst::new((a_ptr.raw_ptr()).add(i * stride)) };
145 let b_elem = unsafe { PtrConst::new((b_ptr.raw_ptr()).add(i * stride)) };
146 match unsafe { def.t.call_partial_cmp(a_elem, b_elem)? } {
147 Some(Ordering::Equal) => continue,
148 other => return Some(other),
149 }
150 }
151 Some(Some(a_len.cmp(&b_len)))
152}
153
154unsafe fn slice_cmp(a: OxPtrConst, b: OxPtrConst) -> Option<Ordering> {
156 let shape = a.shape();
157 let def = get_slice_def(shape)?;
158
159 let a_len = unsafe { (def.vtable.len)(a.ptr()) };
160 let b_len = unsafe { (def.vtable.len)(b.ptr()) };
161
162 let a_ptr = unsafe { (def.vtable.as_ptr)(a.ptr()) };
163 let b_ptr = unsafe { (def.vtable.as_ptr)(b.ptr()) };
164 let stride = def.t.layout.sized_layout().ok()?.pad_to_align().size();
165
166 let min_len = a_len.min(b_len);
167 for i in 0..min_len {
168 let a_elem = unsafe { PtrConst::new((a_ptr.raw_ptr()).add(i * stride)) };
169 let b_elem = unsafe { PtrConst::new((b_ptr.raw_ptr()).add(i * stride)) };
170 match unsafe { def.t.call_cmp(a_elem, b_elem)? } {
171 Ordering::Equal => continue,
172 other => return Some(other),
173 }
174 }
175 Some(a_len.cmp(&b_len))
176}
177
178const SLICE_VTABLE: VTableIndirect = VTableIndirect {
180 display: None,
181 debug: Some(slice_debug),
182 hash: Some(slice_hash),
183 invariants: None,
184 parse: None,
185 parse_bytes: None,
186 try_from: None,
187 try_into_inner: None,
188 try_borrow_inner: None,
189 partial_eq: Some(slice_partial_eq),
190 partial_cmp: Some(slice_partial_cmp),
191 cmp: Some(slice_cmp),
192};
193
194unsafe impl<'a, T> Facet<'a> for [T]
195where
196 T: Facet<'a>,
197{
198 const SHAPE: &'static Shape = &const {
199 const fn build_type_name<'a, T: Facet<'a>>() -> TypeNameFn {
200 fn type_name_impl<'a, T: Facet<'a>>(
201 _shape: &'static Shape,
202 f: &mut core::fmt::Formatter<'_>,
203 opts: TypeNameOpts,
204 ) -> core::fmt::Result {
205 if let Some(opts) = opts.for_children() {
206 write!(f, "[")?;
207 T::SHAPE.write_type_name(f, opts)?;
208 write!(f, "]")
209 } else {
210 write!(f, "[…]")
211 }
212 }
213 type_name_impl::<T>
214 }
215
216 const fn build_slice_vtable<'a, T: Facet<'a>>() -> SliceVTable {
217 SliceVTable {
218 len: slice_len::<T>,
219 as_ptr: slice_as_ptr::<T>,
220 as_mut_ptr: slice_as_mut_ptr::<T>,
221 }
222 }
223
224 ShapeBuilder::for_unsized::<Self>("[_]")
225 .type_name(build_type_name::<T>())
226 .vtable_indirect(&SLICE_VTABLE)
227 .ty(Type::Sequence(SequenceType::Slice(SliceType {
228 t: T::SHAPE,
229 })))
230 .def(Def::Slice(SliceDef::new(
231 &const { build_slice_vtable::<T>() },
232 T::SHAPE,
233 )))
234 .type_params(&[TypeParam {
235 name: "T",
236 shape: T::SHAPE,
237 }])
238 .type_ops_indirect(
239 &const {
240 TypeOpsIndirect {
241 drop_in_place: slice_drop,
242 default_in_place: None,
243 clone_into: None,
244 is_truthy: Some(slice_truthy::<T>),
245 }
246 },
247 )
248 .build()
249 };
250}