use parking_lot::{Mutex, RwLock};
use std::fmt::{self, Debug, Display};
use std::marker::PhantomData;
use std::mem;
use std::sync::Arc;
use std::time::Duration;
use crate::export::NativeClass;
pub unsafe trait UserData: Sized + Clone {
type Target: NativeClass;
fn new(val: Self::Target) -> Self;
fn into_user_data(self) -> *const libc::c_void;
unsafe fn consume_user_data_unchecked(ptr: *const libc::c_void) -> Self;
unsafe fn clone_from_user_data_unchecked(ptr: *const libc::c_void) -> Self;
}
pub trait Map: UserData {
type Err: Debug;
fn map<F, U>(&self, op: F) -> Result<U, Self::Err>
where
F: FnOnce(&Self::Target) -> U;
}
pub trait MapMut: UserData {
type Err: Debug;
fn map_mut<F, U>(&self, op: F) -> Result<U, Self::Err>
where
F: FnOnce(&mut Self::Target) -> U;
}
pub trait MapOwned: UserData {
type Err: Debug;
fn map_owned<F, U>(&self, op: F) -> Result<U, Self::Err>
where
F: FnOnce(Self::Target) -> U;
}
pub type DefaultUserData<T> = LocalCellData<T>;
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
pub enum Infallible {}
impl std::fmt::Display for Infallible {
#[inline]
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "operation that can't fail just failed")
}
}
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
pub enum DeadlockPolicy {
Allow,
Pessimistic,
Timeout(Duration),
}
pub trait LockOptions {
const DEADLOCK_POLICY: DeadlockPolicy;
}
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Default)]
pub struct DefaultLockPolicy;
impl LockOptions for DefaultLockPolicy {
const DEADLOCK_POLICY: DeadlockPolicy = DeadlockPolicy::Allow;
}
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
pub enum LockFailed {
Pessimistic,
Timeout(Duration),
}
impl std::fmt::Display for LockFailed {
#[inline]
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
LockFailed::Timeout(wait) => write!(f, "failed to acquire lock within {wait:?}"),
LockFailed::Pessimistic => write!(f, "failed to acquire lock, it was already held"),
}
}
}
impl std::error::Error for LockFailed {}
#[derive(Debug)]
pub struct MutexData<T, OPT = DefaultLockPolicy> {
lock: Arc<Mutex<T>>,
_marker: PhantomData<OPT>,
}
unsafe impl<T, OPT> UserData for MutexData<T, OPT>
where
T: NativeClass + Send,
OPT: LockOptions,
{
type Target = T;
#[inline]
fn new(val: Self::Target) -> Self {
MutexData {
lock: Arc::new(Mutex::new(val)),
_marker: PhantomData,
}
}
#[inline]
fn into_user_data(self) -> *const libc::c_void {
Arc::into_raw(self.lock) as *const libc::c_void
}
#[inline]
unsafe fn consume_user_data_unchecked(ptr: *const libc::c_void) -> Self {
MutexData {
lock: Arc::from_raw(ptr as *const Mutex<T>),
_marker: PhantomData,
}
}
#[inline]
unsafe fn clone_from_user_data_unchecked(ptr: *const libc::c_void) -> Self {
let borrowed = Arc::from_raw(ptr as *const Mutex<T>);
let lock = borrowed.clone();
mem::forget(borrowed);
MutexData {
lock,
_marker: PhantomData,
}
}
}
impl<T, OPT> Map for MutexData<T, OPT>
where
T: NativeClass + Send,
OPT: LockOptions,
{
type Err = LockFailed;
#[inline]
fn map<F, U>(&self, op: F) -> Result<U, LockFailed>
where
F: FnOnce(&T) -> U,
{
self.map_mut(|val| op(val))
}
}
impl<T, OPT> MapMut for MutexData<T, OPT>
where
T: NativeClass + Send,
OPT: LockOptions,
{
type Err = LockFailed;
#[inline]
fn map_mut<F, U>(&self, op: F) -> Result<U, LockFailed>
where
F: FnOnce(&mut T) -> U,
{
let mut guard = match OPT::DEADLOCK_POLICY {
DeadlockPolicy::Allow => self.lock.lock(),
DeadlockPolicy::Pessimistic => self.lock.try_lock().ok_or(LockFailed::Pessimistic)?,
DeadlockPolicy::Timeout(dur) => self
.lock
.try_lock_for(dur)
.ok_or(LockFailed::Timeout(dur))?,
};
Ok(op(&mut *guard))
}
}
impl<T, OPT> Clone for MutexData<T, OPT> {
#[inline]
fn clone(&self) -> Self {
MutexData {
lock: self.lock.clone(),
_marker: PhantomData,
}
}
}
#[derive(Debug)]
pub struct RwLockData<T, OPT = DefaultLockPolicy> {
lock: Arc<RwLock<T>>,
_marker: PhantomData<OPT>,
}
unsafe impl<T, OPT> UserData for RwLockData<T, OPT>
where
T: NativeClass + Send + Sync,
OPT: LockOptions,
{
type Target = T;
#[inline]
fn new(val: Self::Target) -> Self {
RwLockData {
lock: Arc::new(RwLock::new(val)),
_marker: PhantomData,
}
}
#[inline]
fn into_user_data(self) -> *const libc::c_void {
Arc::into_raw(self.lock) as *const libc::c_void
}
#[inline]
unsafe fn consume_user_data_unchecked(ptr: *const libc::c_void) -> Self {
RwLockData {
lock: Arc::from_raw(ptr as *const RwLock<T>),
_marker: PhantomData,
}
}
#[inline]
unsafe fn clone_from_user_data_unchecked(ptr: *const libc::c_void) -> Self {
let borrowed = Arc::from_raw(ptr as *const RwLock<T>);
let lock = borrowed.clone();
mem::forget(borrowed);
RwLockData {
lock,
_marker: PhantomData,
}
}
}
impl<T, OPT> Map for RwLockData<T, OPT>
where
T: NativeClass + Send + Sync,
OPT: LockOptions,
{
type Err = LockFailed;
#[inline]
fn map<F, U>(&self, op: F) -> Result<U, LockFailed>
where
F: FnOnce(&T) -> U,
{
let guard = match OPT::DEADLOCK_POLICY {
DeadlockPolicy::Allow => self.lock.read(),
DeadlockPolicy::Pessimistic => self.lock.try_read().ok_or(LockFailed::Pessimistic)?,
DeadlockPolicy::Timeout(dur) => self
.lock
.try_read_for(dur)
.ok_or(LockFailed::Timeout(dur))?,
};
Ok(op(&*guard))
}
}
impl<T, OPT> MapMut for RwLockData<T, OPT>
where
T: NativeClass + Send + Sync,
OPT: LockOptions,
{
type Err = LockFailed;
#[inline]
fn map_mut<F, U>(&self, op: F) -> Result<U, LockFailed>
where
F: FnOnce(&mut T) -> U,
{
let mut guard = match OPT::DEADLOCK_POLICY {
DeadlockPolicy::Allow => self.lock.write(),
DeadlockPolicy::Pessimistic => self.lock.try_write().ok_or(LockFailed::Pessimistic)?,
DeadlockPolicy::Timeout(dur) => self
.lock
.try_write_for(dur)
.ok_or(LockFailed::Timeout(dur))?,
};
Ok(op(&mut *guard))
}
}
impl<T, OPT> Clone for RwLockData<T, OPT> {
#[inline]
fn clone(&self) -> Self {
RwLockData {
lock: self.lock.clone(),
_marker: PhantomData,
}
}
}
#[derive(Debug)]
pub struct ArcData<T>(Arc<T>);
impl<T> ArcData<T> {
#[inline]
pub fn into_inner(self) -> Arc<T> {
self.0
}
}
unsafe impl<T> UserData for ArcData<T>
where
T: NativeClass + Send + Sync,
{
type Target = T;
#[inline]
fn new(val: Self::Target) -> Self {
ArcData(Arc::new(val))
}
#[inline]
fn into_user_data(self) -> *const libc::c_void {
Arc::into_raw(self.0) as *const libc::c_void
}
#[inline]
unsafe fn consume_user_data_unchecked(ptr: *const libc::c_void) -> Self {
ArcData(Arc::from_raw(ptr as *const T))
}
#[inline]
unsafe fn clone_from_user_data_unchecked(ptr: *const libc::c_void) -> Self {
let borrowed = Arc::from_raw(ptr as *const T);
let arc = borrowed.clone();
mem::forget(borrowed);
ArcData(arc)
}
}
impl<T> Map for ArcData<T>
where
T: NativeClass + Send + Sync,
{
type Err = Infallible;
#[inline]
fn map<F, U>(&self, op: F) -> Result<U, Infallible>
where
F: FnOnce(&T) -> U,
{
Ok(op(&*self.0))
}
}
impl<T> Clone for ArcData<T> {
#[inline]
fn clone(&self) -> Self {
ArcData(self.0.clone())
}
}
#[derive(Debug)]
pub struct LocalCellData<T> {
inner: Arc<local_cell::LocalCell<T>>,
}
pub use self::local_cell::LocalCellError;
mod local_cell {
use std::cell::{Ref, RefCell, RefMut};
use std::mem::ManuallyDrop;
use std::thread::{self, ThreadId};
#[derive(Debug)]
pub struct LocalCell<T> {
thread_id: ThreadId,
cell: RefCell<ManuallyDrop<T>>,
}
impl<T> Drop for LocalCell<T> {
fn drop(&mut self) {
if self.thread_id == thread::current().id() {
unsafe {
ManuallyDrop::drop(self.cell.get_mut());
}
}
}
}
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
pub enum LocalCellError {
DifferentThread {
original: ThreadId,
current: ThreadId,
},
BorrowFailed,
}
impl std::fmt::Display for LocalCellError {
#[inline]
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
LocalCellError::DifferentThread { original, current } => write!(
f,
"accessing from the wrong thread, expected {original:?} found {current:?}"
),
LocalCellError::BorrowFailed => write!(
f,
"borrow failed; a &mut reference was requested, but one already exists. The cause is likely a re-entrant call \
(e.g. a GDNative Rust method calls to GDScript, which again calls a Rust method on the same object)"
),
}
}
}
impl std::error::Error for LocalCellError {}
impl<T> LocalCell<T> {
#[inline]
pub fn new(val: T) -> Self {
LocalCell {
thread_id: thread::current().id(),
cell: RefCell::new(ManuallyDrop::new(val)),
}
}
#[inline]
fn inner(&self) -> Result<&RefCell<ManuallyDrop<T>>, LocalCellError> {
let current = thread::current().id();
if self.thread_id == current {
Ok(&self.cell)
} else {
Err(LocalCellError::DifferentThread {
original: self.thread_id,
current,
})
}
}
#[inline]
pub fn try_borrow(&self) -> Result<Ref<ManuallyDrop<T>>, LocalCellError> {
let inner = self.inner()?;
inner.try_borrow().map_err(|_| LocalCellError::BorrowFailed)
}
#[inline]
pub fn try_borrow_mut(&self) -> Result<RefMut<ManuallyDrop<T>>, LocalCellError> {
let inner = self.inner()?;
inner
.try_borrow_mut()
.map_err(|_| LocalCellError::BorrowFailed)
}
}
unsafe impl<T> Send for LocalCell<T> {}
unsafe impl<T> Sync for LocalCell<T> {}
}
unsafe impl<T> UserData for LocalCellData<T>
where
T: NativeClass,
{
type Target = T;
#[inline]
fn new(val: Self::Target) -> Self {
LocalCellData {
inner: Arc::new(local_cell::LocalCell::new(val)),
}
}
#[inline]
fn into_user_data(self) -> *const libc::c_void {
Arc::into_raw(self.inner) as *const libc::c_void
}
#[inline]
unsafe fn consume_user_data_unchecked(ptr: *const libc::c_void) -> Self {
LocalCellData {
inner: Arc::from_raw(ptr as *const local_cell::LocalCell<T>),
}
}
#[inline]
unsafe fn clone_from_user_data_unchecked(ptr: *const libc::c_void) -> Self {
let borrowed = Arc::from_raw(ptr as *const local_cell::LocalCell<T>);
let arc = borrowed.clone();
mem::forget(borrowed);
LocalCellData { inner: arc }
}
}
impl<T> Map for LocalCellData<T>
where
T: NativeClass,
{
type Err = LocalCellError;
#[inline]
fn map<F, U>(&self, op: F) -> Result<U, Self::Err>
where
F: FnOnce(&Self::Target) -> U,
{
self.inner.try_borrow().map(|r| op(&r))
}
}
impl<T> MapMut for LocalCellData<T>
where
T: NativeClass,
{
type Err = LocalCellError;
#[inline]
fn map_mut<F, U>(&self, op: F) -> Result<U, Self::Err>
where
F: FnOnce(&mut Self::Target) -> U,
{
self.inner.try_borrow_mut().map(|mut w| op(&mut w))
}
}
impl<T> Clone for LocalCellData<T> {
#[inline]
fn clone(&self) -> Self {
LocalCellData {
inner: self.inner.clone(),
}
}
}
#[derive(Copy, Debug)]
pub struct Aether<T> {
_marker: PhantomData<T>,
}
unsafe impl<T> Send for Aether<T> {}
unsafe impl<T> Sync for Aether<T> {}
impl<T> Clone for Aether<T> {
#[inline]
fn clone(&self) -> Self {
Aether::default()
}
}
impl<T> Default for Aether<T> {
#[inline]
fn default() -> Self {
Aether {
_marker: PhantomData,
}
}
}
unsafe impl<T> UserData for Aether<T>
where
T: NativeClass + Copy + Default,
{
type Target = T;
#[inline]
fn new(_val: Self::Target) -> Self {
Aether::default()
}
#[inline]
fn into_user_data(self) -> *const libc::c_void {
1 as *const libc::c_void
}
#[inline]
unsafe fn consume_user_data_unchecked(_ptr: *const libc::c_void) -> Self {
Aether::default()
}
#[inline]
unsafe fn clone_from_user_data_unchecked(_ptr: *const libc::c_void) -> Self {
Aether::default()
}
}
impl<T> Map for Aether<T>
where
T: NativeClass + Copy + Default,
{
type Err = Infallible;
#[inline]
fn map<F, U>(&self, op: F) -> Result<U, Infallible>
where
F: FnOnce(&T) -> U,
{
Ok(op(&Default::default()))
}
}
pub struct Once<T>(Arc<atomic_take::AtomicTake<T>>);
impl<T> Clone for Once<T> {
#[inline]
fn clone(&self) -> Self {
Once(Arc::clone(&self.0))
}
}
unsafe impl<T> UserData for Once<T>
where
T: NativeClass + Send,
{
type Target = T;
#[inline]
fn new(val: Self::Target) -> Self {
Once(Arc::new(atomic_take::AtomicTake::new(val)))
}
#[inline]
fn into_user_data(self) -> *const libc::c_void {
Arc::into_raw(self.0) as *const _
}
#[inline]
unsafe fn consume_user_data_unchecked(ptr: *const libc::c_void) -> Self {
Once(Arc::from_raw(ptr as *const _))
}
#[inline]
unsafe fn clone_from_user_data_unchecked(ptr: *const libc::c_void) -> Self {
let borrowed = Arc::from_raw(ptr as *const _);
let arc = Arc::clone(&borrowed);
mem::forget(borrowed);
Once(arc)
}
}
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Default)]
pub struct ValueTaken;
impl std::error::Error for ValueTaken {}
impl Display for ValueTaken {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "this object has already been used once")
}
}
impl<T> MapOwned for Once<T>
where
T: NativeClass + Send,
{
type Err = ValueTaken;
#[inline]
fn map_owned<F, U>(&self, op: F) -> Result<U, Self::Err>
where
F: FnOnce(Self::Target) -> U,
{
let v = self.0.take().ok_or(ValueTaken)?;
Ok(op(v))
}
}