use core::fmt;
use crate::{
Def, Facet, HashProxy, KnownPointer, OxPtrConst, OxPtrMut, PointerDef, PointerFlags,
PointerType, PointerVTable, PtrConst, Shape, ShapeBuilder, Type, TypeNameOpts, TypeOpsIndirect,
TypeParam, VTableIndirect, ValuePointerType, Variance, VarianceDep, VarianceDesc,
};
fn ref_type_name(
shape: &'static Shape,
f: &mut fmt::Formatter<'_>,
opts: TypeNameOpts,
) -> fmt::Result {
let pointee = match &shape.def {
Def::Pointer(ptr_def) => ptr_def.pointee,
_ => None,
};
write!(f, "&")?;
if let Some(pointee) = pointee {
if let Some(opts) = opts.for_children() {
pointee.write_type_name(f, opts)?;
} else {
write!(f, "…")?;
}
} else {
write!(f, "?")?;
}
Ok(())
}
fn ref_mut_type_name(
shape: &'static Shape,
f: &mut fmt::Formatter<'_>,
opts: TypeNameOpts,
) -> fmt::Result {
let pointee = match &shape.def {
Def::Pointer(ptr_def) => ptr_def.pointee,
_ => None,
};
write!(f, "&mut ")?;
if let Some(pointee) = pointee {
if let Some(opts) = opts.for_children() {
pointee.write_type_name(f, opts)?;
} else {
write!(f, "…")?;
}
} else {
write!(f, "?")?;
}
Ok(())
}
unsafe fn deref_to_pointee(ox: OxPtrConst) -> Option<(&'static Shape, PtrConst)> {
let shape = ox.shape();
let Def::Pointer(ptr_def) = shape.def else {
return None;
};
let pointee_shape = ptr_def.pointee?;
let ref_size = shape.layout.sized_layout().ok()?.size();
if ref_size == core::mem::size_of::<*const ()>() {
let inner_ptr = unsafe { *(ox.ptr().as_byte_ptr() as *const *const u8) };
Some((pointee_shape, PtrConst::new(inner_ptr as *const ())))
} else {
let fat_ptr_location = ox.ptr().as_byte_ptr() as *const [*const u8; 2];
let [data_ptr, metadata] = unsafe { *fat_ptr_location };
Some((
pointee_shape,
PtrConst::new_wide(data_ptr, metadata as *const ()),
))
}
}
unsafe fn ref_debug(ox: OxPtrConst, f: &mut core::fmt::Formatter<'_>) -> Option<core::fmt::Result> {
let (pointee_shape, inner) = unsafe { deref_to_pointee(ox)? };
unsafe { pointee_shape.call_debug(inner, f) }
}
unsafe fn ref_display(
ox: OxPtrConst,
f: &mut core::fmt::Formatter<'_>,
) -> Option<core::fmt::Result> {
let (pointee_shape, inner) = unsafe { deref_to_pointee(ox)? };
unsafe { pointee_shape.call_display(inner, f) }
}
unsafe fn ref_hash(ox: OxPtrConst, hasher: &mut HashProxy<'_>) -> Option<()> {
let (pointee_shape, inner) = unsafe { deref_to_pointee(ox)? };
unsafe { pointee_shape.call_hash(inner, hasher) }
}
unsafe fn ref_partial_eq(a: OxPtrConst, b: OxPtrConst) -> Option<bool> {
let (pointee_shape, a_inner) = unsafe { deref_to_pointee(a)? };
let (_, b_inner) = unsafe { deref_to_pointee(b)? };
unsafe { pointee_shape.call_partial_eq(a_inner, b_inner) }
}
unsafe fn ref_partial_cmp(a: OxPtrConst, b: OxPtrConst) -> Option<Option<core::cmp::Ordering>> {
let (pointee_shape, a_inner) = unsafe { deref_to_pointee(a)? };
let (_, b_inner) = unsafe { deref_to_pointee(b)? };
unsafe { pointee_shape.call_partial_cmp(a_inner, b_inner) }
}
unsafe fn ref_cmp(a: OxPtrConst, b: OxPtrConst) -> Option<core::cmp::Ordering> {
let (pointee_shape, a_inner) = unsafe { deref_to_pointee(a)? };
let (_, b_inner) = unsafe { deref_to_pointee(b)? };
unsafe { pointee_shape.call_cmp(a_inner, b_inner) }
}
const unsafe fn ref_drop(_ptr: OxPtrMut) {
}
unsafe fn ref_clone(src: OxPtrConst, dst: OxPtrMut) {
let Some(size) = src.shape().layout.sized_layout().ok().map(|l| l.size()) else {
return;
};
unsafe {
core::ptr::copy_nonoverlapping(src.ptr().as_byte_ptr(), dst.ptr().as_mut_byte_ptr(), size);
}
}
const REF_VTABLE: VTableIndirect = VTableIndirect {
display: Some(ref_display),
debug: Some(ref_debug),
hash: Some(ref_hash),
invariants: None,
parse: None,
parse_bytes: None,
try_from: None,
try_into_inner: None,
try_borrow_inner: None,
partial_eq: Some(ref_partial_eq),
partial_cmp: Some(ref_partial_cmp),
cmp: Some(ref_cmp),
};
static REF_TYPE_OPS: TypeOpsIndirect = TypeOpsIndirect {
drop_in_place: ref_drop,
default_in_place: None,
clone_into: Some(ref_clone),
is_truthy: None,
};
const REF_MUT_VTABLE: VTableIndirect = VTableIndirect {
display: Some(ref_display),
debug: Some(ref_debug),
hash: Some(ref_hash),
invariants: None,
parse: None,
parse_bytes: None,
try_from: None,
try_into_inner: None,
try_borrow_inner: None,
partial_eq: Some(ref_partial_eq),
partial_cmp: Some(ref_partial_cmp),
cmp: Some(ref_cmp),
};
static REF_MUT_TYPE_OPS: TypeOpsIndirect = TypeOpsIndirect {
drop_in_place: ref_drop,
default_in_place: None,
clone_into: None,
is_truthy: None,
};
unsafe extern "C" fn ref_borrow<T: ?Sized>(this: PtrConst) -> PtrConst {
let ptr: &&T = unsafe { this.get::<&T>() };
let ptr: &T = ptr;
PtrConst::new(ptr as *const T)
}
unsafe extern "C" fn ref_mut_borrow<T: ?Sized>(this: PtrConst) -> PtrConst {
let ptr: &&mut T = unsafe { this.get::<&mut T>() };
let ptr: &T = ptr;
PtrConst::new(ptr as *const T)
}
unsafe impl<'a, T: ?Sized + Facet<'a>> Facet<'a> for &'a T {
const SHAPE: &'static Shape = &const {
const fn build_pointer_vtable<T: ?Sized>() -> PointerVTable {
PointerVTable {
borrow_fn: Some(ref_borrow::<T>),
..PointerVTable::new()
}
}
ShapeBuilder::for_sized::<&T>("&T")
.decl_id(crate::DeclId::new(crate::decl_id_hash("#ref#&T")))
.type_name(ref_type_name)
.ty({
let vpt = ValuePointerType {
mutable: false,
wide: size_of::<*const T>() != size_of::<*const ()>(),
target: T::SHAPE,
};
Type::Pointer(PointerType::Reference(vpt))
})
.def(Def::Pointer(PointerDef {
vtable: &const { build_pointer_vtable::<T>() },
pointee: Some(T::SHAPE),
weak: None,
strong: None,
flags: PointerFlags::EMPTY,
known: Some(KnownPointer::SharedReference),
}))
.type_params(&[TypeParam {
name: "T",
shape: T::SHAPE,
}])
.inner(T::SHAPE)
.variance(VarianceDesc {
base: Variance::Covariant,
deps: &const { [VarianceDep::covariant(T::SHAPE)] },
})
.vtable_indirect(&REF_VTABLE)
.type_ops_indirect(&REF_TYPE_OPS)
.build()
};
}
unsafe impl<'a, T: ?Sized + Facet<'a>> Facet<'a> for &'a mut T {
const SHAPE: &'static Shape = &const {
const fn build_pointer_vtable<T: ?Sized>() -> PointerVTable {
PointerVTable {
borrow_fn: Some(ref_mut_borrow::<T>),
..PointerVTable::new()
}
}
ShapeBuilder::for_sized::<&mut T>("&mut T")
.decl_id(crate::DeclId::new(crate::decl_id_hash("#ref#&mut T")))
.type_name(ref_mut_type_name)
.ty({
let vpt = ValuePointerType {
mutable: true,
wide: size_of::<*const T>() != size_of::<*const ()>(),
target: T::SHAPE,
};
Type::Pointer(PointerType::Reference(vpt))
})
.def(Def::Pointer(PointerDef {
vtable: &const { build_pointer_vtable::<T>() },
pointee: Some(T::SHAPE),
weak: None,
strong: None,
flags: PointerFlags::EMPTY,
known: Some(KnownPointer::ExclusiveReference),
}))
.type_params(&[TypeParam {
name: "T",
shape: T::SHAPE,
}])
.inner(T::SHAPE)
.variance(VarianceDesc {
base: Variance::Covariant,
deps: &const { [VarianceDep::invariant(T::SHAPE)] },
})
.vtable_indirect(&REF_MUT_VTABLE)
.type_ops_indirect(&REF_MUT_TYPE_OPS)
.build()
};
}