1 // Copyright 2018 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
11 //! `Cell` variant for (scoped) existential lifetimes.
15 use std::ops::{Deref, DerefMut};
17 /// Type lambda application, with a lifetime.
18 pub trait ApplyL<'a> {
22 /// Type lambda taking a lifetime, i.e., `Lifetime -> Type`.
23 pub trait LambdaL: for<'a> ApplyL<'a> {}
25 impl<T: for<'a> ApplyL<'a>> LambdaL for T {}
27 // HACK(eddyb) work around projection limitations with a newtype
28 // FIXME(#52812) replace with `&'a mut <T as ApplyL<'b>>::Out`
29 pub struct RefMutL<'a, 'b, T: LambdaL>(&'a mut <T as ApplyL<'b>>::Out);
31 impl<'a, 'b, T: LambdaL> Deref for RefMutL<'a, 'b, T> {
32 type Target = <T as ApplyL<'b>>::Out;
33 fn deref(&self) -> &Self::Target {
38 impl<'a, 'b, T: LambdaL> DerefMut for RefMutL<'a, 'b, T> {
39 fn deref_mut(&mut self) -> &mut Self::Target {
44 pub struct ScopedCell<T: LambdaL>(Cell<<T as ApplyL<'static>>::Out>);
46 impl<T: LambdaL> ScopedCell<T> {
47 pub const fn new(value: <T as ApplyL<'static>>::Out) -> Self {
48 ScopedCell(Cell::new(value))
51 /// Set the value in `self` to `replacement` while
52 /// running `f`, which gets the old value, mutably.
53 /// The old value will be restored after `f` exits, even
54 /// by panic, including modifications made to it by `f`.
55 pub fn replace<'a, R>(
57 replacement: <T as ApplyL<'a>>::Out,
58 f: impl for<'b, 'c> FnOnce(RefMutL<'b, 'c, T>) -> R,
60 /// Wrapper that ensures that the cell always gets filled
61 /// (with the original state, optionally changed by `f`),
62 /// even if `f` had panicked.
63 struct PutBackOnDrop<'a, T: LambdaL> {
64 cell: &'a ScopedCell<T>,
65 value: Option<<T as ApplyL<'static>>::Out>,
68 impl<'a, T: LambdaL> Drop for PutBackOnDrop<'a, T> {
70 self.cell.0.set(self.value.take().unwrap());
74 let mut put_back_on_drop = PutBackOnDrop {
76 value: Some(self.0.replace(unsafe {
77 let erased = mem::transmute_copy(&replacement);
78 mem::forget(replacement);
83 f(RefMutL(put_back_on_drop.value.as_mut().unwrap()))
86 /// Set the value in `self` to `value` while running `f`.
87 pub fn set<'a, R>(&self, value: <T as ApplyL<'a>>::Out, f: impl FnOnce() -> R) -> R {
88 self.replace(value, |_| f())