graphcal_compiler/registry/
time_scale.rs1use std::fmt;
7use std::str::FromStr;
8
9#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
14pub enum TimeScale {
15 UTC,
17 TAI,
19 TT,
21 TDB,
23 ET,
25 GPST,
27 GST,
29 BDT,
31 QZSST,
33}
34
35impl TimeScale {
36 pub const ALL_NAMES: &[&str] = &[
38 "UTC", "TAI", "TT", "TDB", "ET", "GPST", "GST", "BDT", "QZSST",
39 ];
40
41 #[must_use]
43 pub const fn is_utc(self) -> bool {
44 matches!(self, Self::UTC)
45 }
46
47 #[must_use]
49 pub const fn name(self) -> &'static str {
50 match self {
51 Self::UTC => "UTC",
52 Self::TAI => "TAI",
53 Self::TT => "TT",
54 Self::TDB => "TDB",
55 Self::ET => "ET",
56 Self::GPST => "GPST",
57 Self::GST => "GST",
58 Self::BDT => "BDT",
59 Self::QZSST => "QZSST",
60 }
61 }
62
63 #[must_use]
65 pub const fn to_hifitime(self) -> hifitime::TimeScale {
66 match self {
67 Self::UTC => hifitime::TimeScale::UTC,
68 Self::TAI => hifitime::TimeScale::TAI,
69 Self::TT => hifitime::TimeScale::TT,
70 Self::TDB => hifitime::TimeScale::TDB,
71 Self::ET => hifitime::TimeScale::ET,
72 Self::GPST => hifitime::TimeScale::GPST,
73 Self::GST => hifitime::TimeScale::GST,
74 Self::BDT => hifitime::TimeScale::BDT,
75 Self::QZSST => hifitime::TimeScale::QZSST,
76 }
77 }
78
79 #[must_use]
81 pub const fn from_hifitime(ts: hifitime::TimeScale) -> Self {
82 match ts {
83 hifitime::TimeScale::TAI => Self::TAI,
84 hifitime::TimeScale::TT => Self::TT,
85 hifitime::TimeScale::TDB => Self::TDB,
86 hifitime::TimeScale::ET => Self::ET,
87 hifitime::TimeScale::GPST => Self::GPST,
88 hifitime::TimeScale::GST => Self::GST,
89 hifitime::TimeScale::BDT => Self::BDT,
90 hifitime::TimeScale::QZSST => Self::QZSST,
91 _ => Self::UTC,
93 }
94 }
95}
96
97#[must_use]
102pub fn time_scale_from_conversion_fn(name: &str) -> Option<TimeScale> {
103 match name {
104 "to_utc" => Some(TimeScale::UTC),
105 "to_tai" => Some(TimeScale::TAI),
106 "to_tt" => Some(TimeScale::TT),
107 "to_tdb" => Some(TimeScale::TDB),
108 "to_et" => Some(TimeScale::ET),
109 "to_gpst" => Some(TimeScale::GPST),
110 "to_gst" => Some(TimeScale::GST),
111 "to_bdt" => Some(TimeScale::BDT),
112 "to_qzsst" => Some(TimeScale::QZSST),
113 _ => None,
114 }
115}
116
117impl fmt::Display for TimeScale {
118 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
119 f.write_str(self.name())
120 }
121}
122
123#[derive(Debug, Clone, PartialEq, Eq)]
125pub struct ParseTimeScaleError {
126 pub input: String,
128}
129
130impl fmt::Display for ParseTimeScaleError {
131 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
132 write!(
133 f,
134 "unknown time scale `{}`; expected one of: {}",
135 self.input,
136 TimeScale::ALL_NAMES.join(", ")
137 )
138 }
139}
140
141impl std::error::Error for ParseTimeScaleError {}
142
143impl FromStr for TimeScale {
144 type Err = ParseTimeScaleError;
145
146 fn from_str(s: &str) -> Result<Self, Self::Err> {
147 let variants = [
149 Self::UTC,
150 Self::TAI,
151 Self::TT,
152 Self::TDB,
153 Self::ET,
154 Self::GPST,
155 Self::GST,
156 Self::BDT,
157 Self::QZSST,
158 ];
159
160 for variant in variants {
161 if variant.name() == s {
162 return Ok(variant);
163 }
164 }
165
166 Err(ParseTimeScaleError {
167 input: s.to_string(),
168 })
169 }
170}
171
172#[cfg(test)]
173mod tests {
174 use super::*;
175
176 #[test]
177 fn display_roundtrip() {
178 let scales = [
179 TimeScale::UTC,
180 TimeScale::TAI,
181 TimeScale::TT,
182 TimeScale::TDB,
183 TimeScale::ET,
184 TimeScale::GPST,
185 TimeScale::GST,
186 TimeScale::BDT,
187 TimeScale::QZSST,
188 ];
189 for scale in &scales {
190 let s = scale.to_string();
191 let parsed: TimeScale = s.parse().unwrap();
192 assert_eq!(*scale, parsed);
193 }
194 }
195
196 #[test]
197 fn from_str_unknown() {
198 let err = "INVALID".parse::<TimeScale>().unwrap_err();
199 assert_eq!(err.input, "INVALID");
200 assert!(err.to_string().contains("unknown time scale"));
201 }
202
203 #[test]
204 fn hifitime_roundtrip() {
205 let scales = [
206 TimeScale::UTC,
207 TimeScale::TAI,
208 TimeScale::TT,
209 TimeScale::TDB,
210 TimeScale::ET,
211 TimeScale::GPST,
212 TimeScale::GST,
213 TimeScale::BDT,
214 TimeScale::QZSST,
215 ];
216 for scale in &scales {
217 let hf = scale.to_hifitime();
218 let back = TimeScale::from_hifitime(hf);
219 assert_eq!(*scale, back);
220 }
221 }
222
223 #[test]
224 fn utc_is_default() {
225 assert!(TimeScale::UTC.is_utc());
226 assert!(!TimeScale::TT.is_utc());
227 }
228}