Skip to main content

structured_cms/timestamp/
profile.rs

1//! Parse-once profile inspection, separate from common timestamp semantics.
2
3use super::{CheckError, InfoCheckError, InfoError, MappedCheckError, Token, TokenInfo};
4use crate::{
5    Error,
6    content_source::{ContentError, SourceMap},
7    ess::SigningAttributes,
8};
9use core::convert::Infallible;
10use structured_asn1::Reader;
11
12/// The coordinate domain of a profile's original refusal.
13#[derive(Debug, Clone, Copy, PartialEq, Eq)]
14pub enum ProfileSource {
15    /// Original CMS/ESS envelope fields use the producing outer reader/map.
16    Envelope,
17    /// Original carried `TSTInfo` fields use its own reader/map.
18    Information,
19}
20
21/// Exact caller-owned cause and the source from which its coordinates came.
22/// The common core does not rewrite an opaque error or invent its location.
23#[derive(Debug)]
24pub struct ProfileFailure<E> {
25    /// Actual coordinate domain; never apply an inner map to an outer field.
26    pub source: ProfileSource,
27    /// Original independent cause. It cannot borrow a temporary joined source.
28    pub cause: E,
29}
30
31/// Original already decoded fields, scoped to one profile invocation.
32/// These are structural facts, not successful mathematics, authority or trust.
33/// Outer and carried sources can have different coordinate systems even when
34/// they share an execution account. Scans, copies and parameter queries must
35/// admit their work through the corresponding reader's current execution.
36///
37/// An information view cannot escape into an independently retained result or
38/// error: its bytes may belong to a temporary joined buffer.
39///
40/// ```compile_fail
41/// use structured_cms::timestamp::{ProfileInput, TokenInfo};
42/// fn escape<'a>(input: ProfileInput<'_, 'a, 'a, '_>) -> &'a TokenInfo<'a> {
43///     input.info
44/// }
45/// ```
46pub struct ProfileInput<'view, 'document, 'envelope, 'information> {
47    /// Same original token being checked, without a second envelope parse.
48    pub token: &'view Token<'document>,
49    /// Original CMS/ESS producing reader with current operation funding.
50    pub parent: &'view Reader<'envelope>,
51    /// Outer source map for a logically joined envelope. None means the outer
52    /// reader already uses original coordinates, not an absent original source.
53    pub envelope: Option<&'view SourceMap>,
54    /// Same original signed ESS attributes used by the subsequent binding.
55    pub ess: &'view SigningAttributes<'envelope>,
56    /// Same original information reading used by the subsequent complete check.
57    pub info: &'view TokenInfo<'information>,
58    /// Producing carried-source reader, including original depth and ceilings.
59    pub reader: &'view Reader<'information>,
60    /// Original projection for coordinates derived from that carried reader.
61    pub source: &'view SourceMap,
62}
63
64/// Extended profile execution refusal. Existing public common error enums are
65/// unchanged, including their exhaustive matching surface.
66#[derive(Debug)]
67pub enum ProfileCheckError<SE, PE, RE, FE> {
68    /// Unchanged common processing/provider/source/recognition failure.
69    Common(CheckError<SE, PE, RE>),
70    /// Terminal profile refusal before cryptographic/content callbacks.
71    Profile {
72        /// Original cause and its explicit coordinate domain.
73        source: ProfileFailure<FE>,
74        /// Independent inner map, surviving the joined information buffer.
75        /// Use this only for Information; Envelope uses original outer
76        /// coordinates or the mapped wrapper's separately retained envelope.
77        context: SourceMap,
78    },
79}
80
81/// A profile check in a logical envelope retains both independent source maps.
82#[derive(Debug)]
83pub enum MappedProfileCheckError<SE, PE, RE, FE> {
84    /// Original source/session refusal before map allocation or dispatch.
85    Preflight(CheckError<SE, PE, RE>),
86    /// Outer-map admission failed at its original physical enclosure.
87    Provenance(Error),
88    /// Original extended cause with its separately retained outer coordinates.
89    Execution {
90        /// Original CMS envelope map, never the carried-information map.
91        envelope: SourceMap,
92        /// Unchanged common/profile cause and any retained inner context.
93        source: ProfileCheckError<SE, PE, RE, FE>,
94    },
95}
96
97pub(super) enum InformationFailure<SE, PE, RE, FE> {
98    Common(InfoCheckError<SE, PE, RE>),
99    Profile(ProfileFailure<FE>),
100}
101
102impl<SE, PE, RE, FE> From<CheckError<SE, PE, RE>> for ProfileCheckError<SE, PE, RE, FE> {
103    fn from(value: CheckError<SE, PE, RE>) -> Self {
104        Self::Common(value)
105    }
106}
107
108impl<SE, PE, RE, FE> From<InfoCheckError<SE, PE, RE>> for InformationFailure<SE, PE, RE, FE> {
109    fn from(value: InfoCheckError<SE, PE, RE>) -> Self {
110        Self::Common(value)
111    }
112}
113
114impl<SE, PE, RE> ProfileCheckError<SE, PE, RE, Infallible> {
115    pub(super) fn into_common(self) -> CheckError<SE, PE, RE> {
116        match self {
117            Self::Common(source) => source,
118            Self::Profile { source, .. } => match source.cause {},
119        }
120    }
121}
122
123impl<SE, PE, RE> MappedProfileCheckError<SE, PE, RE, Infallible> {
124    pub(super) fn into_common(self) -> MappedCheckError<SE, PE, RE> {
125        match self {
126            Self::Preflight(source) => MappedCheckError::Preflight(source),
127            Self::Provenance(source) => MappedCheckError::Provenance(source),
128            Self::Execution { envelope, source } => MappedCheckError::Execution {
129                envelope,
130                source: source.into_common(),
131            },
132        }
133    }
134}
135
136pub(super) fn information_error<SE, PE, RE, FE>(
137    error: ContentError<InfoError<InformationFailure<SE, PE, RE, FE>>>,
138) -> ProfileCheckError<SE, PE, RE, FE> {
139    let common = |source| ProfileCheckError::Common(CheckError::Information(source));
140    match error {
141        ContentError::Processing(source) => common(ContentError::Processing(source)),
142        ContentError::Decoding { source, context } => {
143            common(ContentError::Decoding { source, context })
144        }
145        ContentError::Callback {
146            source: InfoError::Processing(source),
147            context,
148        } => common(ContentError::Callback {
149            source: InfoError::Processing(source),
150            context,
151        }),
152        ContentError::Callback {
153            source: InfoError::Callback(InformationFailure::Common(source)),
154            context,
155        } => common(ContentError::Callback {
156            source: InfoError::Callback(source),
157            context,
158        }),
159        ContentError::Callback {
160            source: InfoError::Callback(InformationFailure::Profile(source)),
161            context,
162        } => ProfileCheckError::Profile { source, context },
163    }
164}