facet_core/impls_core/
array.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 { value.drop_in_place::<[T; L]>() });
27                    if T::SHAPE.vtable.display.is_some() {
28                        builder = builder.display(|value, f| {
29                            let value = unsafe { value.get::<[T; L]>() };
30                            write!(f, "[")?;
31
32                            for (idx, value) in value.iter().enumerate() {
33                                unsafe {
34                                    (T::SHAPE.vtable.display.unwrap_unchecked())(
35                                        PtrConst::new(value),
36                                        f,
37                                    )?
38                                };
39                                if idx != L - 1 {
40                                    write!(f, ", ")?;
41                                }
42                            }
43                            write!(f, "]")
44                        });
45                    }
46                    if T::SHAPE.vtable.debug.is_some() {
47                        builder = builder.debug(|value, f| {
48                            let value = unsafe { value.get::<[T; L]>() };
49                            write!(f, "[")?;
50
51                            for (idx, value) in value.iter().enumerate() {
52                                unsafe {
53                                    (T::SHAPE.vtable.debug.unwrap_unchecked())(
54                                        PtrConst::new(value),
55                                        f,
56                                    )?
57                                };
58                                if idx != L - 1 {
59                                    write!(f, ", ")?;
60                                }
61                            }
62                            write!(f, "]")
63                        });
64                    }
65                    if T::SHAPE.vtable.eq.is_some() {
66                        builder = builder.eq(|a, b| {
67                            let a = unsafe { a.get::<[T; L]>() };
68                            let b = unsafe { b.get::<[T; L]>() };
69                            zip(a, b).all(|(a, b)| unsafe {
70                                (T::SHAPE.vtable.eq.unwrap_unchecked())(
71                                    PtrConst::new(a),
72                                    PtrConst::new(b),
73                                )
74                            })
75                        });
76                    }
77                    if L == 0 {
78                        // Zero-length arrays implement `Default` irrespective of the element type
79                        builder =
80                            builder.default_in_place(|target| unsafe { target.assume_init() });
81                    } else if L <= 32 && T::SHAPE.vtable.default_in_place.is_some() {
82                        builder = builder.default_in_place(|target| unsafe {
83                            let t_dip = T::SHAPE.vtable.default_in_place.unwrap_unchecked();
84                            let stride = T::SHAPE.layout.pad_to_align().size();
85                            for idx in 0..L {
86                                t_dip(target.field_uninit_at(idx * stride));
87                            }
88                            target.assume_init()
89                        });
90                    } else {
91                        // arrays do not yet implement `Default` for > 32 elements due to
92                        // specializing the `0` len case
93                    }
94                    if T::SHAPE.vtable.clone_into.is_some() {
95                        builder = builder.clone_into(|src, dst| unsafe {
96                            let t_cip = T::SHAPE.vtable.clone_into.unwrap_unchecked();
97                            let src = src.get::<[T; L]>();
98                            let stride = T::SHAPE.layout.pad_to_align().size();
99                            for (idx, src) in src.iter().enumerate() {
100                                (t_cip)(PtrConst::new(src), dst.field_uninit_at(idx * stride));
101                            }
102                            dst.assume_init()
103                        });
104                    }
105                    if T::SHAPE.vtable.partial_ord.is_some() {
106                        builder = builder.partial_ord(|a, b| {
107                            let a = unsafe { a.get::<[T; L]>() };
108                            let b = unsafe { b.get::<[T; L]>() };
109                            zip(a, b)
110                                .find_map(|(a, b)| unsafe {
111                                    match (T::SHAPE.vtable.partial_ord.unwrap_unchecked())(
112                                        PtrConst::new(a),
113                                        PtrConst::new(b),
114                                    ) {
115                                        Some(Ordering::Equal) => None,
116                                        c => Some(c),
117                                    }
118                                })
119                                .unwrap_or(Some(Ordering::Equal))
120                        });
121                    }
122                    if T::SHAPE.vtable.ord.is_some() {
123                        builder = builder.ord(|a, b| {
124                            let a = unsafe { a.get::<[T; L]>() };
125                            let b = unsafe { b.get::<[T; L]>() };
126                            zip(a, b)
127                                .find_map(|(a, b)| unsafe {
128                                    match (T::SHAPE.vtable.ord.unwrap_unchecked())(
129                                        PtrConst::new(a),
130                                        PtrConst::new(b),
131                                    ) {
132                                        Ordering::Equal => None,
133                                        c => Some(c),
134                                    }
135                                })
136                                .unwrap_or(Ordering::Equal)
137                        });
138                    }
139                    if T::SHAPE.vtable.hash.is_some() {
140                        builder = builder.hash(|value, state, hasher| {
141                            let value = unsafe { value.get::<[T; L]>() };
142                            for value in value {
143                                unsafe {
144                                    (T::SHAPE.vtable.hash.unwrap_unchecked())(
145                                        PtrConst::new(value),
146                                        state,
147                                        hasher,
148                                    )
149                                }
150                            }
151                        });
152                    }
153                    builder.build()
154                },
155            )
156            .def(Def::Array(
157                ArrayDef::builder()
158                    .vtable(
159                        &const {
160                            ArrayVTable::builder()
161                                .get_item_ptr(|ptr, index| unsafe {
162                                    if index >= L {
163                                        panic!(
164                                            "Index out of bounds: the len is {L} but the index is {index}"
165                                        );
166                                    }
167                                    PtrConst::new(ptr.as_ptr::<[T; L]>())
168                                })
169                                .build()
170                        },
171                    )
172                    .n(L)
173                    .t(|| T::SHAPE)
174                    .build(),
175            ))
176            .build()
177    };
178}