1use alloc::boxed::Box;
4use core::ptr::NonNull;
5use std::sync::{LazyLock, Mutex, MutexGuard, OnceLock, RwLock, RwLockReadGuard, RwLockWriteGuard};
6
7use crate::{
8 DeclId, Def, Facet, KnownPointer, LockGuardVTable, OxPtrMut, PointerDef, PointerFlags,
9 PointerVTable, PtrConst, PtrMut, PtrUninit, ReadLockResult, Shape, ShapeBuilder, Type,
10 TypeNameOpts, TypeOpsIndirect, TypeParam, UserType, VTableIndirect, Variance, VarianceDep,
11 VarianceDesc, WriteLockResult, decl_id_hash,
12};
13
14fn type_name_mutex<'a, T: Facet<'a>>(
19 _shape: &'static Shape,
20 f: &mut core::fmt::Formatter<'_>,
21 opts: TypeNameOpts,
22) -> core::fmt::Result {
23 write!(f, "Mutex")?;
24 if let Some(opts) = opts.for_children() {
25 write!(f, "<")?;
26 T::SHAPE.write_type_name(f, opts)?;
27 write!(f, ">")?;
28 } else {
29 write!(f, "<\u{2026}>")?;
30 }
31 Ok(())
32}
33
34unsafe extern "C" fn mutex_new_into<T>(this: PtrUninit, value: PtrMut) -> PtrMut {
35 unsafe {
36 let t = value.read::<T>();
37 this.put(Mutex::<T>::new(t))
38 }
39}
40
41unsafe fn mutex_drop<T>(ox: OxPtrMut) {
42 unsafe { core::ptr::drop_in_place(ox.ptr().as_ptr::<Mutex<T>>() as *mut Mutex<T>) }
43}
44
45unsafe fn mutex_lock<'a, T: Facet<'a>>(opaque: PtrConst) -> Result<WriteLockResult, ()> {
46 unsafe {
47 let mutex = &*opaque.as_ptr::<Mutex<T>>();
48
49 let mut guard = match mutex.lock() {
51 Ok(g) => g,
52 Err(e) => e.into_inner(),
53 };
54
55 let data_ptr = &mut *guard as *mut T;
58
59 let guard_box = Box::new(guard);
61 let guard_ptr = Box::into_raw(guard_box) as *const u8;
62
63 Ok(WriteLockResult::new(
64 PtrMut::new(data_ptr as *mut u8),
65 PtrConst::new(guard_ptr),
66 &const { mutex_guard_vtable::<T>() },
67 ))
68 }
69}
70
71const fn mutex_guard_vtable<T>() -> LockGuardVTable {
72 unsafe fn drop_guard<T>(guard: PtrConst) {
73 unsafe {
74 drop(Box::from_raw(
75 guard.as_ptr::<MutexGuard<'_, T>>() as *mut MutexGuard<'_, T>
76 ));
77 }
78 }
79
80 LockGuardVTable {
81 drop_in_place: drop_guard::<T>,
82 }
83}
84
85unsafe impl<'a, T: Facet<'a>> Facet<'a> for Mutex<T> {
86 const SHAPE: &'static Shape = &const {
87 ShapeBuilder::for_sized::<Self>("Mutex")
88 .decl_id(DeclId::new(decl_id_hash("#std#Mutex")))
89 .type_name(type_name_mutex::<T>)
90 .vtable_indirect(&VTableIndirect::EMPTY)
91 .type_ops_indirect(
92 &const {
93 TypeOpsIndirect {
94 drop_in_place: mutex_drop::<T>,
95 default_in_place: None,
96 clone_into: None,
97 is_truthy: None,
98 }
99 },
100 )
101 .ty(Type::User(UserType::Opaque))
102 .def(Def::Pointer(PointerDef {
103 vtable: &const {
104 PointerVTable {
105 lock_fn: Some(mutex_lock::<T>),
106 new_into_fn: Some(mutex_new_into::<T>),
107 ..PointerVTable::new()
108 }
109 },
110 pointee: Some(T::SHAPE),
111 weak: None,
112 strong: None,
113 flags: PointerFlags::LOCK,
114 known: Some(KnownPointer::Mutex),
115 }))
116 .type_params(&[TypeParam {
117 name: "T",
118 shape: T::SHAPE,
119 }])
120 .inner(T::SHAPE)
121 .variance(VarianceDesc {
123 base: Variance::Bivariant,
124 deps: &const { [VarianceDep::invariant(T::SHAPE)] },
125 })
126 .build()
127 };
128}
129
130fn type_name_rwlock<'a, T: Facet<'a>>(
135 _shape: &'static Shape,
136 f: &mut core::fmt::Formatter<'_>,
137 opts: TypeNameOpts,
138) -> core::fmt::Result {
139 write!(f, "RwLock")?;
140 if let Some(opts) = opts.for_children() {
141 write!(f, "<")?;
142 T::SHAPE.write_type_name(f, opts)?;
143 write!(f, ">")?;
144 } else {
145 write!(f, "<\u{2026}>")?;
146 }
147 Ok(())
148}
149
150unsafe extern "C" fn rwlock_new_into<T>(this: PtrUninit, value: PtrMut) -> PtrMut {
151 unsafe {
152 let t = value.read::<T>();
153 this.put(RwLock::<T>::new(t))
154 }
155}
156
157unsafe fn rwlock_drop<T>(ox: OxPtrMut) {
158 unsafe { core::ptr::drop_in_place(ox.ptr().as_ptr::<RwLock<T>>() as *mut RwLock<T>) }
159}
160
161const fn rwlock_read_guard_vtable<T>() -> LockGuardVTable {
162 unsafe fn drop_guard<T>(guard: PtrConst) {
163 unsafe {
164 drop(Box::from_raw(
165 guard.as_ptr::<RwLockReadGuard<'_, T>>() as *mut RwLockReadGuard<'_, T>
166 ));
167 }
168 }
169
170 LockGuardVTable {
171 drop_in_place: drop_guard::<T>,
172 }
173}
174
175const fn rwlock_write_guard_vtable<T>() -> LockGuardVTable {
176 unsafe fn drop_guard<T>(guard: PtrConst) {
177 unsafe {
178 drop(Box::from_raw(
179 guard.as_ptr::<RwLockWriteGuard<'_, T>>() as *mut RwLockWriteGuard<'_, T>
180 ));
181 }
182 }
183
184 LockGuardVTable {
185 drop_in_place: drop_guard::<T>,
186 }
187}
188
189unsafe fn rwlock_read<'a, T: Facet<'a>>(opaque: PtrConst) -> Result<ReadLockResult, ()> {
190 unsafe {
191 let rwlock = &*opaque.as_ptr::<RwLock<T>>();
192
193 let guard = match rwlock.read() {
195 Ok(g) => g,
196 Err(e) => e.into_inner(),
197 };
198
199 let data_ptr = &*guard as *const T;
201 let guard_box = Box::new(guard);
202 let guard_ptr = Box::into_raw(guard_box) as *const u8;
203
204 Ok(ReadLockResult::new(
205 PtrConst::new(data_ptr as *const u8),
206 PtrConst::new(guard_ptr),
207 &const { rwlock_read_guard_vtable::<T>() },
208 ))
209 }
210}
211
212unsafe fn rwlock_write<'a, T: Facet<'a>>(opaque: PtrConst) -> Result<WriteLockResult, ()> {
213 unsafe {
214 let rwlock = &*opaque.as_ptr::<RwLock<T>>();
215
216 let mut guard = match rwlock.write() {
218 Ok(g) => g,
219 Err(e) => e.into_inner(),
220 };
221
222 let data_ptr = &mut *guard as *mut T;
224 let guard_box = Box::new(guard);
225 let guard_ptr = Box::into_raw(guard_box) as *const u8;
226
227 Ok(WriteLockResult::new(
228 PtrMut::new(data_ptr as *mut u8),
229 PtrConst::new(guard_ptr),
230 &const { rwlock_write_guard_vtable::<T>() },
231 ))
232 }
233}
234
235unsafe impl<'a, T: Facet<'a>> Facet<'a> for RwLock<T> {
236 const SHAPE: &'static Shape = &const {
237 ShapeBuilder::for_sized::<Self>("RwLock")
238 .decl_id(DeclId::new(decl_id_hash("#std#RwLock")))
239 .type_name(type_name_rwlock::<T>)
240 .vtable_indirect(&VTableIndirect::EMPTY)
241 .type_ops_indirect(
242 &const {
243 TypeOpsIndirect {
244 drop_in_place: rwlock_drop::<T>,
245 default_in_place: None,
246 clone_into: None,
247 is_truthy: None,
248 }
249 },
250 )
251 .ty(Type::User(UserType::Opaque))
252 .def(Def::Pointer(PointerDef {
253 vtable: &const {
254 PointerVTable {
255 read_fn: Some(rwlock_read::<T>),
256 write_fn: Some(rwlock_write::<T>),
257 new_into_fn: Some(rwlock_new_into::<T>),
258 ..PointerVTable::new()
259 }
260 },
261 pointee: Some(T::SHAPE),
262 weak: None,
263 strong: None,
264 flags: PointerFlags::LOCK,
265 known: Some(KnownPointer::RwLock),
266 }))
267 .type_params(&[TypeParam {
268 name: "T",
269 shape: T::SHAPE,
270 }])
271 .inner(T::SHAPE)
272 .variance(VarianceDesc {
274 base: Variance::Bivariant,
275 deps: &const { [VarianceDep::invariant(T::SHAPE)] },
276 })
277 .build()
278 };
279}
280
281fn type_name_mutex_guard<'a, T: Facet<'a>>(
286 _shape: &'static Shape,
287 f: &mut core::fmt::Formatter<'_>,
288 opts: TypeNameOpts,
289) -> core::fmt::Result {
290 write!(f, "MutexGuard")?;
291 if let Some(opts) = opts.for_children() {
292 write!(f, "<")?;
293 T::SHAPE.write_type_name(f, opts)?;
294 write!(f, ">")?;
295 } else {
296 write!(f, "<\u{2026}>")?;
297 }
298 Ok(())
299}
300
301unsafe fn mutex_guard_drop<T>(ox: OxPtrMut) {
302 unsafe {
303 core::ptr::drop_in_place(ox.ptr().as_ptr::<MutexGuard<'_, T>>() as *mut MutexGuard<'_, T>)
304 }
305}
306
307unsafe extern "C" fn mutex_guard_borrow<'a, T: Facet<'a>>(opaque: PtrConst) -> PtrConst {
308 unsafe {
309 let guard = &*opaque.as_ptr::<MutexGuard<'_, T>>();
310 PtrConst::new(NonNull::from(&**guard).as_ptr())
311 }
312}
313
314unsafe impl<'a, T: Facet<'a>> Facet<'a> for MutexGuard<'a, T> {
315 const SHAPE: &'static Shape = &const {
316 ShapeBuilder::for_sized::<Self>("MutexGuard")
317 .decl_id(DeclId::new(decl_id_hash("#std#MutexGuard")))
318 .type_name(type_name_mutex_guard::<T>)
319 .vtable_indirect(&VTableIndirect::EMPTY)
320 .type_ops_indirect(
321 &const {
322 TypeOpsIndirect {
323 drop_in_place: mutex_guard_drop::<T>,
324 default_in_place: None,
325 clone_into: None,
326 is_truthy: None,
327 }
328 },
329 )
330 .ty(Type::User(UserType::Opaque))
331 .def(Def::Pointer(PointerDef {
332 vtable: &const {
333 PointerVTable {
334 borrow_fn: Some(mutex_guard_borrow::<T>),
335 ..PointerVTable::new()
336 }
337 },
338 pointee: Some(T::SHAPE),
339 weak: None,
340 strong: None,
341 flags: PointerFlags::empty(),
342 known: None,
343 }))
344 .type_params(&[TypeParam {
345 name: "T",
346 shape: T::SHAPE,
347 }])
348 .inner(T::SHAPE)
349 .variance(VarianceDesc {
351 base: Variance::Bivariant,
352 deps: &const { [VarianceDep::invariant(T::SHAPE)] },
353 })
354 .build()
355 };
356}
357
358fn type_name_rwlock_read_guard<'a, T: Facet<'a>>(
359 _shape: &'static Shape,
360 f: &mut core::fmt::Formatter<'_>,
361 opts: TypeNameOpts,
362) -> core::fmt::Result {
363 write!(f, "RwLockReadGuard")?;
364 if let Some(opts) = opts.for_children() {
365 write!(f, "<")?;
366 T::SHAPE.write_type_name(f, opts)?;
367 write!(f, ">")?;
368 } else {
369 write!(f, "<\u{2026}>")?;
370 }
371 Ok(())
372}
373
374unsafe fn rwlock_read_guard_drop<T>(ox: OxPtrMut) {
375 unsafe {
376 core::ptr::drop_in_place(
377 ox.ptr().as_ptr::<RwLockReadGuard<'_, T>>() as *mut RwLockReadGuard<'_, T>
378 )
379 }
380}
381
382unsafe extern "C" fn rwlock_read_guard_borrow<'a, T: Facet<'a>>(opaque: PtrConst) -> PtrConst {
383 unsafe {
384 let guard = &*opaque.as_ptr::<RwLockReadGuard<'_, T>>();
385 PtrConst::new(NonNull::from(&**guard).as_ptr())
386 }
387}
388
389unsafe impl<'a, T: Facet<'a>> Facet<'a> for RwLockReadGuard<'a, T> {
390 const SHAPE: &'static Shape = &const {
391 ShapeBuilder::for_sized::<Self>("RwLockReadGuard")
392 .decl_id(DeclId::new(decl_id_hash("#std#RwLockReadGuard")))
393 .type_name(type_name_rwlock_read_guard::<T>)
394 .vtable_indirect(&VTableIndirect::EMPTY)
395 .type_ops_indirect(
396 &const {
397 TypeOpsIndirect {
398 drop_in_place: rwlock_read_guard_drop::<T>,
399 default_in_place: None,
400 clone_into: None,
401 is_truthy: None,
402 }
403 },
404 )
405 .ty(Type::User(UserType::Opaque))
406 .def(Def::Pointer(PointerDef {
407 vtable: &const {
408 PointerVTable {
409 borrow_fn: Some(rwlock_read_guard_borrow::<T>),
410 ..PointerVTable::new()
411 }
412 },
413 pointee: Some(T::SHAPE),
414 weak: None,
415 strong: None,
416 flags: PointerFlags::empty(),
417 known: None,
418 }))
419 .type_params(&[TypeParam {
420 name: "T",
421 shape: T::SHAPE,
422 }])
423 .inner(T::SHAPE)
424 .variance(VarianceDesc {
426 base: Variance::Bivariant,
427 deps: &const { [VarianceDep::covariant(T::SHAPE)] },
428 })
429 .build()
430 };
431}
432
433fn type_name_rwlock_write_guard<'a, T: Facet<'a>>(
434 _shape: &'static Shape,
435 f: &mut core::fmt::Formatter<'_>,
436 opts: TypeNameOpts,
437) -> core::fmt::Result {
438 write!(f, "RwLockWriteGuard")?;
439 if let Some(opts) = opts.for_children() {
440 write!(f, "<")?;
441 T::SHAPE.write_type_name(f, opts)?;
442 write!(f, ">")?;
443 } else {
444 write!(f, "<\u{2026}>")?;
445 }
446 Ok(())
447}
448
449unsafe fn rwlock_write_guard_drop<T>(ox: OxPtrMut) {
450 unsafe {
451 core::ptr::drop_in_place(
452 ox.ptr().as_ptr::<RwLockWriteGuard<'_, T>>() as *mut RwLockWriteGuard<'_, T>
453 )
454 }
455}
456
457unsafe extern "C" fn rwlock_write_guard_borrow<'a, T: Facet<'a>>(opaque: PtrConst) -> PtrConst {
458 unsafe {
459 let guard = &*opaque.as_ptr::<RwLockWriteGuard<'_, T>>();
460 PtrConst::new(NonNull::from(&**guard).as_ptr())
461 }
462}
463
464unsafe impl<'a, T: Facet<'a>> Facet<'a> for RwLockWriteGuard<'a, T> {
465 const SHAPE: &'static Shape = &const {
466 ShapeBuilder::for_sized::<Self>("RwLockWriteGuard")
467 .decl_id(DeclId::new(decl_id_hash("#std#RwLockWriteGuard")))
468 .type_name(type_name_rwlock_write_guard::<T>)
469 .vtable_indirect(&VTableIndirect::EMPTY)
470 .type_ops_indirect(
471 &const {
472 TypeOpsIndirect {
473 drop_in_place: rwlock_write_guard_drop::<T>,
474 default_in_place: None,
475 clone_into: None,
476 is_truthy: None,
477 }
478 },
479 )
480 .ty(Type::User(UserType::Opaque))
481 .def(Def::Pointer(PointerDef {
482 vtable: &const {
483 PointerVTable {
484 borrow_fn: Some(rwlock_write_guard_borrow::<T>),
485 ..PointerVTable::new()
486 }
487 },
488 pointee: Some(T::SHAPE),
489 weak: None,
490 strong: None,
491 flags: PointerFlags::empty(),
492 known: None,
493 }))
494 .type_params(&[TypeParam {
495 name: "T",
496 shape: T::SHAPE,
497 }])
498 .inner(T::SHAPE)
499 .variance(VarianceDesc {
501 base: Variance::Bivariant,
502 deps: &const { [VarianceDep::invariant(T::SHAPE)] },
503 })
504 .build()
505 };
506}
507
508fn type_name_oncelock<'a, T: Facet<'a>>(
513 _shape: &'static Shape,
514 f: &mut core::fmt::Formatter<'_>,
515 opts: TypeNameOpts,
516) -> core::fmt::Result {
517 write!(f, "OnceLock")?;
518 if let Some(opts) = opts.for_children() {
519 write!(f, "<")?;
520 T::SHAPE.write_type_name(f, opts)?;
521 write!(f, ">")?;
522 } else {
523 write!(f, "<\u{2026}>")?;
524 }
525 Ok(())
526}
527
528unsafe extern "C" fn oncelock_new_into<T>(this: PtrUninit, value: PtrMut) -> PtrMut {
529 unsafe {
530 let t = value.read::<T>();
531 let lock = OnceLock::new();
532 lock.set(t).ok();
533 this.put(lock)
534 }
535}
536
537unsafe fn oncelock_drop<T>(ox: OxPtrMut) {
538 unsafe { core::ptr::drop_in_place(ox.ptr().as_ptr::<OnceLock<T>>() as *mut OnceLock<T>) }
539}
540
541const fn oncelock_guard_vtable() -> LockGuardVTable {
542 const unsafe fn drop_guard(_guard: PtrConst) {
543 }
545 LockGuardVTable {
546 drop_in_place: drop_guard,
547 }
548}
549
550unsafe fn oncelock_read<'a, T: Facet<'a>>(opaque: PtrConst) -> Result<ReadLockResult, ()> {
552 unsafe {
553 let lock = opaque.get::<OnceLock<T>>();
554 match lock.get() {
555 Some(data) => {
556 let data_ptr = NonNull::from(data).as_ptr();
557 Ok(ReadLockResult::new(
559 PtrConst::new(data_ptr as *const u8),
560 PtrConst::new(core::ptr::null::<()>()),
561 &const { oncelock_guard_vtable() },
562 ))
563 }
564 None => Err(()),
565 }
566 }
567}
568
569unsafe impl<'a, T: Facet<'a>> Facet<'a> for OnceLock<T> {
570 const SHAPE: &'static Shape = &const {
571 ShapeBuilder::for_sized::<Self>("OnceLock")
572 .decl_id(DeclId::new(decl_id_hash("#std#OnceLock")))
573 .type_name(type_name_oncelock::<T>)
574 .vtable_indirect(&VTableIndirect::EMPTY)
575 .type_ops_indirect(
576 &const {
577 TypeOpsIndirect {
578 drop_in_place: oncelock_drop::<T>,
579 default_in_place: None,
580 clone_into: None,
581 is_truthy: None,
582 }
583 },
584 )
585 .ty(Type::User(UserType::Opaque))
586 .def(Def::Pointer(PointerDef {
587 vtable: &const {
588 PointerVTable {
589 read_fn: Some(oncelock_read::<T>),
590 new_into_fn: Some(oncelock_new_into::<T>),
591 ..PointerVTable::new()
592 }
593 },
594 pointee: Some(T::SHAPE),
595 weak: None,
596 strong: None,
597 flags: PointerFlags::empty(),
598 known: Some(KnownPointer::OnceLock),
599 }))
600 .type_params(&[TypeParam {
601 name: "T",
602 shape: T::SHAPE,
603 }])
604 .inner(T::SHAPE)
605 .variance(VarianceDesc {
607 base: Variance::Bivariant,
608 deps: &const { [VarianceDep::invariant(T::SHAPE)] },
609 })
610 .build()
611 };
612}
613
614fn type_name_lazylock<'a, T: Facet<'a>>(
619 _shape: &'static Shape,
620 f: &mut core::fmt::Formatter<'_>,
621 opts: TypeNameOpts,
622) -> core::fmt::Result {
623 write!(f, "LazyLock")?;
624 if let Some(opts) = opts.for_children() {
625 write!(f, "<")?;
626 T::SHAPE.write_type_name(f, opts)?;
627 write!(f, ">")?;
628 } else {
629 write!(f, "<\u{2026}>")?;
630 }
631 Ok(())
632}
633
634unsafe fn lazylock_drop<T, F>(ox: OxPtrMut) {
635 unsafe { core::ptr::drop_in_place(ox.ptr().as_ptr::<LazyLock<T, F>>() as *mut LazyLock<T, F>) }
636}
637
638unsafe extern "C" fn lazylock_borrow<'a, T: Facet<'a>, F: FnOnce() -> T>(
640 opaque: PtrConst,
641) -> PtrConst {
642 unsafe {
643 let lock = opaque.get::<LazyLock<T, F>>();
644 let data = LazyLock::force(lock);
645 PtrConst::new(NonNull::from(data).as_ptr())
646 }
647}
648
649unsafe impl<'a, T: Facet<'a>, F: FnOnce() -> T + 'a> Facet<'a> for LazyLock<T, F> {
650 const SHAPE: &'static Shape = &const {
651 ShapeBuilder::for_sized::<Self>("LazyLock")
652 .decl_id(DeclId::new(decl_id_hash("#std#LazyLock")))
653 .type_name(type_name_lazylock::<T>)
654 .vtable_indirect(&VTableIndirect::EMPTY)
655 .type_ops_indirect(
656 &const {
657 TypeOpsIndirect {
658 drop_in_place: lazylock_drop::<T, F>,
659 default_in_place: None,
660 clone_into: None,
661 is_truthy: None,
662 }
663 },
664 )
665 .ty(Type::User(UserType::Opaque))
666 .def(Def::Pointer(PointerDef {
667 vtable: &const {
668 PointerVTable {
669 borrow_fn: Some(lazylock_borrow::<T, F>),
670 ..PointerVTable::new()
671 }
672 },
673 pointee: Some(T::SHAPE),
674 weak: None,
675 strong: None,
676 flags: PointerFlags::empty(),
677 known: Some(KnownPointer::LazyLock),
678 }))
679 .type_params(&[TypeParam {
680 name: "T",
681 shape: T::SHAPE,
682 }])
683 .inner(T::SHAPE)
684 .variance(VarianceDesc {
686 base: Variance::Bivariant,
687 deps: &const { [VarianceDep::invariant(T::SHAPE)] },
688 })
689 .build()
690 };
691}
692
693#[cfg(test)]
698mod tests {
699 use super::*;
700 use alloc::string::String;
701
702 #[test]
707 fn test_mutex_shape() {
708 facet_testhelpers::setup();
709
710 let shape = <Mutex<i32>>::SHAPE;
711 assert_eq!(shape.type_identifier, "Mutex");
712
713 let [type_param] = shape.type_params else {
715 panic!("Mutex should have 1 type param");
716 };
717 assert_eq!(type_param.name, "T");
718 assert_eq!(type_param.shape, i32::SHAPE);
719 }
720
721 #[test]
722 fn test_rwlock_shape() {
723 facet_testhelpers::setup();
724
725 let shape = <RwLock<String>>::SHAPE;
726 assert_eq!(shape.type_identifier, "RwLock");
727
728 let [type_param] = shape.type_params else {
730 panic!("RwLock should have 1 type param");
731 };
732 assert_eq!(type_param.name, "T");
733 assert_eq!(type_param.shape, String::SHAPE);
734 }
735
736 #[test]
737 fn test_mutex_guard_shape() {
738 facet_testhelpers::setup();
739
740 let shape = <MutexGuard<'_, i32>>::SHAPE;
741 assert_eq!(shape.type_identifier, "MutexGuard");
742
743 let [type_param] = shape.type_params else {
744 panic!("MutexGuard should have 1 type param");
745 };
746 assert_eq!(type_param.name, "T");
747 }
748
749 #[test]
750 fn test_rwlock_read_guard_shape() {
751 facet_testhelpers::setup();
752
753 let shape = <RwLockReadGuard<'_, i32>>::SHAPE;
754 assert_eq!(shape.type_identifier, "RwLockReadGuard");
755
756 let [type_param] = shape.type_params else {
757 panic!("RwLockReadGuard should have 1 type param");
758 };
759 assert_eq!(type_param.name, "T");
760 }
761
762 #[test]
763 fn test_rwlock_write_guard_shape() {
764 facet_testhelpers::setup();
765
766 let shape = <RwLockWriteGuard<'_, i32>>::SHAPE;
767 assert_eq!(shape.type_identifier, "RwLockWriteGuard");
768
769 let [type_param] = shape.type_params else {
770 panic!("RwLockWriteGuard should have 1 type param");
771 };
772 assert_eq!(type_param.name, "T");
773 }
774
775 #[test]
780 fn test_mutex_vtable() {
781 facet_testhelpers::setup();
782
783 let shape = <Mutex<i32>>::SHAPE;
784 let pointer_def = shape
785 .def
786 .into_pointer()
787 .expect("Mutex should be a pointer type");
788
789 assert!(
791 pointer_def.vtable.lock_fn.is_some(),
792 "Mutex should have lock_fn"
793 );
794 assert!(
795 pointer_def.vtable.new_into_fn.is_some(),
796 "Mutex should have new_into_fn"
797 );
798
799 assert!(
801 pointer_def.vtable.read_fn.is_none(),
802 "Mutex should not have read_fn"
803 );
804 assert!(
805 pointer_def.vtable.write_fn.is_none(),
806 "Mutex should not have write_fn"
807 );
808
809 assert!(
811 pointer_def.flags.contains(PointerFlags::LOCK),
812 "Mutex should have LOCK flag"
813 );
814 assert_eq!(pointer_def.known, Some(KnownPointer::Mutex));
815 }
816
817 #[test]
818 fn test_rwlock_vtable() {
819 facet_testhelpers::setup();
820
821 let shape = <RwLock<i32>>::SHAPE;
822 let pointer_def = shape
823 .def
824 .into_pointer()
825 .expect("RwLock should be a pointer type");
826
827 assert!(
829 pointer_def.vtable.read_fn.is_some(),
830 "RwLock should have read_fn"
831 );
832 assert!(
833 pointer_def.vtable.write_fn.is_some(),
834 "RwLock should have write_fn"
835 );
836 assert!(
837 pointer_def.vtable.new_into_fn.is_some(),
838 "RwLock should have new_into_fn"
839 );
840
841 assert!(
843 pointer_def.vtable.lock_fn.is_none(),
844 "RwLock should not have lock_fn"
845 );
846
847 assert!(
849 pointer_def.flags.contains(PointerFlags::LOCK),
850 "RwLock should have LOCK flag"
851 );
852 assert_eq!(pointer_def.known, Some(KnownPointer::RwLock));
853 }
854
855 #[test]
856 fn test_guard_vtables_have_borrow_fn() {
857 facet_testhelpers::setup();
858
859 let mutex_guard_shape = <MutexGuard<'_, i32>>::SHAPE;
861 let mutex_guard_def = mutex_guard_shape
862 .def
863 .into_pointer()
864 .expect("MutexGuard should be a pointer type");
865 assert!(
866 mutex_guard_def.vtable.borrow_fn.is_some(),
867 "MutexGuard should have borrow_fn"
868 );
869
870 let read_guard_shape = <RwLockReadGuard<'_, i32>>::SHAPE;
872 let read_guard_def = read_guard_shape
873 .def
874 .into_pointer()
875 .expect("RwLockReadGuard should be a pointer type");
876 assert!(
877 read_guard_def.vtable.borrow_fn.is_some(),
878 "RwLockReadGuard should have borrow_fn"
879 );
880
881 let write_guard_shape = <RwLockWriteGuard<'_, i32>>::SHAPE;
883 let write_guard_def = write_guard_shape
884 .def
885 .into_pointer()
886 .expect("RwLockWriteGuard should be a pointer type");
887 assert!(
888 write_guard_def.vtable.borrow_fn.is_some(),
889 "RwLockWriteGuard should have borrow_fn"
890 );
891 }
892
893 #[test]
898 fn test_mutex_lock_and_access() {
899 facet_testhelpers::setup();
900
901 let mutex = Mutex::new(42i32);
902
903 let shape = <Mutex<i32>>::SHAPE;
905 let pointer_def = shape.def.into_pointer().unwrap();
906 let lock_fn = pointer_def.vtable.lock_fn.unwrap();
907
908 let mutex_ptr = PtrConst::new(&mutex as *const _ as *const u8);
910 let lock_result = unsafe { lock_fn(mutex_ptr) }.expect("Lock should succeed");
911
912 let data_ptr = lock_result.data();
914 let value = unsafe { data_ptr.as_const().get::<i32>() };
915 assert_eq!(*value, 42);
916
917 drop(lock_result);
919
920 let lock_result2 = unsafe { lock_fn(mutex_ptr) }.expect("Second lock should succeed");
922 drop(lock_result2);
923 }
924
925 #[test]
926 fn test_rwlock_read_access() {
927 facet_testhelpers::setup();
928
929 let rwlock = RwLock::new(String::from("hello"));
930
931 let shape = <RwLock<String>>::SHAPE;
932 let pointer_def = shape.def.into_pointer().unwrap();
933 let read_fn = pointer_def.vtable.read_fn.unwrap();
934
935 let rwlock_ptr = PtrConst::new(&rwlock as *const _ as *const u8);
936
937 let read_result = unsafe { read_fn(rwlock_ptr) }.expect("Read lock should succeed");
939
940 let data_ptr = read_result.data();
942 let value = unsafe { data_ptr.get::<String>() };
943 assert_eq!(value.as_str(), "hello");
944
945 drop(read_result);
946 }
947
948 #[test]
949 fn test_rwlock_write_access() {
950 facet_testhelpers::setup();
951
952 let rwlock = RwLock::new(100i32);
953
954 let shape = <RwLock<i32>>::SHAPE;
955 let pointer_def = shape.def.into_pointer().unwrap();
956 let write_fn = pointer_def.vtable.write_fn.unwrap();
957
958 let rwlock_ptr = PtrConst::new(&rwlock as *const _ as *const u8);
959
960 let write_result = unsafe { write_fn(rwlock_ptr) }.expect("Write lock should succeed");
962
963 let data_ptr = write_result.data();
965 unsafe {
966 *data_ptr.as_mut_ptr::<i32>() = 200;
967 }
968
969 drop(write_result);
970
971 let read_fn = pointer_def.vtable.read_fn.unwrap();
973 let read_result = unsafe { read_fn(rwlock_ptr) }.expect("Read lock should succeed");
974 let value = unsafe { read_result.data().get::<i32>() };
976 assert_eq!(*value, 200);
977 }
978
979 #[test]
980 fn test_poisoned_mutex_still_works() {
981 facet_testhelpers::setup();
982
983 let mutex = Mutex::new(42i32);
984
985 let _ = std::panic::catch_unwind(core::panic::AssertUnwindSafe(|| {
987 let _guard = mutex.lock().unwrap();
988 panic!("Intentional panic to poison the mutex");
989 }));
990
991 let shape = <Mutex<i32>>::SHAPE;
993 let pointer_def = shape.def.into_pointer().unwrap();
994 let lock_fn = pointer_def.vtable.lock_fn.unwrap();
995
996 let mutex_ptr = PtrConst::new(&mutex as *const _ as *const u8);
997
998 let lock_result =
1000 unsafe { lock_fn(mutex_ptr) }.expect("Lock should succeed even when poisoned");
1001
1002 let data_ptr = lock_result.data();
1004 let value = unsafe { data_ptr.as_const().get::<i32>() };
1005 assert_eq!(*value, 42);
1006 }
1007
1008 #[test]
1009 fn test_poisoned_rwlock_still_works() {
1010 facet_testhelpers::setup();
1011
1012 let rwlock = RwLock::new(String::from("hello"));
1013
1014 let _ = std::panic::catch_unwind(core::panic::AssertUnwindSafe(|| {
1016 let _guard = rwlock.write().unwrap();
1017 panic!("Intentional panic to poison the rwlock");
1018 }));
1019
1020 let shape = <RwLock<String>>::SHAPE;
1022 let pointer_def = shape.def.into_pointer().unwrap();
1023 let read_fn = pointer_def.vtable.read_fn.unwrap();
1024
1025 let rwlock_ptr = PtrConst::new(&rwlock as *const _ as *const u8);
1026
1027 let read_result =
1029 unsafe { read_fn(rwlock_ptr) }.expect("Read should succeed even when poisoned");
1030
1031 let data_ptr = read_result.data();
1033 let value = unsafe { data_ptr.get::<String>() };
1034 assert_eq!(value.as_str(), "hello");
1035 }
1036
1037 #[test]
1042 fn test_oncelock_shape() {
1043 facet_testhelpers::setup();
1044
1045 let shape = <OnceLock<i32>>::SHAPE;
1046 assert_eq!(shape.type_identifier, "OnceLock");
1047
1048 let [type_param] = shape.type_params else {
1049 panic!("OnceLock should have 1 type param");
1050 };
1051 assert_eq!(type_param.name, "T");
1052 assert_eq!(type_param.shape, i32::SHAPE);
1053 }
1054
1055 #[test]
1056 fn test_oncelock_vtable() {
1057 facet_testhelpers::setup();
1058
1059 let shape = <OnceLock<i32>>::SHAPE;
1060 let pointer_def = shape
1061 .def
1062 .into_pointer()
1063 .expect("OnceLock should be a pointer type");
1064
1065 assert!(
1067 pointer_def.vtable.read_fn.is_some(),
1068 "OnceLock should have read_fn"
1069 );
1070 assert!(
1071 pointer_def.vtable.new_into_fn.is_some(),
1072 "OnceLock should have new_into_fn"
1073 );
1074
1075 assert!(
1077 pointer_def.vtable.borrow_fn.is_none(),
1078 "OnceLock should not have borrow_fn"
1079 );
1080
1081 assert_eq!(pointer_def.known, Some(KnownPointer::OnceLock));
1082 }
1083
1084 #[test]
1085 fn test_oncelock_read_initialized() {
1086 facet_testhelpers::setup();
1087
1088 let lock = OnceLock::new();
1089 lock.set(42i32).ok();
1090
1091 let shape = <OnceLock<i32>>::SHAPE;
1092 let pointer_def = shape.def.into_pointer().unwrap();
1093 let read_fn = pointer_def.vtable.read_fn.unwrap();
1094
1095 let lock_ptr = PtrConst::new(&lock as *const _ as *const u8);
1096 let read_result =
1097 unsafe { read_fn(lock_ptr) }.expect("Read should succeed when initialized");
1098
1099 let value = unsafe { read_result.data().get::<i32>() };
1100 assert_eq!(*value, 42);
1101 }
1102
1103 #[test]
1104 fn test_oncelock_read_uninitialized() {
1105 facet_testhelpers::setup();
1106
1107 let lock: OnceLock<i32> = OnceLock::new();
1108
1109 let shape = <OnceLock<i32>>::SHAPE;
1110 let pointer_def = shape.def.into_pointer().unwrap();
1111 let read_fn = pointer_def.vtable.read_fn.unwrap();
1112
1113 let lock_ptr = PtrConst::new(&lock as *const _ as *const u8);
1114 let result = unsafe { read_fn(lock_ptr) };
1115
1116 assert!(result.is_err(), "Read should fail when uninitialized");
1117 }
1118
1119 #[test]
1124 fn test_lazylock_shape() {
1125 facet_testhelpers::setup();
1126
1127 let shape = <LazyLock<i32, fn() -> i32>>::SHAPE;
1128 assert_eq!(shape.type_identifier, "LazyLock");
1129
1130 let [type_param] = shape.type_params else {
1132 panic!("LazyLock should have 1 type param");
1133 };
1134 assert_eq!(type_param.name, "T");
1135 assert_eq!(type_param.shape, i32::SHAPE);
1136 }
1137
1138 #[test]
1139 fn test_lazylock_vtable() {
1140 facet_testhelpers::setup();
1141
1142 let shape = <LazyLock<i32, fn() -> i32>>::SHAPE;
1143 let pointer_def = shape
1144 .def
1145 .into_pointer()
1146 .expect("LazyLock should be a pointer type");
1147
1148 assert!(
1150 pointer_def.vtable.borrow_fn.is_some(),
1151 "LazyLock should have borrow_fn"
1152 );
1153
1154 assert!(
1156 pointer_def.vtable.read_fn.is_none(),
1157 "LazyLock should not have read_fn"
1158 );
1159
1160 assert_eq!(pointer_def.known, Some(KnownPointer::LazyLock));
1161 }
1162
1163 #[test]
1164 fn test_lazylock_borrow() {
1165 facet_testhelpers::setup();
1166
1167 let lock: LazyLock<i32, fn() -> i32> = LazyLock::new(|| 42);
1168
1169 let shape = <LazyLock<i32, fn() -> i32>>::SHAPE;
1170 let pointer_def = shape.def.into_pointer().unwrap();
1171 let borrow_fn = pointer_def.vtable.borrow_fn.unwrap();
1172
1173 let lock_ptr = PtrConst::new(&lock as *const _ as *const u8);
1174 let data_ptr = unsafe { borrow_fn(lock_ptr) };
1175
1176 let value = unsafe { data_ptr.get::<i32>() };
1177 assert_eq!(*value, 42);
1178 }
1179}