structured_cms/timestamp/response/
check.rs1use super::{Response, Status};
4use crate::timestamp::{
5 CheckContext, CheckError, CheckedTimestamp, ImprintOperand, ProfileCheckError, ProfileFailure,
6 ProfileInput, RequestFieldError, TokenExtension,
7};
8use crate::{Error, ErrorCode, provider::SignatureProvider, stream::Source};
9use core::convert::Infallible;
10use structured_asn1::{Reader, memory::Execution};
11
12pub struct CheckedResponse<'a> {
15 status: Status,
16 timestamp: Option<CheckedTimestamp<'a>>,
17}
18impl<'a> CheckedResponse<'a> {
19 #[must_use]
21 pub fn status(&self) -> Status {
22 self.status
23 }
24 #[must_use]
26 pub fn timestamp(&self) -> Option<&CheckedTimestamp<'a>> {
27 self.timestamp.as_ref()
28 }
29 pub fn into_timestamp(self) -> Option<CheckedTimestamp<'a>> {
31 self.timestamp
32 }
33}
34impl<'doc> Response<'doc> {
35 #[expect(
41 clippy::result_large_err,
42 reason = "preserve the existing original token/source refusal without allocating an error box on resource exhaustion"
43 )]
44 pub fn check<'a, P, S: Source, PE, RE>(
45 &'a self,
46 provider: &'a P,
47 query: &Reader<'a>,
48 context: &CheckContext<'a, '_>,
49 covered: &mut S,
50 recognizes: impl FnMut(&TokenExtension<'_>, &Execution<'_>) -> Result<bool, RE>,
51 ) -> Result<CheckedResponse<'a>, CheckError<S::Error, PE, RE>>
52 where
53 'doc: 'a,
54 P: for<'scope> SignatureProvider<'scope, Error = PE>,
55 {
56 self.check_with_profile(provider, query, context, covered, recognizes, |_| {
57 Ok::<(), ProfileFailure<Infallible>>(())
58 })
59 .map_err(ProfileCheckError::into_common)
60 }
61 #[expect(
64 clippy::result_large_err,
65 reason = "retain the existing typed token/profile/source cause without another fallible allocation"
66 )]
67 pub fn check_with_profile<'a, P, S: Source, PE, RE, FE>(
68 &'a self,
69 provider: &'a P,
70 query: &Reader<'a>,
71 context: &CheckContext<'a, '_>,
72 covered: &mut S,
73 recognizes: impl FnMut(&TokenExtension<'_>, &Execution<'_>) -> Result<bool, RE>,
74 profile: impl for<'view, 'scope> FnOnce(
75 ProfileInput<'view, 'doc, 'a, 'scope>,
76 ) -> Result<(), ProfileFailure<FE>>,
77 ) -> Result<CheckedResponse<'a>, ProfileCheckError<S::Error, PE, RE, FE>>
78 where
79 'doc: 'a,
80 P: for<'scope> SignatureProvider<'scope, Error = PE>,
81 {
82 let Some(requested) = &context.requested else {
83 return Err(CheckError::Processing(Error::schema(
84 ErrorCode::InvalidLocation,
85 "timeStampResp.requestContext",
86 self.element().span().start,
87 ))
88 .into());
89 };
90 requested
91 .request
92 .imprint()
93 .require_session(requested.parent)
94 .map_err(|source| {
95 CheckError::RequestField(RequestFieldError {
96 operand: ImprintOperand::Requested,
97 source,
98 })
99 })?;
100 let timestamp = match self.token_in(query).map_err(CheckError::Processing)? {
101 Some((token, reader)) => Some(
102 token
103 .check_with_profile(provider, &reader, context, covered, recognizes, profile)?,
104 ),
105 None => None,
106 };
107 Ok(CheckedResponse {
108 status: self.status().status(),
109 timestamp,
110 })
111 }
112}