Skip to main content

structured_asic/
session.rs

1//! One original `ASiC` source budget and cumulative decode allowance.
2
3use crate::error::{Error, Limit};
4use core::cell::Cell;
5use structured_asn1::{
6    Encoding, Parser, Span,
7    memory::{Execution, Memory, Work},
8};
9
10/// Caller-selected mechanism bounds, independent of signature/trust policy.
11#[derive(Debug, Clone, Copy)]
12pub struct Limits {
13    /// Shared original source and carried ASN.1 work/depth ceilings.
14    pub processing: structured_asn1::Limits,
15    /// Cumulative original member admissions.
16    pub max_entries: u64,
17    /// Cumulative decoded output, independent of live scratch capacity.
18    pub max_decoded: u64,
19}
20impl Default for Limits {
21    fn default() -> Self {
22        Self {
23            processing: structured_asn1::Limits::default(),
24            max_entries: 1_000_000,
25            max_decoded: 64 * 1024 * 1024,
26        }
27    }
28}
29
30/// Caller-owned original execution. ZIP input is not parsed as ASN.1; the
31/// shared parser supplies one budget for ZIP, carried CMS and PKIX operations.
32pub struct Session {
33    parser: Parser,
34    limits: Limits,
35    entries: Cell<u64>,
36    decoded: Cell<u64>,
37}
38impl Session {
39    /// Constructs trusted state without allocation or source acquisition.
40    #[must_use]
41    pub fn new(limits: Limits, memory: Memory) -> Self {
42        Self {
43            parser: Parser::new(Encoding::Der, limits.processing, memory),
44            limits,
45            entries: Cell::new(0),
46            decoded: Cell::new(0),
47        }
48    }
49    /// Original mechanism ceilings, without mutable policy discovery.
50    #[must_use]
51    pub fn limits(&self) -> Limits {
52        self.limits
53    }
54    /// Original source work, without a new cursor or account owner.
55    #[must_use]
56    pub fn execution(&self) -> Execution<'_> {
57        self.parser.execution_in(self.parser.memory())
58    }
59    /// Preserves this original source AND the current root-operation ceiling.
60    #[must_use]
61    pub fn query<'q, W: Work>(&'q self, work: &'q W) -> Execution<'q> {
62        work.execution_for(&self.parser)
63    }
64    pub(crate) fn carried<'q, W: Work + 'q>(
65        &'q self,
66        bytes: &'q [u8],
67        work: &W,
68    ) -> structured_asn1::Result<structured_asn1::Reader<'q>> {
69        work.read_source(&self.parser, bytes, 0, Encoding::Ber, 0)
70    }
71    pub(crate) fn owns(&self, reader: &structured_asn1::Reader<'_>) -> bool {
72        core::ptr::eq(core::ptr::from_ref(&self.parser), reader.parser())
73    }
74    pub(crate) fn entries<E>(&self, count: u64, range: Span) -> Result<(), Error<E>> {
75        Self::admit(
76            &self.entries,
77            count,
78            self.limits.max_entries,
79            range,
80            Limit::Entries,
81        )
82    }
83    pub(crate) fn remaining(&self) -> u64 {
84        self.limits.max_decoded - self.decoded.get()
85    }
86    pub(crate) fn decode<E>(&self, count: u64, range: Span) -> Result<(), Error<E>> {
87        Self::admit(
88            &self.decoded,
89            count,
90            self.limits.max_decoded,
91            range,
92            Limit::Decoded,
93        )
94    }
95    fn admit<E>(
96        counter: &Cell<u64>,
97        count: u64,
98        maximum: u64,
99        range: Span,
100        kind: Limit,
101    ) -> Result<(), Error<E>> {
102        let used = counter.get();
103        debug_assert!(used <= maximum);
104        if count > maximum - used {
105            return Err(Error::Limit { range, kind });
106        }
107        counter.set(used + count);
108        Ok(())
109    }
110}