1use super::BasicStage;
4use crate::pki::SignerReceipt;
5use crate::source::{Query, ScopeError};
6use crate::timestamp::{
7 Purpose, SignatureTime, SignatureTimeBinding, SignatureTimeError, SignatureTimeFailure,
8 TimestampPaths, TimestampScope, signature_time_path,
9};
10use structured_asn1::memory::{MemoryError, OwnedVec, Work};
11
12pub enum SignatureTimeFact<'a, S, N, D, G, I> {
15 Bound(SignatureTime<'a, S, N, D, G, I>),
17 Unproven {
19 property: N,
21 cause: SignatureTimeFailure,
23 },
24}
25
26pub struct Timed<'a, 'certificate, 'document, B, S, N, D, G, I> {
31 basic: &'a B,
32 paths: &'a TimestampPaths<'a, 'certificate, 'document, N, D, G, I>,
33 signatures: OwnedVec<SignatureTimeFact<'a, S, N, D, G, I>>,
34 static_complete: bool,
35}
36
37impl<'a, 'c, 'd, B, S, N, D, G, I> Timed<'a, 'c, 'd, B, S, N, D, G, I> {
38 #[must_use]
40 pub fn basic(&self) -> &'a B {
41 self.basic
42 }
43 #[must_use]
45 pub fn paths(&self) -> &'a TimestampPaths<'a, 'c, 'd, N, D, G, I> {
46 self.paths
47 }
48 #[must_use]
50 pub fn signatures(&self) -> &[SignatureTimeFact<'a, S, N, D, G, I>] {
51 &self.signatures
52 }
53 #[must_use]
57 pub fn all_static_time_requirements_met(&self) -> bool {
58 self.static_complete
59 }
60}
61
62#[derive(Debug, Clone, Copy, PartialEq, Eq)]
64pub enum TimeError<N> {
65 Foreign {
67 signature: N,
69 },
70 Scope(ScopeError<N>),
73 Signature(SignatureTimeError<N>),
75 Resource {
77 node: N,
79 cause: MemoryError,
81 },
82}
83
84pub type TimeResult<'a, 'c, 'd, B, S, Q, I> = Result<
86 Timed<'a, 'c, 'd, B, S, <Q as Query>::Id, <Q as Query>::Document, <Q as Query>::Generation, I>,
87 TimeError<<Q as Query>::Id>,
88>;
89
90pub fn timestamped<'a, 'c, 'd, 'path, 'document, B, Q, I>(
98 basic: &'a B,
99 paths: &'a TimestampPaths<'a, 'c, 'd, Q::Id, Q::Document, Q::Generation, I>,
100 query: &Q,
101) -> TimeResult<'a, 'c, 'd, B, B::Signer, Q, I>
102where
103 'document: 'path,
104 B: BasicStage<'path, 'document, Id = Q::Id, Document = Q::Document, Generation = Q::Generation>,
105 Q: Query,
106{
107 let selected = basic.signer().signature();
108 let signature = selected.node;
109 let required = paths.required();
110 let resource = |cause| TimeError::Resource {
111 node: signature,
112 cause,
113 };
114 if !matches!(required.scope(), TimestampScope::All(_))
115 || required.scope().location().snapshot != query.snapshot()
116 || selected.snapshot != query.snapshot()
117 || !query
118 .equal(required.signature(), signature)
119 .map_err(resource)?
120 || !required
121 .includes_counters(basic.counters(), query)
122 .map_err(TimeError::Scope)?
123 {
124 return Err(TimeError::Foreign { signature });
125 }
126 query.admit(signature, 1).map_err(TimeError::Scope)?;
127 let mut signatures = query.execution().vector();
128 let mut static_complete = basic.all_requirements_met();
129 for path in paths.paths() {
130 query.execution().charge_work(1).map_err(resource)?;
131 let verified = path.actor().verified();
132 if verified.purpose() != Purpose::Signature
133 || !query
134 .equal(verified.signature(), signature)
135 .map_err(resource)?
136 {
137 continue;
138 }
139 signatures.try_reserve(1).map_err(resource)?;
140 let fact =
141 match signature_time_path(basic.signer(), path, query).map_err(TimeError::Signature)? {
142 SignatureTimeBinding::Bound(value) => SignatureTimeFact::Bound(value),
143 SignatureTimeBinding::Unproven(cause) => {
144 static_complete = false;
145 SignatureTimeFact::Unproven {
146 property: verified.property(),
147 cause,
148 }
149 }
150 };
151 signatures.try_push(fact).map_err(resource)?;
152 }
153 if signatures.is_empty() {
154 static_complete = false;
155 }
156 query.admit(signature, 1).map_err(TimeError::Scope)?;
157 Ok(Timed {
158 basic,
159 paths,
160 signatures: signatures.into_owned(),
161 static_complete,
162 })
163}