use crate::thread::Thread;
use atomic::Ordering;
use std::{
marker::PhantomData,
ptr::{null_mut, NonNull},
sync::atomic::AtomicPtr,
};
use super::{
object::{Allocation, Handle},
traits::Object,
};
static mut HEAD_REF: AtomicPtr<u8> = AtomicPtr::new(null_mut());
unsafe impl<T: ?Sized + Object> Send for WeakReference<T> {}
unsafe impl<T: ?Sized + Object> Sync for WeakReference<T> {}
pub struct WeakReference<T: ?Sized + Object> {
ptr: *mut u8,
next: AtomicPtr<u8>,
_marker: PhantomData<T>,
}
impl<T: ?Sized + Object> WeakReference<T> {
pub fn new(thread: &mut Thread, target: Handle<T>) -> Handle<WeakReference<T>>
where
T: 'static,
{
unsafe {
let this = thread.allocate(WeakReference {
ptr: target.as_ptr(),
next: AtomicPtr::new(null_mut()),
_marker: PhantomData,
});
let this_ptr = this.as_ptr();
let mut old_val = HEAD_REF.load(Ordering::Relaxed);
loop {
this.next.store(old_val, Ordering::Relaxed);
match HEAD_REF.compare_exchange_weak(
old_val,
this_ptr,
Ordering::Relaxed,
Ordering::Relaxed,
) {
Ok(_) => break,
Err(val) => old_val = val,
}
}
this
}
}
pub(crate) unsafe fn process(mut update_reference: impl FnMut(*mut u8) -> *mut u8) {
let mut wr = HEAD_REF.load(Ordering::Relaxed);
let mut tail = null_mut::<WeakReference<dyn Object>>();
while !wr.is_null() {
let weak = wr as *mut WeakReference<dyn Object>;
let next = (*weak).next.load(Ordering::Relaxed);
wr = update_reference(wr);
if wr.is_null() {
println!("unlinking weak reference {:p}", weak);
wr = next;
if !tail.is_null() {
(*tail).next = AtomicPtr::new(wr);
} else {
HEAD_REF.store(wr, Ordering::Relaxed);
}
} else {
let target = update_reference((*weak).ptr);
(*weak).ptr = target;
if tail.is_null() {
HEAD_REF.store(wr, Ordering::Relaxed);
} else {
(*tail).next = AtomicPtr::new(wr);
}
tail = weak;
wr = next;
}
}
}
pub fn upgrade(&self) -> Option<Handle<T>> {
unsafe {
let ptr = self.ptr;
if ptr.is_null() {
return None;
}
Some(Handle::from_raw(ptr))
}
}
}
unsafe impl<T: ?Sized + Object> Object for WeakReference<T> {}
unsafe impl<T: ?Sized + Object> Allocation for WeakReference<T> {}
pub struct WeakMapping<K: ?Sized + Object, V: ?Sized + Object> {
key: *mut u8,
value: Handle<V>,
next: AtomicPtr<u8>,
marker: PhantomData<K>,
}