pub trait Work: Clone + Sealed {
type Retained: Debug;
// Required methods
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 work_remaining(&self) -> usize;
fn read_scoped_source<'source: 'operation, 'operation>(
&'operation self,
parser: &'source Parser,
data: &'source [u8],
base: u64,
encoding: Encoding,
depth: u32,
) -> Result<ScopedReader<'source, 'operation>>;
fn read_nested<'source>(
&self,
parser: &'source Parser,
data: &'source [u8],
base: u64,
encoding: Encoding,
outer: u32,
) -> Result<Reader<'source>>
where Self: 'source;
fn read_source<'source>(
&self,
parser: &'source Parser,
data: &'source [u8],
base: u64,
encoding: Encoding,
depth: u32,
) -> Result<Reader<'source>>
where Self: 'source;
// Provided methods
fn read_scoped_nested<'source: 'operation, 'operation>(
&'operation self,
parser: &'source Parser,
data: &'source [u8],
base: u64,
encoding: Encoding,
outer: u32,
) -> Result<ScopedReader<'source, 'operation>> { ... }
fn vector<T>(&self) -> OwnedVec<T, Self> { ... }
fn map<K: HashWork, V>(&self) -> OwnedMap<K, V, Self> { ... }
}Expand description
Required Associated Types§
Required Methods§
Sourcefn retain_storage(&self) -> Self::Retained
fn retain_storage(&self) -> Self::Retained
Sourcefn into_storage_owner(self, retained: Self::Retained) -> Memory
fn into_storage_owner(self, retained: Self::Retained) -> Memory
Moves the existing account owner when finishing independently owned storage. The sealed implementations preserve the account without cloning it.
Sourcefn with_storage_owner(&self, memory: Memory) -> (Self, Self::Retained)
fn with_storage_owner(&self, memory: Memory) -> (Self, Self::Retained)
Attaches current work while moving an existing same-account owner. The caller verifies account identity before transferring storage.
Sourcefn charge_work(&self, amount: u64) -> Result<(), MemoryError>
fn charge_work(&self, amount: u64) -> Result<(), MemoryError>
Admits work before execution, against every applicable ceiling.
Sourcefn work_remaining(&self) -> usize
fn work_remaining(&self) -> usize
The largest amount Work::charge_work would admit now, across every
ceiling it checks, without reserving it.
Use it to bound work that cannot be charged step by step, such as an external engine given a work limit up front. Concurrent consumption can lower the observation, so the work must still be charged before it runs.
§Examples
use std::sync::Arc;
use structured_asn1::{Encoding, Limits, Parser, memory::{Memory, MemoryAccount, Work}};
let memory = Memory::new(Arc::new(MemoryAccount::new(1024, 1_000)));
let limits = Limits { max_work: 40, ..Limits::default() };
let parser = Parser::new(Encoding::Der, limits, memory);
let reader = parser.read(&[], 0)?;
let execution = reader.execution();
// The parser session is tighter than the shared account.
let remaining = execution.work_remaining();
assert_eq!(remaining, 40);
execution.charge_work(remaining as u64).unwrap();
assert!(execution.charge_work(1).is_err());Sourcefn read_scoped_source<'source: 'operation, 'operation>(
&'operation self,
parser: &'source Parser,
data: &'source [u8],
base: u64,
encoding: Encoding,
depth: u32,
) -> Result<ScopedReader<'source, 'operation>>
fn read_scoped_source<'source: 'operation, 'operation>( &'operation self, parser: &'source Parser, data: &'source [u8], base: u64, encoding: Encoding, depth: u32, ) -> Result<ScopedReader<'source, 'operation>>
Opens original input while borrowing this operation only for decoding. Parsed elements and scalar views retain the longer original input lifetime; no result needs to keep a completed operation alive merely because it borrows input. Source and current ceilings still apply to every read, scratch allocation and copy before that work. A cursor itself cannot escape a local operation:
use structured_asn1::{Encoding, Parser, ScopedReader, memory::Work};
fn escape<'source>(source: &'source Parser, data: &'source [u8])
-> ScopedReader<'source, 'source>
{
let operation = Parser::der(source.memory().clone());
let query = operation.read(&[], 900).unwrap();
let execution = query.execution();
execution.read_scoped_source(source, data, 400, Encoding::Der, 0).unwrap()
}Sourcefn read_nested<'source>(
&self,
parser: &'source Parser,
data: &'source [u8],
base: u64,
encoding: Encoding,
outer: u32,
) -> Result<Reader<'source>>where
Self: 'source,
fn read_nested<'source>(
&self,
parser: &'source Parser,
data: &'source [u8],
base: u64,
encoding: Encoding,
outer: u32,
) -> Result<Reader<'source>>where
Self: 'source,
Opens original nested bytes without discarding this execution boundary.
Memory retains its existing source-plus-aggregate admission; Execution
additionally preserves the current root operation before any decode.
Source parser/data/base/encoding and actual outer + 1 depth remain
original. A transition replaces a previous foreign source ceiling,
never the operation owner. A fresh document uses depth zero through
Work::read_source, rather than inventing a nested carrier level.
Self: 'source retains the real budget lifetimes, not the borrow of a
temporary Execution wrapper. The returned reader owns its account handle;
no parser/diagnostic clone, new domain or budget reset is introduced.
It still cannot outlive either actual parser budget:
use std::sync::Arc;
use structured_asn1::{Parser, Encoding, memory::{Memory,MemoryAccount,Work}};
let memory = Memory::new(Arc::new(MemoryAccount::new(4096,4096)));
let source = Parser::ber(memory.clone());
let mut lazy;
{
let operation = Parser::ber(memory);
let query = operation.read(&[],900).unwrap();
lazy = query.execution().read_nested(&source,&[2,1,7],400,Encoding::Ber,0).unwrap();
}
lazy.next_element().unwrap();use std::sync::Arc;
use structured_asn1::{Parser, Encoding, memory::{Memory,MemoryAccount,Work}};
let memory = Memory::new(Arc::new(MemoryAccount::new(4096,4096)));
let operation = Parser::ber(memory.clone());
let query = operation.read(&[],900).unwrap();
let mut lazy;
{
let source = Parser::ber(memory);
lazy = query.execution().read_nested(&source,&[2,1,7],400,Encoding::Ber,0).unwrap();
}
lazy.next_element().unwrap();Sourcefn read_source<'source>(
&self,
parser: &'source Parser,
data: &'source [u8],
base: u64,
encoding: Encoding,
depth: u32,
) -> Result<Reader<'source>>where
Self: 'source,
fn read_source<'source>(
&self,
parser: &'source Parser,
data: &'source [u8],
base: u64,
encoding: Encoding,
depth: u32,
) -> Result<Reader<'source>>where
Self: 'source,
Opens an original source window at its actual ASN.1 depth.
This has the same source/account and lifetime guarantees as
Work::read_nested, without adding a carrier level. A fresh document
begins at zero; an already nested window must supply its original depth.
Current operation ceilings remain in force even when a retained query
uses a new source parser bounded by the retained input size.
Provided Methods§
Sourcefn read_scoped_nested<'source: 'operation, 'operation>(
&'operation self,
parser: &'source Parser,
data: &'source [u8],
base: u64,
encoding: Encoding,
outer: u32,
) -> 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, ) -> Result<ScopedReader<'source, 'operation>>
Nested form of Work::read_scoped_source, retaining actual outer+1
depth. Only decoding borrows this operation; returned input views do not.
Sourcefn vector<T>(&self) -> OwnedVec<T, Self>
fn vector<T>(&self) -> OwnedVec<T, Self>
Creates empty accounted scratch retaining this execution boundary.
No allocation occurs until a fallible growth operation. A collection
borrowing Execution cannot outlive that parser or execution account.
§Examples
use std::sync::Arc;
use structured_asn1::{Parser, memory::{Memory, MemoryAccount, Work}};
let parser = Parser::ber(Memory::new(Arc::new(MemoryAccount::new(1024, 1024))));
let reader = parser.read(&[], 0).unwrap();
let mut scratch = reader.execution().vector();
scratch.try_push(42_u8)?;
assert_eq!(&*scratch, &[42]);Dyn Compatibility§
This trait is not dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety".