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 const 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 const 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#[expect(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 const fn consume(self) -> FrameToken {
198 FrameToken(self.init)
199 }
200}
201
202#[expect(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 fn cpsb(&self) -> u64;
244
245 fn set_cpsb(&mut self, cpsb: u64);
251}
252
253#[cfg(test)]
254mod tests {
255 use super::*;
256
257 #[test]
258 fn frame_stack() {
259 let mut stack = FrameStack::new_prealloc(1);
260 let mut frame = stack.start_init();
261 *frame.get(|| 2) += 1;
263
264 let token = frame.consume();
265 unsafe { stack.end_init(token) };
266
267 assert_eq!(stack.index(), Some(0));
268 assert_eq!(stack.stack.len(), 1);
269
270 let a = stack.get();
271 assert_eq!(a, &mut 1);
272 let mut b = stack.get_next();
273 assert!(!b.init);
274 assert_eq!(b.get(|| 2), &mut 2);
275 let token = b.consume(); unsafe { stack.push(token) };
277
278 assert_eq!(stack.index(), Some(1));
279 assert_eq!(stack.stack.len(), 2);
280 let a = stack.get();
281 assert_eq!(a, &mut 2);
282 let b = stack.get_next();
283 assert!(!b.init);
284
285 stack.pop();
286
287 assert_eq!(stack.index(), Some(0));
288 assert_eq!(stack.stack.len(), 2);
289 let a = stack.get();
290 assert_eq!(a, &mut 1);
291 let mut b = stack.get_next();
292 assert!(b.init);
293 assert_eq!(unsafe { b.get_unchecked() }, &mut 2);
294 }
295}