1#![doc(html_root_url = "https://docs.rs/mapped-guard/0.0.1")]
9#![warn(clippy::pedantic)]
10
11use core::{mem::transmute, ops::Deref};
12use std::{
13 cell::Ref,
14 sync::{MutexGuard, RwLockReadGuard, RwLockWriteGuard},
15};
16
17#[cfg(doctest)]
18pub mod readme {
19 doc_comment::doctest!("../README.md");
20}
21
22#[derive(Debug)]
27pub struct MappedGuard<G, R> {
28 guard: G,
29 target: R,
30}
31
32impl<G, R> MappedGuard<G, R> {
33 pub fn new(guard: G, target: R) -> Self {
34 Self { guard, target }
35 }
36}
37
38impl<G, R: Deref> Deref for MappedGuard<G, R> {
39 type Target = R::Target;
41
42 #[inline]
43 fn deref(&self) -> &Self::Target {
44 &self.target
45 }
46}
47
48pub trait BoxedMapped {}
51impl<'a, T> BoxedMapped for MutexGuard<'a, T> {}
52impl<'a, T> BoxedMapped for RwLockReadGuard<'a, T> {}
53impl<'a, T> BoxedMapped for RwLockWriteGuard<'a, T> {}
54impl<'a, T> BoxedMapped for Ref<'a, T> {}
55
56impl<G, R> BoxedMapped for MappedGuard<G, R> {}
58
59impl<G, R1, R> From<MappedGuard<MappedGuard<G, R1>, R>> for MappedGuard<G, R> {
61 #[inline]
63 fn from(from: MappedGuard<MappedGuard<G, R1>, R>) -> Self {
64 Self {
65 guard: from.guard.guard,
66 target: from.target,
67 }
68 }
69}
70
71pub trait MapGuard<'a, G, R1, R2: 'a> {
72 fn map_guard(self, map: impl FnOnce(R1) -> R2) -> MappedGuard<G, R2>;
73
74 fn maybe_map_guard(
76 self,
77 maybe_map: impl FnOnce(R1) -> Option<R2>,
78 ) -> Option<MappedGuard<G, R2>>;
79}
80pub trait TryMapGuard<'a, G, R1, R2: 'a, E: 'a> {
81 #[allow(clippy::missing_errors_doc)]
82 fn try_map_guard(
83 self,
84 try_map: impl FnOnce(R1) -> Result<R2, E>,
85 ) -> Result<MappedGuard<G, R2>, E>;
86}
87
88impl<'a, G: BoxedMapped + 'a, R: 'a> MapGuard<'a, Box<G>, &'a G, R> for G {
90 #[inline]
91 fn map_guard(self, map: impl FnOnce(&'a G) -> R) -> MappedGuard<Box<G>, R> {
92 let boxed = Box::new(self);
93 MappedGuard {
94 target: map(unsafe {
95 detach_borrow(&*boxed)
97 }),
98 guard: boxed,
99 }
100 }
101
102 #[inline]
103 fn maybe_map_guard(
104 self,
105 maybe_map: impl FnOnce(&'a G) -> Option<R>,
106 ) -> Option<MappedGuard<Box<G>, R>> {
107 let boxed = Box::new(self);
108 maybe_map(unsafe {
109 detach_borrow(&*boxed)
111 })
112 .map(|target| MappedGuard {
113 target,
114 guard: boxed,
115 })
116 }
117}
118impl<'a, G: BoxedMapped + 'a, R: 'a, E: 'a> TryMapGuard<'a, Box<G>, &'a G, R, E> for G {
119 #[inline]
120 fn try_map_guard(
121 self,
122 try_map: impl FnOnce(&'a G) -> Result<R, E>,
123 ) -> Result<MappedGuard<Box<G>, R>, E> {
124 let boxed = Box::new(self);
125 Ok(MappedGuard {
126 target: try_map(unsafe {
127 detach_borrow(&*boxed)
129 })?,
130 guard: boxed,
131 })
132 }
133}
134
135#[inline]
136unsafe fn detach_borrow<'a, 'b, T>(reference: &'a T) -> &'b T {
137 transmute(reference)
138}