use std::{
any::Any,
cell::{Cell, UnsafeCell},
marker::PhantomData,
};
use crate::{
ll::{
bytecode::DispatchTable,
gc::{Gc, GcRaw},
value::{self, RawValue},
},
Error,
};
pub trait UserData: Any {
#[allow(unused_variables)]
fn visit_references(&self, visit: &mut dyn FnMut(RawValue)) {}
}
#[derive(Debug)]
pub(crate) struct Type<T> {
dtable: Gc<DispatchTable>,
_data: PhantomData<T>,
}
impl<T> Type<T> {
pub(crate) fn new(dtable: Gc<DispatchTable>) -> Self {
Self { dtable, _data: PhantomData }
}
}
impl<T> value::UserData for Type<T>
where
T: Any,
{
fn dtable_gcraw(&self) -> GcRaw<DispatchTable> {
Gc::as_raw(&self.dtable)
}
fn as_any(&self) -> &dyn Any {
self
}
}
#[derive(Debug)]
pub(crate) struct Object<T> {
pub(crate) dtable: Gc<DispatchTable>,
shared_borrows: Cell<usize>,
borrowed_mutably: Cell<bool>,
data: UnsafeCell<T>,
}
impl<T> Object<T> {
pub(crate) fn new(dtable: GcRaw<DispatchTable>, data: T) -> Self {
Self {
dtable: unsafe { Gc::from_raw(dtable) },
shared_borrows: Cell::new(0),
borrowed_mutably: Cell::new(false),
data: UnsafeCell::new(data),
}
}
#[doc(hidden)]
pub(crate) unsafe fn unsafe_borrow(&self) -> Result<(&T, UnsafeRefGuard<T>), Error> {
if self.borrowed_mutably.get() {
return Err(Error::ReentrantMutableBorrow);
}
self.shared_borrows.set(self.shared_borrows.get() + 1);
let reference = &*self.data.get();
Ok((reference, UnsafeRefGuard { object: self as *const _ }))
}
#[doc(hidden)]
pub(crate) unsafe fn unsafe_borrow_mut(&self) -> Result<(&mut T, UnsafeMutGuard<T>), Error> {
if self.shared_borrows.get() > 0 {
return Err(Error::ReentrantMutableBorrow);
}
self.borrowed_mutably.set(true);
let reference = &mut *self.data.get();
Ok((reference, UnsafeMutGuard { object: self as *const _ }))
}
}
impl<T> value::UserData for Object<T>
where
T: Any,
{
fn dtable_gcraw(&self) -> GcRaw<DispatchTable> {
Gc::as_raw(&self.dtable)
}
fn as_any(&self) -> &dyn Any {
self
}
}
#[doc(hidden)]
#[derive(Debug)]
pub struct UnsafeRefGuard<T> {
object: *const Object<T>,
}
impl<T> Drop for UnsafeRefGuard<T> {
fn drop(&mut self) {
unsafe {
let object = &*self.object;
object.shared_borrows.set(object.shared_borrows.get() - 1);
}
}
}
#[doc(hidden)]
#[derive(Debug)]
pub struct UnsafeMutGuard<T> {
object: *const Object<T>,
}
impl<T> Drop for UnsafeMutGuard<T> {
fn drop(&mut self) {
unsafe {
let object = &*self.object;
object.borrowed_mutably.set(false);
}
}
}