Add Projection type

This can be used when you primarily want to return a reference but in order for
that reference to live long enough it must be returned with an object.

i.e. given `Mutex<Foo { bar }>` you want a function to lock the mutex and return
a reference to `bar` but you can't return that reference since it has a lifetime
dependency on `MutexGuard` (which only derefs to all of `Foo` and not just
`bar`). You can return a `Projection` owning the `MutexGuard<Foo>` and set it up
to deref to `&bar`.
This commit is contained in:
Mahmoud Al-Qudsi 2023-05-16 10:43:48 -05:00
parent bec8e8df05
commit d32fee74f9

View File

@ -1985,6 +1985,56 @@ pub fn get_by_sorted_name<T: Named>(name: &wstr, vals: &'static [T]) -> Option<&
}
}
/// Takes ownership of a variable and `Deref`s/`DerefMut`s into a projection of that variable.
///
/// Can be used as a workaround for the lack of `MutexGuard::map()` to return a `MutexGuard`
/// exposing only a variable of the Mutex-owned object.
pub struct Projection<T, V, F1, F2>
where
F1: Fn(&T) -> &V,
F2: Fn(&mut T) -> &mut V,
{
value: T,
view: F1,
view_mut: F2,
}
impl<T, V, F1, F2> Projection<T, V, F1, F2>
where
F1: Fn(&T) -> &V,
F2: Fn(&mut T) -> &mut V,
{
pub fn new(owned: T, project: F1, project_mut: F2) -> Self {
Projection {
value: owned,
view: project,
view_mut: project_mut,
}
}
}
impl<T, V, F1, F2> Deref for Projection<T, V, F1, F2>
where
F1: Fn(&T) -> &V,
F2: Fn(&mut T) -> &mut V,
{
type Target = V;
fn deref(&self) -> &Self::Target {
(self.view)(&self.value)
}
}
impl<T, V, F1, F2> DerefMut for Projection<T, V, F1, F2>
where
F1: Fn(&T) -> &V,
F2: Fn(&mut T) -> &mut V,
{
fn deref_mut(&mut self) -> &mut Self::Target {
(self.view_mut)(&mut self.value)
}
}
#[allow(unused_macros)]
macro_rules! fwprintf {
($fd:expr, $format:literal $(, $arg:expr)*) => {