use std::marker::PhantomData;
use std::sync::Arc;
#[repr(C, align(16))]
pub struct UmbraPointer<T> {
target: *const T,
prefix: u32,
_pad: u32,
_phantom: PhantomData<T>,
}
unsafe impl<T: Send> Send for UmbraPointer<T> {}
unsafe impl<T: Sync> Sync for UmbraPointer<T> {}
impl<T> UmbraPointer<T> {
pub const SIGNATURE: subetha_core::AxisMask = subetha_core::AxisMask::from_axes(
&[subetha_core::Axis::ContentPrefix],
);
#[inline]
pub const unsafe fn from_raw(prefix: u32, target: *const T) -> Self {
Self { target, prefix, _pad: 0, _phantom: PhantomData }
}
#[inline]
pub const fn prefix(&self) -> u32 { self.prefix }
#[inline]
pub const fn as_raw(&self) -> *const T { self.target }
#[inline]
pub const fn prefix_eq(&self, other: &Self) -> bool {
self.prefix == other.prefix
}
#[inline]
pub const fn matches_prefix(&self, query: u32) -> bool {
self.prefix == query
}
}
impl<T> UmbraPointer<T> {
pub fn with_content_prefix(value: T) -> Box<UmbraOwner<T>> {
let bytes = unsafe {
let p = &value as *const T as *const u8;
let n = std::mem::size_of::<T>().min(4);
let mut buf = [0u8; 4];
std::ptr::copy_nonoverlapping(p, buf.as_mut_ptr(), n);
buf
};
let prefix = u32::from_le_bytes(bytes);
let boxed = Box::new(value);
let target = Box::into_raw(boxed) as *const T;
let ptr = unsafe { Self::from_raw(prefix, target) };
Box::new(UmbraOwner { ptr })
}
pub fn with_hash_prefix(value: T) -> Box<UmbraOwner<T>>
where T: std::hash::Hash,
{
use std::collections::hash_map::DefaultHasher;
use std::hash::Hasher;
let mut h = DefaultHasher::new();
value.hash(&mut h);
let full = h.finish();
let prefix = full as u32;
let boxed = Box::new(value);
let target = Box::into_raw(boxed) as *const T;
let ptr = unsafe { Self::from_raw(prefix, target) };
Box::new(UmbraOwner { ptr })
}
pub fn from_arc(value: Arc<T>, prefix: u32) -> ArcUmbra<T> {
let target = Arc::as_ptr(&value);
let ptr = unsafe { Self::from_raw(prefix, target) };
ArcUmbra { ptr, _arc: value }
}
#[inline]
pub unsafe fn deref_unchecked(&self) -> &T {
unsafe { &*self.target }
}
}
pub struct UmbraOwner<T> {
ptr: UmbraPointer<T>,
}
impl<T> UmbraOwner<T> {
#[inline]
pub fn ptr(&self) -> &UmbraPointer<T> { &self.ptr }
#[inline]
pub fn prefix(&self) -> u32 { self.ptr.prefix }
#[inline]
pub fn value(&self) -> &T {
unsafe { &*self.ptr.target }
}
}
impl<T> Drop for UmbraOwner<T> {
fn drop(&mut self) {
let raw = self.ptr.target as *mut T;
if !raw.is_null() {
unsafe { drop(Box::from_raw(raw)); }
}
}
}
pub struct ArcUmbra<T> {
ptr: UmbraPointer<T>,
_arc: Arc<T>,
}
impl<T> ArcUmbra<T> {
#[inline]
pub fn ptr(&self) -> &UmbraPointer<T> { &self.ptr }
#[inline]
pub fn prefix(&self) -> u32 { self.ptr.prefix }
#[inline]
pub fn value(&self) -> &T {
unsafe { &*self.ptr.target }
}
#[inline]
pub fn into_arc(self) -> Arc<T> { self._arc.clone() }
}
impl<T> Clone for ArcUmbra<T> {
fn clone(&self) -> Self {
Self {
ptr: unsafe { UmbraPointer::from_raw(self.ptr.prefix, self.ptr.target) },
_arc: self._arc.clone(),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn layout_is_exactly_16_bytes() {
assert_eq!(std::mem::size_of::<UmbraPointer<u64>>(), 16);
assert_eq!(std::mem::align_of::<UmbraPointer<u64>>(), 16);
}
#[test]
fn prefix_eq_does_not_deref() {
let p1: UmbraPointer<u64> = unsafe {
UmbraPointer::from_raw(0xDEADBEEF, std::ptr::dangling::<u64>())
};
let p2: UmbraPointer<u64> = unsafe {
UmbraPointer::from_raw(0xDEADBEEF, std::ptr::dangling::<u64>())
};
let p3: UmbraPointer<u64> = unsafe {
UmbraPointer::from_raw(0xCAFEBABE, std::ptr::dangling::<u64>())
};
assert!(p1.prefix_eq(&p2), "same prefix matches without deref");
assert!(!p1.prefix_eq(&p3), "different prefix does not match");
assert!(p1.matches_prefix(0xDEADBEEF));
assert!(!p1.matches_prefix(0));
}
#[test]
fn with_content_prefix_copies_first_4_bytes() {
let owner = UmbraPointer::with_content_prefix(0x0000_0000_0000_BEEF_u64);
assert_eq!(owner.prefix(), 0x0000_BEEF);
assert_eq!(*owner.value(), 0x0000_0000_0000_BEEF_u64);
}
#[test]
fn with_hash_prefix_is_deterministic_for_same_value() {
let a = UmbraPointer::with_hash_prefix(42u64);
let b = UmbraPointer::with_hash_prefix(42u64);
assert_eq!(a.prefix(), b.prefix());
assert_eq!(*a.value(), 42);
assert_eq!(*b.value(), 42);
}
#[test]
fn with_hash_prefix_distinguishes_different_values() {
let a = UmbraPointer::with_hash_prefix(42u64);
let b = UmbraPointer::with_hash_prefix(43u64);
assert_ne!(a.prefix(), b.prefix());
}
#[test]
fn arc_umbra_keeps_target_alive() {
let arc: Arc<u64> = Arc::new(1234);
let u = UmbraPointer::from_arc(arc.clone(), 0xABCD);
drop(arc);
assert_eq!(u.prefix(), 0xABCD);
assert_eq!(*u.value(), 1234);
}
#[test]
fn owner_drops_target() {
use std::sync::atomic::{AtomicUsize, Ordering};
static DROPS: AtomicUsize = AtomicUsize::new(0);
struct DropCounter(u64);
impl Drop for DropCounter {
fn drop(&mut self) { DROPS.fetch_add(1, Ordering::Relaxed); }
}
let before = DROPS.load(Ordering::Relaxed);
let owner = UmbraPointer::with_content_prefix(DropCounter(99));
assert_eq!(owner.value().0, 99);
drop(owner);
let after = DROPS.load(Ordering::Relaxed);
assert!(after > before, "boxed target should be dropped");
}
#[test]
fn dedup_scan_via_prefix() {
let owners: Vec<_> = (0..100u32)
.map(UmbraPointer::with_content_prefix)
.collect();
let mut prefixes: Vec<u32> = owners.iter().map(|o| o.prefix()).collect();
prefixes.sort_unstable();
prefixes.dedup();
assert_eq!(prefixes.len(), 100);
}
#[test]
fn skip_on_mismatch_zero_dereferences() {
let umbras: Vec<ArcUmbra<u64>> = (0..10u64)
.map(|i| UmbraPointer::from_arc(Arc::new(i * 1000), (i + 1) as u32))
.collect();
let query_prefix = 99u32;
let mut matches = 0;
for u in &umbras {
if u.ptr().matches_prefix(query_prefix) {
matches += 1;
let _val = u.value();
}
}
assert_eq!(matches, 0,
"no prefix in 1..=10 should equal 99");
}
}