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 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 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 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 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 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 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 fn lazylock_borrow<'a, T: Facet<'a>, F: FnOnce() -> T>(opaque: PtrConst) -> PtrConst {
640 unsafe {
641 let lock = opaque.get::<LazyLock<T, F>>();
642 let data = LazyLock::force(lock);
643 PtrConst::new(NonNull::from(data).as_ptr())
644 }
645}
646
647unsafe impl<'a, T: Facet<'a>, F: FnOnce() -> T + 'a> Facet<'a> for LazyLock<T, F> {
648 const SHAPE: &'static Shape = &const {
649 ShapeBuilder::for_sized::<Self>("LazyLock")
650 .decl_id(DeclId::new(decl_id_hash("#std#LazyLock")))
651 .type_name(type_name_lazylock::<T>)
652 .vtable_indirect(&VTableIndirect::EMPTY)
653 .type_ops_indirect(
654 &const {
655 TypeOpsIndirect {
656 drop_in_place: lazylock_drop::<T, F>,
657 default_in_place: None,
658 clone_into: None,
659 is_truthy: None,
660 }
661 },
662 )
663 .ty(Type::User(UserType::Opaque))
664 .def(Def::Pointer(PointerDef {
665 vtable: &const {
666 PointerVTable {
667 borrow_fn: Some(lazylock_borrow::<T, F>),
668 ..PointerVTable::new()
669 }
670 },
671 pointee: Some(T::SHAPE),
672 weak: None,
673 strong: None,
674 flags: PointerFlags::empty(),
675 known: Some(KnownPointer::LazyLock),
676 }))
677 .type_params(&[TypeParam {
678 name: "T",
679 shape: T::SHAPE,
680 }])
681 .inner(T::SHAPE)
682 .variance(VarianceDesc {
684 base: Variance::Bivariant,
685 deps: &const { [VarianceDep::invariant(T::SHAPE)] },
686 })
687 .build()
688 };
689}
690
691#[cfg(test)]
696mod tests {
697 use super::*;
698 use alloc::string::String;
699
700 #[test]
705 fn test_mutex_shape() {
706 facet_testhelpers::setup();
707
708 let shape = <Mutex<i32>>::SHAPE;
709 assert_eq!(shape.type_identifier, "Mutex");
710
711 let [type_param] = shape.type_params else {
713 panic!("Mutex should have 1 type param");
714 };
715 assert_eq!(type_param.name, "T");
716 assert_eq!(type_param.shape, i32::SHAPE);
717 }
718
719 #[test]
720 fn test_rwlock_shape() {
721 facet_testhelpers::setup();
722
723 let shape = <RwLock<String>>::SHAPE;
724 assert_eq!(shape.type_identifier, "RwLock");
725
726 let [type_param] = shape.type_params else {
728 panic!("RwLock should have 1 type param");
729 };
730 assert_eq!(type_param.name, "T");
731 assert_eq!(type_param.shape, String::SHAPE);
732 }
733
734 #[test]
735 fn test_mutex_guard_shape() {
736 facet_testhelpers::setup();
737
738 let shape = <MutexGuard<'_, i32>>::SHAPE;
739 assert_eq!(shape.type_identifier, "MutexGuard");
740
741 let [type_param] = shape.type_params else {
742 panic!("MutexGuard should have 1 type param");
743 };
744 assert_eq!(type_param.name, "T");
745 }
746
747 #[test]
748 fn test_rwlock_read_guard_shape() {
749 facet_testhelpers::setup();
750
751 let shape = <RwLockReadGuard<'_, i32>>::SHAPE;
752 assert_eq!(shape.type_identifier, "RwLockReadGuard");
753
754 let [type_param] = shape.type_params else {
755 panic!("RwLockReadGuard should have 1 type param");
756 };
757 assert_eq!(type_param.name, "T");
758 }
759
760 #[test]
761 fn test_rwlock_write_guard_shape() {
762 facet_testhelpers::setup();
763
764 let shape = <RwLockWriteGuard<'_, i32>>::SHAPE;
765 assert_eq!(shape.type_identifier, "RwLockWriteGuard");
766
767 let [type_param] = shape.type_params else {
768 panic!("RwLockWriteGuard should have 1 type param");
769 };
770 assert_eq!(type_param.name, "T");
771 }
772
773 #[test]
778 fn test_mutex_vtable() {
779 facet_testhelpers::setup();
780
781 let shape = <Mutex<i32>>::SHAPE;
782 let pointer_def = shape
783 .def
784 .into_pointer()
785 .expect("Mutex should be a pointer type");
786
787 assert!(
789 pointer_def.vtable.lock_fn.is_some(),
790 "Mutex should have lock_fn"
791 );
792 assert!(
793 pointer_def.vtable.new_into_fn.is_some(),
794 "Mutex should have new_into_fn"
795 );
796
797 assert!(
799 pointer_def.vtable.read_fn.is_none(),
800 "Mutex should not have read_fn"
801 );
802 assert!(
803 pointer_def.vtable.write_fn.is_none(),
804 "Mutex should not have write_fn"
805 );
806
807 assert!(
809 pointer_def.flags.contains(PointerFlags::LOCK),
810 "Mutex should have LOCK flag"
811 );
812 assert_eq!(pointer_def.known, Some(KnownPointer::Mutex));
813 }
814
815 #[test]
816 fn test_rwlock_vtable() {
817 facet_testhelpers::setup();
818
819 let shape = <RwLock<i32>>::SHAPE;
820 let pointer_def = shape
821 .def
822 .into_pointer()
823 .expect("RwLock should be a pointer type");
824
825 assert!(
827 pointer_def.vtable.read_fn.is_some(),
828 "RwLock should have read_fn"
829 );
830 assert!(
831 pointer_def.vtable.write_fn.is_some(),
832 "RwLock should have write_fn"
833 );
834 assert!(
835 pointer_def.vtable.new_into_fn.is_some(),
836 "RwLock should have new_into_fn"
837 );
838
839 assert!(
841 pointer_def.vtable.lock_fn.is_none(),
842 "RwLock should not have lock_fn"
843 );
844
845 assert!(
847 pointer_def.flags.contains(PointerFlags::LOCK),
848 "RwLock should have LOCK flag"
849 );
850 assert_eq!(pointer_def.known, Some(KnownPointer::RwLock));
851 }
852
853 #[test]
854 fn test_guard_vtables_have_borrow_fn() {
855 facet_testhelpers::setup();
856
857 let mutex_guard_shape = <MutexGuard<'_, i32>>::SHAPE;
859 let mutex_guard_def = mutex_guard_shape
860 .def
861 .into_pointer()
862 .expect("MutexGuard should be a pointer type");
863 assert!(
864 mutex_guard_def.vtable.borrow_fn.is_some(),
865 "MutexGuard should have borrow_fn"
866 );
867
868 let read_guard_shape = <RwLockReadGuard<'_, i32>>::SHAPE;
870 let read_guard_def = read_guard_shape
871 .def
872 .into_pointer()
873 .expect("RwLockReadGuard should be a pointer type");
874 assert!(
875 read_guard_def.vtable.borrow_fn.is_some(),
876 "RwLockReadGuard should have borrow_fn"
877 );
878
879 let write_guard_shape = <RwLockWriteGuard<'_, i32>>::SHAPE;
881 let write_guard_def = write_guard_shape
882 .def
883 .into_pointer()
884 .expect("RwLockWriteGuard should be a pointer type");
885 assert!(
886 write_guard_def.vtable.borrow_fn.is_some(),
887 "RwLockWriteGuard should have borrow_fn"
888 );
889 }
890
891 #[test]
896 fn test_mutex_lock_and_access() {
897 facet_testhelpers::setup();
898
899 let mutex = Mutex::new(42i32);
900
901 let shape = <Mutex<i32>>::SHAPE;
903 let pointer_def = shape.def.into_pointer().unwrap();
904 let lock_fn = pointer_def.vtable.lock_fn.unwrap();
905
906 let mutex_ptr = PtrConst::new(&mutex as *const _ as *const u8);
908 let lock_result = unsafe { lock_fn(mutex_ptr) }.expect("Lock should succeed");
909
910 let data_ptr = lock_result.data();
912 let value = unsafe { data_ptr.as_const().get::<i32>() };
913 assert_eq!(*value, 42);
914
915 drop(lock_result);
917
918 let lock_result2 = unsafe { lock_fn(mutex_ptr) }.expect("Second lock should succeed");
920 drop(lock_result2);
921 }
922
923 #[test]
924 fn test_rwlock_read_access() {
925 facet_testhelpers::setup();
926
927 let rwlock = RwLock::new(String::from("hello"));
928
929 let shape = <RwLock<String>>::SHAPE;
930 let pointer_def = shape.def.into_pointer().unwrap();
931 let read_fn = pointer_def.vtable.read_fn.unwrap();
932
933 let rwlock_ptr = PtrConst::new(&rwlock as *const _ as *const u8);
934
935 let read_result = unsafe { read_fn(rwlock_ptr) }.expect("Read lock should succeed");
937
938 let data_ptr = read_result.data();
940 let value = unsafe { data_ptr.get::<String>() };
941 assert_eq!(value.as_str(), "hello");
942
943 drop(read_result);
944 }
945
946 #[test]
947 fn test_rwlock_write_access() {
948 facet_testhelpers::setup();
949
950 let rwlock = RwLock::new(100i32);
951
952 let shape = <RwLock<i32>>::SHAPE;
953 let pointer_def = shape.def.into_pointer().unwrap();
954 let write_fn = pointer_def.vtable.write_fn.unwrap();
955
956 let rwlock_ptr = PtrConst::new(&rwlock as *const _ as *const u8);
957
958 let write_result = unsafe { write_fn(rwlock_ptr) }.expect("Write lock should succeed");
960
961 let data_ptr = write_result.data();
963 unsafe {
964 *data_ptr.as_mut_ptr::<i32>() = 200;
965 }
966
967 drop(write_result);
968
969 let read_fn = pointer_def.vtable.read_fn.unwrap();
971 let read_result = unsafe { read_fn(rwlock_ptr) }.expect("Read lock should succeed");
972 let value = unsafe { read_result.data().get::<i32>() };
974 assert_eq!(*value, 200);
975 }
976
977 #[test]
978 fn test_poisoned_mutex_still_works() {
979 facet_testhelpers::setup();
980
981 let mutex = Mutex::new(42i32);
982
983 let _ = std::panic::catch_unwind(core::panic::AssertUnwindSafe(|| {
985 let _guard = mutex.lock().unwrap();
986 panic!("Intentional panic to poison the mutex");
987 }));
988
989 let shape = <Mutex<i32>>::SHAPE;
991 let pointer_def = shape.def.into_pointer().unwrap();
992 let lock_fn = pointer_def.vtable.lock_fn.unwrap();
993
994 let mutex_ptr = PtrConst::new(&mutex as *const _ as *const u8);
995
996 let lock_result =
998 unsafe { lock_fn(mutex_ptr) }.expect("Lock should succeed even when poisoned");
999
1000 let data_ptr = lock_result.data();
1002 let value = unsafe { data_ptr.as_const().get::<i32>() };
1003 assert_eq!(*value, 42);
1004 }
1005
1006 #[test]
1007 fn test_poisoned_rwlock_still_works() {
1008 facet_testhelpers::setup();
1009
1010 let rwlock = RwLock::new(String::from("hello"));
1011
1012 let _ = std::panic::catch_unwind(core::panic::AssertUnwindSafe(|| {
1014 let _guard = rwlock.write().unwrap();
1015 panic!("Intentional panic to poison the rwlock");
1016 }));
1017
1018 let shape = <RwLock<String>>::SHAPE;
1020 let pointer_def = shape.def.into_pointer().unwrap();
1021 let read_fn = pointer_def.vtable.read_fn.unwrap();
1022
1023 let rwlock_ptr = PtrConst::new(&rwlock as *const _ as *const u8);
1024
1025 let read_result =
1027 unsafe { read_fn(rwlock_ptr) }.expect("Read should succeed even when poisoned");
1028
1029 let data_ptr = read_result.data();
1031 let value = unsafe { data_ptr.get::<String>() };
1032 assert_eq!(value.as_str(), "hello");
1033 }
1034
1035 #[test]
1040 fn test_oncelock_shape() {
1041 facet_testhelpers::setup();
1042
1043 let shape = <OnceLock<i32>>::SHAPE;
1044 assert_eq!(shape.type_identifier, "OnceLock");
1045
1046 let [type_param] = shape.type_params else {
1047 panic!("OnceLock should have 1 type param");
1048 };
1049 assert_eq!(type_param.name, "T");
1050 assert_eq!(type_param.shape, i32::SHAPE);
1051 }
1052
1053 #[test]
1054 fn test_oncelock_vtable() {
1055 facet_testhelpers::setup();
1056
1057 let shape = <OnceLock<i32>>::SHAPE;
1058 let pointer_def = shape
1059 .def
1060 .into_pointer()
1061 .expect("OnceLock should be a pointer type");
1062
1063 assert!(
1065 pointer_def.vtable.read_fn.is_some(),
1066 "OnceLock should have read_fn"
1067 );
1068 assert!(
1069 pointer_def.vtable.new_into_fn.is_some(),
1070 "OnceLock should have new_into_fn"
1071 );
1072
1073 assert!(
1075 pointer_def.vtable.borrow_fn.is_none(),
1076 "OnceLock should not have borrow_fn"
1077 );
1078
1079 assert_eq!(pointer_def.known, Some(KnownPointer::OnceLock));
1080 }
1081
1082 #[test]
1083 fn test_oncelock_read_initialized() {
1084 facet_testhelpers::setup();
1085
1086 let lock = OnceLock::new();
1087 lock.set(42i32).ok();
1088
1089 let shape = <OnceLock<i32>>::SHAPE;
1090 let pointer_def = shape.def.into_pointer().unwrap();
1091 let read_fn = pointer_def.vtable.read_fn.unwrap();
1092
1093 let lock_ptr = PtrConst::new(&lock as *const _ as *const u8);
1094 let read_result =
1095 unsafe { read_fn(lock_ptr) }.expect("Read should succeed when initialized");
1096
1097 let value = unsafe { read_result.data().get::<i32>() };
1098 assert_eq!(*value, 42);
1099 }
1100
1101 #[test]
1102 fn test_oncelock_read_uninitialized() {
1103 facet_testhelpers::setup();
1104
1105 let lock: OnceLock<i32> = OnceLock::new();
1106
1107 let shape = <OnceLock<i32>>::SHAPE;
1108 let pointer_def = shape.def.into_pointer().unwrap();
1109 let read_fn = pointer_def.vtable.read_fn.unwrap();
1110
1111 let lock_ptr = PtrConst::new(&lock as *const _ as *const u8);
1112 let result = unsafe { read_fn(lock_ptr) };
1113
1114 assert!(result.is_err(), "Read should fail when uninitialized");
1115 }
1116
1117 #[test]
1122 fn test_lazylock_shape() {
1123 facet_testhelpers::setup();
1124
1125 let shape = <LazyLock<i32, fn() -> i32>>::SHAPE;
1126 assert_eq!(shape.type_identifier, "LazyLock");
1127
1128 let [type_param] = shape.type_params else {
1130 panic!("LazyLock should have 1 type param");
1131 };
1132 assert_eq!(type_param.name, "T");
1133 assert_eq!(type_param.shape, i32::SHAPE);
1134 }
1135
1136 #[test]
1137 fn test_lazylock_vtable() {
1138 facet_testhelpers::setup();
1139
1140 let shape = <LazyLock<i32, fn() -> i32>>::SHAPE;
1141 let pointer_def = shape
1142 .def
1143 .into_pointer()
1144 .expect("LazyLock should be a pointer type");
1145
1146 assert!(
1148 pointer_def.vtable.borrow_fn.is_some(),
1149 "LazyLock should have borrow_fn"
1150 );
1151
1152 assert!(
1154 pointer_def.vtable.read_fn.is_none(),
1155 "LazyLock should not have read_fn"
1156 );
1157
1158 assert_eq!(pointer_def.known, Some(KnownPointer::LazyLock));
1159 }
1160
1161 #[test]
1162 fn test_lazylock_borrow() {
1163 facet_testhelpers::setup();
1164
1165 let lock: LazyLock<i32, fn() -> i32> = LazyLock::new(|| 42);
1166
1167 let shape = <LazyLock<i32, fn() -> i32>>::SHAPE;
1168 let pointer_def = shape.def.into_pointer().unwrap();
1169 let borrow_fn = pointer_def.vtable.borrow_fn.unwrap();
1170
1171 let lock_ptr = PtrConst::new(&lock as *const _ as *const u8);
1172 let data_ptr = unsafe { borrow_fn(lock_ptr) };
1173
1174 let value = unsafe { data_ptr.get::<i32>() };
1175 assert_eq!(*value, 42);
1176 }
1177}