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}