1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
//! # A note on the implementation
//!
//! This library is a workaround until mapped guards become available in the standard library and uses boxing internally.
//!
//! While it's in practice likely possible to implement this more efficiently (without boxing) for many guards,
//! this isn't safe except for mutable borrows where the documentation explicitly states they are write-through.

#![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");
}

// There are a few requirements that must hold for this library to be sound:
// I: G is movable independently from R (base premise)
// II: It is impossible to separate G and R, except if that transformation is guarateed to keep R valid which is enabled by III.
// III: Consumers can't acquire a direct reference to `target` while consuming `self`.
#[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> {
	// Safety: III only holds if the deref defers to R's Target because MappedGuard is UnpinDereferenced!
	type Target = R::Target;

	#[inline]
	fn deref(&self) -> &Self::Target {
		&self.target
	}
}

/// Marker types for guards that are mapped by first being boxed (because they make no guarantees that their target reference can be detached from their location in memory.)
/// Technically this could be anything, but the operation only really makes sense for guards, in order to return the mapping from a function.
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> {}

// TODO: This is a bit inefficient. Provide another implementation that uses a flatter mapping if R is Deref.
impl<G, R> BoxedMapped for MappedGuard<G, R> {}

//TODO: Mention this in the struct documentation!
impl<G, R1, R> From<MappedGuard<MappedGuard<G, R1>, R>> for MappedGuard<G, R> {
	/// Flattens nested `MappedGuard` instances.
	#[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>;

	//TODO: What's the naming convention for this?
	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>;
}

//TODO: These should be default implementations and associated types instead.
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 {
				//SAFETY: `guard` can't be dropped independently from `target`.
				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 {
			//SAFETY: `guard` can't be dropped independently from `target`.
			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 {
				//SAFETY: `guard` can't be dropped independently from `target`.
				detach_borrow(&*boxed)
			})?,
			guard: boxed,
		})
	}
}

#[inline]
unsafe fn detach_borrow<'a, 'b, T>(reference: &'a T) -> &'b T {
	transmute(reference)
}