mod guards;
use crate::error::OrUserError;
use crate::container::Container;
use crate::manager::FileManager;
pub use self::guards::{
AccessGuard,
AccessGuardMut,
OwnedAccessGuard,
OwnedAccessGuardMut
};
use parking_lot::RwLock;
use std::path::Path;
use std::sync::Arc;
pub type StandardContainerShared<T, Format> = ContainerShared<T, crate::manager::standard::StandardManager<Format>>;
pub type StandardContainerSharedOptions = crate::manager::standard::StandardManagerOptions;
#[cfg_attr(docsrs, doc(cfg(feature = "atomic")))]
#[cfg(feature = "atomic")]
pub type AtomicContainerShared<T, Format, Support> = ContainerShared<T, crate::manager::atomic::AtomicManager<Format, Support>>;
#[cfg_attr(docsrs, doc(cfg(feature = "atomic")))]
#[cfg(feature = "atomic")]
pub type AtomicContainerSharedOptions<Support> = crate::manager::atomic::AtomicManagerOptions<Support>;
#[repr(transparent)]
#[derive(Debug)]
pub struct ContainerShared<T, Manager> {
ptr: Arc<RwLock<Container<T, Manager>>>
}
impl<T, Manager> ContainerShared<T, Manager> {
pub fn new(value: T, manager: Manager) -> Self {
ContainerShared::from(Container::new(value, manager))
}
pub fn try_unwrap(self) -> Result<Container<T, Manager>, Self> {
match Arc::try_unwrap(self.ptr) {
Ok(inner) => Ok(RwLock::into_inner(inner)),
Err(ptr) => Err(ContainerShared { ptr })
}
}
pub fn get_mut(&mut self) -> Option<&mut Container<T, Manager>> {
Arc::get_mut(&mut self.ptr).map(RwLock::get_mut)
}
#[inline]
pub fn access(&self) -> AccessGuard<'_, T, Manager> {
AccessGuard::new(self.ptr.read())
}
#[inline]
pub fn access_mut(&self) -> AccessGuardMut<'_, T, Manager> {
AccessGuardMut::new(self.ptr.write())
}
#[inline]
pub fn access_owned(&self) -> OwnedAccessGuard<T, Manager> {
OwnedAccessGuard::new(self.ptr.read_arc())
}
#[inline]
pub fn access_owned_mut(&self) -> OwnedAccessGuardMut<T, Manager> {
OwnedAccessGuardMut::new(self.ptr.write_arc())
}
#[inline]
pub fn try_access(&self) -> Option<AccessGuard<'_, T, Manager>> {
self.ptr.try_read().map(AccessGuard::new)
}
#[inline]
pub fn try_access_mut(&self) -> Option<AccessGuardMut<'_, T, Manager>> {
self.ptr.try_write().map(AccessGuardMut::new)
}
#[inline]
pub fn try_access_owned(&self) -> Option<OwnedAccessGuard<T, Manager>> {
self.ptr.try_read_arc().map(OwnedAccessGuard::new)
}
#[inline]
pub fn try_access_owned_mut(&self) -> Option<OwnedAccessGuardMut<T, Manager>> {
self.ptr.try_write_arc().map(OwnedAccessGuardMut::new)
}
pub fn operate<F, R>(&self, operation: F) -> R
where F: FnOnce(&T) -> R {
operation(&*self.access())
}
pub fn operate_mut<F, R>(&self, operation: F) -> R
where F: FnOnce(&mut T) -> R {
operation(&mut *self.access_mut())
}
}
impl<T, Manager> ContainerShared<T, Manager>
where Manager: FileManager<T> {
pub fn open<P: AsRef<Path>>(
path: P, format: Manager::Format, options: Manager::Options
) -> Result<Self, Manager::Error> {
Container::<T, _>::open(path, format, options).map(From::from)
}
pub fn create_overwrite<P: AsRef<Path>>(
path: P, format: Manager::Format, options: Manager::Options, value: T
) -> Result<Self, Manager::Error> {
Container::<T, _>::create_overwrite(path, format, options, value).map(From::from)
}
pub fn create_or<P: AsRef<Path>>(
path: P, format: Manager::Format, options: Manager::Options, value: T
) -> Result<Self, Manager::Error> {
Container::<T, _>::create_or(path, format, options, value).map(From::from)
}
pub fn create_or_else<P: AsRef<Path>, C>(
path: P, format: Manager::Format, options: Manager::Options, closure: C
) -> Result<Self, Manager::Error>
where C: FnOnce() -> T {
Container::<T, _>::create_or_else(path, format, options, closure).map(From::from)
}
pub fn create_or_default<P: AsRef<Path>>(
path: P, format: Manager::Format, options: Manager::Options
) -> Result<Self, Manager::Error>
where T: Default {
Container::<T, _>::create_or_default(path, format, options).map(From::from)
}
#[doc(alias = "operate_load", alias = "operate_reload")]
pub fn operate_refresh<F, R>(&self, operation: F) -> Result<R, Manager::Error>
where F: FnOnce(&T, T) -> R {
let mut guard = self.access_mut();
let old_value = guard.container_mut().refresh()?;
let guard = AccessGuardMut::downgrade(guard);
Ok(operation(&guard, old_value))
}
#[doc(alias = "operate_mut_store", alias = "operate_mut_save")]
pub fn operate_mut_commit<F, R, U>(&self, operation: F) -> Result<R, OrUserError<Manager::Error, U>>
where F: FnOnce(&mut T) -> Result<R, U> {
let mut guard = self.access_mut();
let ret = operation(&mut guard).map_err(OrUserError::User)?;
Self::commit_with_guard(guard)?;
Ok(ret)
}
#[doc(alias = "load", alias = "reload")]
pub fn refresh(&self) -> Result<T, Manager::Error> {
AccessGuardMut::container_mut(&mut self.access_mut()).refresh()
}
#[doc(alias = "store", alias = "save")]
pub fn commit(&self) -> Result<(), Manager::Error> {
let guard = self.access_mut();
Self::commit_with_guard(guard)
}
pub fn commit_with_guard(mut guard: AccessGuardMut<'_, T, Manager>) -> Result<(), Manager::Error> {
AccessGuardMut::container_mut(&mut guard).commit()
}
pub fn commit_with_guard_owned(mut guard: OwnedAccessGuardMut<T, Manager>) -> Result<(), Manager::Error> {
OwnedAccessGuardMut::container_mut(&mut guard).commit()
}
#[doc(alias = "replace")]
pub fn overwrite(&self, value: T) -> Result<(), Manager::Error> {
AccessGuardMut::container_mut(&mut self.access_mut()).overwrite(value)
}
}
impl<T, Manager> Clone for ContainerShared<T, Manager> {
#[inline]
fn clone(&self) -> Self {
ContainerShared { ptr: Arc::clone(&self.ptr) }
}
}
impl<T, Manager> From<Container<T, Manager>> for ContainerShared<T, Manager> {
#[inline]
fn from(container: Container<T, Manager>) -> Self {
ContainerShared { ptr: Arc::new(RwLock::new(container)) }
}
}