1use derive_more::{Display, Error};
4
5#[derive(Debug, Display, Error, Clone, Copy, PartialEq, Eq, Hash)]
14#[display(
15 "parse timedelta error: expected `0`, or counts with units from coarsest to finest, as `1m30s`"
16)]
17pub struct ParseTimedeltaError;
18
19#[derive(Debug, Display, Error, Clone, Copy, PartialEq, Eq, Hash)]
29#[display(
30 "parse timestamp error: expected RFC 3339 in UTC from 1677 to 2262, as `2026-09-16T07:45:35Z`"
31)]
32pub struct ParseTimestampError;
33
34#[derive(Debug, Display, Error, Clone, Copy, PartialEq, Eq, Hash)]
44#[display(
45 "parse TAI timestamp error: expected an RFC 3339 date and time in TAI from 1677 to 2262, as \
46 `2026-09-16T07:46:12 TAI`"
47)]
48pub struct ParseTaiTimestampError;
49
50#[derive(Debug, Display, Error, Clone, Copy, PartialEq, Eq, Hash)]
59#[display("parse tickdelta error: expected a count of ticks, as `24 ticks`")]
60pub struct ParseTickdeltaError;
61
62#[derive(Debug, Display, Error, Clone, Copy, PartialEq, Eq, Hash)]
71#[display("parse tick rate error: expected a count of hertz above zero, as `24000000 Hz`")]
72pub struct ParseTickRateError;
73
74#[derive(Debug, Display, Error, Clone, Copy, PartialEq, Eq, Hash)]
87#[display("out of range error: the time is outside what the target type holds")]
88pub struct OutOfRangeError;
89
90#[inline]
92pub(crate) fn narrow<T, N: TryInto<T>>(count: N) -> Result<T, OutOfRangeError> {
93 count.try_into().map_err(|_past_the_range| OutOfRangeError)
94}
95
96#[cfg(test)]
97mod tests {
98 use alloc::string::{String, ToString as _};
99
100 use rstest::rstest;
101
102 use crate::{
103 OutOfRangeError, ParseTaiTimestampError, ParseTickRateError, ParseTickdeltaError,
104 ParseTimedeltaError, ParseTimestampError,
105 };
106
107 #[rstest]
108 #[case::a_span(
109 ParseTimedeltaError.to_string(),
110 "parse timedelta error: expected `0`, or counts with units from coarsest to finest, as `1m30s`"
111 )]
112 #[case::an_instant(
113 ParseTimestampError.to_string(),
114 "parse timestamp error: expected RFC 3339 in UTC from 1677 to 2262, as `2026-09-16T07:45:35Z`"
115 )]
116 #[case::a_tai_instant(
117 ParseTaiTimestampError.to_string(),
118 "parse TAI timestamp error: expected an RFC 3339 date and time in TAI from 1677 to 2262, \
119 as `2026-09-16T07:46:12 TAI`"
120 )]
121 #[case::a_count_of_ticks(
122 ParseTickdeltaError.to_string(),
123 "parse tickdelta error: expected a count of ticks, as `24 ticks`"
124 )]
125 #[case::a_rate(
126 ParseTickRateError.to_string(),
127 "parse tick rate error: expected a count of hertz above zero, as `24000000 Hz`"
128 )]
129 #[case::a_conversion(
130 OutOfRangeError.to_string(),
131 "out of range error: the time is outside what the target type holds"
132 )]
133 fn each_refusal_says_why(#[case] message: String, #[case] text: &str) {
134 assert_eq!(message, text, "the message names what would have been read");
135 }
136}