evm_future/
lib.rs

1#![no_std]
2
3extern crate alloc;
4
5use alloc::{boxed::Box, rc::Rc, vec::Vec};
6use core::{
7	cell::Cell,
8	future::Future,
9	marker::PhantomData,
10	pin::Pin,
11	task::{Context, Poll, Waker},
12};
13use evm::interpreter::{
14	error::{Capture, ExitError, ExitFatal, ExitResult},
15	FeedbackInterpreter, Interpreter,
16};
17
18pub trait FutureInterpreterAction<S, H> {
19	type Feedback;
20	type Trap;
21
22	fn run(
23		self,
24		state: &mut S,
25		retbuf: &mut Vec<u8>,
26		handle: &mut H,
27	) -> Capture<Self::Feedback, Self::Trap>;
28}
29
30pub struct FutureInterpreterSubmit<A, F> {
31	action: Cell<Option<A>>,
32	action_feedback: Cell<Option<F>>,
33}
34
35impl<A, F> FutureInterpreterSubmit<A, F> {
36	fn new() -> Self {
37		Self {
38			action: Cell::new(None),
39			action_feedback: Cell::new(None),
40		}
41	}
42
43	pub fn submit(self: Rc<Self>, action: A) -> impl Future<Output = F> {
44		struct SubmitFuture<A, F>(Cell<Option<A>>, Rc<FutureInterpreterSubmit<A, F>>);
45
46		impl<A, F> Future for SubmitFuture<A, F> {
47			type Output = F;
48
49			fn poll(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<F> {
50				let action_feedback = self.1.action_feedback.take();
51				if let Some(action_feedback) = action_feedback {
52					Poll::Ready(action_feedback)
53				} else {
54					let action = match self.0.replace(None) {
55						Some(action) => action,
56						None => panic!("future was already finished; should not be polled"),
57					};
58					self.1.action.set(Some(action));
59					Poll::Pending
60				}
61			}
62		}
63
64		SubmitFuture(Cell::new(Some(action)), self.clone())
65	}
66}
67
68pub struct FutureInterpreter<A, F, S, Tr> {
69	state: S,
70	retbuf: Vec<u8>,
71	inner: Pin<Box<dyn Future<Output = ExitResult>>>,
72	submit: Rc<FutureInterpreterSubmit<A, F>>,
73	_marker: PhantomData<Tr>,
74}
75
76impl<A, F, S, Tr> FutureInterpreter<A, F, S, Tr> {
77	pub fn new<Fn, Fu>(state: S, retbuf: Vec<u8>, f: Fn) -> Self
78	where
79		Fn: FnOnce(Rc<FutureInterpreterSubmit<A, F>>) -> Fu,
80		Fu: Future<Output = ExitResult> + 'static,
81	{
82		let submit = Rc::new(FutureInterpreterSubmit::new());
83		Self {
84			state,
85			retbuf,
86			inner: Box::pin(f(submit.clone())),
87			submit,
88			_marker: PhantomData,
89		}
90	}
91}
92
93impl<A, F, S, H, Tr> Interpreter<H> for FutureInterpreter<A, F, S, Tr>
94where
95	F: 'static,
96	A: FutureInterpreterAction<S, H, Feedback = F> + 'static,
97	Tr: From<A::Trap>,
98{
99	type State = S;
100	type Trap = Tr;
101
102	fn deconstruct(self) -> (S, Vec<u8>) {
103		(self.state, self.retbuf)
104	}
105
106	fn run(&mut self, handle: &mut H) -> Capture<ExitResult, Self::Trap> {
107		let waker = Waker::noop();
108		let mut ctx = Context::from_waker(waker);
109
110		loop {
111			match self.inner.as_mut().poll(&mut ctx) {
112				Poll::Ready(ret) => return Capture::Exit(ret),
113				Poll::Pending => {
114					let action = match self.submit.action.replace(None) {
115						Some(action) => action,
116						None => {
117							return Capture::Exit(
118								ExitFatal::Other("cannot advance future".into()).into(),
119							)
120						}
121					};
122
123					match action.run(&mut self.state, &mut self.retbuf, handle) {
124						Capture::Exit(feedback) => {
125							self.submit.action_feedback.set(Some(feedback));
126						}
127						Capture::Trap(trap) => return Capture::Trap(Box::new((*trap).into())),
128					}
129				}
130			}
131		}
132	}
133}
134
135impl<Feedback, A, F, S, H, Tr> FeedbackInterpreter<H, Feedback> for FutureInterpreter<A, F, S, Tr>
136where
137	F: 'static,
138	A: FutureInterpreterAction<S, H, Feedback = F> + 'static,
139	Tr: From<A::Trap>,
140	Feedback: Into<A::Feedback>,
141{
142	fn feedback(&mut self, feedback: Feedback, _handler: &mut H) -> Result<(), ExitError> {
143		let feedback: A::Feedback = feedback.into();
144		self.submit.action_feedback.set(Some(feedback));
145		Ok(())
146	}
147}