use super::{lock, CoordinateError, Subject};
use either::{Either, Left, Right};
use std::marker::PhantomData;
pub trait Faceted<'a> {
type FacetFree;
type FacetShared;
type FacetExclusive;
fn facet_free(&'a self) -> Self::FacetFree;
fn facet_shared(&'a self) -> Self::FacetShared;
fn facet_exclusive(&'a self) -> Self::FacetExclusive;
}
pub struct ResourceFree<'a, R: Subject + Faceted<'a>> {
lock: lock::UnlockedFile,
inner: R,
phantom: PhantomData<&'a R>,
}
impl<'a, R> ResourceFree<'a, R>
where
R: Subject + Faceted<'a>,
{
pub fn new(lock: lock::UnlockedFile, inner: R) -> Self {
Self { lock, inner, phantom: PhantomData }
}
pub fn facet(&'a self) -> R::FacetFree {
self.inner.facet_free()
}
pub fn try_shared(
self,
) -> Result<Either<Self, ResourceShared<'a, R>>, CoordinateError<R::Error>> {
Ok(match self.lock.try_lock_shared()? {
Left(lock) => Left(Self { inner: self.inner, lock, phantom: PhantomData }),
Right(lock) => Right(ResourceShared { inner: self.inner, lock, phantom: PhantomData }),
})
}
pub fn shared(self) -> Result<ResourceShared<'a, R>, CoordinateError<R::Error>> {
let lock = self.lock.lock_shared()?;
Ok(ResourceShared { inner: self.inner, lock, phantom: PhantomData })
}
pub fn try_exclusive(
self,
) -> Result<Either<Self, ResourceExclusive<'a, R>>, CoordinateError<R::Error>> {
Ok(match self.lock.try_lock_exclusive()? {
Left(lock) => Left(Self { inner: self.inner, lock, phantom: PhantomData }),
Right(lock) => {
Right(ResourceExclusive { inner: self.inner, lock, phantom: PhantomData })
}
})
}
pub fn exclusive(self) -> Result<ResourceExclusive<'a, R>, CoordinateError<R::Error>> {
let lock = self.lock.lock_exclusive()?;
Ok(ResourceExclusive { inner: self.inner, lock, phantom: PhantomData })
}
pub fn into_parts(self) -> (lock::UnlockedFile, R) {
(self.lock, self.inner)
}
}
pub struct ResourceShared<'a, R: Subject + Faceted<'a>> {
lock: lock::LockedFileShared,
inner: R,
phantom: PhantomData<&'a R>,
}
impl<'a, R> ResourceShared<'a, R>
where
R: Subject + Faceted<'a>,
{
pub fn new(lock: lock::LockedFileShared, inner: R) -> Self {
Self { lock, inner, phantom: PhantomData }
}
pub fn facet(&'a self) -> R::FacetShared {
self.inner.facet_shared()
}
pub fn try_exclusive(
self,
) -> Result<Either<Self, ResourceExclusive<'a, R>>, CoordinateError<R::Error>> {
Ok(match self.lock.try_lock_exclusive()? {
Left(lock) => Left(Self { inner: self.inner, lock, phantom: PhantomData }),
Right(lock) => {
Right(ResourceExclusive { inner: self.inner, lock, phantom: PhantomData })
}
})
}
pub fn exclusive(self) -> Result<ResourceExclusive<'a, R>, CoordinateError<R::Error>> {
let lock = self.lock.lock_exclusive()?;
Ok(ResourceExclusive { inner: self.inner, lock, phantom: PhantomData })
}
pub fn try_release(
self,
) -> Result<Either<Self, ResourceFree<'a, R>>, CoordinateError<R::Error>> {
Ok(match self.lock.try_unlock()? {
Left(lock) => Left(Self { inner: self.inner, lock, phantom: PhantomData }),
Right(lock) => Right(ResourceFree { inner: self.inner, lock, phantom: PhantomData }),
})
}
pub fn release(self) -> Result<ResourceFree<'a, R>, CoordinateError<R::Error>> {
let lock = self.lock.unlock()?;
Ok(ResourceFree { inner: self.inner, lock, phantom: PhantomData })
}
}
pub struct ResourceExclusive<'a, R: Subject + Faceted<'a>> {
lock: lock::LockedFileExclusive,
inner: R,
phantom: PhantomData<&'a R>,
}
impl<'a, R> ResourceExclusive<'a, R>
where
R: Subject + Faceted<'a>,
{
pub fn new(lock: lock::LockedFileExclusive, inner: R) -> Self {
Self { lock, inner, phantom: PhantomData }
}
pub fn facet(&'a self) -> R::FacetExclusive {
self.inner.facet_exclusive()
}
pub fn try_shared(
self,
) -> Result<Either<Self, ResourceShared<'a, R>>, CoordinateError<R::Error>> {
Ok(match self.lock.try_lock_shared()? {
Left(lock) => Left(Self { inner: self.inner, lock, phantom: PhantomData }),
Right(lock) => Right(ResourceShared { inner: self.inner, lock, phantom: PhantomData }),
})
}
pub fn shared(self) -> Result<ResourceShared<'a, R>, CoordinateError<R::Error>> {
let lock = self.lock.lock_shared()?;
Ok(ResourceShared { inner: self.inner, lock, phantom: PhantomData })
}
pub fn try_release(
self,
) -> Result<Either<Self, ResourceFree<'a, R>>, CoordinateError<R::Error>> {
Ok(match self.lock.try_unlock()? {
Left(lock) => Left(Self { inner: self.inner, lock, phantom: PhantomData }),
Right(lock) => Right(ResourceFree { inner: self.inner, lock, phantom: PhantomData }),
})
}
pub fn release(self) -> Result<ResourceFree<'a, R>, CoordinateError<R::Error>> {
let lock = self.lock.unlock()?;
Ok(ResourceFree { inner: self.inner, lock, phantom: PhantomData })
}
}