use core::ops::Deref;
use core::ptr::NonNull;
use avr_oxide::alloc::boxed::Box;
use avr_oxide::concurrency::interrupt;
use avr_oxide::util::datatypes::Volatile;
pub struct Arc<T: ?Sized> {
ptr: NonNull<ArcInner<T>>
}
#[repr(C)]
struct ArcInner<T: ?Sized> {
strong: Volatile<usize>,
data: T,
}
unsafe impl<T: ?Sized + Sync + Send> Send for Arc<T> {}
unsafe impl<T: ?Sized + Sync + Send> Sync for Arc<T> {}
unsafe impl<T: ?Sized + Sync + Send> Send for ArcInner<T> {}
unsafe impl<T: ?Sized + Sync + Send> Sync for ArcInner<T> {}
impl<T: ?Sized> Arc<T> {
#[allow(dead_code)]
unsafe fn from_inner(ptr: NonNull<ArcInner<T>>) -> Self {
Self { ptr }
}
#[allow(dead_code)]
unsafe fn from_ptr(ptr: *mut ArcInner<T>) -> Self {
Self::from_inner(NonNull::new_unchecked(ptr))
}
}
impl <T> Arc<T>{
pub fn new(data: T) -> Arc<T> {
let inner = Box::new(ArcInner {
strong: Volatile::<usize>::zero(),
data
});
Arc {
ptr: Box::leak(inner).into()
}
}
}
impl<T: ?Sized> Clone for Arc<T> {
fn clone(&self) -> Self {
unsafe {
(*self.ptr.as_ptr()).strong += 1;
Arc {
ptr: self.ptr
}
}
}
}
impl<T: ?Sized> Drop for Arc<T> {
fn drop(&mut self) {
interrupt::isolated(|_isotoken|{
unsafe {
if (*self.ptr.as_ptr()).strong == 0 {
core::ptr::drop_in_place(self.ptr.as_ptr());
} else {
(*self.ptr.as_ptr()).strong -= 1;
}
}
});
}
}
impl<T: ?Sized> Deref for Arc<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
unsafe {
&(*self.ptr.as_ptr()).data
}
}
}