facet_core/impls_core/slice.rs
1use crate::*;
2use core::alloc::Layout;
3
4unsafe impl<T> Facet for &[T]
5where
6 T: Facet,
7{
8 const SHAPE: &'static Shape = &const {
9 Shape::builder()
10 .id(ConstTypeId::of::<&[T]>())
11 .layout(Layout::new::<&[T]>())
12 .type_params(&[
13 TypeParam {
14 name: "T",
15 shape: || T::SHAPE,
16 }
17 ])
18 .def(Def::Slice(
19 SliceDef::builder()
20 .vtable(
21 &const {
22 SliceVTable::builder()
23 .len(|ptr| unsafe {
24 let slice = ptr.get::<&[T]>();
25 slice.len()
26 })
27 .get_item_ptr(|ptr, index| unsafe {
28 let slice = ptr.get::<&[T]>();
29 let len = slice.len();
30 if index >= len {
31 panic!(
32 "Index out of bounds: the len is {len} but the index is {index}"
33 );
34 }
35 PtrConst::new(slice.as_ptr().add(index))
36 })
37 .build()
38 },
39 )
40 .t(|| T::SHAPE)
41 .build(),
42 ))
43 .vtable(
44 &const {
45 let mut builder = ValueVTable::builder()
46 .type_name(|f, opts| {
47 if let Some(opts) = opts.for_children() {
48 write!(f, "&[")?;
49 (T::SHAPE.vtable.type_name)(f, opts)?;
50 write!(f, "]")
51 } else {
52 write!(f, "&[⋯]")
53 }
54 })
55 .marker_traits(T::SHAPE.vtable.marker_traits)
56 .default_in_place(|ptr| unsafe { ptr.put(&[] as &[T]) })
57 .clone_into(|src, dst| unsafe {
58 // This works because we're cloning a shared reference (&[T]), not the actual slice data.
59 // We're just copying the fat pointer (ptr + length) that makes up the slice reference.
60 dst.put(src.get::<&[T]>())
61 });
62
63 if T::SHAPE.vtable.debug.is_some() {
64 builder = builder.debug(|value, f| {
65 let value = unsafe { value.get::<&[T]>() };
66 write!(f, "[")?;
67 for (i, item) in value.iter().enumerate() {
68 if i > 0 {
69 write!(f, ", ")?;
70 }
71 unsafe {
72 (T::SHAPE.vtable.debug.unwrap_unchecked())(
73 PtrConst::new(item as *const _),
74 f,
75 )?;
76 }
77 }
78 write!(f, "]")
79 });
80 }
81
82 if T::SHAPE.vtable.eq.is_some() {
83 builder = builder.eq(|a, b| {
84 let a = unsafe { a.get::<&[T]>() };
85 let b = unsafe { b.get::<&[T]>() };
86 if a.len() != b.len() {
87 return false;
88 }
89 for (x, y) in a.iter().zip(b.iter()) {
90 if !unsafe {
91 (T::SHAPE.vtable.eq.unwrap_unchecked())(
92 PtrConst::new(x as *const _),
93 PtrConst::new(y as *const _),
94 )
95 } {
96 return false;
97 }
98 }
99 true
100 });
101 }
102
103 if T::SHAPE.vtable.ord.is_some() {
104 builder = builder.ord(|a, b| {
105 let a = unsafe { a.get::<&[T]>() };
106 let b = unsafe { b.get::<&[T]>() };
107 for (x, y) in a.iter().zip(b.iter()) {
108 let ord = unsafe {
109 (T::SHAPE.vtable.ord.unwrap_unchecked())(
110 PtrConst::new(x as *const _),
111 PtrConst::new(y as *const _),
112 )
113 };
114 if ord != core::cmp::Ordering::Equal {
115 return ord;
116 }
117 }
118 a.len().cmp(&b.len())
119 });
120 }
121
122 if T::SHAPE.vtable.partial_ord.is_some() {
123 builder = builder.partial_ord(|a, b| {
124 let a = unsafe { a.get::<&[T]>() };
125 let b = unsafe { b.get::<&[T]>() };
126 for (x, y) in a.iter().zip(b.iter()) {
127 let ord = unsafe {
128 (T::SHAPE.vtable.partial_ord.unwrap_unchecked())(
129 PtrConst::new(x as *const _),
130 PtrConst::new(y as *const _),
131 )
132 };
133 match ord {
134 Some(core::cmp::Ordering::Equal) => continue,
135 Some(order) => return Some(order),
136 None => return None,
137 }
138 }
139 a.len().partial_cmp(&b.len())
140 });
141 }
142
143 if T::SHAPE.vtable.hash.is_some() {
144 builder = builder.hash(|value, state, hasher| {
145 let value = unsafe { value.get::<&[T]>() };
146 for item in value.iter() {
147 unsafe {
148 (T::SHAPE.vtable.hash.unwrap_unchecked())(
149 PtrConst::new(item as *const _),
150 state,
151 hasher,
152 )
153 };
154 }
155 });
156 }
157
158 builder.build()
159 },
160 )
161 .build()
162 };
163}