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