use structured_pkix::temporal::{Instant, LeapTable, Reading, Uncertainty};
mod accuracy;
pub use accuracy::{AccuracyReading, Component, ComponentReading, DeviationError, DeviationReason};
mod imprint;
pub use imprint::{HashAlgorithmReading, MessageImprint};
mod imprint_check;
pub use imprint_check::{ImprintAgreement, ImprintError};
mod computed;
pub use computed::{
ComputedInput, ImprintContext, ImprintDigest, ImprintProof, ImprintState, InputFailure,
RawInput,
};
mod requested;
pub use requested::{ImprintOperand, RequestAgreement, RequestImprintError, RequestedContentError};
mod extension;
pub use extension::{RecognitionError, TokenExtension, TokenExtensions};
mod info;
pub use info::{IntegerField, TokenInfo};
mod tsa;
pub use tsa::TsaReading;
mod token;
pub use computed::{AsyncComputedInput, AsyncRawInput};
pub use token::{AsyncInfoVisitor, InfoError, Token};
mod timeliness;
pub use timeliness::{RequestWindow, Timeliness, timeliness};
mod request;
pub use request::Request;
pub mod response;
pub use response::Response;
mod request_extensions;
mod request_fields;
pub use request_fields::{RequestFieldError, RequestFields};
mod authority;
mod carried;
mod signature;
pub use authority::{AuthorityError, AuthorityFacts, AuthoritySource, TsaIdentity, TsaUsage};
pub use signature::{SignatureError, TokenSignature};
mod check;
mod profile;
pub use check::{
CheckContext, CheckError, CheckedTimestamp, Evidence, EvidenceCopyError, InfoCheckError,
MappedCheckError, Requested,
};
pub use profile::{
MappedProfileCheckError, ProfileCheckError, ProfileFailure, ProfileInput, ProfileSource,
};
mod retained;
pub use retained::{RetainedFacts, RetainedImprint};
pub(crate) fn record<W: structured_asn1::memory::Work>(
faults: &mut structured_asn1::memory::OwnedVec<crate::Error, W>,
error: crate::Error,
) -> crate::Result<()> {
if error.is_terminal() {
return Err(error);
}
let at = error.offset();
let field = error.field();
faults
.try_push(error)
.map_err(|reason| crate::Error::resource(reason, field, at))
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Accuracy {
seconds: u64,
millis: u64,
micros: u64,
}
impl Accuracy {
#[must_use]
pub const fn new(seconds: u64, millis: u64, micros: u64) -> Self {
Self {
seconds,
millis,
micros,
}
}
#[must_use]
pub const fn seconds(self) -> u64 {
self.seconds
}
#[must_use]
pub const fn millis(self) -> u64 {
self.millis
}
#[must_use]
pub const fn micros(self) -> u64 {
self.micros
}
#[must_use]
pub fn nanos(self) -> u128 {
u128::from(self.seconds) * 1_000_000_000
+ u128::from(self.millis) * 1_000_000
+ u128::from(self.micros) * 1_000
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum BoundUncertainty {
AccuracyUnstated,
Utc(Uncertainty),
}
pub use structured_pkix::temporal::CompareError as GenerationOrderError;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct GenerationInterval {
pub earliest: Instant,
pub latest: Instant,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum IntervalError {
Resource(structured_asn1::memory::MemoryError),
Uncertain(BoundUncertainty),
}
pub fn interval_in<W: structured_asn1::memory::Work>(
reading: Reading,
accuracy: Option<Accuracy>,
utc: &LeapTable<'_>,
work: &W,
) -> core::result::Result<GenerationInterval, IntervalError> {
let bits = usize::BITS - utc.transitions().len().leading_zeros();
work.charge_work(48 + 9 * (u64::from(bits) + 1))
.map_err(IntervalError::Resource)?;
Ok(GenerationInterval {
earliest: earliest(reading, accuracy, utc).map_err(IntervalError::Uncertain)?,
latest: latest(reading, accuracy, utc).map_err(IntervalError::Uncertain)?,
})
}
pub fn earliest(
reading: Reading,
accuracy: Option<Accuracy>,
utc: &LeapTable<'_>,
) -> Result<Instant, BoundUncertainty> {
let accuracy = accuracy.ok_or(BoundUncertainty::AccuracyUnstated)?;
shift(reading.start(), accuracy, true, utc)
}
pub fn latest(
reading: Reading,
accuracy: Option<Accuracy>,
utc: &LeapTable<'_>,
) -> Result<Instant, BoundUncertainty> {
let accuracy = accuracy.ok_or(BoundUncertainty::AccuracyUnstated)?;
let upper = reading.upper_bound(utc).map_err(BoundUncertainty::Utc)?;
shift(upper, accuracy, false, utc)
}
fn shift(
at: Instant,
accuracy: Accuracy,
earlier: bool,
utc: &LeapTable<'_>,
) -> Result<Instant, BoundUncertainty> {
let nanos = i128::try_from(accuracy.nanos())
.map_err(|_| BoundUncertainty::Utc(Uncertainty::OutOfRange))?;
utc.shift(at, if earlier { -nanos } else { nanos })
.map_err(BoundUncertainty::Utc)
}