revm_context_interface/
local.rs1use core::{
3 cell::{Ref, RefCell},
4 ops::Range,
5};
6use std::{rc::Rc, string::String, vec::Vec};
7
8#[derive(Debug, Clone)]
10pub struct FrameStack<T> {
11 stack: Vec<T>,
12 index: Option<usize>,
13}
14
15impl<T> Default for FrameStack<T> {
16 fn default() -> Self {
17 Self::new()
18 }
19}
20
21impl<T> FrameStack<T> {
22 pub fn new() -> Self {
24 Self {
27 stack: Vec::with_capacity(8),
28 index: None,
29 }
30 }
31
32 pub fn new_prealloc(len: usize) -> Self
35 where
36 T: Default,
37 {
38 let mut stack = Vec::with_capacity(len);
39 stack.resize_with(len, T::default);
40 Self { stack, index: None }
41 }
42
43 #[inline]
45 pub fn start_init(&mut self) -> OutFrame<'_, T> {
46 self.index = None;
47 if self.stack.is_empty() {
48 self.stack.reserve(8);
49 }
50 self.out_frame_at(0)
51 }
52
53 #[inline]
59 pub unsafe fn end_init(&mut self, token: FrameToken) {
60 token.assert();
61 if self.stack.is_empty() {
62 unsafe { self.stack.set_len(1) };
63 }
64 self.index = Some(0);
65 }
66
67 #[inline]
69 pub fn index(&self) -> Option<usize> {
70 self.index
71 }
72
73 #[inline]
80 pub unsafe fn push(&mut self, token: FrameToken) {
81 token.assert();
82 let index = self.index.as_mut().unwrap();
83 *index += 1;
84 debug_assert!(
86 *index < self.stack.capacity(),
87 "Stack capacity is not enough for index"
88 );
89 if *index == self.stack.len() {
91 unsafe { self.stack.set_len(self.stack.len() + 1) };
92 }
93 }
94
95 #[inline]
98 pub fn clear(&mut self) {
99 self.index = None;
100 }
101
102 #[inline]
104 pub fn pop(&mut self) {
105 self.index = self.index.unwrap_or(0).checked_sub(1);
106 }
107
108 #[inline]
110 pub fn get(&mut self) -> &mut T {
111 debug_assert!(
112 self.stack.capacity() > self.index.unwrap(),
113 "Stack capacity is not enough for index"
114 );
115 unsafe { &mut *self.stack.as_mut_ptr().add(self.index.unwrap()) }
116 }
117
118 #[inline]
120 pub fn get_next(&mut self) -> OutFrame<'_, T> {
121 if self.index.unwrap() + 1 == self.stack.capacity() {
122 self.stack.reserve(8);
124 }
125 self.out_frame_at(self.index.unwrap() + 1)
126 }
127
128 fn out_frame_at(&mut self, idx: usize) -> OutFrame<'_, T> {
129 unsafe {
130 OutFrame::new_maybe_uninit(self.stack.as_mut_ptr().add(idx), idx < self.stack.len())
131 }
132 }
133}
134
135#[allow(missing_debug_implementations)]
137pub struct OutFrame<'a, T> {
138 ptr: *mut T,
139 init: bool,
140 lt: core::marker::PhantomData<&'a mut T>,
141}
142
143impl<'a, T> OutFrame<'a, T> {
144 pub fn new_init(slot: &'a mut T) -> Self {
146 unsafe { Self::new_maybe_uninit(slot, true) }
147 }
148
149 pub fn new_uninit(slot: &'a mut core::mem::MaybeUninit<T>) -> Self {
151 unsafe { Self::new_maybe_uninit(slot.as_mut_ptr(), false) }
152 }
153
154 pub unsafe fn new_maybe_uninit(ptr: *mut T, init: bool) -> Self {
162 Self {
163 ptr,
164 init,
165 lt: Default::default(),
166 }
167 }
168
169 pub fn get(&mut self, f: impl FnOnce() -> T) -> &mut T {
171 if !self.init {
172 self.do_init(f);
173 }
174 unsafe { &mut *self.ptr }
175 }
176
177 #[inline(never)]
178 #[cold]
179 fn do_init(&mut self, f: impl FnOnce() -> T) {
180 unsafe {
181 self.init = true;
182 self.ptr.write(f());
183 }
184 }
185
186 pub unsafe fn get_unchecked(&mut self) -> &mut T {
192 debug_assert!(self.init, "OutFrame must be initialized before use");
193 unsafe { &mut *self.ptr }
194 }
195
196 pub fn consume(self) -> FrameToken {
198 FrameToken(self.init)
199 }
200}
201
202#[allow(missing_debug_implementations)]
204pub struct FrameToken(bool);
205
206impl FrameToken {
207 #[cfg_attr(debug_assertions, track_caller)]
209 pub fn assert(self) {
210 assert!(self.0, "FrameToken must be initialized before use");
211 }
212}
213
214pub trait LocalContextTr {
216 fn shared_memory_buffer(&self) -> &Rc<RefCell<Vec<u8>>>;
218
219 fn shared_memory_buffer_slice(&self, range: Range<usize>) -> Option<Ref<'_, [u8]>> {
221 Ref::filter_map(self.shared_memory_buffer().borrow(), |b| b.get(range)).ok()
222 }
223
224 fn clear(&mut self);
226
227 fn set_precompile_error_context(&mut self, _output: String);
232
233 fn take_precompile_error_context(&mut self) -> Option<String>;
237}
238
239#[cfg(test)]
240mod tests {
241 use super::*;
242
243 #[test]
244 fn frame_stack() {
245 let mut stack = FrameStack::new_prealloc(1);
246 let mut frame = stack.start_init();
247 *frame.get(|| 2) += 1;
249
250 let token = frame.consume();
251 unsafe { stack.end_init(token) };
252
253 assert_eq!(stack.index(), Some(0));
254 assert_eq!(stack.stack.len(), 1);
255
256 let a = stack.get();
257 assert_eq!(a, &mut 1);
258 let mut b = stack.get_next();
259 assert!(!b.init);
260 assert_eq!(b.get(|| 2), &mut 2);
261 let token = b.consume(); unsafe { stack.push(token) };
263
264 assert_eq!(stack.index(), Some(1));
265 assert_eq!(stack.stack.len(), 2);
266 let a = stack.get();
267 assert_eq!(a, &mut 2);
268 let b = stack.get_next();
269 assert!(!b.init);
270
271 stack.pop();
272
273 assert_eq!(stack.index(), Some(0));
274 assert_eq!(stack.stack.len(), 2);
275 let a = stack.get();
276 assert_eq!(a, &mut 1);
277 let mut b = stack.get_next();
278 assert!(b.init);
279 assert_eq!(unsafe { b.get_unchecked() }, &mut 2);
280 }
281}