erfa_rust/
G14_safe.rs

1// G14
2//   eqec06.c       → eraEqec06_safe
3//   eqeq94.c       → eraEqeq94_safe
4//   era00.c        → eraEra00_safe
5//   erfadatextra.c → eraGetLeapSeconds_safe, eraSetLeapSeconds_safe, eraDatini_safe
6//   erfaversion.c  → eraVersion_safe, eraVersionMajor_safe, eraVersionMinor_safe, eraVersionMicro_safe, eraSofaVersion_safe
7
8use std::sync::RwLock;
9
10use crate::G11_safe::eraEcm06_safe;
11use crate::G1_safe::{eraAnp_safe, eraAnpm_safe};
12use crate::G23_safe::{eraNut80_safe, eraObl80_safe};
13use crate::G28_safe::eraRxp_safe;
14use crate::G29_safe::eraS2c_safe;
15use crate::G7_safe::eraC2s_safe;
16use crate::H1_safe::{eraLEAPSECOND, ERFA_D2PI, ERFA_DAS2R, ERFA_DJ00, ERFA_DJC};
17
18pub type ErfaResult<T> = Result<T, ()>;
19
20// Built-in leap second table for initialization.
21const G14_BUILTIN_LEAPSECONDS: &[eraLEAPSECOND] = &[
22    eraLEAPSECOND {
23        iyear: 1960,
24        month: 1,
25        delat: 1.4178180,
26    },
27    eraLEAPSECOND {
28        iyear: 1961,
29        month: 1,
30        delat: 1.4228180,
31    },
32    eraLEAPSECOND {
33        iyear: 1961,
34        month: 8,
35        delat: 1.3728180,
36    },
37    eraLEAPSECOND {
38        iyear: 1962,
39        month: 1,
40        delat: 1.8458580,
41    },
42    eraLEAPSECOND {
43        iyear: 1963,
44        month: 11,
45        delat: 1.9458580,
46    },
47    eraLEAPSECOND {
48        iyear: 1964,
49        month: 1,
50        delat: 3.2401300,
51    },
52    eraLEAPSECOND {
53        iyear: 1964,
54        month: 4,
55        delat: 3.3401300,
56    },
57    eraLEAPSECOND {
58        iyear: 1964,
59        month: 9,
60        delat: 3.4401300,
61    },
62    eraLEAPSECOND {
63        iyear: 1965,
64        month: 1,
65        delat: 3.5401300,
66    },
67    eraLEAPSECOND {
68        iyear: 1965,
69        month: 3,
70        delat: 3.6401300,
71    },
72    eraLEAPSECOND {
73        iyear: 1965,
74        month: 7,
75        delat: 3.7401300,
76    },
77    eraLEAPSECOND {
78        iyear: 1965,
79        month: 9,
80        delat: 3.8401300,
81    },
82    eraLEAPSECOND {
83        iyear: 1966,
84        month: 1,
85        delat: 4.3131700,
86    },
87    eraLEAPSECOND {
88        iyear: 1968,
89        month: 2,
90        delat: 4.2131700,
91    },
92    eraLEAPSECOND {
93        iyear: 1972,
94        month: 1,
95        delat: 10.0,
96    },
97    eraLEAPSECOND {
98        iyear: 1972,
99        month: 7,
100        delat: 11.0,
101    },
102    eraLEAPSECOND {
103        iyear: 1973,
104        month: 1,
105        delat: 12.0,
106    },
107    eraLEAPSECOND {
108        iyear: 1974,
109        month: 1,
110        delat: 13.0,
111    },
112    eraLEAPSECOND {
113        iyear: 1975,
114        month: 1,
115        delat: 14.0,
116    },
117    eraLEAPSECOND {
118        iyear: 1976,
119        month: 1,
120        delat: 15.0,
121    },
122    eraLEAPSECOND {
123        iyear: 1977,
124        month: 1,
125        delat: 16.0,
126    },
127    eraLEAPSECOND {
128        iyear: 1978,
129        month: 1,
130        delat: 17.0,
131    },
132    eraLEAPSECOND {
133        iyear: 1979,
134        month: 1,
135        delat: 18.0,
136    },
137    eraLEAPSECOND {
138        iyear: 1980,
139        month: 1,
140        delat: 19.0,
141    },
142    eraLEAPSECOND {
143        iyear: 1981,
144        month: 7,
145        delat: 20.0,
146    },
147    eraLEAPSECOND {
148        iyear: 1982,
149        month: 7,
150        delat: 21.0,
151    },
152    eraLEAPSECOND {
153        iyear: 1983,
154        month: 7,
155        delat: 22.0,
156    },
157    eraLEAPSECOND {
158        iyear: 1985,
159        month: 7,
160        delat: 23.0,
161    },
162    eraLEAPSECOND {
163        iyear: 1988,
164        month: 1,
165        delat: 24.0,
166    },
167    eraLEAPSECOND {
168        iyear: 1990,
169        month: 1,
170        delat: 25.0,
171    },
172    eraLEAPSECOND {
173        iyear: 1991,
174        month: 1,
175        delat: 26.0,
176    },
177    eraLEAPSECOND {
178        iyear: 1992,
179        month: 7,
180        delat: 27.0,
181    },
182    eraLEAPSECOND {
183        iyear: 1993,
184        month: 7,
185        delat: 28.0,
186    },
187    eraLEAPSECOND {
188        iyear: 1994,
189        month: 7,
190        delat: 29.0,
191    },
192    eraLEAPSECOND {
193        iyear: 1996,
194        month: 1,
195        delat: 30.0,
196    },
197    eraLEAPSECOND {
198        iyear: 1997,
199        month: 7,
200        delat: 31.0,
201    },
202    eraLEAPSECOND {
203        iyear: 1999,
204        month: 1,
205        delat: 32.0,
206    },
207    eraLEAPSECOND {
208        iyear: 2006,
209        month: 1,
210        delat: 33.0,
211    },
212    eraLEAPSECOND {
213        iyear: 2009,
214        month: 1,
215        delat: 34.0,
216    },
217    eraLEAPSECOND {
218        iyear: 2012,
219        month: 7,
220        delat: 35.0,
221    },
222    eraLEAPSECOND {
223        iyear: 2015,
224        month: 7,
225        delat: 36.0,
226    },
227    eraLEAPSECOND {
228        iyear: 2017,
229        month: 1,
230        delat: 37.0,
231    },
232];
233
234// Minimal state for leap seconds.
235#[derive(Clone, Default)]
236struct LeapState {
237    ndat: i32,
238    table: Vec<eraLEAPSECOND>,
239}
240
241static LEAP_STATE: RwLock<LeapState> = RwLock::new(LeapState {
242    ndat: -1,
243    table: Vec::new(),
244});
245
246// G14/eqec06.c → eraEqec06_safe
247// ICRS equatorial to ecliptic (mean of date, IAU 2006).
248pub fn eraEqec06_safe(date1: f64, date2: f64, dr: f64, dd: f64) -> ErfaResult<(f64, f64)> {
249    let v1 = eraS2c_safe(dr, dd)?;
250    let mut rm = [[0.0_f64; 3]; 3];
251    eraEcm06_safe(date1, date2, &mut rm)?;
252    let v2 = eraRxp_safe(&rm, &v1)?;
253    let (a, b) = eraC2s_safe(&v2)?;
254    let dl = eraAnp_safe(a)?;
255    let db = eraAnpm_safe(b)?;
256    Ok((dl, db))
257}
258
259// G14/eqeq94.c → eraEqeq94_safe
260// Equation of the equinoxes, IAU 1994 model.
261pub fn eraEqeq94_safe(date1: f64, date2: f64) -> ErfaResult<f64> {
262    let t = ((date1 - ERFA_DJ00) + date2) / ERFA_DJC;
263    let a = -5.0 * t;
264    let fmod1 = a - a.trunc();
265    let om = eraAnpm_safe(
266        (450_160.280 + (-482_890.539 + (7.455 + 0.008 * t) * t) * t) * ERFA_DAS2R
267            + fmod1 * ERFA_D2PI,
268    )?;
269    let (dpsi, _deps) = eraNut80_safe(date1, date2)?;
270    let eps0 = eraObl80_safe(date1, date2)?;
271    let ee = dpsi * eps0.cos() + ERFA_DAS2R * (0.00264 * om.sin() + 0.000_063 * (2.0 * om).sin());
272    Ok(ee)
273}
274
275// G14/era00.c → eraEra00_safe
276// Earth rotation angle (IAU 2000), radians in range 0..2π.
277pub fn eraEra00_safe(dj1: f64, dj2: f64) -> ErfaResult<f64> {
278    let (d1, d2) = if dj1 < dj2 { (dj1, dj2) } else { (dj2, dj1) };
279    let t = d1 + (d2 - ERFA_DJ00);
280    let f1 = d1 - d1.trunc();
281    let f2 = d2 - d2.trunc();
282    let f = f1 + f2;
283    let theta = eraAnp_safe(ERFA_D2PI * (f + 0.779_057_273_264_0 + 0.002_737_811_911_354_48 * t))?;
284    Ok(theta)
285}
286
287// G14/erfadatextra.c → eraGetLeapSeconds_safe
288// Return current leap-second table (copy); init to builtin if needed.
289pub fn eraGetLeapSeconds_safe() -> ErfaResult<Vec<eraLEAPSECOND>> {
290    {
291        let guard = LEAP_STATE.read().map_err(|_| ())?;
292        if guard.ndat > 0 {
293            return Ok(guard.table.clone());
294        }
295    }
296    let _ = eraDatini_safe(G14_BUILTIN_LEAPSECONDS)?;
297    let guard = LEAP_STATE.read().map_err(|_| ())?;
298    if guard.ndat > 0 {
299        Ok(guard.table.clone())
300    } else {
301        Err(())
302    }
303}
304
305// G14/erfadatextra.c → eraSetLeapSeconds_safe
306// Replace current leap-second table; empty slice marks reset-to-builtin.
307pub fn eraSetLeapSeconds_safe(table: &[eraLEAPSECOND]) -> ErfaResult<()> {
308    let mut guard = LEAP_STATE.write().map_err(|_| ())?;
309    if table.is_empty() {
310        guard.table.clear();
311        guard.ndat = 0;
312    } else {
313        guard.table = table.to_vec();
314        guard.ndat = guard.table.len() as i32;
315    }
316    Ok(())
317}
318
319// G14/erfadatextra.c → eraDatini_safe
320// Ensure table is initialized to builtin if needed; return current copy.
321pub fn eraDatini_safe(builtin: &[eraLEAPSECOND]) -> ErfaResult<Vec<eraLEAPSECOND>> {
322    let mut guard = LEAP_STATE.write().map_err(|_| ())?;
323    if guard.ndat <= 0 {
324        guard.table = builtin.to_vec();
325        guard.ndat = guard.table.len() as i32;
326    }
327    Ok(guard.table.clone())
328}
329
330// G14/erfaversion.c → version helpers
331// Return crate version string.
332pub fn eraVersion_safe() -> &'static str {
333    env!("CARGO_PKG_VERSION")
334}
335
336// Return major version number.
337pub fn eraVersionMajor_safe() -> i32 {
338    let v = env!("CARGO_PKG_VERSION");
339    v.split('.')
340        .next()
341        .unwrap_or("0")
342        .parse::<i32>()
343        .unwrap_or(0)
344}
345
346// Return minor version number.
347pub fn eraVersionMinor_safe() -> i32 {
348    let v = env!("CARGO_PKG_VERSION");
349    v.split('.')
350        .nth(1)
351        .unwrap_or("0")
352        .parse::<i32>()
353        .unwrap_or(0)
354}
355
356// Return micro/patch version number.
357pub fn eraVersionMicro_safe() -> i32 {
358    let v = env!("CARGO_PKG_VERSION");
359    v.split('.')
360        .nth(2)
361        .unwrap_or("0")
362        .parse::<i32>()
363        .unwrap_or(0)
364}
365
366// Return upstream SOFA version string (not tracked in this port).
367pub fn eraSofaVersion_safe() -> &'static str {
368    "unknown"
369}