facet_core/impls_core/
slice.rs

1use crate::*;
2use core::alloc::Layout;
3
4unsafe impl<'a, T> Facet<'a> for &'a [T]
5where
6    T: Facet<'a>,
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}