aboutsummaryrefslogtreecommitdiff
path: root/crates/proc_macro_srv/src/proc_macro/bridge/scoped_cell.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/proc_macro_srv/src/proc_macro/bridge/scoped_cell.rs')
-rw-r--r--crates/proc_macro_srv/src/proc_macro/bridge/scoped_cell.rs84
1 files changed, 84 insertions, 0 deletions
diff --git a/crates/proc_macro_srv/src/proc_macro/bridge/scoped_cell.rs b/crates/proc_macro_srv/src/proc_macro/bridge/scoped_cell.rs
new file mode 100644
index 000000000..6ef7ea43c
--- /dev/null
+++ b/crates/proc_macro_srv/src/proc_macro/bridge/scoped_cell.rs
@@ -0,0 +1,84 @@
1//! lib-proc-macro `Cell` variant for (scoped) existential lifetimes.
2//!
3//! Copy from https://github.com/rust-lang/rust/blob/6050e523bae6de61de4e060facc43dc512adaccd/src/libproc_macro/bridge/scoped_cell.rs#L1
4//! augmented with removing unstable features
5
6use std::cell::Cell;
7use std::mem;
8use std::ops::{Deref, DerefMut};
9
10/// Type lambda application, with a lifetime.
11#[allow(unused_lifetimes)]
12pub trait ApplyL<'a> {
13 type Out;
14}
15
16/// Type lambda taking a lifetime, i.e., `Lifetime -> Type`.
17pub trait LambdaL: for<'a> ApplyL<'a> {}
18
19impl<T: for<'a> ApplyL<'a>> LambdaL for T {}
20
21// HACK(eddyb) work around projection limitations with a newtype
22// FIXME(#52812) replace with `&'a mut <T as ApplyL<'b>>::Out`
23pub struct RefMutL<'a, 'b, T: LambdaL>(&'a mut <T as ApplyL<'b>>::Out);
24
25impl<'a, 'b, T: LambdaL> Deref for RefMutL<'a, 'b, T> {
26 type Target = <T as ApplyL<'b>>::Out;
27 fn deref(&self) -> &Self::Target {
28 self.0
29 }
30}
31
32impl<'a, 'b, T: LambdaL> DerefMut for RefMutL<'a, 'b, T> {
33 fn deref_mut(&mut self) -> &mut Self::Target {
34 self.0
35 }
36}
37
38pub struct ScopedCell<T: LambdaL>(Cell<<T as ApplyL<'static>>::Out>);
39
40impl<T: LambdaL> ScopedCell<T> {
41 pub fn new(value: <T as ApplyL<'static>>::Out) -> Self {
42 ScopedCell(Cell::new(value))
43 }
44
45 /// Sets the value in `self` to `replacement` while
46 /// running `f`, which gets the old value, mutably.
47 /// The old value will be restored after `f` exits, even
48 /// by panic, including modifications made to it by `f`.
49 pub fn replace<'a, R>(
50 &self,
51 replacement: <T as ApplyL<'a>>::Out,
52 f: impl for<'b, 'c> FnOnce(RefMutL<'b, 'c, T>) -> R,
53 ) -> R {
54 /// Wrapper that ensures that the cell always gets filled
55 /// (with the original state, optionally changed by `f`),
56 /// even if `f` had panicked.
57 struct PutBackOnDrop<'a, T: LambdaL> {
58 cell: &'a ScopedCell<T>,
59 value: Option<<T as ApplyL<'static>>::Out>,
60 }
61
62 impl<'a, T: LambdaL> Drop for PutBackOnDrop<'a, T> {
63 fn drop(&mut self) {
64 self.cell.0.set(self.value.take().unwrap());
65 }
66 }
67
68 let mut put_back_on_drop = PutBackOnDrop {
69 cell: self,
70 value: Some(self.0.replace(unsafe {
71 let erased = mem::transmute_copy(&replacement);
72 mem::forget(replacement);
73 erased
74 })),
75 };
76
77 f(RefMutL(put_back_on_drop.value.as_mut().unwrap()))
78 }
79
80 /// Sets the value in `self` to `value` while running `f`.
81 pub fn set<R>(&self, value: <T as ApplyL<'_>>::Out, f: impl FnOnce() -> R) -> R {
82 self.replace(value, |_| f())
83 }
84}