#![doc(html_root_url = "https://docs.rs/mapped-guard/0.0.1")]
#![warn(clippy::pedantic)]
use core::{mem::transmute, ops::Deref};
use std::{
cell::Ref,
sync::{MutexGuard, RwLockReadGuard, RwLockWriteGuard},
};
#[cfg(doctest)]
pub mod readme {
doc_comment::doctest!("../README.md");
}
#[derive(Debug)]
pub struct MappedGuard<G, R> {
guard: G,
target: R,
}
impl<G, R> MappedGuard<G, R> {
pub fn new(guard: G, target: R) -> Self {
Self { guard, target }
}
}
impl<G, R: Deref> Deref for MappedGuard<G, R> {
type Target = R::Target;
#[inline]
fn deref(&self) -> &Self::Target {
&self.target
}
}
pub trait BoxedMapped {}
impl<'a, T> BoxedMapped for MutexGuard<'a, T> {}
impl<'a, T> BoxedMapped for RwLockReadGuard<'a, T> {}
impl<'a, T> BoxedMapped for RwLockWriteGuard<'a, T> {}
impl<'a, T> BoxedMapped for Ref<'a, T> {}
impl<G, R> BoxedMapped for MappedGuard<G, R> {}
impl<G, R1, R> From<MappedGuard<MappedGuard<G, R1>, R>> for MappedGuard<G, R> {
#[inline]
fn from(from: MappedGuard<MappedGuard<G, R1>, R>) -> Self {
Self {
guard: from.guard.guard,
target: from.target,
}
}
}
pub trait MapGuard<'a, G, R1, R2: 'a> {
fn map_guard(self, map: impl FnOnce(R1) -> R2) -> MappedGuard<G, R2>;
fn maybe_map_guard(
self,
maybe_map: impl FnOnce(R1) -> Option<R2>,
) -> Option<MappedGuard<G, R2>>;
}
pub trait TryMapGuard<'a, G, R1, R2: 'a, E: 'a> {
#[allow(clippy::missing_errors_doc)]
fn try_map_guard(
self,
try_map: impl FnOnce(R1) -> Result<R2, E>,
) -> Result<MappedGuard<G, R2>, E>;
}
impl<'a, G: BoxedMapped + 'a, R: 'a> MapGuard<'a, Box<G>, &'a G, R> for G {
#[inline]
fn map_guard(self, map: impl FnOnce(&'a G) -> R) -> MappedGuard<Box<G>, R> {
let boxed = Box::new(self);
MappedGuard {
target: map(unsafe {
detach_borrow(&*boxed)
}),
guard: boxed,
}
}
#[inline]
fn maybe_map_guard(
self,
maybe_map: impl FnOnce(&'a G) -> Option<R>,
) -> Option<MappedGuard<Box<G>, R>> {
let boxed = Box::new(self);
maybe_map(unsafe {
detach_borrow(&*boxed)
})
.map(|target| MappedGuard {
target,
guard: boxed,
})
}
}
impl<'a, G: BoxedMapped + 'a, R: 'a, E: 'a> TryMapGuard<'a, Box<G>, &'a G, R, E> for G {
#[inline]
fn try_map_guard(
self,
try_map: impl FnOnce(&'a G) -> Result<R, E>,
) -> Result<MappedGuard<Box<G>, R>, E> {
let boxed = Box::new(self);
Ok(MappedGuard {
target: try_map(unsafe {
detach_borrow(&*boxed)
})?,
guard: boxed,
})
}
}
#[inline]
unsafe fn detach_borrow<'a, 'b, T>(reference: &'a T) -> &'b T {
transmute(reference)
}