use alloc::boxed::Box;
use core::ptr::NonNull;
use std::sync::{LazyLock, Mutex, MutexGuard, OnceLock, RwLock, RwLockReadGuard, RwLockWriteGuard};
use crate::{
DeclId, Def, Facet, KnownPointer, LockGuardVTable, OxPtrMut, PointerDef, PointerFlags,
PointerVTable, PtrConst, PtrMut, PtrUninit, ReadLockResult, Shape, ShapeBuilder, Type,
TypeNameOpts, TypeOpsIndirect, TypeParam, UserType, VTableIndirect, Variance, VarianceDep,
VarianceDesc, WriteLockResult, decl_id_hash,
};
fn type_name_mutex<'a, T: Facet<'a>>(
_shape: &'static Shape,
f: &mut core::fmt::Formatter<'_>,
opts: TypeNameOpts,
) -> core::fmt::Result {
write!(f, "Mutex")?;
if let Some(opts) = opts.for_children() {
write!(f, "<")?;
T::SHAPE.write_type_name(f, opts)?;
write!(f, ">")?;
} else {
write!(f, "<\u{2026}>")?;
}
Ok(())
}
unsafe extern "C" fn mutex_new_into<T>(this: PtrUninit, value: PtrMut) -> PtrMut {
unsafe {
let t = value.read::<T>();
this.put(Mutex::<T>::new(t))
}
}
unsafe fn mutex_drop<T>(ox: OxPtrMut) {
unsafe { core::ptr::drop_in_place(ox.ptr().as_ptr::<Mutex<T>>() as *mut Mutex<T>) }
}
unsafe fn mutex_lock<'a, T: Facet<'a>>(opaque: PtrConst) -> Result<WriteLockResult, ()> {
unsafe {
let mutex = &*opaque.as_ptr::<Mutex<T>>();
let mut guard = match mutex.lock() {
Ok(g) => g,
Err(e) => e.into_inner(),
};
let data_ptr = &mut *guard as *mut T;
let guard_box = Box::new(guard);
let guard_ptr = Box::into_raw(guard_box) as *const u8;
Ok(WriteLockResult::new(
PtrMut::new(data_ptr as *mut u8),
PtrConst::new(guard_ptr),
&const { mutex_guard_vtable::<T>() },
))
}
}
const fn mutex_guard_vtable<T>() -> LockGuardVTable {
unsafe fn drop_guard<T>(guard: PtrConst) {
unsafe {
drop(Box::from_raw(
guard.as_ptr::<MutexGuard<'_, T>>() as *mut MutexGuard<'_, T>
));
}
}
LockGuardVTable {
drop_in_place: drop_guard::<T>,
}
}
unsafe impl<'a, T: Facet<'a>> Facet<'a> for Mutex<T> {
const SHAPE: &'static Shape = &const {
ShapeBuilder::for_sized::<Self>("Mutex")
.decl_id(DeclId::new(decl_id_hash("#std#Mutex")))
.type_name(type_name_mutex::<T>)
.vtable_indirect(&VTableIndirect::EMPTY)
.type_ops_indirect(
&const {
TypeOpsIndirect {
drop_in_place: mutex_drop::<T>,
default_in_place: None,
clone_into: None,
is_truthy: None,
}
},
)
.ty(Type::User(UserType::Opaque))
.def(Def::Pointer(PointerDef {
vtable: &const {
PointerVTable {
lock_fn: Some(mutex_lock::<T>),
new_into_fn: Some(mutex_new_into::<T>),
..PointerVTable::new()
}
},
pointee: Some(T::SHAPE),
weak: None,
strong: None,
flags: PointerFlags::LOCK,
known: Some(KnownPointer::Mutex),
}))
.type_params(&[TypeParam {
name: "T",
shape: T::SHAPE,
}])
.inner(T::SHAPE)
.variance(VarianceDesc {
base: Variance::Bivariant,
deps: &const { [VarianceDep::invariant(T::SHAPE)] },
})
.build()
};
}
fn type_name_rwlock<'a, T: Facet<'a>>(
_shape: &'static Shape,
f: &mut core::fmt::Formatter<'_>,
opts: TypeNameOpts,
) -> core::fmt::Result {
write!(f, "RwLock")?;
if let Some(opts) = opts.for_children() {
write!(f, "<")?;
T::SHAPE.write_type_name(f, opts)?;
write!(f, ">")?;
} else {
write!(f, "<\u{2026}>")?;
}
Ok(())
}
unsafe extern "C" fn rwlock_new_into<T>(this: PtrUninit, value: PtrMut) -> PtrMut {
unsafe {
let t = value.read::<T>();
this.put(RwLock::<T>::new(t))
}
}
unsafe fn rwlock_drop<T>(ox: OxPtrMut) {
unsafe { core::ptr::drop_in_place(ox.ptr().as_ptr::<RwLock<T>>() as *mut RwLock<T>) }
}
const fn rwlock_read_guard_vtable<T>() -> LockGuardVTable {
unsafe fn drop_guard<T>(guard: PtrConst) {
unsafe {
drop(Box::from_raw(
guard.as_ptr::<RwLockReadGuard<'_, T>>() as *mut RwLockReadGuard<'_, T>
));
}
}
LockGuardVTable {
drop_in_place: drop_guard::<T>,
}
}
const fn rwlock_write_guard_vtable<T>() -> LockGuardVTable {
unsafe fn drop_guard<T>(guard: PtrConst) {
unsafe {
drop(Box::from_raw(
guard.as_ptr::<RwLockWriteGuard<'_, T>>() as *mut RwLockWriteGuard<'_, T>
));
}
}
LockGuardVTable {
drop_in_place: drop_guard::<T>,
}
}
unsafe fn rwlock_read<'a, T: Facet<'a>>(opaque: PtrConst) -> Result<ReadLockResult, ()> {
unsafe {
let rwlock = &*opaque.as_ptr::<RwLock<T>>();
let guard = match rwlock.read() {
Ok(g) => g,
Err(e) => e.into_inner(),
};
let data_ptr = &*guard as *const T;
let guard_box = Box::new(guard);
let guard_ptr = Box::into_raw(guard_box) as *const u8;
Ok(ReadLockResult::new(
PtrConst::new(data_ptr as *const u8),
PtrConst::new(guard_ptr),
&const { rwlock_read_guard_vtable::<T>() },
))
}
}
unsafe fn rwlock_write<'a, T: Facet<'a>>(opaque: PtrConst) -> Result<WriteLockResult, ()> {
unsafe {
let rwlock = &*opaque.as_ptr::<RwLock<T>>();
let mut guard = match rwlock.write() {
Ok(g) => g,
Err(e) => e.into_inner(),
};
let data_ptr = &mut *guard as *mut T;
let guard_box = Box::new(guard);
let guard_ptr = Box::into_raw(guard_box) as *const u8;
Ok(WriteLockResult::new(
PtrMut::new(data_ptr as *mut u8),
PtrConst::new(guard_ptr),
&const { rwlock_write_guard_vtable::<T>() },
))
}
}
unsafe impl<'a, T: Facet<'a>> Facet<'a> for RwLock<T> {
const SHAPE: &'static Shape = &const {
ShapeBuilder::for_sized::<Self>("RwLock")
.decl_id(DeclId::new(decl_id_hash("#std#RwLock")))
.type_name(type_name_rwlock::<T>)
.vtable_indirect(&VTableIndirect::EMPTY)
.type_ops_indirect(
&const {
TypeOpsIndirect {
drop_in_place: rwlock_drop::<T>,
default_in_place: None,
clone_into: None,
is_truthy: None,
}
},
)
.ty(Type::User(UserType::Opaque))
.def(Def::Pointer(PointerDef {
vtable: &const {
PointerVTable {
read_fn: Some(rwlock_read::<T>),
write_fn: Some(rwlock_write::<T>),
new_into_fn: Some(rwlock_new_into::<T>),
..PointerVTable::new()
}
},
pointee: Some(T::SHAPE),
weak: None,
strong: None,
flags: PointerFlags::LOCK,
known: Some(KnownPointer::RwLock),
}))
.type_params(&[TypeParam {
name: "T",
shape: T::SHAPE,
}])
.inner(T::SHAPE)
.variance(VarianceDesc {
base: Variance::Bivariant,
deps: &const { [VarianceDep::invariant(T::SHAPE)] },
})
.build()
};
}
fn type_name_mutex_guard<'a, T: Facet<'a>>(
_shape: &'static Shape,
f: &mut core::fmt::Formatter<'_>,
opts: TypeNameOpts,
) -> core::fmt::Result {
write!(f, "MutexGuard")?;
if let Some(opts) = opts.for_children() {
write!(f, "<")?;
T::SHAPE.write_type_name(f, opts)?;
write!(f, ">")?;
} else {
write!(f, "<\u{2026}>")?;
}
Ok(())
}
unsafe fn mutex_guard_drop<T>(ox: OxPtrMut) {
unsafe {
core::ptr::drop_in_place(ox.ptr().as_ptr::<MutexGuard<'_, T>>() as *mut MutexGuard<'_, T>)
}
}
unsafe extern "C" fn mutex_guard_borrow<'a, T: Facet<'a>>(opaque: PtrConst) -> PtrConst {
unsafe {
let guard = &*opaque.as_ptr::<MutexGuard<'_, T>>();
PtrConst::new(NonNull::from(&**guard).as_ptr())
}
}
unsafe impl<'a, T: Facet<'a>> Facet<'a> for MutexGuard<'a, T> {
const SHAPE: &'static Shape = &const {
ShapeBuilder::for_sized::<Self>("MutexGuard")
.decl_id(DeclId::new(decl_id_hash("#std#MutexGuard")))
.type_name(type_name_mutex_guard::<T>)
.vtable_indirect(&VTableIndirect::EMPTY)
.type_ops_indirect(
&const {
TypeOpsIndirect {
drop_in_place: mutex_guard_drop::<T>,
default_in_place: None,
clone_into: None,
is_truthy: None,
}
},
)
.ty(Type::User(UserType::Opaque))
.def(Def::Pointer(PointerDef {
vtable: &const {
PointerVTable {
borrow_fn: Some(mutex_guard_borrow::<T>),
..PointerVTable::new()
}
},
pointee: Some(T::SHAPE),
weak: None,
strong: None,
flags: PointerFlags::empty(),
known: None,
}))
.type_params(&[TypeParam {
name: "T",
shape: T::SHAPE,
}])
.inner(T::SHAPE)
.variance(VarianceDesc {
base: Variance::Bivariant,
deps: &const { [VarianceDep::invariant(T::SHAPE)] },
})
.build()
};
}
fn type_name_rwlock_read_guard<'a, T: Facet<'a>>(
_shape: &'static Shape,
f: &mut core::fmt::Formatter<'_>,
opts: TypeNameOpts,
) -> core::fmt::Result {
write!(f, "RwLockReadGuard")?;
if let Some(opts) = opts.for_children() {
write!(f, "<")?;
T::SHAPE.write_type_name(f, opts)?;
write!(f, ">")?;
} else {
write!(f, "<\u{2026}>")?;
}
Ok(())
}
unsafe fn rwlock_read_guard_drop<T>(ox: OxPtrMut) {
unsafe {
core::ptr::drop_in_place(
ox.ptr().as_ptr::<RwLockReadGuard<'_, T>>() as *mut RwLockReadGuard<'_, T>
)
}
}
unsafe extern "C" fn rwlock_read_guard_borrow<'a, T: Facet<'a>>(opaque: PtrConst) -> PtrConst {
unsafe {
let guard = &*opaque.as_ptr::<RwLockReadGuard<'_, T>>();
PtrConst::new(NonNull::from(&**guard).as_ptr())
}
}
unsafe impl<'a, T: Facet<'a>> Facet<'a> for RwLockReadGuard<'a, T> {
const SHAPE: &'static Shape = &const {
ShapeBuilder::for_sized::<Self>("RwLockReadGuard")
.decl_id(DeclId::new(decl_id_hash("#std#RwLockReadGuard")))
.type_name(type_name_rwlock_read_guard::<T>)
.vtable_indirect(&VTableIndirect::EMPTY)
.type_ops_indirect(
&const {
TypeOpsIndirect {
drop_in_place: rwlock_read_guard_drop::<T>,
default_in_place: None,
clone_into: None,
is_truthy: None,
}
},
)
.ty(Type::User(UserType::Opaque))
.def(Def::Pointer(PointerDef {
vtable: &const {
PointerVTable {
borrow_fn: Some(rwlock_read_guard_borrow::<T>),
..PointerVTable::new()
}
},
pointee: Some(T::SHAPE),
weak: None,
strong: None,
flags: PointerFlags::empty(),
known: None,
}))
.type_params(&[TypeParam {
name: "T",
shape: T::SHAPE,
}])
.inner(T::SHAPE)
.variance(VarianceDesc {
base: Variance::Bivariant,
deps: &const { [VarianceDep::covariant(T::SHAPE)] },
})
.build()
};
}
fn type_name_rwlock_write_guard<'a, T: Facet<'a>>(
_shape: &'static Shape,
f: &mut core::fmt::Formatter<'_>,
opts: TypeNameOpts,
) -> core::fmt::Result {
write!(f, "RwLockWriteGuard")?;
if let Some(opts) = opts.for_children() {
write!(f, "<")?;
T::SHAPE.write_type_name(f, opts)?;
write!(f, ">")?;
} else {
write!(f, "<\u{2026}>")?;
}
Ok(())
}
unsafe fn rwlock_write_guard_drop<T>(ox: OxPtrMut) {
unsafe {
core::ptr::drop_in_place(
ox.ptr().as_ptr::<RwLockWriteGuard<'_, T>>() as *mut RwLockWriteGuard<'_, T>
)
}
}
unsafe extern "C" fn rwlock_write_guard_borrow<'a, T: Facet<'a>>(opaque: PtrConst) -> PtrConst {
unsafe {
let guard = &*opaque.as_ptr::<RwLockWriteGuard<'_, T>>();
PtrConst::new(NonNull::from(&**guard).as_ptr())
}
}
unsafe impl<'a, T: Facet<'a>> Facet<'a> for RwLockWriteGuard<'a, T> {
const SHAPE: &'static Shape = &const {
ShapeBuilder::for_sized::<Self>("RwLockWriteGuard")
.decl_id(DeclId::new(decl_id_hash("#std#RwLockWriteGuard")))
.type_name(type_name_rwlock_write_guard::<T>)
.vtable_indirect(&VTableIndirect::EMPTY)
.type_ops_indirect(
&const {
TypeOpsIndirect {
drop_in_place: rwlock_write_guard_drop::<T>,
default_in_place: None,
clone_into: None,
is_truthy: None,
}
},
)
.ty(Type::User(UserType::Opaque))
.def(Def::Pointer(PointerDef {
vtable: &const {
PointerVTable {
borrow_fn: Some(rwlock_write_guard_borrow::<T>),
..PointerVTable::new()
}
},
pointee: Some(T::SHAPE),
weak: None,
strong: None,
flags: PointerFlags::empty(),
known: None,
}))
.type_params(&[TypeParam {
name: "T",
shape: T::SHAPE,
}])
.inner(T::SHAPE)
.variance(VarianceDesc {
base: Variance::Bivariant,
deps: &const { [VarianceDep::invariant(T::SHAPE)] },
})
.build()
};
}
fn type_name_oncelock<'a, T: Facet<'a>>(
_shape: &'static Shape,
f: &mut core::fmt::Formatter<'_>,
opts: TypeNameOpts,
) -> core::fmt::Result {
write!(f, "OnceLock")?;
if let Some(opts) = opts.for_children() {
write!(f, "<")?;
T::SHAPE.write_type_name(f, opts)?;
write!(f, ">")?;
} else {
write!(f, "<\u{2026}>")?;
}
Ok(())
}
unsafe extern "C" fn oncelock_new_into<T>(this: PtrUninit, value: PtrMut) -> PtrMut {
unsafe {
let t = value.read::<T>();
let lock = OnceLock::new();
lock.set(t).ok();
this.put(lock)
}
}
unsafe fn oncelock_drop<T>(ox: OxPtrMut) {
unsafe { core::ptr::drop_in_place(ox.ptr().as_ptr::<OnceLock<T>>() as *mut OnceLock<T>) }
}
const fn oncelock_guard_vtable() -> LockGuardVTable {
const unsafe fn drop_guard(_guard: PtrConst) {
}
LockGuardVTable {
drop_in_place: drop_guard,
}
}
unsafe fn oncelock_read<'a, T: Facet<'a>>(opaque: PtrConst) -> Result<ReadLockResult, ()> {
unsafe {
let lock = opaque.get::<OnceLock<T>>();
match lock.get() {
Some(data) => {
let data_ptr = NonNull::from(data).as_ptr();
Ok(ReadLockResult::new(
PtrConst::new(data_ptr as *const u8),
PtrConst::new(core::ptr::null::<()>()),
&const { oncelock_guard_vtable() },
))
}
None => Err(()),
}
}
}
unsafe impl<'a, T: Facet<'a>> Facet<'a> for OnceLock<T> {
const SHAPE: &'static Shape = &const {
ShapeBuilder::for_sized::<Self>("OnceLock")
.decl_id(DeclId::new(decl_id_hash("#std#OnceLock")))
.type_name(type_name_oncelock::<T>)
.vtable_indirect(&VTableIndirect::EMPTY)
.type_ops_indirect(
&const {
TypeOpsIndirect {
drop_in_place: oncelock_drop::<T>,
default_in_place: None,
clone_into: None,
is_truthy: None,
}
},
)
.ty(Type::User(UserType::Opaque))
.def(Def::Pointer(PointerDef {
vtable: &const {
PointerVTable {
read_fn: Some(oncelock_read::<T>),
new_into_fn: Some(oncelock_new_into::<T>),
..PointerVTable::new()
}
},
pointee: Some(T::SHAPE),
weak: None,
strong: None,
flags: PointerFlags::empty(),
known: Some(KnownPointer::OnceLock),
}))
.type_params(&[TypeParam {
name: "T",
shape: T::SHAPE,
}])
.inner(T::SHAPE)
.variance(VarianceDesc {
base: Variance::Bivariant,
deps: &const { [VarianceDep::invariant(T::SHAPE)] },
})
.build()
};
}
fn type_name_lazylock<'a, T: Facet<'a>>(
_shape: &'static Shape,
f: &mut core::fmt::Formatter<'_>,
opts: TypeNameOpts,
) -> core::fmt::Result {
write!(f, "LazyLock")?;
if let Some(opts) = opts.for_children() {
write!(f, "<")?;
T::SHAPE.write_type_name(f, opts)?;
write!(f, ">")?;
} else {
write!(f, "<\u{2026}>")?;
}
Ok(())
}
unsafe fn lazylock_drop<T, F>(ox: OxPtrMut) {
unsafe { core::ptr::drop_in_place(ox.ptr().as_ptr::<LazyLock<T, F>>() as *mut LazyLock<T, F>) }
}
unsafe extern "C" fn lazylock_borrow<'a, T: Facet<'a>, F: FnOnce() -> T>(
opaque: PtrConst,
) -> PtrConst {
unsafe {
let lock = opaque.get::<LazyLock<T, F>>();
let data = LazyLock::force(lock);
PtrConst::new(NonNull::from(data).as_ptr())
}
}
unsafe impl<'a, T: Facet<'a>, F: FnOnce() -> T + 'a> Facet<'a> for LazyLock<T, F> {
const SHAPE: &'static Shape = &const {
ShapeBuilder::for_sized::<Self>("LazyLock")
.decl_id(DeclId::new(decl_id_hash("#std#LazyLock")))
.type_name(type_name_lazylock::<T>)
.vtable_indirect(&VTableIndirect::EMPTY)
.type_ops_indirect(
&const {
TypeOpsIndirect {
drop_in_place: lazylock_drop::<T, F>,
default_in_place: None,
clone_into: None,
is_truthy: None,
}
},
)
.ty(Type::User(UserType::Opaque))
.def(Def::Pointer(PointerDef {
vtable: &const {
PointerVTable {
borrow_fn: Some(lazylock_borrow::<T, F>),
..PointerVTable::new()
}
},
pointee: Some(T::SHAPE),
weak: None,
strong: None,
flags: PointerFlags::empty(),
known: Some(KnownPointer::LazyLock),
}))
.type_params(&[TypeParam {
name: "T",
shape: T::SHAPE,
}])
.inner(T::SHAPE)
.variance(VarianceDesc {
base: Variance::Bivariant,
deps: &const { [VarianceDep::invariant(T::SHAPE)] },
})
.build()
};
}
#[cfg(test)]
mod tests {
use super::*;
use alloc::string::String;
#[test]
fn test_mutex_shape() {
facet_testhelpers::setup();
let shape = <Mutex<i32>>::SHAPE;
assert_eq!(shape.type_identifier, "Mutex");
let [type_param] = shape.type_params else {
panic!("Mutex should have 1 type param");
};
assert_eq!(type_param.name, "T");
assert_eq!(type_param.shape, i32::SHAPE);
}
#[test]
fn test_rwlock_shape() {
facet_testhelpers::setup();
let shape = <RwLock<String>>::SHAPE;
assert_eq!(shape.type_identifier, "RwLock");
let [type_param] = shape.type_params else {
panic!("RwLock should have 1 type param");
};
assert_eq!(type_param.name, "T");
assert_eq!(type_param.shape, String::SHAPE);
}
#[test]
fn test_mutex_guard_shape() {
facet_testhelpers::setup();
let shape = <MutexGuard<'_, i32>>::SHAPE;
assert_eq!(shape.type_identifier, "MutexGuard");
let [type_param] = shape.type_params else {
panic!("MutexGuard should have 1 type param");
};
assert_eq!(type_param.name, "T");
}
#[test]
fn test_rwlock_read_guard_shape() {
facet_testhelpers::setup();
let shape = <RwLockReadGuard<'_, i32>>::SHAPE;
assert_eq!(shape.type_identifier, "RwLockReadGuard");
let [type_param] = shape.type_params else {
panic!("RwLockReadGuard should have 1 type param");
};
assert_eq!(type_param.name, "T");
}
#[test]
fn test_rwlock_write_guard_shape() {
facet_testhelpers::setup();
let shape = <RwLockWriteGuard<'_, i32>>::SHAPE;
assert_eq!(shape.type_identifier, "RwLockWriteGuard");
let [type_param] = shape.type_params else {
panic!("RwLockWriteGuard should have 1 type param");
};
assert_eq!(type_param.name, "T");
}
#[test]
fn test_mutex_vtable() {
facet_testhelpers::setup();
let shape = <Mutex<i32>>::SHAPE;
let pointer_def = shape
.def
.into_pointer()
.expect("Mutex should be a pointer type");
assert!(
pointer_def.vtable.lock_fn.is_some(),
"Mutex should have lock_fn"
);
assert!(
pointer_def.vtable.new_into_fn.is_some(),
"Mutex should have new_into_fn"
);
assert!(
pointer_def.vtable.read_fn.is_none(),
"Mutex should not have read_fn"
);
assert!(
pointer_def.vtable.write_fn.is_none(),
"Mutex should not have write_fn"
);
assert!(
pointer_def.flags.contains(PointerFlags::LOCK),
"Mutex should have LOCK flag"
);
assert_eq!(pointer_def.known, Some(KnownPointer::Mutex));
}
#[test]
fn test_rwlock_vtable() {
facet_testhelpers::setup();
let shape = <RwLock<i32>>::SHAPE;
let pointer_def = shape
.def
.into_pointer()
.expect("RwLock should be a pointer type");
assert!(
pointer_def.vtable.read_fn.is_some(),
"RwLock should have read_fn"
);
assert!(
pointer_def.vtable.write_fn.is_some(),
"RwLock should have write_fn"
);
assert!(
pointer_def.vtable.new_into_fn.is_some(),
"RwLock should have new_into_fn"
);
assert!(
pointer_def.vtable.lock_fn.is_none(),
"RwLock should not have lock_fn"
);
assert!(
pointer_def.flags.contains(PointerFlags::LOCK),
"RwLock should have LOCK flag"
);
assert_eq!(pointer_def.known, Some(KnownPointer::RwLock));
}
#[test]
fn test_guard_vtables_have_borrow_fn() {
facet_testhelpers::setup();
let mutex_guard_shape = <MutexGuard<'_, i32>>::SHAPE;
let mutex_guard_def = mutex_guard_shape
.def
.into_pointer()
.expect("MutexGuard should be a pointer type");
assert!(
mutex_guard_def.vtable.borrow_fn.is_some(),
"MutexGuard should have borrow_fn"
);
let read_guard_shape = <RwLockReadGuard<'_, i32>>::SHAPE;
let read_guard_def = read_guard_shape
.def
.into_pointer()
.expect("RwLockReadGuard should be a pointer type");
assert!(
read_guard_def.vtable.borrow_fn.is_some(),
"RwLockReadGuard should have borrow_fn"
);
let write_guard_shape = <RwLockWriteGuard<'_, i32>>::SHAPE;
let write_guard_def = write_guard_shape
.def
.into_pointer()
.expect("RwLockWriteGuard should be a pointer type");
assert!(
write_guard_def.vtable.borrow_fn.is_some(),
"RwLockWriteGuard should have borrow_fn"
);
}
#[test]
fn test_mutex_lock_and_access() {
facet_testhelpers::setup();
let mutex = Mutex::new(42i32);
let shape = <Mutex<i32>>::SHAPE;
let pointer_def = shape.def.into_pointer().unwrap();
let lock_fn = pointer_def.vtable.lock_fn.unwrap();
let mutex_ptr = PtrConst::new(&mutex as *const _ as *const u8);
let lock_result = unsafe { lock_fn(mutex_ptr) }.expect("Lock should succeed");
let data_ptr = lock_result.data();
let value = unsafe { data_ptr.as_const().get::<i32>() };
assert_eq!(*value, 42);
drop(lock_result);
let lock_result2 = unsafe { lock_fn(mutex_ptr) }.expect("Second lock should succeed");
drop(lock_result2);
}
#[test]
fn test_rwlock_read_access() {
facet_testhelpers::setup();
let rwlock = RwLock::new(String::from("hello"));
let shape = <RwLock<String>>::SHAPE;
let pointer_def = shape.def.into_pointer().unwrap();
let read_fn = pointer_def.vtable.read_fn.unwrap();
let rwlock_ptr = PtrConst::new(&rwlock as *const _ as *const u8);
let read_result = unsafe { read_fn(rwlock_ptr) }.expect("Read lock should succeed");
let data_ptr = read_result.data();
let value = unsafe { data_ptr.get::<String>() };
assert_eq!(value.as_str(), "hello");
drop(read_result);
}
#[test]
fn test_rwlock_write_access() {
facet_testhelpers::setup();
let rwlock = RwLock::new(100i32);
let shape = <RwLock<i32>>::SHAPE;
let pointer_def = shape.def.into_pointer().unwrap();
let write_fn = pointer_def.vtable.write_fn.unwrap();
let rwlock_ptr = PtrConst::new(&rwlock as *const _ as *const u8);
let write_result = unsafe { write_fn(rwlock_ptr) }.expect("Write lock should succeed");
let data_ptr = write_result.data();
unsafe {
*data_ptr.as_mut_ptr::<i32>() = 200;
}
drop(write_result);
let read_fn = pointer_def.vtable.read_fn.unwrap();
let read_result = unsafe { read_fn(rwlock_ptr) }.expect("Read lock should succeed");
let value = unsafe { read_result.data().get::<i32>() };
assert_eq!(*value, 200);
}
#[test]
fn test_poisoned_mutex_still_works() {
facet_testhelpers::setup();
let mutex = Mutex::new(42i32);
let _ = std::panic::catch_unwind(core::panic::AssertUnwindSafe(|| {
let _guard = mutex.lock().unwrap();
panic!("Intentional panic to poison the mutex");
}));
let shape = <Mutex<i32>>::SHAPE;
let pointer_def = shape.def.into_pointer().unwrap();
let lock_fn = pointer_def.vtable.lock_fn.unwrap();
let mutex_ptr = PtrConst::new(&mutex as *const _ as *const u8);
let lock_result =
unsafe { lock_fn(mutex_ptr) }.expect("Lock should succeed even when poisoned");
let data_ptr = lock_result.data();
let value = unsafe { data_ptr.as_const().get::<i32>() };
assert_eq!(*value, 42);
}
#[test]
fn test_poisoned_rwlock_still_works() {
facet_testhelpers::setup();
let rwlock = RwLock::new(String::from("hello"));
let _ = std::panic::catch_unwind(core::panic::AssertUnwindSafe(|| {
let _guard = rwlock.write().unwrap();
panic!("Intentional panic to poison the rwlock");
}));
let shape = <RwLock<String>>::SHAPE;
let pointer_def = shape.def.into_pointer().unwrap();
let read_fn = pointer_def.vtable.read_fn.unwrap();
let rwlock_ptr = PtrConst::new(&rwlock as *const _ as *const u8);
let read_result =
unsafe { read_fn(rwlock_ptr) }.expect("Read should succeed even when poisoned");
let data_ptr = read_result.data();
let value = unsafe { data_ptr.get::<String>() };
assert_eq!(value.as_str(), "hello");
}
#[test]
fn test_oncelock_shape() {
facet_testhelpers::setup();
let shape = <OnceLock<i32>>::SHAPE;
assert_eq!(shape.type_identifier, "OnceLock");
let [type_param] = shape.type_params else {
panic!("OnceLock should have 1 type param");
};
assert_eq!(type_param.name, "T");
assert_eq!(type_param.shape, i32::SHAPE);
}
#[test]
fn test_oncelock_vtable() {
facet_testhelpers::setup();
let shape = <OnceLock<i32>>::SHAPE;
let pointer_def = shape
.def
.into_pointer()
.expect("OnceLock should be a pointer type");
assert!(
pointer_def.vtable.read_fn.is_some(),
"OnceLock should have read_fn"
);
assert!(
pointer_def.vtable.new_into_fn.is_some(),
"OnceLock should have new_into_fn"
);
assert!(
pointer_def.vtable.borrow_fn.is_none(),
"OnceLock should not have borrow_fn"
);
assert_eq!(pointer_def.known, Some(KnownPointer::OnceLock));
}
#[test]
fn test_oncelock_read_initialized() {
facet_testhelpers::setup();
let lock = OnceLock::new();
lock.set(42i32).ok();
let shape = <OnceLock<i32>>::SHAPE;
let pointer_def = shape.def.into_pointer().unwrap();
let read_fn = pointer_def.vtable.read_fn.unwrap();
let lock_ptr = PtrConst::new(&lock as *const _ as *const u8);
let read_result =
unsafe { read_fn(lock_ptr) }.expect("Read should succeed when initialized");
let value = unsafe { read_result.data().get::<i32>() };
assert_eq!(*value, 42);
}
#[test]
fn test_oncelock_read_uninitialized() {
facet_testhelpers::setup();
let lock: OnceLock<i32> = OnceLock::new();
let shape = <OnceLock<i32>>::SHAPE;
let pointer_def = shape.def.into_pointer().unwrap();
let read_fn = pointer_def.vtable.read_fn.unwrap();
let lock_ptr = PtrConst::new(&lock as *const _ as *const u8);
let result = unsafe { read_fn(lock_ptr) };
assert!(result.is_err(), "Read should fail when uninitialized");
}
#[test]
fn test_lazylock_shape() {
facet_testhelpers::setup();
let shape = <LazyLock<i32, fn() -> i32>>::SHAPE;
assert_eq!(shape.type_identifier, "LazyLock");
let [type_param] = shape.type_params else {
panic!("LazyLock should have 1 type param");
};
assert_eq!(type_param.name, "T");
assert_eq!(type_param.shape, i32::SHAPE);
}
#[test]
fn test_lazylock_vtable() {
facet_testhelpers::setup();
let shape = <LazyLock<i32, fn() -> i32>>::SHAPE;
let pointer_def = shape
.def
.into_pointer()
.expect("LazyLock should be a pointer type");
assert!(
pointer_def.vtable.borrow_fn.is_some(),
"LazyLock should have borrow_fn"
);
assert!(
pointer_def.vtable.read_fn.is_none(),
"LazyLock should not have read_fn"
);
assert_eq!(pointer_def.known, Some(KnownPointer::LazyLock));
}
#[test]
fn test_lazylock_borrow() {
facet_testhelpers::setup();
let lock: LazyLock<i32, fn() -> i32> = LazyLock::new(|| 42);
let shape = <LazyLock<i32, fn() -> i32>>::SHAPE;
let pointer_def = shape.def.into_pointer().unwrap();
let borrow_fn = pointer_def.vtable.borrow_fn.unwrap();
let lock_ptr = PtrConst::new(&lock as *const _ as *const u8);
let data_ptr = unsafe { borrow_fn(lock_ptr) };
let value = unsafe { data_ptr.get::<i32>() };
assert_eq!(*value, 42);
}
}