essential_state_read_vm/
state_read.rsuse crate::{
error::{OpAsyncError, StackError},
OpAsyncResult, Vm,
};
use core::{
future::Future,
pin::Pin,
task::{Context, Poll},
};
use essential_types::{convert::u8_32_from_word_4, ContentAddress, Key, Word};
pub trait StateRead {
type Error: core::fmt::Debug + core::fmt::Display;
type Future: Future<Output = Result<Vec<Vec<Word>>, Self::Error>> + Unpin;
fn key_range(&self, contract_addr: ContentAddress, key: Key, num_values: usize)
-> Self::Future;
}
pub(crate) struct StateReadFuture<'vm, S>
where
S: StateRead,
{
future: S::Future,
slot_index: usize,
pub(crate) vm: &'vm mut Vm,
}
impl<'vm, S> Future for StateReadFuture<'vm, S>
where
S: StateRead,
{
type Output = OpAsyncResult<(), S::Error>;
fn poll(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
match Pin::new(&mut self.future).poll(cx) {
Poll::Pending => Poll::Pending,
Poll::Ready(res) => {
let slot_index = self.slot_index;
let res = res
.map_err(OpAsyncError::StateRead)
.and_then(|words| write_values_to_state_slots(self.vm, slot_index, words));
Poll::Ready(res)
}
}
}
}
pub fn key_range<'vm, S>(
state_read: &S,
contract_addr: &ContentAddress,
vm: &'vm mut Vm,
) -> OpAsyncResult<StateReadFuture<'vm, S>, S::Error>
where
S: StateRead,
{
let slot_index = vm.stack.pop()?;
let slot_index = usize::try_from(slot_index).map_err(|_| StackError::IndexOutOfBounds)?;
let future = read_key_range(state_read, contract_addr, vm)?;
Ok(StateReadFuture {
future,
slot_index,
vm,
})
}
pub fn key_range_ext<'vm, S>(
state_read: &S,
vm: &'vm mut Vm,
) -> OpAsyncResult<StateReadFuture<'vm, S>, S::Error>
where
S: StateRead,
{
let slot_index = vm.stack.pop()?;
let slot_index = usize::try_from(slot_index).map_err(|_| StackError::IndexOutOfBounds)?;
let future = read_key_range_ext(state_read, vm)?;
Ok(StateReadFuture {
future,
slot_index,
vm,
})
}
fn read_key_range<S>(
state_read: &S,
contract_addr: &ContentAddress,
vm: &mut Vm,
) -> OpAsyncResult<S::Future, S::Error>
where
S: StateRead,
{
let num_keys = vm.stack.pop()?;
let num_keys = usize::try_from(num_keys).map_err(|_| StackError::IndexOutOfBounds)?;
let key = vm
.stack
.pop_len_words::<_, _, StackError>(|words| Ok(words.to_vec()))?;
Ok(state_read.key_range(contract_addr.clone(), key, num_keys))
}
fn read_key_range_ext<S>(state_read: &S, vm: &mut Vm) -> OpAsyncResult<S::Future, S::Error>
where
S: StateRead,
{
let num_keys = vm.stack.pop()?;
let num_keys = usize::try_from(num_keys).map_err(|_| StackError::IndexOutOfBounds)?;
let key = vm
.stack
.pop_len_words::<_, _, StackError>(|words| Ok(words.to_vec()))?;
let contract_addr = ContentAddress(u8_32_from_word_4(vm.stack.pop4()?));
Ok(state_read.key_range(contract_addr, key, num_keys))
}
fn write_values_to_state_slots<E>(
vm: &mut Vm,
slot_index: usize,
values: Vec<Vec<Word>>,
) -> OpAsyncResult<(), E> {
vm.state_memory.store_slots_range(slot_index, values)?;
Ok(())
}