#![deny(unsafe_code)]
#![cfg_attr(not(test), no_std)]
#![warn(missing_docs)]
#![deny(intra_doc_link_resolution_failure)]
pub mod clock;
pub mod duration;
mod frequency;
mod instant;
mod numeric_constructor;
mod period;
mod time_int;
mod timer;
pub use clock::Clock;
use core::{convert::Infallible, fmt};
pub use instant::Instant;
pub use period::Period;
pub(crate) use time_int::TimeInt;
pub use timer::Timer;
#[doc(hidden)]
pub mod traits {
pub use crate::clock::Clock as _;
pub use crate::duration::Duration as _;
pub use crate::duration::TryConvertFrom as _;
pub use crate::duration::TryConvertInto as _;
pub use crate::numeric_constructor::NumericConstructor as _;
pub use crate::time_int::TimeInt as _;
}
pub mod units {
#[doc(inline)]
pub use crate::duration::units::*;
#[doc(inline)]
pub use crate::frequency::units::*;
}
pub trait Error: fmt::Debug + Eq {}
#[non_exhaustive]
#[derive(Debug, Eq, PartialEq)]
pub enum TimeError<E: Error = ()> {
ConversionFailure,
Overflow,
DivByZero,
NegDuration,
Clock(clock::Error<E>),
}
impl<E: Error> Error for TimeError<E> {}
impl<E: Error> From<clock::Error<E>> for TimeError<E> {
fn from(clock_error: clock::Error<E>) -> Self {
TimeError::<E>::Clock(clock_error)
}
}
impl Error for () {}
impl Error for Infallible {}
#[non_exhaustive]
#[derive(Debug, Eq, PartialEq)]
pub enum ConversionError {
ConversionFailure,
Overflow,
DivByZero,
NegDuration,
}
impl<E: Error> From<ConversionError> for TimeError<E> {
fn from(error: ConversionError) -> Self {
match error {
ConversionError::ConversionFailure => TimeError::ConversionFailure,
ConversionError::Overflow => TimeError::Overflow,
ConversionError::DivByZero => TimeError::DivByZero,
ConversionError::NegDuration => TimeError::NegDuration,
}
}
}
#[cfg(test)]
#[allow(unused_imports)]
mod tests {
use crate::duration::TryConvertFrom;
use crate::{self as time, clock, traits::*, units::*};
use core::{
convert::{Infallible, TryFrom, TryInto},
fmt::{self, Formatter},
};
struct MockClock64;
impl time::Clock for MockClock64 {
type Rep = u64;
const PERIOD: time::Period = <time::Period>::new(1, 64_000_000);
type ImplError = Infallible;
fn now(&self) -> Result<time::Instant<Self>, time::clock::Error<Self::ImplError>> {
Ok(time::Instant::new(128_000_000))
}
}
#[derive(Debug)]
struct MockClock32;
impl time::Clock for MockClock32 {
type Rep = u32;
const PERIOD: time::Period = <time::Period>::new(1, 16_000_000);
type ImplError = Infallible;
fn now(&self) -> Result<time::Instant<Self>, time::clock::Error<Self::ImplError>> {
Ok(time::Instant::new(32_000_000))
}
}
#[non_exhaustive]
#[derive(Debug, Eq, PartialEq)]
pub enum ClockImplError {
NotStarted,
}
impl crate::Error for ClockImplError {}
#[derive(Debug)]
struct BadClock;
impl time::Clock for BadClock {
type Rep = u32;
const PERIOD: time::Period = <time::Period>::new(1, 16_000_000);
type ImplError = ClockImplError;
fn now(&self) -> Result<time::Instant<Self>, time::clock::Error<Self::ImplError>> {
Err(time::clock::Error::Other(ClockImplError::NotStarted))
}
}
fn get_time<Clock: time::Clock>(clock: &Clock)
where
u32: TryFrom<Clock::Rep>,
Clock::Rep: TryFrom<u32>,
{
assert_eq!(
Ok(Seconds(2_u32)),
clock.now().unwrap().duration_since_epoch::<Seconds<u32>>()
);
}
#[test]
fn common_types() {
let then = MockClock32.now().unwrap();
let now = MockClock32.now().unwrap();
let clock64 = MockClock64 {};
let clock32 = MockClock32 {};
get_time(&clock64);
get_time(&clock32);
let then = then - Seconds(1_u32);
assert_ne!(then, now);
assert!(then < now);
}
#[test]
fn clock_error() {
assert_eq!(
BadClock.now(),
Err(time::clock::Error::Other(ClockImplError::NotStarted))
);
}
struct Timestamp<Clock>(time::Instant<Clock>)
where
Clock: time::Clock;
impl<Clock> Timestamp<Clock>
where
Clock: time::Clock,
{
pub fn new(instant: time::Instant<Clock>) -> Self {
Timestamp(instant)
}
}
impl<Clock> fmt::Display for Timestamp<Clock>
where
Clock: time::Clock,
{
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
let duration = self
.0
.duration_since_epoch::<Milliseconds<u64>>()
.map_err(|_| fmt::Error {})?;
let hours = Hours::<u32>::try_convert_from(duration).map_err(|_| fmt::Error {})?;
let minutes = Minutes::<u32>::try_convert_from(duration).map_err(|_| fmt::Error {})?
% Hours(1_u32);
let seconds = Seconds::<u32>::try_convert_from(duration).map_err(|_| fmt::Error {})?
% Minutes(1_u32);
let milliseconds = Milliseconds::<u32>::try_convert_from(duration)
.map_err(|_| fmt::Error {})?
% Seconds(1_u32);
f.write_fmt(format_args!(
"{}:{:02}:{:02}.{:03}",
hours, minutes, seconds, milliseconds
))
}
}
#[test]
fn format() {
let timestamp = Timestamp::new(time::Instant::<MockClock64>::new(321_643_392_000));
let formatted_timestamp = timestamp.to_string();
assert_eq!(formatted_timestamp, "1:23:45.678");
}
}