Skip to main content

lox_time/offsets/
impls.rs

1// SPDX-FileCopyrightText: 2025 Helge Eichhorn <git@helgeeichhorn.de>
2//
3// SPDX-License-Identifier: MPL-2.0
4
5use std::convert::Infallible;
6
7use lox_core::time::deltas::TimeDelta;
8
9use crate::{
10    offsets::{Offset, OffsetProvider, TryOffset},
11    time_scales::{DynTimeScale, Tai, Tcb, Tcg, Tdb, Tt, Ut1},
12};
13
14// No-ops
15
16macro_rules! impl_noop {
17    ($($scale:ident),*) => {
18        $(
19            impl<T> TryOffset<$scale, $scale> for T
20            where
21                T: OffsetProvider,
22            {
23                type Error = Infallible;
24
25                fn try_offset(
26                    &self,
27                    _origin: $scale,
28                    _target: $scale,
29                    _delta: TimeDelta
30                ) -> Result<TimeDelta, Self::Error> {
31                    Ok(TimeDelta::default())
32                }
33            }
34        )*
35    };
36}
37
38impl_noop!(Tai, Tcb, Tcg, Tdb, Tt, Ut1);
39
40// TAI <-> TT
41
42impl<T> TryOffset<Tai, Tt> for T
43where
44    T: OffsetProvider,
45{
46    type Error = Infallible;
47
48    fn try_offset(
49        &self,
50        _origin: Tai,
51        _target: Tt,
52        _delta: TimeDelta,
53    ) -> Result<TimeDelta, Self::Error> {
54        Ok(self.tai_to_tt())
55    }
56}
57
58impl<T> TryOffset<Tt, Tai> for T
59where
60    T: OffsetProvider,
61{
62    type Error = Infallible;
63
64    fn try_offset(
65        &self,
66        _origin: Tt,
67        _target: Tai,
68        _delta: TimeDelta,
69    ) -> Result<TimeDelta, Self::Error> {
70        Ok(self.tt_to_tai())
71    }
72}
73
74// TT <-> TCG
75
76impl<T> TryOffset<Tt, Tcg> for T
77where
78    T: OffsetProvider,
79{
80    type Error = Infallible;
81
82    fn try_offset(
83        &self,
84        _origin: Tt,
85        _target: Tcg,
86        delta: TimeDelta,
87    ) -> Result<TimeDelta, Self::Error> {
88        Ok(self.tt_to_tcg(delta))
89    }
90}
91
92impl<T> TryOffset<Tcg, Tt> for T
93where
94    T: OffsetProvider,
95{
96    type Error = Infallible;
97
98    fn try_offset(
99        &self,
100        _origin: Tcg,
101        _target: Tt,
102        delta: TimeDelta,
103    ) -> Result<TimeDelta, Self::Error> {
104        Ok(self.tcg_to_tt(delta))
105    }
106}
107
108// TDB <-> TCB
109
110impl<T> TryOffset<Tdb, Tcb> for T
111where
112    T: OffsetProvider,
113{
114    type Error = Infallible;
115
116    fn try_offset(
117        &self,
118        _origin: Tdb,
119        _target: Tcb,
120        delta: TimeDelta,
121    ) -> Result<TimeDelta, Self::Error> {
122        Ok(self.tdb_to_tcb(delta))
123    }
124}
125
126impl<T> TryOffset<Tcb, Tdb> for T
127where
128    T: OffsetProvider,
129{
130    type Error = Infallible;
131
132    fn try_offset(
133        &self,
134        _origin: Tcb,
135        _target: Tdb,
136        delta: TimeDelta,
137    ) -> Result<TimeDelta, Self::Error> {
138        Ok(self.tcb_to_tdb(delta))
139    }
140}
141
142// TT <-> TDB
143
144impl<T> TryOffset<Tt, Tdb> for T
145where
146    T: OffsetProvider,
147{
148    type Error = Infallible;
149
150    fn try_offset(
151        &self,
152        _origin: Tt,
153        _target: Tdb,
154        delta: TimeDelta,
155    ) -> Result<TimeDelta, Self::Error> {
156        Ok(self.tt_to_tdb(delta))
157    }
158}
159
160impl<T> TryOffset<Tdb, Tt> for T
161where
162    T: OffsetProvider,
163{
164    type Error = Infallible;
165
166    fn try_offset(
167        &self,
168        _origin: Tdb,
169        _target: Tt,
170        delta: TimeDelta,
171    ) -> Result<TimeDelta, Self::Error> {
172        Ok(self.tdb_to_tt(delta))
173    }
174}
175
176// TAI <-> UT1
177
178impl<T> TryOffset<Tai, Ut1> for T
179where
180    T: OffsetProvider,
181{
182    type Error = <Self as OffsetProvider>::Error;
183
184    fn try_offset(
185        &self,
186        _origin: Tai,
187        _target: Ut1,
188        delta: TimeDelta,
189    ) -> Result<TimeDelta, Self::Error> {
190        self.tai_to_ut1(delta)
191    }
192}
193
194impl<T> TryOffset<Ut1, Tai> for T
195where
196    T: OffsetProvider,
197{
198    type Error = <Self as OffsetProvider>::Error;
199
200    fn try_offset(
201        &self,
202        _origin: Ut1,
203        _target: Tai,
204        delta: TimeDelta,
205    ) -> Result<TimeDelta, Self::Error> {
206        self.ut1_to_tai(delta)
207    }
208}
209
210// Two-step
211
212macro_rules! impl_two_step {
213    ($(($origin:ident, $via:ident, $target:ident)),*) => {
214        $(
215            impl<T> TryOffset<$origin, $target> for T
216            where
217                T: OffsetProvider,
218            {
219                type Error = Infallible;
220
221                fn try_offset(
222                    &self,
223                    origin: $origin,
224                    target: $target,
225                    delta: TimeDelta,
226                ) -> Result<TimeDelta, Self::Error> {
227                    Ok(super::two_step_offset(self, origin, $via, target, delta))
228                }
229            }
230
231            impl<T> TryOffset<$target, $origin> for T
232            where
233                T: OffsetProvider,
234            {
235                type Error = Infallible;
236
237                fn try_offset(
238                    &self,
239                    origin: $target,
240                    target: $origin,
241                    delta: TimeDelta,
242                ) -> Result<TimeDelta, Self::Error> {
243                    Ok(super::two_step_offset(self, origin, $via, target, delta))
244                }
245            }
246        )*
247    }
248}
249
250impl_two_step!(
251    (Tai, Tt, Tdb),
252    (Tdb, Tt, Tcg),
253    (Tai, Tt, Tcg),
254    (Tai, Tdb, Tcb),
255    (Tt, Tdb, Tcb),
256    (Tcb, Tdb, Tcg)
257);
258
259macro_rules! impl_two_step_ut1 {
260    ($($scale:ident),*) => {
261        $(
262            impl<T> TryOffset<$scale, Ut1> for T
263            where
264                T: OffsetProvider,
265            {
266                type Error = <Self as OffsetProvider>::Error;
267
268                fn try_offset(
269                    &self,
270                    _origin: $scale,
271                    _target: Ut1,
272                    delta: TimeDelta,
273                ) -> Result<TimeDelta, Self::Error> {
274                    let mut offset = self.offset($scale, Tai, delta);
275                    offset += self.try_offset(Tai, Ut1, delta + offset)?;
276                    Ok(offset)
277                }
278            }
279
280            impl<T> TryOffset<Ut1, $scale> for T
281            where
282                T: OffsetProvider,
283            {
284                type Error = <Self as OffsetProvider>::Error;
285
286                fn try_offset(
287                    &self,
288                    _origin: Ut1,
289                    _target: $scale,
290                    delta: TimeDelta,
291                ) -> Result<TimeDelta, Self::Error> {
292                    let mut offset = self.try_offset(Ut1, Tai, delta)?;
293                    offset += self.offset(Tai, $scale, delta + offset);
294                    Ok(offset)
295                }
296            }
297        )*
298    };
299}
300
301impl_two_step_ut1!(Tcb, Tcg, Tdb, Tt);
302
303// Dynamic
304
305impl<T> TryOffset<DynTimeScale, DynTimeScale> for T
306where
307    T: OffsetProvider,
308{
309    type Error = <Self as OffsetProvider>::Error;
310
311    fn try_offset(
312        &self,
313        origin: DynTimeScale,
314        target: DynTimeScale,
315        delta: TimeDelta,
316    ) -> Result<TimeDelta, Self::Error> {
317        if origin == target {
318            return Ok(TimeDelta::default());
319        }
320        match (origin, target) {
321            (DynTimeScale::Tai, DynTimeScale::Tcb) => Ok(self.offset(Tai, Tcb, delta)),
322            (DynTimeScale::Tai, DynTimeScale::Tcg) => Ok(self.offset(Tai, Tcg, delta)),
323            (DynTimeScale::Tai, DynTimeScale::Tdb) => Ok(self.offset(Tai, Tdb, delta)),
324            (DynTimeScale::Tai, DynTimeScale::Tt) => Ok(self.offset(Tai, Tt, delta)),
325            (DynTimeScale::Tai, DynTimeScale::Ut1) => self.try_offset(Tai, Ut1, delta),
326            (DynTimeScale::Tcb, DynTimeScale::Tai) => Ok(self.offset(Tcb, Tai, delta)),
327            (DynTimeScale::Tcb, DynTimeScale::Tcg) => Ok(self.offset(Tcb, Tcg, delta)),
328            (DynTimeScale::Tcb, DynTimeScale::Tdb) => Ok(self.offset(Tcb, Tdb, delta)),
329            (DynTimeScale::Tcb, DynTimeScale::Tt) => Ok(self.offset(Tcb, Tt, delta)),
330            (DynTimeScale::Tcb, DynTimeScale::Ut1) => self.try_offset(Tcb, Ut1, delta),
331            (DynTimeScale::Tcg, DynTimeScale::Tai) => Ok(self.offset(Tcg, Tai, delta)),
332            (DynTimeScale::Tcg, DynTimeScale::Tcb) => Ok(self.offset(Tcg, Tcb, delta)),
333            (DynTimeScale::Tcg, DynTimeScale::Tdb) => Ok(self.offset(Tcg, Tdb, delta)),
334            (DynTimeScale::Tcg, DynTimeScale::Tt) => Ok(self.offset(Tcg, Tt, delta)),
335            (DynTimeScale::Tcg, DynTimeScale::Ut1) => self.try_offset(Tcg, Ut1, delta),
336            (DynTimeScale::Tdb, DynTimeScale::Tai) => Ok(self.offset(Tdb, Tai, delta)),
337            (DynTimeScale::Tdb, DynTimeScale::Tcb) => Ok(self.offset(Tdb, Tcb, delta)),
338            (DynTimeScale::Tdb, DynTimeScale::Tcg) => Ok(self.offset(Tdb, Tcg, delta)),
339            (DynTimeScale::Tdb, DynTimeScale::Tt) => Ok(self.offset(Tdb, Tt, delta)),
340            (DynTimeScale::Tdb, DynTimeScale::Ut1) => self.try_offset(Tdb, Ut1, delta),
341            (DynTimeScale::Tt, DynTimeScale::Tai) => Ok(self.offset(Tt, Tai, delta)),
342            (DynTimeScale::Tt, DynTimeScale::Tcb) => Ok(self.offset(Tt, Tcb, delta)),
343            (DynTimeScale::Tt, DynTimeScale::Tcg) => Ok(self.offset(Tt, Tcg, delta)),
344            (DynTimeScale::Tt, DynTimeScale::Tdb) => Ok(self.offset(Tt, Tdb, delta)),
345            (DynTimeScale::Tt, DynTimeScale::Ut1) => self.try_offset(Tt, Ut1, delta),
346            (DynTimeScale::Ut1, DynTimeScale::Tai) => self.try_offset(Ut1, Tai, delta),
347            (DynTimeScale::Ut1, DynTimeScale::Tcb) => self.try_offset(Ut1, Tcb, delta),
348            (DynTimeScale::Ut1, DynTimeScale::Tcg) => self.try_offset(Ut1, Tcg, delta),
349            (DynTimeScale::Ut1, DynTimeScale::Tdb) => self.try_offset(Ut1, Tdb, delta),
350            (DynTimeScale::Ut1, DynTimeScale::Tt) => self.try_offset(Ut1, Tt, delta),
351            (_, _) => Ok(TimeDelta::default()),
352        }
353    }
354}
355
356macro_rules! impl_dyn {
357    ($($scale:ident),*) => {
358        $(
359            impl<T> TryOffset<$scale, DynTimeScale> for T
360            where
361                T: OffsetProvider,
362            {
363                type Error = <Self as OffsetProvider>::Error;
364
365                fn try_offset(
366                    &self,
367                    origin: $scale,
368                    target: DynTimeScale,
369                    delta: TimeDelta,
370                ) -> Result<TimeDelta, Self::Error> {
371                    let origin: DynTimeScale = origin.into();
372                    self.try_offset(origin, target, delta)
373                }
374            }
375
376            impl<T> TryOffset<DynTimeScale, $scale> for T
377            where
378                T: OffsetProvider,
379            {
380                type Error = <Self as OffsetProvider>::Error;
381
382                fn try_offset(
383                    &self,
384                    origin: DynTimeScale,
385                    target: $scale,
386                    delta: TimeDelta,
387                ) -> Result<TimeDelta, Self::Error> {
388                    let target: DynTimeScale = target.into();
389                    self.try_offset(origin, target, delta)
390                }
391            }
392        )*
393    };
394}
395
396impl_dyn!(Tai, Tcb, Tcg, Tdb, Tt, Ut1);