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