Replace ScopedPush with scoped_push which is underpinned by ScopeGuard

This allows us to use the scoped push in more scenarios by appeasing the
borrow checker.

Use it in a couple of places instead of ScopeGuard. Hopefully this is makes
porting easier.
This commit is contained in:
Johannes Altmanninger 2023-04-09 13:58:47 +02:00
parent 2d4fbc290b
commit a5cae59082
2 changed files with 51 additions and 41 deletions

View File

@ -1855,38 +1855,44 @@ impl<T, F: FnOnce(&mut T), C> Drop for ScopeGuard<T, F, C> {
}
}
/// A scoped manager to save the current value of some variable, and optionally set it to a new
/// value. When dropped, it restores the variable to its old value.
///
/// This can be handy when there are multiple code paths to exit a block. Note that this can only be
/// used if the code does not access the captured variable again for the duration of the scope. If
/// that's not the case (the code will refuse to compile), use a [`ScopeGuard`] instance instead.
pub struct ScopedPush<'a, T> {
var: &'a mut T,
saved_value: Option<T>,
}
impl<'a, T> ScopedPush<'a, T> {
pub fn new(var: &'a mut T, new_value: T) -> Self {
let saved_value = mem::replace(var, new_value);
Self {
var,
saved_value: Some(saved_value),
}
/// A scoped manager to save the current value of some variable, and set it to a new value. When
/// dropped, it restores the variable to its old value.
#[allow(clippy::type_complexity)] // Not sure how to extract the return type.
pub fn scoped_push<Context, Accessor, T>(
mut ctx: Context,
accessor: Accessor,
new_value: T,
) -> ScopeGuard<(Context, Accessor, T), fn(&mut (Context, Accessor, T)), Context>
where
Accessor: Fn(&mut Context) -> &mut T,
T: Copy,
{
fn restore_saved_value<Context, Accessor, T: Copy>(data: &mut (Context, Accessor, T))
where
Accessor: Fn(&mut Context) -> &mut T,
{
let (ref mut ctx, ref accessor, saved_value) = data;
*accessor(ctx) = *saved_value;
}
pub fn restore(&mut self) {
if let Some(saved_value) = self.saved_value.take() {
*self.var = saved_value;
}
fn view_context<Context, Accessor, T>(data: &(Context, Accessor, T)) -> &Context
where
Accessor: Fn(&mut Context) -> &mut T,
{
&data.0
}
}
impl<'a, T> Drop for ScopedPush<'a, T> {
fn drop(&mut self) {
self.restore()
fn view_context_mut<Context, Accessor, T>(data: &mut (Context, Accessor, T)) -> &mut Context
where
Accessor: Fn(&mut Context) -> &mut T,
{
&mut data.0
}
let saved_value = mem::replace(accessor(&mut ctx), new_value);
ScopeGuard::with_view(
(ctx, accessor, saved_value),
view_context,
view_context_mut,
restore_saved_value,
)
}
pub const fn assert_send<T: Send>() {}

View File

@ -13,7 +13,7 @@ use std::sync::{Arc, Mutex};
use widestring_suffix::widestrs;
use crate::builtins::shared::io_streams_t;
use crate::common::{escape_string, replace_with, EscapeFlags, EscapeStringStyle, ScopeGuard};
use crate::common::{escape_string, scoped_push, EscapeFlags, EscapeStringStyle, ScopeGuard};
use crate::ffi::{self, block_t, parser_t, signal_check_cancel, signal_handle, Repin};
use crate::flog::FLOG;
use crate::signal::Signal;
@ -676,13 +676,17 @@ fn fire_internal(parser: &mut parser_t, event: &Event) {
);
// Suppress fish_trace during events.
let saved_is_event = replace_with(&mut parser.libdata_pod().is_event, |old| old + 1);
let saved_suppress_fish_trace =
std::mem::replace(&mut parser.libdata_pod().suppress_fish_trace, true);
let mut parser = ScopeGuard::new(parser, |parser| {
parser.libdata_pod().is_event = saved_is_event;
parser.libdata_pod().suppress_fish_trace = saved_suppress_fish_trace;
});
let is_event = parser.libdata_pod().is_event;
let mut parser = scoped_push(
parser,
|parser| &mut parser.libdata_pod().is_event,
is_event + 1,
);
let mut parser = scoped_push(
&mut *parser,
|parser| &mut parser.libdata_pod().suppress_fish_trace,
true,
);
// Capture the event handlers that match this event.
let fire: Vec<_> = EVENT_HANDLERS
@ -717,7 +721,7 @@ fn fire_internal(parser: &mut parser_t, event: &Event) {
let saved_is_interactive =
std::mem::replace(&mut parser.libdata_pod().is_interactive, false);
let saved_statuses = parser.get_last_statuses().within_unique_ptr();
let mut parser = ScopeGuard::new(&mut parser, |parser| {
let mut parser = ScopeGuard::new(&mut *parser, |parser| {
parser.pin().set_last_statuses(saved_statuses);
parser.libdata_pod().is_interactive = saved_is_interactive;
});
@ -731,14 +735,14 @@ fn fire_internal(parser: &mut parser_t, event: &Event) {
"'"
);
let b = parser
let b = (*parser)
.pin()
.push_block(block_t::event_block((event as *const Event).cast()).within_unique_ptr());
parser
(*parser)
.pin()
.eval_string_ffi1(&buffer.to_ffi())
.within_unique_ptr();
parser.pin().pop_block(b);
(*parser).pin().pop_block(b);
handler.fired.store(true, Ordering::Relaxed);
fired_one_shot |= handler.is_one_shot();