use super::{HashWork, Memory, MemoryError, OwnedMap, OwnedVec, allocator};
use crate::limits::BudgetView;
use crate::{Encoding, Parser, Reader, ScopedReader};
mod private {
pub trait Sealed {}
}
pub trait Work: Clone + private::Sealed {
type Retained: core::fmt::Debug;
fn retain_storage(&self) -> Self::Retained;
fn into_storage_owner(self, retained: Self::Retained) -> Memory;
fn with_storage_owner(&self, memory: Memory) -> (Self, Self::Retained);
fn memory(&self) -> &Memory;
fn charge_work(&self, amount: u64) -> Result<(), MemoryError>;
fn read_scoped_source<'source: 'operation, 'operation>(
&'operation self,
parser: &'source Parser,
data: &'source [u8],
base: u64,
encoding: Encoding,
depth: u32,
) -> crate::Result<ScopedReader<'source, 'operation>>;
fn read_scoped_nested<'source: 'operation, 'operation>(
&'operation self,
parser: &'source Parser,
data: &'source [u8],
base: u64,
encoding: Encoding,
outer: u32,
) -> crate::Result<ScopedReader<'source, 'operation>> {
let depth = outer.checked_add(1).ok_or_else(|| {
crate::Error::new(
crate::ErrorCode::LimitExceeded(crate::Limit::Depth),
base,
crate::Path::default(),
)
})?;
self.read_scoped_source(parser, data, base, encoding, depth)
}
fn read_nested<'source>(
&self,
parser: &'source Parser,
data: &'source [u8],
base: u64,
encoding: Encoding,
outer: u32,
) -> crate::Result<Reader<'source>>
where
Self: 'source;
fn read_source<'source>(
&self,
parser: &'source Parser,
data: &'source [u8],
base: u64,
encoding: Encoding,
depth: u32,
) -> crate::Result<Reader<'source>>
where
Self: 'source;
#[must_use]
fn vector<T>(&self) -> OwnedVec<T, Self> {
OwnedVec {
values: allocator_api2::vec::Vec::new_in(allocator::AccountAllocator::new(
self.clone(),
)),
}
}
#[must_use]
fn map<K: HashWork, V>(&self) -> OwnedMap<K, V, Self> {
OwnedMap::new(self.clone())
}
}
impl private::Sealed for Memory {}
impl Work for Memory {
type Retained = ();
fn retain_storage(&self) {}
fn into_storage_owner(self, (): ()) -> Memory {
self
}
fn with_storage_owner(&self, memory: Memory) -> (Self, ()) {
(memory, ())
}
fn memory(&self) -> &Memory {
self
}
fn charge_work(&self, amount: u64) -> Result<(), MemoryError> {
Memory::charge_work(self, amount)
}
fn read_scoped_source<'source: 'operation, 'operation>(
&'operation self,
parser: &'source Parser,
data: &'source [u8],
base: u64,
encoding: Encoding,
depth: u32,
) -> crate::Result<ScopedReader<'source, 'operation>> {
parser.read_scoped_source_in(data, base, encoding, depth, None, self)
}
fn read_nested<'source>(
&self,
parser: &'source Parser,
data: &'source [u8],
base: u64,
encoding: Encoding,
outer: u32,
) -> crate::Result<Reader<'source>>
where
Self: 'source,
{
parser.read_nested_in(data, base, encoding, outer, self)
}
fn read_source<'source>(
&self,
parser: &'source Parser,
data: &'source [u8],
base: u64,
encoding: Encoding,
depth: u32,
) -> crate::Result<Reader<'source>>
where
Self: 'source,
{
parser.read_source_in(data, base, encoding, depth, self)
}
}
#[derive(Debug, Clone, Copy)]
pub struct Execution<'a> {
memory: &'a Memory,
budget: BudgetView<'a>,
}
impl<'a> Execution<'a> {
pub(crate) fn new(memory: &'a Memory, budget: BudgetView<'a>) -> Self {
Self { memory, budget }
}
}
impl private::Sealed for Execution<'_> {}
impl Work for Execution<'_> {
type Retained = Memory;
fn retain_storage(&self) -> Memory {
self.memory.clone()
}
fn into_storage_owner(self, retained: Memory) -> Memory {
retained
}
fn with_storage_owner(&self, memory: Memory) -> (Self, Memory) {
(*self, memory)
}
fn memory(&self) -> &Memory {
self.memory
}
fn charge_work(&self, amount: u64) -> Result<(), MemoryError> {
self.budget
.work_in(amount, self.memory)
.map_err(|_| MemoryError::WorkExceeded)
}
fn read_scoped_source<'source: 'operation, 'operation>(
&'operation self,
parser: &'source Parser,
data: &'source [u8],
base: u64,
encoding: Encoding,
depth: u32,
) -> crate::Result<ScopedReader<'source, 'operation>> {
parser.read_scoped_source_in(
data,
base,
encoding,
depth,
Some(self.budget.operation()),
self.memory,
)
}
fn read_nested<'source>(
&self,
parser: &'source Parser,
data: &'source [u8],
base: u64,
encoding: Encoding,
outer: u32,
) -> crate::Result<Reader<'source>>
where
Self: 'source,
{
parser.read_nested_operation_in(
data,
base,
encoding,
outer,
self.budget.operation(),
self.memory,
)
}
fn read_source<'source>(
&self,
parser: &'source Parser,
data: &'source [u8],
base: u64,
encoding: Encoding,
depth: u32,
) -> crate::Result<Reader<'source>>
where
Self: 'source,
{
parser.read_query_budget_in(
data,
base,
encoding,
depth,
self.budget.operation(),
self.memory,
)
}
}