From 2d4fbc290bafe3f8f7eada8528e5469948217798 Mon Sep 17 00:00:00 2001 From: Johannes Altmanninger Date: Sun, 9 Apr 2023 13:56:40 +0200 Subject: [PATCH] Teach ScopeGuard to expose a custom view on deref() This allows the upcoming scoped_push to stuff internal data into the context, but not expose it to the user. (This change is a bit ugly, needs polish) --- fish-rust/src/common.rs | 43 +++++++++++++++++++++++++++++++---------- 1 file changed, 33 insertions(+), 10 deletions(-) diff --git a/fish-rust/src/common.rs b/fish-rust/src/common.rs index 7de35c916..ede940074 100644 --- a/fish-rust/src/common.rs +++ b/fish-rust/src/common.rs @@ -1739,7 +1739,7 @@ pub fn replace_with T>(old: &mut T, with: F) -> T { std::mem::replace(old, new) } -pub type Cleanup = ScopeGuard; +pub type Cleanup = ScopeGuard; /// A RAII cleanup object. Unlike in C++ where there is no borrow checker, we can't just provide a /// callback that modifies live objects willy-nilly because then there would be two &mut references @@ -1766,21 +1766,44 @@ pub fn replace_with T>(old: &mut T, with: F) -> T { /// /// // hello will be written first, then goodbye. /// ``` -pub struct ScopeGuard { +pub struct ScopeGuard { captured: ManuallyDrop, + view: fn(&T) -> &C, + view_mut: fn(&mut T) -> &mut C, on_drop: Option, + marker: std::marker::PhantomData, } -impl ScopeGuard { +fn identity(t: &T) -> &T { + t +} +fn identity_mut(t: &mut T) -> &mut T { + t +} + +impl ScopeGuard { /// Creates a new `ScopeGuard` wrapping `value`. The `on_drop` callback is executed when the /// ScopeGuard's lifetime expires or when it is manually dropped. pub fn new(value: T, on_drop: F) -> Self { + Self::with_view(value, identity, identity_mut, on_drop) + } +} + +impl ScopeGuard { + pub fn with_view( + value: T, + view: fn(&T) -> &C, + view_mut: fn(&mut T) -> &mut C, + on_drop: F, + ) -> Self { Self { captured: ManuallyDrop::new(value), + view, + view_mut, on_drop: Some(on_drop), + marker: Default::default(), } } - /// Cancel the unwind operation, e.g. do not call the previously passed-in `on_drop` callback /// when the current scope expires. pub fn cancel(guard: &mut Self) { @@ -1808,21 +1831,21 @@ pub fn commit(mut guard: Self) -> T { } } -impl Deref for ScopeGuard { - type Target = T; +impl Deref for ScopeGuard { + type Target = C; fn deref(&self) -> &Self::Target { - &self.captured + (self.view)(&self.captured) } } -impl DerefMut for ScopeGuard { +impl DerefMut for ScopeGuard { fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.captured + (self.view_mut)(&mut self.captured) } } -impl Drop for ScopeGuard { +impl Drop for ScopeGuard { fn drop(&mut self) { if let Some(on_drop) = self.on_drop.take() { on_drop(&mut self.captured);