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