use super::Signed;
use crate::xml::{Access, AccessError, Snapshot, Xml};
use structured_asn1::memory::Work;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum DateTimeFact {
Malformed,
Unsupported,
Valid {
timezone_minutes: Option<i16>,
},
}
pub trait DateTimeXml: Xml {
fn date_time<W: Work>(
&self,
snapshot: Snapshot<Self::Document, Self::Generation>,
node: Self::Id,
execution: &W,
) -> Result<DateTimeFact, Self::Error>;
}
#[derive(Debug, Clone, Copy)]
pub struct CalendarValue<'view> {
pub negative_year: bool,
pub year_digits: &'view str,
pub month: u8,
pub day: u8,
pub hour: u8,
pub minute: u8,
pub second: u8,
pub fraction_digits: Option<&'view str>,
pub timezone_minutes: Option<i16>,
}
#[derive(Debug, Clone, Copy)]
pub enum CalendarFact<'view> {
Malformed,
Unsupported,
Value(CalendarValue<'view>),
}
pub trait CalendarXml: DateTimeXml {
fn with_calendar<R, VE, W: Work>(
&self,
snapshot: Snapshot<Self::Document, Self::Generation>,
node: Self::Id,
execution: &W,
visitor: impl for<'view> FnOnce(CalendarFact<'view>) -> Result<R, VE>,
) -> Result<R, crate::reference::VisitError<Self::Error, VE>>;
}
pub struct ClaimedTime<N, D, G> {
snapshot: Snapshot<D, G>,
signature: N,
node: N,
timezone_minutes: i16,
}
impl<N: Copy, D: Copy, G: Copy> ClaimedTime<N, D, G> {
#[must_use]
pub fn snapshot(&self) -> Snapshot<D, G> {
self.snapshot
}
#[must_use]
pub fn signature(&self) -> N {
self.signature
}
#[must_use]
pub fn node(&self) -> N {
self.node
}
#[must_use]
pub fn timezone_minutes(&self) -> i16 {
self.timezone_minutes
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ClaimedTimeFailure {
Malformed,
TimezoneUnstated,
Unsupported,
}
pub enum ClaimedTimeBinding<N, D, G> {
Bound(ClaimedTime<N, D, G>),
Unproven {
node: N,
cause: ClaimedTimeFailure,
},
}
#[derive(Debug)]
pub enum ClaimedTimeError<E, N> {
Foreign {
node: N,
},
Access(AccessError<E, N>),
}
pub type ClaimedTimeResult<X> = Result<
ClaimedTimeBinding<<X as Xml>::Id, <X as Xml>::Document, <X as Xml>::Generation>,
ClaimedTimeError<<X as Xml>::Error, <X as Xml>::Id>,
>;
pub fn check_time<X: DateTimeXml, W: Work>(
signed: &Signed<X::Id, X::Document, X::Generation>,
access: &Access<'_, X, W>,
) -> ClaimedTimeResult<X> {
let node = signed.signing_time();
if signed.snapshot() != access.snapshot() {
return Err(ClaimedTimeError::Foreign { node });
}
let fact = access
.query(node, |xml, snapshot, work| {
xml.date_time(snapshot, node, work)
})
.map_err(ClaimedTimeError::Access)?;
let cause = match fact {
DateTimeFact::Malformed => ClaimedTimeFailure::Malformed,
DateTimeFact::Unsupported => ClaimedTimeFailure::Unsupported,
DateTimeFact::Valid {
timezone_minutes: None,
} => ClaimedTimeFailure::TimezoneUnstated,
DateTimeFact::Valid {
timezone_minutes: Some(timezone_minutes),
} => {
return Ok(ClaimedTimeBinding::Bound(ClaimedTime {
snapshot: signed.snapshot(),
signature: signed.signature(),
node,
timezone_minutes,
}));
}
};
Ok(ClaimedTimeBinding::Unproven { node, cause })
}