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