use parking_lot::{Mutex, RwLock};
use std::fmt::Debug;
use std::marker::PhantomData;
use std::mem;
use std::sync::Arc;
use std::time::Duration;
use crate::NativeClass;
pub unsafe trait UserData: Sized + Clone {
type Target: NativeClass;
fn new(val: Self::Target) -> Self;
unsafe 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 type DefaultUserData<T> = LocalCellData<T>;
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
pub enum Infallible {}
#[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, Default)]
pub struct 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;
fn new(val: Self::Target) -> Self {
MutexData {
lock: Arc::new(Mutex::new(val)),
_marker: PhantomData,
}
}
unsafe fn into_user_data(self) -> *const libc::c_void {
Arc::into_raw(self.lock) as *const libc::c_void
}
unsafe fn consume_user_data_unchecked(ptr: *const libc::c_void) -> Self {
MutexData {
lock: Arc::from_raw(ptr as *const Mutex<T>),
_marker: PhantomData,
}
}
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;
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;
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)?,
DeadlockPolicy::Timeout(dur) => self.lock.try_lock_for(dur).ok_or(LockFailed)?,
};
Ok(op(&mut *guard))
}
}
impl<T, OPT> Clone for MutexData<T, OPT> {
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;
fn new(val: Self::Target) -> Self {
RwLockData {
lock: Arc::new(RwLock::new(val)),
_marker: PhantomData,
}
}
unsafe fn into_user_data(self) -> *const libc::c_void {
Arc::into_raw(self.lock) as *const libc::c_void
}
unsafe fn consume_user_data_unchecked(ptr: *const libc::c_void) -> Self {
RwLockData {
lock: Arc::from_raw(ptr as *const RwLock<T>),
_marker: PhantomData,
}
}
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;
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)?,
DeadlockPolicy::Timeout(dur) => self.lock.try_read_for(dur).ok_or(LockFailed)?,
};
Ok(op(&*guard))
}
}
impl<T, OPT> MapMut for RwLockData<T, OPT>
where
T: NativeClass + Send + Sync,
OPT: LockOptions,
{
type Err = LockFailed;
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)?,
DeadlockPolicy::Timeout(dur) => self.lock.try_write_for(dur).ok_or(LockFailed)?,
};
Ok(op(&mut *guard))
}
}
impl<T, OPT> Clone for RwLockData<T, OPT> {
fn clone(&self) -> Self {
RwLockData {
lock: self.lock.clone(),
_marker: PhantomData,
}
}
}
#[derive(Debug)]
pub struct ArcData<T>(Arc<T>);
unsafe impl<T> UserData for ArcData<T>
where
T: NativeClass + Send + Sync,
{
type Target = T;
fn new(val: Self::Target) -> Self {
ArcData(Arc::new(val))
}
unsafe fn into_user_data(self) -> *const libc::c_void {
Arc::into_raw(self.0) as *const libc::c_void
}
unsafe fn consume_user_data_unchecked(ptr: *const libc::c_void) -> Self {
ArcData(Arc::from_raw(ptr as *const T))
}
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;
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> {
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::thread::{self, ThreadId};
#[derive(Debug)]
pub struct LocalCell<T> {
thread_id: ThreadId,
cell: RefCell<T>,
}
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
pub enum LocalCellError {
DifferentThread {
original: ThreadId,
current: ThreadId,
},
BorrowFailed,
}
impl<T> LocalCell<T> {
pub fn new(val: T) -> Self {
LocalCell {
thread_id: thread::current().id(),
cell: RefCell::new(val),
}
}
fn inner(&self) -> Result<&RefCell<T>, LocalCellError> {
let current = thread::current().id();
if self.thread_id == current {
Ok(&self.cell)
} else {
Err(LocalCellError::DifferentThread {
original: self.thread_id,
current,
})
}
}
pub fn try_borrow(&self) -> Result<Ref<T>, LocalCellError> {
let inner = self.inner()?;
inner.try_borrow().map_err(|_| LocalCellError::BorrowFailed)
}
pub fn try_borrow_mut(&self) -> Result<RefMut<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;
fn new(val: Self::Target) -> Self {
LocalCellData {
inner: Arc::new(local_cell::LocalCell::new(val)),
}
}
unsafe fn into_user_data(self) -> *const libc::c_void {
Arc::into_raw(self.inner) as *const libc::c_void
}
unsafe fn consume_user_data_unchecked(ptr: *const libc::c_void) -> Self {
LocalCellData {
inner: Arc::from_raw(ptr as *const local_cell::LocalCell<T>),
}
}
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;
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;
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> {
fn clone(&self) -> Self {
LocalCellData {
inner: self.inner.clone(),
}
}
}