1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
//! Per-row observer resolution from Polars observer columns.
//!
//! This module converts the nullable observer columns extracted from a Polars
//! [`DataFrame`](polars::frame::DataFrame) into typed observer identities.
//! It is used exclusively by the ingestion pipeline in
//! [`crate::io::polars`].
//!
//! ## Resolution rules
//!
//! For each row the columns are examined in the following precedence order:
//!
//! 1. `mpc_code_obs` non-null → [`ResolvedObserver::Mpc`] (three-byte ASCII
//! code; takes precedence over the geodetic triplet).
//! 2. `obs_lon`, `obs_lat`, and `obs_alt` all non-null → [`ResolvedObserver::Geodetic`]
//! (custom ground-based site; `obs_ra_acc` and `obs_dec_acc` must also be
//! non-null).
//! 3. All observer columns null or absent → [`ResolvedObserver::None`].
//!
//! A partially-null geodetic triplet (one or two columns present, the others
//! absent) is always rejected with [`crate::io::polars::error::PolarsError::PartialTripletNull`].
//!
//! ## Public items
//!
//! | Item | Kind | Description |
//! |------|------|-------------|
//! | [`RawObsRow`] | struct | Data carrier holding the nullable observer inputs for one row |
//! | [`ResolvedObserver`] | enum | Typed observer identity returned by [`resolve_observer`] |
//! | [`resolve_observer`] | fn (pub crate) | Resolve one row's observer columns into a [`ResolvedObserver`] |
// ── per-row observer resolution ───────────────────────────────────────────────
use crate::;
/// All nullable observer inputs for one row, already extracted from the
/// [`ChunkedArray`](polars::prelude::ChunkedArray)s.
///
/// This struct is a plain data carrier used exclusively by
/// [`resolve_observer`]. Each field corresponds to one observer column in
/// the source [`DataFrame`]; a value of `None` means the cell was `null` or
/// the column was absent from the frame.
///
/// The lifetime `'df` is tied to the source [`DataFrame`]: the `mpc_code`
/// field borrows string data directly from Polars' internal memory so that no
/// per-row heap allocation is needed for the common case of an absent or null
/// MPC code.
pub
/// Result of resolving one row's observer fields into a typed observer
/// identity.
///
/// [`resolve_observer`] returns one of these three variants depending on
/// which observer columns were populated for the row.
/// Resolve the observer for a single row according to the column precedence
/// rules.
///
/// The resolution is applied in the following order:
///
/// 1. If `mpc_code` is non-null it takes precedence over the geodetic triplet
/// regardless of whether the triplet columns are also populated.
/// 2. If `mpc_code` is null and the geodetic triplet (`obs_lon`, `obs_lat`,
/// `obs_alt`) is fully non-null, a custom [`Observer`] is constructed.
/// `obs_ra_acc` and `obs_dec_acc` must also be non-null in this case.
/// 3. If `mpc_code` is null and the geodetic triplet is entirely null (or all
/// three columns were absent from the frame), the observer is
/// [`ResolvedObserver::None`].
/// 4. A partially-null geodetic triplet — where one or two of the three
/// columns are non-null — is always an error regardless of the other
/// fields.
///
/// # Arguments
///
/// - `row` — the nullable observer values for this row.
/// - `row_idx` — zero-based row index, used in error messages.
///
/// # Returns
///
/// A [`ResolvedObserver`] variant describing the observer for this row.
///
/// # Errors
///
/// - [`PolarsError::InvalidMpcCode`] if `mpc_code` is non-null but is not
/// exactly three ASCII bytes.
/// - [`PolarsError::MissingAccuracyForGeodesic`] if the geodetic triplet is
/// fully non-null but `obs_ra_acc` or `obs_dec_acc` is `null`.
/// - [`PolarsError::PartialTripletNull`] if exactly one or two of the three
/// geodetic columns are non-null.
/// - [`PolarsError::DataConversionError`] if [`Observer::new`] rejects the
/// coordinate values (e.g. a `NaN` was encountered).
pub