use std::cell::UnsafeCell;
use std::ops::{Deref, DerefMut};
use std::ptr::NonNull;
use std::sync::Arc;
use std::sync::atomic::{AtomicBool, Ordering};
#[derive(Debug)]
pub struct PropertyBinding<T> {
value: NonNull<T>,
lock: Arc<AtomicBool>,
}
impl<T> Deref for PropertyBinding<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
unsafe { self.value.as_ref() }
}
}
impl<T> DerefMut for PropertyBinding<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
unsafe { self.value.as_mut() }
}
}
impl<T> Drop for PropertyBinding<T> {
fn drop(&mut self) {
if self.lock.swap(false, Ordering::SeqCst) == false {
panic!("PropertyBinding<{}>: Tried to drop a lock that was already unlocked!", std::any::type_name::<T>())
}
}
}
unsafe impl<T: Send> Send for PropertyBinding<T> {}
#[derive(Debug)]
pub struct Property<T> {
property: UnsafeCell<T>,
mut_lock: Arc<AtomicBool>
}
impl<T> Property<T> {
pub fn new(value: T) -> Self {
Property {
property: UnsafeCell::new(value),
mut_lock: Arc::new(AtomicBool::new(false))
}
}
pub fn bind(&self) -> PropertyBinding<T> {
let was_locked = self.mut_lock.swap(true, Ordering::SeqCst);
if was_locked {
panic!("PropertyBinding<{}>: Tried to bind a property that was already bound!", std::any::type_name::<T>());
}
PropertyBinding {
value: NonNull::new(self.property.get()).unwrap(),
lock: self.mut_lock.clone()
}
}
pub fn try_bind(&self) -> Result<PropertyBinding<T>, ()> {
let was_locked = self.mut_lock.swap(true, Ordering::SeqCst);
if was_locked {
Err(())
}
else {
Ok(PropertyBinding {
value: NonNull::new(self.property.get()).unwrap(),
lock: self.mut_lock.clone()
})
}
}
}
unsafe impl<T: Send> Send for Property<T> {}
unsafe impl<T: Send + Sync> Sync for Property<T> {}