use super::elapsed::elapsed;
use super::types::{Opening, Reader, Source};
use super::{
ClockFailure, ClockReadRefusal, HarnessClock, MeasurementReading, MeasurementStart,
MeasurementTick,
};
use std::panic::catch_unwind;
enum ReadOutcome {
Tick(MeasurementTick),
Refused,
Unwound,
}
fn read_once(reader: Reader) -> ReadOutcome {
match reader {
Reader::Infallible(read) => match catch_unwind(read) {
Ok(nanoseconds) => ReadOutcome::Tick(MeasurementTick::admitted(nanoseconds)),
Err(_) => ReadOutcome::Unwound,
},
Reader::Fallible(read) => match catch_unwind(read) {
Ok(Ok(nanoseconds)) => ReadOutcome::Tick(MeasurementTick::admitted(nanoseconds)),
Ok(Err(ClockReadRefusal::Refused)) => ReadOutcome::Refused,
Err(_) => ReadOutcome::Unwound,
},
}
}
fn elapsed_reading(opened: MeasurementTick, closed: MeasurementTick) -> MeasurementReading {
match elapsed(opened, closed) {
Ok(duration) => MeasurementReading::Observed(duration),
Err(failure) => MeasurementReading::Failed(failure),
}
}
fn close_opened(reader: Reader, opened: MeasurementTick) -> MeasurementReading {
match read_once(reader) {
ReadOutcome::Tick(closed) => elapsed_reading(opened, closed),
ReadOutcome::Refused => MeasurementReading::Failed(ClockFailure::ClosingRefused),
ReadOutcome::Unwound => MeasurementReading::Failed(ClockFailure::ClosingUnwound),
}
}
fn finish_opening(opening: &Opening) -> MeasurementReading {
match opening {
Opening::Unavailable => MeasurementReading::Unavailable,
Opening::Failed(failure) => MeasurementReading::Failed(*failure),
Opening::Opened { reader, tick } => close_opened(*reader, *tick),
}
}
impl HarnessClock {
pub fn begin(self) -> MeasurementStart {
let opening = match self.source {
Source::Unavailable => Opening::Unavailable,
Source::Available(reader) => match read_once(reader) {
ReadOutcome::Tick(tick) => Opening::Opened { reader, tick },
ReadOutcome::Refused => Opening::Failed(ClockFailure::OpeningRefused),
ReadOutcome::Unwound => Opening::Failed(ClockFailure::OpeningUnwound),
},
};
MeasurementStart { opening }
}
}
impl MeasurementStart {
pub fn finish(self) -> MeasurementReading {
finish_opening(&self.opening)
}
}