facet_core/_trait/impls/
array_impl.rs

1use crate::*;
2use core::alloc::Layout;
3use core::{cmp::Ordering, iter::zip};
4
5unsafe impl<T, const L: usize> Facet for [T; L]
6where
7    T: Facet,
8{
9    const SHAPE: &'static Shape = &const {
10        Shape::builder()
11            .id(ConstTypeId::of::<[T; L]>())
12            .layout(Layout::new::<[T; L]>())
13            .vtable(
14                &const {
15                    let mut builder = ValueVTable::builder()
16                        .marker_traits(T::SHAPE.vtable.marker_traits)
17                        .type_name(|f, opts| {
18                            if let Some(opts) = opts.for_children() {
19                                write!(f, "[")?;
20                                (T::SHAPE.vtable.type_name)(f, opts)?;
21                                write!(f, "; {L}]")
22                            } else {
23                                write!(f, "[⋯; {L}]")
24                            }
25                        })
26                        .drop_in_place(|value| unsafe {
27                            core::ptr::drop_in_place(value.as_mut::<[T; L]>());
28                        });
29                    if T::SHAPE.vtable.display.is_some() {
30                        builder = builder.display(|value, f| {
31                            let value = unsafe { value.as_ref::<[T; L]>() };
32                            write!(f, "[")?;
33
34                            for (idx, value) in value.iter().enumerate() {
35                                unsafe {
36                                    (T::SHAPE.vtable.display.unwrap_unchecked())(
37                                        OpaqueConst::new(value),
38                                        f,
39                                    )?
40                                };
41                                if idx != L - 1 {
42                                    write!(f, ", ")?;
43                                }
44                            }
45                            write!(f, "]")
46                        });
47                    }
48                    if T::SHAPE.vtable.debug.is_some() {
49                        builder = builder.debug(|value, f| {
50                            let value = unsafe { value.as_ref::<[T; L]>() };
51                            write!(f, "[")?;
52
53                            for (idx, value) in value.iter().enumerate() {
54                                unsafe {
55                                    (T::SHAPE.vtable.debug.unwrap_unchecked())(
56                                        OpaqueConst::new(value),
57                                        f,
58                                    )?
59                                };
60                                if idx != L - 1 {
61                                    write!(f, ", ")?;
62                                }
63                            }
64                            write!(f, "]")
65                        });
66                    }
67                    if T::SHAPE.vtable.eq.is_some() {
68                        builder = builder.eq(|a, b| {
69                            let a = unsafe { a.as_ref::<[T; L]>() };
70                            let b = unsafe { b.as_ref::<[T; L]>() };
71                            zip(a, b).all(|(a, b)| unsafe {
72                                (T::SHAPE.vtable.eq.unwrap_unchecked())(
73                                    OpaqueConst::new(a),
74                                    OpaqueConst::new(b),
75                                )
76                            })
77                        });
78                    }
79                    if L == 0 {
80                        // Zero-length arrays implement `Default` irrespective of the element type
81                        builder =
82                            builder.default_in_place(|target| unsafe { target.assume_init() });
83                    } else if L <= 32 && T::SHAPE.vtable.default_in_place.is_some() {
84                        builder = builder.default_in_place(|target| unsafe {
85                            let t_dip = T::SHAPE.vtable.default_in_place.unwrap_unchecked();
86                            let stride = T::SHAPE.layout.pad_to_align().size();
87                            for idx in 0..L {
88                                t_dip(target.field_uninit(idx * stride));
89                            }
90                            target.assume_init()
91                        });
92                    } else {
93                        // arrays do not yet implement `Default` for > 32 elements due to
94                        // specializing the `0` len case
95                    }
96                    if T::SHAPE.vtable.clone_into.is_some() {
97                        builder = builder.clone_into(|src, dst| unsafe {
98                            let t_cip = T::SHAPE.vtable.clone_into.unwrap_unchecked();
99                            let src = src.as_ref::<[T; L]>();
100                            let stride = T::SHAPE.layout.pad_to_align().size();
101                            for (idx, src) in src.iter().enumerate() {
102                                (t_cip)(OpaqueConst::new(src), dst.field_uninit(idx * stride));
103                            }
104                            dst.assume_init()
105                        });
106                    }
107                    if T::SHAPE.vtable.partial_ord.is_some() {
108                        builder = builder.partial_ord(|a, b| {
109                            let a = unsafe { a.as_ref::<[T; L]>() };
110                            let b = unsafe { b.as_ref::<[T; L]>() };
111                            zip(a, b)
112                                .find_map(|(a, b)| unsafe {
113                                    match (T::SHAPE.vtable.partial_ord.unwrap_unchecked())(
114                                        OpaqueConst::new(a),
115                                        OpaqueConst::new(b),
116                                    ) {
117                                        Some(Ordering::Equal) => None,
118                                        c => Some(c),
119                                    }
120                                })
121                                .unwrap_or(Some(Ordering::Equal))
122                        });
123                    }
124                    if T::SHAPE.vtable.ord.is_some() {
125                        builder = builder.ord(|a, b| {
126                            let a = unsafe { a.as_ref::<[T; L]>() };
127                            let b = unsafe { b.as_ref::<[T; L]>() };
128                            zip(a, b)
129                                .find_map(|(a, b)| unsafe {
130                                    match (T::SHAPE.vtable.ord.unwrap_unchecked())(
131                                        OpaqueConst::new(a),
132                                        OpaqueConst::new(b),
133                                    ) {
134                                        Ordering::Equal => None,
135                                        c => Some(c),
136                                    }
137                                })
138                                .unwrap_or(Ordering::Equal)
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; L]>() };
144                            for value in value {
145                                unsafe {
146                                    (T::SHAPE.vtable.hash.unwrap_unchecked())(
147                                        OpaqueConst::new(value),
148                                        state,
149                                        hasher,
150                                    )
151                                }
152                            }
153                        });
154                    }
155                    builder.build()
156                },
157            )
158            .def(Def::List(
159                ListDef::builder()
160                    .vtable(
161                        &const {
162                            ListVTable::builder()
163                        .init_in_place_with_capacity(|_, _| Err(()))
164                        .push(|_, _| {
165                            panic!("Cannot push to [T; {L}]");
166                        })
167                        .len(|_| L)
168                        .get_item_ptr(|ptr, index| unsafe {
169                            if index >= L {
170                                panic!(
171                                    "Index out of bounds: the len is {L} but the index is {index}"
172                                );
173                            }
174                            OpaqueConst::new(ptr.as_ptr::<[T; L]>())
175                        })
176                        .build()
177                        },
178                    )
179                    .t(T::SHAPE)
180                    .build(),
181            ))
182            .build()
183    };
184}