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}