#![warn(missing_docs)]
use std::{
borrow::{Borrow, BorrowMut},
cell::{Ref, RefCell, RefMut},
cmp::Ordering,
fmt,
hash::{Hash, Hasher},
marker::PhantomData,
ops::{Deref, DerefMut},
ptr,
rc::Rc,
sync::Arc,
};
use parking_lot::{
MappedRwLockReadGuard, MappedRwLockWriteGuard, RwLock, RwLockReadGuard, RwLockWriteGuard,
};
pub type UnsyncByRef<T> = Shared<T, ShareUnsync, ByRef>;
pub type SyncByRef<T> = Shared<T, ShareSync, ByRef>;
pub type UnsyncByVal<T> = Shared<T, ShareUnsync, ByVal>;
pub type SyncByVal<T> = Shared<T, ShareSync, ByVal>;
pub type SyncReadGuard<'a, T> = ReadGuard<'a, T, GuardSync>;
pub type SyncWriteGuard<'a, T> = WriteGuard<'a, T, GuardSync>;
pub type UnsyncReadGuard<'a, T> = ReadGuard<'a, T, GuardUnsync>;
pub type UnsyncWriteGuard<'a, T> = WriteGuard<'a, T, GuardUnsync>;
pub trait PartialEqKind<T, U> {
fn eq<S: ShareKind>(a: &S::Inner<T>, b: &S::Inner<U>) -> bool;
}
pub trait EqKind<T>: PartialEqKind<T, T> {}
pub trait PartialOrdKind<T, U>: PartialEqKind<T, U> {
fn partial_cmp<S: ShareKind>(a: &S::Inner<T>, b: &S::Inner<U>) -> Option<Ordering>;
}
pub trait OrdKind<T>: EqKind<T> + PartialOrdKind<T, T> {
fn cmp<S: ShareKind>(a: &S::Inner<T>, b: &S::Inner<T>) -> Ordering;
}
pub trait HashKind<T> {
fn hash<S: ShareKind, H: Hasher>(inner: &S::Inner<T>, state: &mut H);
}
pub struct ByRef;
pub struct ByVal;
impl<T> PartialEqKind<T, T> for ByRef {
fn eq<S: ShareKind>(a: &S::Inner<T>, b: &S::Inner<T>) -> bool {
S::ptr_eq(a, b)
}
}
impl<T> EqKind<T> for ByRef {}
impl<T, U> PartialOrdKind<T, U> for ByRef
where
Self: PartialEqKind<T, U>,
{
fn partial_cmp<S: ShareKind>(a: &S::Inner<T>, b: &S::Inner<U>) -> Option<Ordering> {
Some(S::ptr_cmp(a, b))
}
}
impl<T> OrdKind<T> for ByRef {
fn cmp<S: ShareKind>(a: &S::Inner<T>, b: &S::Inner<T>) -> Ordering {
S::ptr_cmp(a, b)
}
}
impl<T> HashKind<T> for ByRef {
fn hash<S: ShareKind, H: Hasher>(inner: &S::Inner<T>, state: &mut H) {
S::ptr_hash(inner, state);
}
}
impl<T: PartialEq<U>, U> PartialEqKind<T, U> for ByVal {
fn eq<S: ShareKind>(a: &S::Inner<T>, b: &S::Inner<U>) -> bool {
*S::read(a) == *S::read(b)
}
}
impl<T: Eq> EqKind<T> for ByVal {}
impl<T: PartialOrd<U>, U> PartialOrdKind<T, U> for ByVal
where
Self: PartialEqKind<T, U>,
{
fn partial_cmp<S: ShareKind>(a: &S::Inner<T>, b: &S::Inner<U>) -> Option<Ordering> {
S::read(a).partial_cmp(&S::read(b))
}
}
impl<T: Ord> OrdKind<T> for ByVal
where
Self: EqKind<T> + PartialOrdKind<T, T>,
{
fn cmp<S: ShareKind>(a: &S::Inner<T>, b: &S::Inner<T>) -> Ordering {
S::read(a).cmp(&S::read(b))
}
}
impl<T: Hash> HashKind<T> for ByVal {
fn hash<S: ShareKind, H: Hasher>(inner: &S::Inner<T>, state: &mut H) {
S::read(inner).hash(state);
}
}
pub trait GuardKind {
type ReadGuard<'a, T: 'a>: Deref<Target = T>;
type WriteGuard<'a, T: 'a>: DerefMut<Target = T>;
fn map_read<T, U, F: FnOnce(&T) -> &U>(
guard: Self::ReadGuard<'_, T>,
f: F,
) -> Self::ReadGuard<'_, U>;
fn map_write<T, U, F: FnOnce(&mut T) -> &mut U>(
guard: Self::WriteGuard<'_, T>,
f: F,
) -> Self::WriteGuard<'_, U>;
fn filter_map_read<T, U, F: FnOnce(&T) -> Option<&U>>(
guard: Self::ReadGuard<'_, T>,
f: F,
) -> Result<Self::ReadGuard<'_, U>, Self::ReadGuard<'_, T>>;
fn filter_map_write<T, U, F: FnOnce(&mut T) -> Option<&mut U>>(
guard: Self::WriteGuard<'_, T>,
f: F,
) -> Result<Self::WriteGuard<'_, U>, Self::WriteGuard<'_, T>>;
}
pub struct GuardUnsync;
pub struct GuardSync;
impl GuardKind for GuardUnsync {
type ReadGuard<'a, T: 'a> = Ref<'a, T>;
type WriteGuard<'a, T: 'a> = RefMut<'a, T>;
fn map_read<T, U, F: FnOnce(&T) -> &U>(
guard: Self::ReadGuard<'_, T>,
f: F,
) -> Self::ReadGuard<'_, U> {
Ref::map(guard, f)
}
fn map_write<T, U, F: FnOnce(&mut T) -> &mut U>(
guard: Self::WriteGuard<'_, T>,
f: F,
) -> Self::WriteGuard<'_, U> {
RefMut::map(guard, f)
}
fn filter_map_read<T, U, F: FnOnce(&T) -> Option<&U>>(
guard: Self::ReadGuard<'_, T>,
f: F,
) -> Result<Self::ReadGuard<'_, U>, Self::ReadGuard<'_, T>> {
Ref::filter_map(guard, f)
}
fn filter_map_write<T, U, F: FnOnce(&mut T) -> Option<&mut U>>(
guard: Self::WriteGuard<'_, T>,
f: F,
) -> Result<Self::WriteGuard<'_, U>, Self::WriteGuard<'_, T>> {
RefMut::filter_map(guard, f)
}
}
impl GuardKind for GuardSync {
type ReadGuard<'a, T: 'a> = MappedRwLockReadGuard<'a, T>;
type WriteGuard<'a, T: 'a> = MappedRwLockWriteGuard<'a, T>;
fn map_read<T, U, F: FnOnce(&T) -> &U>(
guard: Self::ReadGuard<'_, T>,
f: F,
) -> Self::ReadGuard<'_, U> {
MappedRwLockReadGuard::map(guard, f)
}
fn map_write<T, U, F: FnOnce(&mut T) -> &mut U>(
guard: Self::WriteGuard<'_, T>,
f: F,
) -> Self::WriteGuard<'_, U> {
MappedRwLockWriteGuard::map(guard, f)
}
fn filter_map_read<T, U, F: FnOnce(&T) -> Option<&U>>(
guard: Self::ReadGuard<'_, T>,
f: F,
) -> Result<Self::ReadGuard<'_, U>, Self::ReadGuard<'_, T>> {
MappedRwLockReadGuard::try_map(guard, f)
}
fn filter_map_write<T, U, F: FnOnce(&mut T) -> Option<&mut U>>(
guard: Self::WriteGuard<'_, T>,
f: F,
) -> Result<Self::WriteGuard<'_, U>, Self::WriteGuard<'_, T>> {
MappedRwLockWriteGuard::try_map(guard, f)
}
}
pub trait ShareKind {
type Inner<T>: Clone;
type GuardKind: GuardKind;
fn make<T>(t: T) -> Self::Inner<T>;
fn read<T>(inner: &Self::Inner<T>) -> <Self::GuardKind as GuardKind>::ReadGuard<'_, T>;
fn write<T>(inner: &mut Self::Inner<T>) -> <Self::GuardKind as GuardKind>::WriteGuard<'_, T>;
fn try_read<T>(
inner: &Self::Inner<T>,
) -> Option<<Self::GuardKind as GuardKind>::ReadGuard<'_, T>>;
fn try_write<T>(
inner: &mut Self::Inner<T>,
) -> Option<<Self::GuardKind as GuardKind>::WriteGuard<'_, T>>;
fn as_mut<T>(inner: &mut Self::Inner<T>) -> Option<&mut T>;
fn make_mut<T: Clone>(inner: &mut Self::Inner<T>) -> &mut T {
if Self::as_mut(inner).is_none() {
let value = Self::read(inner).clone();
*inner = Self::make(value);
}
Self::as_mut(inner).unwrap()
}
fn try_unwrap<T>(inner: Self::Inner<T>) -> Result<T, Self::Inner<T>>;
fn ptr_eq<T, U>(a: &Self::Inner<T>, b: &Self::Inner<U>) -> bool;
fn ptr_cmp<T, U>(a: &Self::Inner<T>, b: &Self::Inner<U>) -> Ordering;
fn ptr_hash<T, H: Hasher>(inner: &Self::Inner<T>, state: &mut H);
}
pub struct ShareUnsync;
impl ShareKind for ShareUnsync {
type Inner<T> = Rc<RefCell<T>>;
type GuardKind = GuardUnsync;
fn make<T>(t: T) -> Self::Inner<T> {
Rc::new(RefCell::new(t))
}
fn read<T>(inner: &Self::Inner<T>) -> <Self::GuardKind as GuardKind>::ReadGuard<'_, T> {
RefCell::borrow(inner)
}
fn write<T>(inner: &mut Self::Inner<T>) -> <Self::GuardKind as GuardKind>::WriteGuard<'_, T> {
RefCell::borrow_mut(inner)
}
fn try_read<T>(
inner: &Self::Inner<T>,
) -> Option<<Self::GuardKind as GuardKind>::ReadGuard<'_, T>> {
inner.try_borrow().ok()
}
fn try_write<T>(
inner: &mut Self::Inner<T>,
) -> Option<<Self::GuardKind as GuardKind>::WriteGuard<'_, T>> {
inner.try_borrow_mut().ok()
}
fn as_mut<T>(inner: &mut Self::Inner<T>) -> Option<&mut T> {
Rc::get_mut(inner).map(RefCell::get_mut)
}
fn make_mut<T: Clone>(inner: &mut Self::Inner<T>) -> &mut T {
Rc::make_mut(inner).get_mut()
}
fn try_unwrap<T>(inner: Self::Inner<T>) -> Result<T, Self::Inner<T>> {
Rc::try_unwrap(inner).map(RefCell::into_inner)
}
fn ptr_eq<T, U>(a: &Self::Inner<T>, b: &Self::Inner<U>) -> bool {
ptr::eq(Rc::as_ptr(a) as *const (), Rc::as_ptr(b) as *const ())
}
fn ptr_cmp<T, U>(a: &Self::Inner<T>, b: &Self::Inner<U>) -> Ordering {
(Rc::as_ptr(a) as *const ()).cmp(&(Rc::as_ptr(b) as *const ()))
}
fn ptr_hash<T, H: Hasher>(inner: &Self::Inner<T>, state: &mut H) {
ptr::hash(Rc::as_ptr(inner), state);
}
}
pub struct ShareSync;
impl ShareKind for ShareSync {
type Inner<T> = Arc<RwLock<T>>;
type GuardKind = GuardSync;
fn make<T>(t: T) -> Self::Inner<T> {
Arc::new(RwLock::new(t))
}
fn read<T>(inner: &Self::Inner<T>) -> <Self::GuardKind as GuardKind>::ReadGuard<'_, T> {
RwLockReadGuard::map(inner.read(), |x| x)
}
fn write<T>(inner: &mut Self::Inner<T>) -> <Self::GuardKind as GuardKind>::WriteGuard<'_, T> {
RwLockWriteGuard::map(inner.write(), |x| x)
}
fn try_read<T>(
inner: &Self::Inner<T>,
) -> Option<<Self::GuardKind as GuardKind>::ReadGuard<'_, T>> {
inner.try_read().map(|x| RwLockReadGuard::map(x, |x| x))
}
fn try_write<T>(
inner: &mut Self::Inner<T>,
) -> Option<<Self::GuardKind as GuardKind>::WriteGuard<'_, T>> {
inner.try_write().map(|x| RwLockWriteGuard::map(x, |x| x))
}
fn as_mut<T>(inner: &mut Self::Inner<T>) -> Option<&mut T> {
Arc::get_mut(inner).map(RwLock::get_mut)
}
fn try_unwrap<T>(inner: Self::Inner<T>) -> Result<T, Self::Inner<T>> {
Arc::try_unwrap(inner).map(RwLock::into_inner)
}
fn ptr_eq<T, U>(a: &Self::Inner<T>, b: &Self::Inner<U>) -> bool {
ptr::eq(Arc::as_ptr(a) as *const (), Arc::as_ptr(b) as *const ())
}
fn ptr_cmp<T, U>(a: &Self::Inner<T>, b: &Self::Inner<U>) -> Ordering {
(Arc::as_ptr(a) as *const ()).cmp(&(Arc::as_ptr(b) as *const ()))
}
fn ptr_hash<T, H: Hasher>(inner: &Self::Inner<T>, state: &mut H) {
ptr::hash(Arc::as_ptr(inner), state);
}
}
pub struct Shared<T, S: ShareKind, E = ByRef>(S::Inner<T>, PhantomData<E>);
impl<T: Default, S: ShareKind, E> Default for Shared<T, S, E> {
fn default() -> Self {
Shared::new(Default::default())
}
}
impl<T, S: ShareKind, E> From<T> for Shared<T, S, E> {
fn from(t: T) -> Self {
Shared::new(t)
}
}
impl<T, S: ShareKind> Shared<T, S, ByRef> {
pub fn new_by_ref(t: T) -> Self {
Shared::new(t)
}
}
impl<T, S: ShareKind> Shared<T, S, ByVal> {
pub fn new_by_val(t: T) -> Self {
Shared::new(t)
}
}
impl<T, S: ShareKind, E> Shared<T, S, E> {
pub fn new(t: T) -> Self {
Shared(S::make(t), PhantomData)
}
pub fn get(&self) -> ReadGuard<T, S::GuardKind> {
ReadGuard(S::read(&self.0))
}
pub fn get_mut(&mut self) -> WriteGuard<T, S::GuardKind> {
WriteGuard(S::write(&mut self.0))
}
pub fn try_get(&self) -> Option<ReadGuard<T, S::GuardKind>> {
S::try_read(&self.0).map(ReadGuard)
}
pub fn try_get_mut(&mut self) -> Option<WriteGuard<T, S::GuardKind>> {
S::try_write(&mut self.0).map(WriteGuard)
}
pub fn set(&mut self, t: T) {
*self.get_mut() = t;
}
pub fn try_set(&mut self, t: T) -> bool {
if let Some(mut guard) = self.try_get_mut() {
*guard = t;
true
} else {
false
}
}
pub fn make_mut(&mut self) -> &mut T
where
T: Clone,
{
S::make_mut(&mut self.0)
}
pub fn copied(&self) -> T
where
T: Copy,
{
*self.get()
}
pub fn cloned(&self) -> T
where
T: Clone,
{
self.get().clone()
}
pub fn try_unwrap(self) -> Result<T, Self> {
S::try_unwrap(self.0).map_err(|inner| Shared(inner, PhantomData))
}
pub fn unwrap_or_clone(self) -> T
where
T: Clone,
{
self.try_unwrap().unwrap_or_else(|shared| shared.cloned())
}
pub fn as_mut(&mut self) -> Option<&mut T> {
S::as_mut(&mut self.0)
}
pub fn bind<F, R>(&self, f: F) -> R
where
F: FnOnce(&T) -> R,
{
f(&self.get())
}
pub fn bind_mut<F, R>(&mut self, f: F) -> R
where
F: FnOnce(&mut T) -> R,
{
if let Some(value) = self.as_mut() {
f(value)
} else {
f(&mut self.get_mut())
}
}
}
impl<T, S: ShareKind, E> Clone for Shared<T, S, E> {
fn clone(&self) -> Self {
Shared(S::Inner::<T>::clone(&self.0), PhantomData)
}
}
impl<T, S: ShareKind, E> fmt::Debug for Shared<T, S, E>
where
T: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if let Some(guard) = self.try_get() {
write!(f, "{:?}", *guard)
} else {
write!(f, "<locked>")
}
}
}
impl<T, S: ShareKind, E> fmt::Display for Shared<T, S, E>
where
T: fmt::Display,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if let Some(guard) = self.try_get() {
write!(f, "{}", *guard)
} else {
write!(f, "<locked>")
}
}
}
impl<T, U, S: ShareKind, E: PartialEqKind<T, U>> PartialEq<Shared<U, S, E>> for Shared<T, S, E> {
fn eq(&self, other: &Shared<U, S, E>) -> bool {
E::eq::<S>(&self.0, &other.0)
}
}
impl<S: ShareKind> PartialEq<str> for Shared<String, S, ByVal> {
fn eq(&self, other: &str) -> bool {
*self.get() == other
}
}
impl<'a, S: ShareKind> PartialEq<&'a str> for Shared<String, S, ByVal> {
fn eq(&self, other: &&'a str) -> bool {
*self.get() == *other
}
}
impl<T, S: ShareKind, E: EqKind<T>> Eq for Shared<T, S, E> {}
impl<T, U, S: ShareKind, E: PartialOrdKind<T, U>> PartialOrd<Shared<U, S, E>> for Shared<T, S, E> {
fn partial_cmp(&self, other: &Shared<U, S, E>) -> Option<Ordering> {
E::partial_cmp::<S>(&self.0, &other.0)
}
}
impl<T, S: ShareKind, E: OrdKind<T>> Ord for Shared<T, S, E> {
fn cmp(&self, other: &Self) -> Ordering {
E::cmp::<S>(&self.0, &other.0)
}
}
impl<T, S: ShareKind, E: HashKind<T>> Hash for Shared<T, S, E> {
fn hash<H: Hasher>(&self, state: &mut H) {
E::hash::<S, _>(&self.0, state)
}
}
pub struct ReadGuard<'a, T: 'a, G: GuardKind>(G::ReadGuard<'a, T>);
pub struct WriteGuard<'a, T: 'a, G: GuardKind>(G::WriteGuard<'a, T>);
macro_rules! guard_impl {
($ty:ident) => {
impl<'a, T, G: GuardKind> Deref for $ty<'a, T, G> {
type Target = T;
fn deref(&self) -> &T {
self.0.deref()
}
}
impl<'a, T: fmt::Debug, G: GuardKind> fmt::Debug for $ty<'a, T, G> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.deref().fmt(f)
}
}
impl<'a, T: fmt::Display, G: GuardKind> fmt::Display for $ty<'a, T, G> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.deref().fmt(f)
}
}
impl<'a, T: PartialEq, G: GuardKind> PartialEq for $ty<'a, T, G> {
fn eq(&self, other: &Self) -> bool {
self.deref().eq(other.deref())
}
}
impl<'a, 'b, T: PartialEq, G: GuardKind> PartialEq<&'b Self> for $ty<'a, T, G> {
fn eq(&self, other: &&'b Self) -> bool {
self.deref().eq(other.deref())
}
}
impl<'a, T: PartialEq, G: GuardKind> PartialEq<T> for $ty<'a, T, G> {
fn eq(&self, other: &T) -> bool {
self.deref().eq(other)
}
}
impl<'a, G: GuardKind> PartialEq<str> for $ty<'a, String, G> {
fn eq(&self, other: &str) -> bool {
self.deref().eq(other)
}
}
impl<'a, 'b, G: GuardKind> PartialEq<&'b str> for $ty<'a, String, G> {
fn eq(&self, other: &&'b str) -> bool {
self.deref().eq(other)
}
}
impl<'a, T: Eq, G: GuardKind> Eq for $ty<'a, T, G> {}
impl<'a, T: PartialOrd, G: GuardKind> PartialOrd for $ty<'a, T, G> {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
self.deref().partial_cmp(other.deref())
}
}
impl<'a, T: Ord, G: GuardKind> Ord for $ty<'a, T, G> {
fn cmp(&self, other: &Self) -> Ordering {
self.deref().cmp(other.deref())
}
}
impl<'a, T: Hash, G: GuardKind> Hash for $ty<'a, T, G> {
fn hash<H: Hasher>(&self, state: &mut H) {
self.deref().hash(state)
}
}
impl<'a, T, G: GuardKind> AsRef<T> for $ty<'a, T, G> {
fn as_ref(&self) -> &T {
self.deref()
}
}
impl<'a, T, G: GuardKind> Borrow<T> for $ty<'a, T, G> {
fn borrow(&self) -> &T {
self.deref()
}
}
};
}
guard_impl!(ReadGuard);
guard_impl!(WriteGuard);
impl<'a, T, G: GuardKind> DerefMut for WriteGuard<'a, T, G> {
fn deref_mut(&mut self) -> &mut T {
self.0.deref_mut()
}
}
impl<'a, T, G: GuardKind> AsMut<T> for WriteGuard<'a, T, G> {
fn as_mut(&mut self) -> &mut T {
self.deref_mut()
}
}
impl<'a, T, G: GuardKind> BorrowMut<T> for WriteGuard<'a, T, G> {
fn borrow_mut(&mut self) -> &mut T {
self.deref_mut()
}
}
impl<'a, T, G: GuardKind> ReadGuard<'a, T, G> {
pub fn map<U, F: FnOnce(&T) -> &U>(self, f: F) -> ReadGuard<'a, U, G> {
ReadGuard(G::map_read(self.0, f))
}
pub fn filter_map<U, F: FnOnce(&T) -> Option<&U>>(
self,
f: F,
) -> Result<ReadGuard<'a, U, G>, Self> {
G::filter_map_read(self.0, f)
.map(ReadGuard)
.map_err(ReadGuard)
}
}
impl<'a, T, G: GuardKind> WriteGuard<'a, T, G> {
pub fn map<U, F: FnOnce(&mut T) -> &mut U>(self, f: F) -> WriteGuard<'a, U, G> {
WriteGuard(G::map_write(self.0, f))
}
pub fn filter_map<U, F: FnOnce(&mut T) -> Option<&mut U>>(
self,
f: F,
) -> Result<WriteGuard<'a, U, G>, Self> {
G::filter_map_write(self.0, f)
.map(WriteGuard)
.map_err(WriteGuard)
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn equality() {
let a = UnsyncByRef::new(1);
let b = UnsyncByRef::new(1);
assert_ne!(a, b);
let a = UnsyncByVal::new_by_val(1);
let b = UnsyncByVal::new_by_val(1);
assert_eq!(a, b);
}
#[test]
fn map() {
struct Foo {
s: String,
}
let mut foo = UnsyncByRef::new(Foo {
s: "hello".to_string(),
});
let mut s = foo.get_mut().map(|f| &mut f.s);
*s = "world".to_string();
drop(s);
assert_eq!(foo.get().s, "world");
}
#[test]
fn as_mut() {
let mut x = UnsyncByRef::new(1);
*x.as_mut().unwrap() += 1;
assert_eq!(x.get(), 2);
let _y = x.clone();
assert!(x.as_mut().is_none());
}
#[test]
fn bind() {
let mut x = UnsyncByRef::new(1);
let y = x.bind_mut(|x| {
*x += 1;
*x * *x
});
assert_eq!(x.get(), 2);
assert_eq!(y, 4);
let _x2 = x.clone();
let y = x.bind_mut(|x| {
*x += 1;
*x * *x
});
assert_eq!(x.get(), 3);
assert_eq!(y, 9);
}
#[test]
fn partial_eq() {
#[derive(Debug)]
struct Foo;
#[derive(Debug)]
struct Bar;
impl PartialEq<Bar> for Foo {
fn eq(&self, _: &Bar) -> bool {
true
}
}
let a = UnsyncByVal::new(Foo);
let b = UnsyncByVal::new(Bar);
assert_eq!(a, b);
}
#[test]
fn unwrap() {
let x = UnsyncByRef::new(1);
assert_eq!(Ok(1), x.try_unwrap());
let x = UnsyncByRef::new(1);
let _y = x.clone();
assert!(x.try_unwrap().is_err());
}
}