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 extern "C" 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 swap: Some(vec_swap_erased),
121};
122
123unsafe extern "C" fn vec_as_ptr_erased(ptr: PtrConst) -> PtrConst {
125 unsafe {
126 let layout = ptr.as_byte_ptr() as *const VecLayout;
127 PtrConst::new((*layout).ptr)
128 }
129}
130
131unsafe extern "C" fn vec_as_mut_ptr_erased(ptr: PtrMut) -> PtrMut {
133 unsafe {
134 let layout = ptr.as_byte_ptr() as *const VecLayout;
135 PtrMut::new((*layout).ptr)
136 }
137}
138
139unsafe fn vec_swap_erased(ptr: PtrMut, a: usize, b: usize, shape: &'static Shape) -> bool {
144 unsafe {
145 let layout = ptr.as_byte_ptr() as *const VecLayout;
146 let len = (*layout).len;
147 if a >= len || b >= len {
148 return false;
149 }
150 if a == b {
151 return true;
152 }
153 let Ok(elem_layout) = shape
154 .type_params
155 .first()
156 .expect("Vec shape must have an element type parameter")
157 .shape
158 .layout
159 .sized_layout()
160 else {
161 return false;
162 };
163 let elem_size = elem_layout.size();
164 let data_ptr = (*layout).ptr;
165 core::ptr::swap_nonoverlapping(
166 data_ptr.add(a * elem_size),
167 data_ptr.add(b * elem_size),
168 elem_size,
169 );
170 true
171 }
172}
173
174fn vec_type_name(
176 shape: &'static Shape,
177 f: &mut core::fmt::Formatter<'_>,
178 opts: TypeNameOpts,
179) -> core::fmt::Result {
180 write!(f, "Vec")?;
181 if let Some(opts) = opts.for_children() {
182 write!(f, "<")?;
183 if let Some(tp) = shape.type_params.first() {
184 tp.shape.write_type_name(f, opts)?;
185 }
186 write!(f, ">")?;
187 } else {
188 write!(f, "<…>")?;
189 }
190 Ok(())
191}
192
193#[inline]
195fn get_list_def(shape: &'static Shape) -> &'static ListDef {
196 match &shape.def {
197 Def::List(list_def) => list_def,
198 _ => panic!("expected List def"),
199 }
200}
201
202unsafe fn vec_debug_erased(
204 ox: OxPtrConst,
205 f: &mut core::fmt::Formatter<'_>,
206) -> Option<core::fmt::Result> {
207 let shape = ox.shape();
208 let elem_shape = shape.type_params.first().map(|tp| tp.shape)?;
209 if !elem_shape.vtable.has_debug() {
210 return None;
211 }
212
213 let list_def = get_list_def(shape);
214 let ptr = ox.ptr();
215 let len = unsafe { (list_def.vtable.len)(ptr) };
216
217 let mut list = f.debug_list();
218 for i in 0..len {
219 if let Some(item_ptr) = unsafe { (list_def.vtable.get)(ptr, i, shape) } {
220 list.entry(&DebugViaShape(elem_shape, item_ptr));
221 }
222 }
223 Some(list.finish())
224}
225
226unsafe fn vec_partial_eq_erased(ox_a: OxPtrConst, ox_b: OxPtrConst) -> Option<bool> {
228 let shape = ox_a.shape();
229 let elem_shape = shape.type_params.first().map(|tp| tp.shape)?;
230 if !elem_shape.vtable.has_partial_eq() {
231 return None;
232 }
233
234 let list_def = get_list_def(shape);
235 let ptr_a = ox_a.ptr();
236 let ptr_b = ox_b.ptr();
237 let len_a = unsafe { (list_def.vtable.len)(ptr_a) };
238 let len_b = unsafe { (list_def.vtable.len)(ptr_b) };
239
240 if len_a != len_b {
241 return Some(false);
242 }
243
244 for i in 0..len_a {
245 let item_a = unsafe { (list_def.vtable.get)(ptr_a, i, shape) }?;
246 let item_b = unsafe { (list_def.vtable.get)(ptr_b, i, shape) }?;
247 match unsafe { elem_shape.call_partial_eq(item_a, item_b) } {
248 Some(true) => continue,
249 Some(false) => return Some(false),
250 None => return None,
251 }
252 }
253 Some(true)
254}
255
256unsafe fn vec_partial_cmp_erased(
258 ox_a: OxPtrConst,
259 ox_b: OxPtrConst,
260) -> Option<Option<core::cmp::Ordering>> {
261 let shape = ox_a.shape();
262 let elem_shape = shape.type_params.first().map(|tp| tp.shape)?;
263 if !elem_shape.vtable.has_partial_ord() {
264 return None;
265 }
266
267 let list_def = get_list_def(shape);
268 let ptr_a = ox_a.ptr();
269 let ptr_b = ox_b.ptr();
270 let len_a = unsafe { (list_def.vtable.len)(ptr_a) };
271 let len_b = unsafe { (list_def.vtable.len)(ptr_b) };
272
273 let min_len = len_a.min(len_b);
274
275 for i in 0..min_len {
276 let item_a = unsafe { (list_def.vtable.get)(ptr_a, i, shape) }?;
277 let item_b = unsafe { (list_def.vtable.get)(ptr_b, i, shape) }?;
278 match unsafe { elem_shape.call_partial_cmp(item_a, item_b) } {
279 Some(Some(core::cmp::Ordering::Equal)) => continue,
280 Some(ord) => return Some(ord),
281 None => return None,
282 }
283 }
284 Some(Some(len_a.cmp(&len_b)))
285}
286
287unsafe fn vec_cmp_erased(ox_a: OxPtrConst, ox_b: OxPtrConst) -> Option<core::cmp::Ordering> {
289 let shape = ox_a.shape();
290 let elem_shape = shape.type_params.first().map(|tp| tp.shape)?;
291 if !elem_shape.vtable.has_ord() {
292 return None;
293 }
294
295 let list_def = get_list_def(shape);
296 let ptr_a = ox_a.ptr();
297 let ptr_b = ox_b.ptr();
298 let len_a = unsafe { (list_def.vtable.len)(ptr_a) };
299 let len_b = unsafe { (list_def.vtable.len)(ptr_b) };
300
301 let min_len = len_a.min(len_b);
302
303 for i in 0..min_len {
304 let item_a = unsafe { (list_def.vtable.get)(ptr_a, i, shape) }?;
305 let item_b = unsafe { (list_def.vtable.get)(ptr_b, i, shape) }?;
306 match unsafe { elem_shape.call_cmp(item_a, item_b) } {
307 Some(core::cmp::Ordering::Equal) => continue,
308 Some(ord) => return Some(ord),
309 None => return None,
310 }
311 }
312 Some(len_a.cmp(&len_b))
313}
314
315type VecIterator<'mem, T> = core::slice::Iter<'mem, T>;
320
321unsafe extern "C" fn vec_init_in_place_with_capacity<T>(
322 uninit: PtrUninit,
323 capacity: usize,
324) -> PtrMut {
325 unsafe { uninit.put(Vec::<T>::with_capacity(capacity)) }
326}
327
328unsafe extern "C" fn vec_push<T>(ptr: PtrMut, item: PtrMut) {
329 unsafe {
330 let vec = ptr.as_mut::<Vec<T>>();
331 let item = item.read::<T>();
332 vec.push(item);
333 }
334}
335
336unsafe extern "C" fn vec_pop<T>(ptr: PtrMut, out: PtrUninit) -> bool {
346 unsafe {
347 let vec = ptr.as_mut::<Vec<T>>();
348 match vec.pop() {
349 Some(value) => {
350 out.put(value);
351 true
352 }
353 None => false,
354 }
355 }
356}
357
358unsafe extern "C" fn vec_set_len<T>(ptr: PtrMut, len: usize) {
365 unsafe {
366 let vec = ptr.as_mut::<Vec<T>>();
367 vec.set_len(len);
368 }
369}
370
371unsafe extern "C" fn vec_as_mut_ptr_typed<T>(ptr: PtrMut) -> *mut u8 {
376 unsafe {
377 let vec = ptr.as_mut::<Vec<T>>();
378 vec.as_mut_ptr() as *mut u8
379 }
380}
381
382unsafe extern "C" fn vec_reserve<T>(ptr: PtrMut, additional: usize) {
387 unsafe {
388 let vec = ptr.as_mut::<Vec<T>>();
389 vec.reserve(additional);
390 }
391}
392
393unsafe extern "C" fn vec_capacity<T>(ptr: PtrConst) -> usize {
398 unsafe {
399 let vec = ptr.get::<Vec<T>>();
400 vec.capacity()
401 }
402}
403
404unsafe extern "C" fn vec_iter_init<T>(ptr: PtrConst) -> PtrMut {
405 unsafe {
406 let vec = ptr.get::<Vec<T>>();
407 let iter: VecIterator<T> = vec.iter();
408 let iter_state = Box::new(iter);
409 PtrMut::new(Box::into_raw(iter_state) as *mut u8)
410 }
411}
412
413unsafe fn vec_iter_next<T>(iter_ptr: PtrMut) -> Option<PtrConst> {
414 unsafe {
418 let state: *mut VecIterator<'_, T> = iter_ptr.as_ptr::<()>() as *mut _;
419 (*state)
420 .next()
421 .map(|value| PtrConst::new(value as *const T))
422 }
423}
424
425unsafe fn vec_iter_next_back<T>(iter_ptr: PtrMut) -> Option<PtrConst> {
426 unsafe {
428 let state: *mut VecIterator<'_, T> = iter_ptr.as_ptr::<()>() as *mut _;
429 (*state)
430 .next_back()
431 .map(|value| PtrConst::new(value as *const T))
432 }
433}
434
435unsafe extern "C" fn vec_iter_dealloc<T>(iter_ptr: PtrMut) {
436 unsafe {
437 drop(Box::from_raw(
438 iter_ptr.as_ptr::<VecIterator<'_, T>>() as *mut VecIterator<'_, T>
439 ))
440 }
441}
442
443unsafe impl<'a, T: Facet<'a>> Facet<'a> for Vec<T> {
444 const SHAPE: &'static Shape =
445 &const {
446 const fn build_list_type_ops<T>() -> ListTypeOps {
448 ListTypeOps::builder()
449 .init_in_place_with_capacity(vec_init_in_place_with_capacity::<T>)
450 .push(vec_push::<T>)
451 .pop(vec_pop::<T>)
452 .set_len(vec_set_len::<T>)
453 .as_mut_ptr_typed(vec_as_mut_ptr_typed::<T>)
454 .reserve(vec_reserve::<T>)
455 .capacity(vec_capacity::<T>)
456 .iter_vtable(IterVTable {
457 init_with_value: Some(vec_iter_init::<T>),
458 next: vec_iter_next::<T>,
459 next_back: Some(vec_iter_next_back::<T>),
460 size_hint: None,
461 dealloc: vec_iter_dealloc::<T>,
462 })
463 .build()
464 }
465
466 ShapeBuilder::for_sized::<Self>("Vec") .module_path("alloc::vec")
467 .type_name(vec_type_name)
468 .ty(Type::User(UserType::Opaque))
469 .def(Def::List(ListDef::with_type_ops(
470 &VEC_LIST_VTABLE,
472 &const { build_list_type_ops::<T>() },
473 T::SHAPE,
474 )))
475 .type_params(&[TypeParam {
476 name: "T",
477 shape: T::SHAPE,
478 }])
479 .inner(T::SHAPE)
480 .variance(VarianceDesc {
482 base: Variance::Bivariant,
483 deps: &const { [VarianceDep::covariant(T::SHAPE)] },
484 })
485 .vtable_indirect(&const {
486 VTableIndirect {
487 debug: Some(vec_debug_erased),
488 partial_eq: Some(vec_partial_eq_erased),
489 partial_cmp: Some(vec_partial_cmp_erased),
490 cmp: Some(vec_cmp_erased),
491 display: None,
492 hash: None,
493 invariants: None,
494 parse: None,
495 parse_bytes: None,
496 try_from: None,
497 try_into_inner: None,
498 try_borrow_inner: None,
499 }
500 })
501 .type_ops_indirect(&const {
502 unsafe fn drop_in_place<T>(ox: OxPtrMut) {
503 unsafe {
504 core::ptr::drop_in_place(ox.ptr().as_ptr::<Vec<T>>() as *mut Vec<T>);
505 }
506 }
507
508 unsafe fn default_in_place<T>(ox: OxPtrUninit) -> bool {
509 unsafe { ox.put(Vec::<T>::new()) };
510 true
511 }
512
513 unsafe fn truthy<T>(ptr: PtrConst) -> bool {
514 !unsafe { ptr.get::<Vec<T>>() }.is_empty()
515 }
516
517 TypeOpsIndirect {
518 drop_in_place: drop_in_place::<T>,
519 default_in_place: Some(default_in_place::<T>),
520 clone_into: None,
521 is_truthy: Some(truthy::<T>),
522 }
523 })
524 .build()
525 };
526}