use crate::implementation::{LockMetadata, SharedImpl, SharedProjection};
use crate::locks::{SharedReadLock, SharedReadLockOwned};
use crate::projection::Projector;
use crate::synchronizer::{SynchronizerType, SynchronizerUnsized};
use crate::{Castable, PoisonPolicy, SharedMut};
use std::sync::Arc;
#[repr(transparent)]
pub struct Shared<T: ?Sized> {
inner: SharedImpl<T>,
}
impl<T: ?Sized> std::panic::RefUnwindSafe for Shared<T> {}
#[cfg(feature = "serde")]
use serde::Serialize;
#[cfg(feature = "serde")]
impl<'a, T: Serialize> Serialize for Shared<T>
where
&'a T: Serialize + 'static,
{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
self.read().serialize(serializer)
}
}
impl<T: ?Sized> Clone for Shared<T> {
fn clone(&self) -> Self {
Self {
inner: self.inner.clone(),
}
}
}
impl<T: std::fmt::Debug> std::fmt::Debug for Shared<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.read().fmt(f)
}
}
impl<T: ?Sized> From<Box<T>> for Shared<T>
where
Box<T>: Send + Sync,
{
fn from(value: Box<T>) -> Self {
Self {
inner: SharedImpl::Box(SynchronizerUnsized::new(
LockMetadata::poison_ignore(),
SynchronizerType::Arc,
value,
)),
}
}
}
impl<T: ?Sized> From<SharedImpl<T>> for Shared<T> {
fn from(inner: SharedImpl<T>) -> Self {
Self { inner }
}
}
impl<T: ?Sized> From<SharedMut<T>> for Shared<T> {
fn from(shared_rw: SharedMut<T>) -> Self {
Self {
inner: shared_rw.inner_impl,
}
}
}
impl<T: ?Sized> Shared<T> {
pub fn from_box(t: Box<T>) -> Self
where
Box<T>: Send + Sync,
{
Self {
inner: SharedImpl::Box(SynchronizerUnsized::new(
LockMetadata::poison_ignore(),
SynchronizerType::Arc,
t,
)),
}
}
pub(crate) const fn from_inner(inner: SharedImpl<T>) -> Self {
Self { inner }
}
}
impl<T: Send> Shared<T> {
pub fn new_unsync(t: T) -> Self {
Self::new_mutex(t)
}
pub fn new_mutex(t: T) -> Self {
Self::new_mutex_with_policy(t, PoisonPolicy::Panic)
}
pub fn new_mutex_with_policy(t: T, policy: PoisonPolicy) -> Self {
Self {
inner: SharedImpl::Value(SynchronizerUnsized::new(
LockMetadata::poison_policy(policy),
SynchronizerType::Mutex,
t,
)),
}
}
}
impl<T: Send + Sync + 'static> Shared<T> {
pub fn new(t: T) -> Self {
Self {
inner: SharedImpl::Value(SynchronizerUnsized::new(
LockMetadata::poison_panic(),
SynchronizerType::Arc,
t,
)),
}
}
}
impl<T> Shared<T> {
pub fn try_unwrap(self) -> Result<T, Self> {
match self.inner.try_unwrap() {
Ok(x) => Ok(x),
Err(inner) => Err(Self { inner }),
}
}
}
impl<T: ?Sized, P: ?Sized> SharedProjection<P> for (Shared<T>, Arc<Projector<T, P>>) {
fn read(&self) -> SharedReadLock<P> {
struct HiddenLock<'a, T: ?Sized, P: ?Sized> {
lock: SharedReadLock<'a, T>,
projector: &'a Projector<T, P>,
}
impl<'a, T: ?Sized, P: ?Sized> std::ops::Deref for HiddenLock<'a, T, P> {
type Target = P;
fn deref(&self) -> &Self::Target {
(self.projector).project(&*self.lock)
}
}
let lock = HiddenLock {
lock: self.0.read(),
projector: &self.1,
};
SharedReadLock::from_projection(Box::new(lock))
}
fn try_lock_read(&self) -> Option<SharedReadLock<P>> {
let lock = self.0.try_read();
if let Some(lock) = lock {
struct HiddenLock<'a, T: ?Sized, P: ?Sized> {
lock: SharedReadLock<'a, T>,
projector: &'a Projector<T, P>,
}
impl<'a, T: ?Sized, P: ?Sized> std::ops::Deref for HiddenLock<'a, T, P> {
type Target = P;
fn deref(&self) -> &Self::Target {
(self.projector).project(&*self.lock)
}
}
let lock = HiddenLock {
lock,
projector: &self.1,
};
Some(SharedReadLock::from_projection(Box::new(lock)))
} else {
None
}
}
}
impl<T: ?Sized> Shared<T> {
pub fn project<P: ?Sized + 'static, I: Into<Projector<T, P>>>(&self, projector: I) -> Shared<P>
where
T: 'static,
{
let projector: Projector<T, P> = projector.into();
let projectable = Arc::new((self.clone(), Arc::new(projector)));
Shared {
inner: SharedImpl::ProjectionRO(projectable),
}
}
pub fn project_fn<P: ?Sized + 'static, RO: (Fn(&T) -> &P) + Send + Sync + 'static>(
&self,
ro: RO,
) -> Shared<P>
where
T: 'static,
{
let projectable = Arc::new((self.clone(), Arc::new(Projector::new(ro))));
Shared {
inner: SharedImpl::ProjectionRO(projectable),
}
}
pub fn read(&self) -> SharedReadLock<T> {
self.inner.lock_read()
}
pub fn try_read(&self) -> Option<SharedReadLock<T>> {
self.inner.try_lock_read()
}
pub fn cast<U>(&self) -> Shared<U>
where
T: Castable<U> + 'static,
U: ?Sized + 'static,
{
let projector = crate::Projector::new(());
let projectable = Arc::new((self.clone(), Arc::new(projector)));
Shared {
inner: SharedImpl::ProjectionRO(projectable),
}
}
#[cfg(feature = "async_experimental")]
pub async fn read_async(&self, spawner: &crate::Spawner) -> SharedReadLock<T>
where
T: 'static,
{
if let Some(lock) = self.try_read() {
return lock;
}
let lock = spawner
.spawn_blocking_map(self.clone(), |lock| lock.read_owned())
.await;
return unsafe { lock.unsafe_reattach(&self.inner) };
}
#[allow(unused)]
pub(crate) fn read_owned(&self) -> SharedReadLockOwned<T> {
self.inner.lock_read_owned()
}
}
#[cfg(test)]
mod test {
use crate::{project, project_cast};
use super::*;
#[allow(unused)]
fn ensure_send<T: Send>() {}
#[allow(unused)]
fn ensure_sync<T: Sync>() {}
#[allow(unused)]
fn test_types() {
ensure_send::<Shared<usize>>();
ensure_sync::<Shared<usize>>();
ensure_send::<Shared<dyn AsRef<str>>>();
ensure_sync::<Shared<dyn AsRef<str>>>();
}
#[test]
pub fn test_shared() {
let shared = Shared::new(1);
assert_eq!(shared.read(), 1);
}
#[test]
pub fn test_shared_projection() {
let shared = Shared::new((1, 2));
let shared_proj = shared.project_fn(|x| &x.0);
assert_eq!(shared_proj.read(), 1);
let shared_proj = shared.project_fn(|x| &x.1);
assert_eq!(shared_proj.read(), 2);
}
#[test]
pub fn test_unsized() {
let shared: Shared<dyn AsRef<str>> =
Shared::new("123".to_owned()).project(project_cast!(x: String => dyn AsRef<str>));
assert_eq!(shared.read().as_ref(), "123");
let shared: Shared<[i32]> = Shared::from_box(Box::new([1, 2, 3]));
assert_eq!(shared.read()[0], 1);
}
#[test]
pub fn test_unwrap() {
let shared = Shared::new(1);
let res = shared.try_unwrap().expect("Expected to unwrap");
assert_eq!(res, 1);
let shared = Shared::new(1);
let shared2 = shared.clone();
assert!(matches!(shared.try_unwrap(), Err(_)));
assert!(matches!(shared2.try_unwrap(), Ok(_)));
}
#[test]
pub fn test_unsync() {
use std::{cell::Cell, marker::PhantomData};
pub type Unsync = PhantomData<Cell<()>>;
Shared::new_unsync(Unsync {});
}
#[cfg(feature = "serde")]
#[test]
pub fn test_serde() {
fn serialize<S: serde::Serialize>(_: S) {}
let shared = Shared::new((1, 2, 3));
serialize(shared);
}
}