From d32fee74f9e6b88dbc0454b2e5c5b4f2d1c61e32 Mon Sep 17 00:00:00 2001 From: Mahmoud Al-Qudsi Date: Tue, 16 May 2023 10:43:48 -0500 Subject: [PATCH] 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` 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` and set it up to deref to `&bar`. --- fish-rust/src/common.rs | 50 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/fish-rust/src/common.rs b/fish-rust/src/common.rs index cb154f08b..9b29cdd3c 100644 --- a/fish-rust/src/common.rs +++ b/fish-rust/src/common.rs @@ -1985,6 +1985,56 @@ pub fn get_by_sorted_name(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 +where + F1: Fn(&T) -> &V, + F2: Fn(&mut T) -> &mut V, +{ + value: T, + view: F1, + view_mut: F2, +} + +impl Projection +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 Deref for Projection +where + F1: Fn(&T) -> &V, + F2: Fn(&mut T) -> &mut V, +{ + type Target = V; + + fn deref(&self) -> &Self::Target { + (self.view)(&self.value) + } +} + +impl DerefMut for Projection +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)*) => {