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}