1use crate::*;
2
3use alloc::boxed::Box;
4use alloc::vec::Vec;
5
6struct DebugViaShape(&'static Shape, PtrConst);
8
9impl core::fmt::Debug for DebugViaShape {
10 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
11 match unsafe { self.0.call_debug(self.1, f) } {
12 Some(result) => result,
13 None => write!(f, "???"),
14 }
15 }
16}
17
18#[repr(C)]
25struct VecLayout {
26 #[allow(dead_code)]
27 cap: usize,
28 ptr: *mut u8,
29 len: usize,
30}
31
32const _: () = {
34 let v: Vec<u8> = Vec::new();
36 let fields: [usize; 3] = unsafe { core::mem::transmute(v) };
37
38 assert!(
42 core::mem::size_of::<Vec<u8>>() == core::mem::size_of::<VecLayout>(),
43 "VecLayout size mismatch"
44 );
45 assert!(
46 core::mem::align_of::<Vec<u8>>() == core::mem::align_of::<VecLayout>(),
47 "VecLayout align mismatch"
48 );
49
50 assert!(fields[0] == 0, "expected cap=0 at offset 0");
55 assert!(fields[1] != 0, "expected non-null ptr at offset 1");
56 assert!(fields[2] == 0, "expected len=0 at offset 2");
57};
58
59unsafe fn vec_len_erased(ptr: PtrConst) -> usize {
61 unsafe {
62 let layout = ptr.as_byte_ptr() as *const VecLayout;
63 (*layout).len
64 }
65}
66
67unsafe fn vec_get_erased(ptr: PtrConst, index: usize, shape: &'static Shape) -> Option<PtrConst> {
69 unsafe {
70 let layout = ptr.as_byte_ptr() as *const VecLayout;
71 let len = (*layout).len;
72 if index >= len {
73 return None;
74 }
75 let elem_size = shape
76 .type_params
77 .first()?
78 .shape
79 .layout
80 .sized_layout()
81 .ok()?
82 .size();
83 let data_ptr = (*layout).ptr;
84 Some(PtrConst::new(data_ptr.add(index * elem_size)))
85 }
86}
87
88unsafe fn vec_get_mut_erased(ptr: PtrMut, index: usize, shape: &'static Shape) -> Option<PtrMut> {
90 unsafe {
91 let layout = ptr.as_byte_ptr() as *const VecLayout;
92 let len = (*layout).len;
93 if index >= len {
94 return None;
95 }
96 let elem_size = shape
97 .type_params
98 .first()?
99 .shape
100 .layout
101 .sized_layout()
102 .ok()?
103 .size();
104 let data_ptr = (*layout).ptr;
105 Some(PtrMut::new(data_ptr.add(index * elem_size)))
106 }
107}
108
109static VEC_LIST_VTABLE: ListVTable = ListVTable {
115 len: vec_len_erased,
116 get: vec_get_erased,
117 get_mut: Some(vec_get_mut_erased),
118 as_ptr: Some(vec_as_ptr_erased),
119 as_mut_ptr: Some(vec_as_mut_ptr_erased),
120};
121
122unsafe fn vec_as_ptr_erased(ptr: PtrConst) -> PtrConst {
124 unsafe {
125 let layout = ptr.as_byte_ptr() as *const VecLayout;
126 PtrConst::new((*layout).ptr)
127 }
128}
129
130unsafe fn vec_as_mut_ptr_erased(ptr: PtrMut) -> PtrMut {
132 unsafe {
133 let layout = ptr.as_byte_ptr() as *const VecLayout;
134 PtrMut::new((*layout).ptr)
135 }
136}
137
138fn vec_type_name(
140 shape: &'static Shape,
141 f: &mut core::fmt::Formatter<'_>,
142 opts: TypeNameOpts,
143) -> core::fmt::Result {
144 write!(f, "Vec")?;
145 if let Some(opts) = opts.for_children() {
146 write!(f, "<")?;
147 if let Some(tp) = shape.type_params.first() {
148 tp.shape.write_type_name(f, opts)?;
149 }
150 write!(f, ">")?;
151 } else {
152 write!(f, "<…>")?;
153 }
154 Ok(())
155}
156
157#[inline]
159fn get_list_def(shape: &'static Shape) -> &'static ListDef {
160 match &shape.def {
161 Def::List(list_def) => list_def,
162 _ => panic!("expected List def"),
163 }
164}
165
166unsafe fn vec_debug_erased(
168 ox: OxPtrConst,
169 f: &mut core::fmt::Formatter<'_>,
170) -> Option<core::fmt::Result> {
171 let shape = ox.shape();
172 let elem_shape = shape.type_params.first().map(|tp| tp.shape)?;
173 if !elem_shape.vtable.has_debug() {
174 return None;
175 }
176
177 let list_def = get_list_def(shape);
178 let ptr = ox.ptr();
179 let len = unsafe { (list_def.vtable.len)(ptr) };
180
181 let mut list = f.debug_list();
182 for i in 0..len {
183 if let Some(item_ptr) = unsafe { (list_def.vtable.get)(ptr, i, shape) } {
184 list.entry(&DebugViaShape(elem_shape, item_ptr));
185 }
186 }
187 Some(list.finish())
188}
189
190unsafe fn vec_partial_eq_erased(ox_a: OxPtrConst, ox_b: OxPtrConst) -> Option<bool> {
192 let shape = ox_a.shape();
193 let elem_shape = shape.type_params.first().map(|tp| tp.shape)?;
194 if !elem_shape.vtable.has_partial_eq() {
195 return None;
196 }
197
198 let list_def = get_list_def(shape);
199 let ptr_a = ox_a.ptr();
200 let ptr_b = ox_b.ptr();
201 let len_a = unsafe { (list_def.vtable.len)(ptr_a) };
202 let len_b = unsafe { (list_def.vtable.len)(ptr_b) };
203
204 if len_a != len_b {
205 return Some(false);
206 }
207
208 for i in 0..len_a {
209 let item_a = unsafe { (list_def.vtable.get)(ptr_a, i, shape) }?;
210 let item_b = unsafe { (list_def.vtable.get)(ptr_b, i, shape) }?;
211 match unsafe { elem_shape.call_partial_eq(item_a, item_b) } {
212 Some(true) => continue,
213 Some(false) => return Some(false),
214 None => return None,
215 }
216 }
217 Some(true)
218}
219
220unsafe fn vec_partial_cmp_erased(
222 ox_a: OxPtrConst,
223 ox_b: OxPtrConst,
224) -> Option<Option<core::cmp::Ordering>> {
225 let shape = ox_a.shape();
226 let elem_shape = shape.type_params.first().map(|tp| tp.shape)?;
227 if !elem_shape.vtable.has_partial_ord() {
228 return None;
229 }
230
231 let list_def = get_list_def(shape);
232 let ptr_a = ox_a.ptr();
233 let ptr_b = ox_b.ptr();
234 let len_a = unsafe { (list_def.vtable.len)(ptr_a) };
235 let len_b = unsafe { (list_def.vtable.len)(ptr_b) };
236
237 let min_len = len_a.min(len_b);
238
239 for i in 0..min_len {
240 let item_a = unsafe { (list_def.vtable.get)(ptr_a, i, shape) }?;
241 let item_b = unsafe { (list_def.vtable.get)(ptr_b, i, shape) }?;
242 match unsafe { elem_shape.call_partial_cmp(item_a, item_b) } {
243 Some(Some(core::cmp::Ordering::Equal)) => continue,
244 Some(ord) => return Some(ord),
245 None => return None,
246 }
247 }
248 Some(Some(len_a.cmp(&len_b)))
249}
250
251unsafe fn vec_cmp_erased(ox_a: OxPtrConst, ox_b: OxPtrConst) -> Option<core::cmp::Ordering> {
253 let shape = ox_a.shape();
254 let elem_shape = shape.type_params.first().map(|tp| tp.shape)?;
255 if !elem_shape.vtable.has_ord() {
256 return None;
257 }
258
259 let list_def = get_list_def(shape);
260 let ptr_a = ox_a.ptr();
261 let ptr_b = ox_b.ptr();
262 let len_a = unsafe { (list_def.vtable.len)(ptr_a) };
263 let len_b = unsafe { (list_def.vtable.len)(ptr_b) };
264
265 let min_len = len_a.min(len_b);
266
267 for i in 0..min_len {
268 let item_a = unsafe { (list_def.vtable.get)(ptr_a, i, shape) }?;
269 let item_b = unsafe { (list_def.vtable.get)(ptr_b, i, shape) }?;
270 match unsafe { elem_shape.call_cmp(item_a, item_b) } {
271 Some(core::cmp::Ordering::Equal) => continue,
272 Some(ord) => return Some(ord),
273 None => return None,
274 }
275 }
276 Some(len_a.cmp(&len_b))
277}
278
279type VecIterator<'mem, T> = core::slice::Iter<'mem, T>;
284
285unsafe fn vec_init_in_place_with_capacity<T>(uninit: PtrUninit, capacity: usize) -> PtrMut {
286 unsafe { uninit.put(Vec::<T>::with_capacity(capacity)) }
287}
288
289unsafe fn vec_push<T: 'static>(ptr: PtrMut, item: PtrMut) {
290 unsafe {
291 let vec = ptr.as_mut::<Vec<T>>();
292 let item = item.read::<T>();
293 vec.push(item);
294 }
295}
296
297unsafe fn vec_set_len<T: 'static>(ptr: PtrMut, len: usize) {
304 unsafe {
305 let vec = ptr.as_mut::<Vec<T>>();
306 vec.set_len(len);
307 }
308}
309
310unsafe fn vec_as_mut_ptr_typed<T: 'static>(ptr: PtrMut) -> *mut u8 {
315 unsafe {
316 let vec = ptr.as_mut::<Vec<T>>();
317 vec.as_mut_ptr() as *mut u8
318 }
319}
320
321unsafe fn vec_iter_init<T: 'static>(ptr: PtrConst) -> PtrMut {
322 unsafe {
323 let vec = ptr.get::<Vec<T>>();
324 let iter: VecIterator<T> = vec.iter();
325 let iter_state = Box::new(iter);
326 PtrMut::new(Box::into_raw(iter_state) as *mut u8)
327 }
328}
329
330unsafe fn vec_iter_next<T: 'static>(iter_ptr: PtrMut) -> Option<PtrConst> {
331 unsafe {
332 let state = iter_ptr.as_mut::<VecIterator<'static, T>>();
333 state.next().map(|value| PtrConst::new(value as *const T))
334 }
335}
336
337unsafe fn vec_iter_next_back<T: 'static>(iter_ptr: PtrMut) -> Option<PtrConst> {
338 unsafe {
339 let state = iter_ptr.as_mut::<VecIterator<'static, T>>();
340 state
341 .next_back()
342 .map(|value| PtrConst::new(value as *const T))
343 }
344}
345
346unsafe fn vec_iter_dealloc<T>(iter_ptr: PtrMut) {
347 unsafe {
348 drop(Box::from_raw(
349 iter_ptr.as_ptr::<VecIterator<'_, T>>() as *mut VecIterator<'_, T>
350 ))
351 }
352}
353
354unsafe impl<'a, T> Facet<'a> for Vec<T>
355where
356 T: Facet<'a> + 'static,
357{
358 const SHAPE: &'static Shape =
359 &const {
360 const fn build_list_type_ops<T: 'static>() -> ListTypeOps {
362 ListTypeOps::builder()
363 .init_in_place_with_capacity(vec_init_in_place_with_capacity::<T>)
364 .push(vec_push::<T>)
365 .set_len(vec_set_len::<T>)
366 .as_mut_ptr_typed(vec_as_mut_ptr_typed::<T>)
367 .iter_vtable(IterVTable {
368 init_with_value: Some(vec_iter_init::<T>),
369 next: vec_iter_next::<T>,
370 next_back: Some(vec_iter_next_back::<T>),
371 size_hint: None,
372 dealloc: vec_iter_dealloc::<T>,
373 })
374 .build()
375 }
376
377 ShapeBuilder::for_sized::<Self>("Vec")
378 .type_name(vec_type_name)
379 .ty(Type::User(UserType::Opaque))
380 .def(Def::List(ListDef::with_type_ops(
381 &VEC_LIST_VTABLE,
383 &const { build_list_type_ops::<T>() },
384 T::SHAPE,
385 )))
386 .type_params(&[TypeParam {
387 name: "T",
388 shape: T::SHAPE,
389 }])
390 .inner(T::SHAPE)
391 .variance(Shape::computed_variance)
393 .vtable_indirect(&const {
394 VTableIndirect {
395 debug: Some(vec_debug_erased),
396 partial_eq: Some(vec_partial_eq_erased),
397 partial_cmp: Some(vec_partial_cmp_erased),
398 cmp: Some(vec_cmp_erased),
399 display: None,
400 hash: None,
401 invariants: None,
402 parse: None,
403 try_from: None,
404 try_into_inner: None,
405 try_borrow_inner: None,
406 }
407 })
408 .type_ops_indirect(&const {
409 unsafe fn drop_in_place<T>(ox: OxPtrMut) {
410 unsafe {
411 core::ptr::drop_in_place(ox.ptr().as_ptr::<Vec<T>>() as *mut Vec<T>);
412 }
413 }
414
415 unsafe fn default_in_place<T>(ox: OxPtrMut) {
416 unsafe { ox.ptr().as_uninit().put(Vec::<T>::new()) };
417 }
418
419 unsafe fn truthy<T>(ptr: PtrConst) -> bool {
420 !unsafe { ptr.get::<Vec<T>>() }.is_empty()
421 }
422
423 TypeOpsIndirect {
424 drop_in_place: drop_in_place::<T>,
425 default_in_place: Some(default_in_place::<T>),
426 clone_into: None,
427 is_truthy: Some(truthy::<T>),
428 }
429 })
430 .build()
431 };
432}