#![deny(broken_intra_doc_links, missing_docs)]
#![cfg_attr(not(any(test, feature = "std")), no_std)]
use core::marker::PhantomData;
use core::ptr::NonNull;
use core::{fmt, ops};
pub extern crate stable_deref_trait;
pub use stable_deref_trait::StableDeref;
pub unsafe trait Guarded {
type Target: ?Sized;
fn borrow_guarded(&self) -> &Self::Target;
}
pub unsafe trait GuardedMut: Guarded {
fn borrow_guarded_mut(&mut self) -> &mut Self::Target;
}
unsafe impl<T, U> Guarded for T
where
T: ops::Deref<Target = U> + StableDeref + 'static,
U: ?Sized,
{
type Target = U;
#[inline]
fn borrow_guarded(&self) -> &U {
&*self
}
}
unsafe impl<T, U> GuardedMut for T
where
T: ops::DerefMut<Target = U> + StableDeref + 'static,
U: ?Sized,
{
#[inline]
fn borrow_guarded_mut(&mut self) -> &mut U {
&mut *self
}
}
#[repr(transparent)]
#[derive(Debug)]
pub struct AssertSafe<T> {
inner: T,
}
impl<T> AssertSafe<T>
where
T: ops::Deref,
{
#[inline]
pub unsafe fn new_unchecked(inner: T) -> Self {
Self { inner }
}
}
unsafe impl<T, U> Guarded for AssertSafe<T>
where
T: ops::Deref<Target = U>,
U: ?Sized,
{
type Target = U;
#[inline]
fn borrow_guarded(&self) -> &Self::Target {
&*self.inner
}
}
unsafe impl<T, U> GuardedMut for AssertSafe<T>
where
T: ops::Deref<Target = U> + ops::DerefMut,
U: ?Sized,
{
#[inline]
fn borrow_guarded_mut(&mut self) -> &mut Self::Target {
&mut *self.inner
}
}
pub struct Mapped<T, U>
where
T: Guarded,
U: ?Sized,
{
inner: T,
mapped: NonNull<U>,
}
impl<T, U> Mapped<T, U>
where
T: Guarded,
U: ?Sized,
{
#[inline]
pub fn into_original(self) -> T {
self.inner
}
#[inline]
pub fn original_by_ref(&self) -> &T {
&self.inner
}
#[inline]
pub fn get_ref(&self) -> &U {
unsafe { self.mapped.as_ref() }
}
#[inline]
pub fn and_then<F, V>(self, f: F) -> Mapped<T, V>
where
F: FnOnce(&U) -> &V,
V: ?Sized,
{
Mapped {
mapped: f(self.get_ref()).into(),
inner: self.inner,
}
}
#[inline]
pub fn try_and_then<F, V, E>(self, f: F) -> Result<Mapped<T, V>, E>
where
F: FnOnce(&U) -> Result<&V, E>,
V: ?Sized,
{
Ok(Mapped {
mapped: f(self.get_ref())?.into(),
inner: self.inner,
})
}
}
impl<T, U> fmt::Debug for Mapped<T, U>
where
T: Guarded,
U: ?Sized + fmt::Debug,
{
#[cold]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_tuple("Mapped").field(&self.get_ref()).finish()
}
}
unsafe impl<T, U> Guarded for Mapped<T, U>
where
T: Guarded,
U: ?Sized,
{
type Target = U;
#[inline]
fn borrow_guarded(&self) -> &Self::Target {
self.get_ref()
}
}
pub struct MappedMut<T, U>
where
T: GuardedMut,
U: ?Sized,
{
inner: T,
mapped: NonNull<U>,
_invariance: PhantomData<*mut U>,
}
impl<T, U> MappedMut<T, U>
where
T: GuardedMut,
U: ?Sized,
{
#[inline]
pub fn into_original(self) -> T {
self.inner
}
#[inline]
pub fn into_immutable(this: MappedMut<T, U>) -> Mapped<T, U> {
Mapped {
inner: this.inner,
mapped: this.mapped,
}
}
#[inline]
pub fn get_ref(&self) -> &U {
unsafe { self.mapped.as_ref() }
}
#[inline]
pub fn get_mut(&mut self) -> &mut U {
unsafe { self.mapped.as_mut() }
}
#[inline]
pub fn and_then<F, V>(mut self, f: F) -> MappedMut<T, V>
where
F: FnOnce(&mut U) -> &mut V,
V: ?Sized,
{
MappedMut {
mapped: f(self.get_mut()).into(),
inner: self.inner,
_invariance: PhantomData,
}
}
#[inline]
pub fn try_and_then<F, V, E>(mut self, f: F) -> Result<MappedMut<T, V>, E>
where
F: FnOnce(&mut U) -> Result<&mut V, E>,
V: ?Sized,
{
Ok(MappedMut {
mapped: f(self.get_mut())?.into(),
inner: self.inner,
_invariance: PhantomData,
})
}
}
unsafe impl<T, U> Guarded for MappedMut<T, U>
where
T: GuardedMut,
U: ?Sized,
{
type Target = U;
#[inline]
fn borrow_guarded(&self) -> &Self::Target {
self.get_ref()
}
}
unsafe impl<T, U> GuardedMut for MappedMut<T, U>
where
T: GuardedMut,
U: ?Sized,
{
#[inline]
fn borrow_guarded_mut(&mut self) -> &mut Self::Target {
self.get_mut()
}
}
mod private {
pub trait Sealed {}
}
pub trait GuardedExt: private::Sealed + Guarded + Sized {
#[inline]
fn map<F, T>(this: Self, f: F) -> Mapped<Self, T>
where
F: FnOnce(&<Self as Guarded>::Target) -> &T,
T: ?Sized,
{
Mapped {
mapped: f(this.borrow_guarded()).into(),
inner: this,
}
}
#[inline]
fn try_map<F, T, E>(this: Self, f: F) -> Result<Mapped<Self, T>, E>
where
F: FnOnce(&<Self as Guarded>::Target) -> Result<&T, E>,
T: ?Sized,
{
Ok(Mapped {
mapped: f(this.borrow_guarded())?.into(),
inner: this,
})
}
}
pub trait GuardedMutExt: private::Sealed + GuardedMut + Sized {
#[inline]
fn map_mut<F, T>(mut this: Self, f: F) -> MappedMut<Self, T>
where
F: FnOnce(&mut <Self as Guarded>::Target) -> &mut T,
T: ?Sized,
{
MappedMut {
mapped: f(this.borrow_guarded_mut()).into(),
inner: this,
_invariance: PhantomData,
}
}
#[inline]
fn try_map_mut<F, T, E>(mut this: Self, f: F) -> Result<MappedMut<Self, T>, E>
where
F: FnOnce(&mut <Self as Guarded>::Target) -> Result<&mut T, E>,
T: ?Sized,
{
Ok(MappedMut {
mapped: f(this.borrow_guarded_mut())?.into(),
inner: this,
_invariance: PhantomData,
})
}
}
impl<T> private::Sealed for T
where
T: Guarded + Sized,
{
}
impl<T> GuardedExt for T
where
T: Guarded + Sized,
{
}
impl<T> GuardedMutExt for T
where
T: GuardedMut + Sized,
{
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn basic_types_implement_guarded() {
use std::rc::Rc;
use std::sync::Arc;
fn does_impl_guarded<T: Guarded>() {}
fn does_impl_guarded_mut<T: GuardedMut>() {}
does_impl_guarded::<Arc<[u8]>>();
does_impl_guarded::<Rc<[u8]>>();
does_impl_guarded::<Box<[u8]>>();
does_impl_guarded::<Vec<u8>>();
does_impl_guarded::<&'static [u8]>();
does_impl_guarded::<&'static mut [u8]>();
does_impl_guarded::<&'static str>();
does_impl_guarded::<String>();
does_impl_guarded_mut::<Box<[u8]>>();
does_impl_guarded_mut::<Vec<u8>>();
does_impl_guarded::<&'static mut [u8]>();
}
#[test]
fn mapped() {
let mut buf = vec! [0x00_u8; 256];
let sub_buf = GuardedMutExt::map_mut(buf, |buf: &mut [u8]| -> &mut [u8] {
&mut buf[128..]
});
let mut subsub_buf = sub_buf.and_then(|buf| &mut buf[..64]);
for byte in subsub_buf.borrow_guarded_mut() {
*byte = 0xFF;
}
buf = subsub_buf.into_original();
assert!(buf[..128].iter().copied().all(|byte| byte == 0x00));
assert!(buf[128..192].iter().copied().all(|byte| byte == 0xFF));
assert!(buf[192..].iter().copied().all(|byte| byte == 0x00));
}
}