diff --git a/src/core/reader/mod.rs b/src/core/reader/mod.rs index 545f25a8..a8a75c75 100644 --- a/src/core/reader/mod.rs +++ b/src/core/reader/mod.rs @@ -7,6 +7,7 @@ pub mod types; /// A struct for managing and reading WASM bytecode /// /// Its purpose is to abstract parsing basic WASM values from the bytecode. +#[derive(Clone)] pub struct WasmReader<'a> { /// Entire WASM binary as slice pub full_wasm_binary: &'a [u8], @@ -148,9 +149,30 @@ impl<'a> WasmReader<'a> { pub fn into_inner(self) -> &'a [u8] { self.full_wasm_binary } + + /// A wrapper function for reads with transaction-like behavior. + /// + /// The provided closure will be called with `&mut self` and its result will be returned. + /// However if the closure returns `Err(_)`, `self` will be reset as if the closure was never called. + #[allow(unused)] + pub fn handle_transaction( + &mut self, + f: impl FnOnce(&mut WasmReader) -> Result, + ) -> Result { + let original = self.clone(); + f(self).map_err(|err| { + *self = original; + err + }) + } } pub trait WasmReadable: Sized { + /// Reads a new [`Self`] from given [`WasmReader`]. + /// + /// Note that if this function returns `Err(_)`, the [`WasmReader`] may still have been advanced, + /// which may lead to unexpected behaviour. + /// To avoid this consider using the [`WasmReader::handle_transaction`] method to wrap this function call. fn read(wasm: &mut WasmReader) -> Result; fn read_unvalidated(wasm: &mut WasmReader) -> Self; }