#![forbid(unsafe_code)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct CorrectionPolicy(u8);
impl CorrectionPolicy {
pub const GEOMETRIC: Self = Self(0);
pub const PROPER_MOTION: Self = Self(1 << 0);
pub const LIGHT_TIME: Self = Self(1 << 1);
pub const ABERRATION: Self = Self(1 << 2);
pub const LIGHT_DEFLECTION: Self = Self(1 << 3);
pub const APPARENT: Self = Self(
Self::PROPER_MOTION.0 | Self::LIGHT_TIME.0 | Self::ABERRATION.0 | Self::LIGHT_DEFLECTION.0,
);
pub const fn contains(self, other: Self) -> bool {
(self.0 & other.0) == other.0
}
pub const fn union(self, other: Self) -> Self {
Self(self.0 | other.0)
}
pub const fn bits(self) -> u8 {
self.0
}
}
impl core::ops::BitOr for CorrectionPolicy {
type Output = Self;
fn bitor(self, rhs: Self) -> Self {
self.union(rhs)
}
}
impl core::ops::BitOrAssign for CorrectionPolicy {
fn bitor_assign(&mut self, rhs: Self) {
self.0 |= rhs.0;
}
}
impl Default for CorrectionPolicy {
fn default() -> Self {
Self::GEOMETRIC
}
}
pub const CORRECTION_ORDER: [CorrectionPolicy; 4] = [
CorrectionPolicy::PROPER_MOTION,
CorrectionPolicy::LIGHT_TIME,
CorrectionPolicy::ABERRATION,
CorrectionPolicy::LIGHT_DEFLECTION,
];
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CorrectionOrder {
Canonical,
}
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
pub struct AppliedCorrections {
pub requested: CorrectionPolicy,
pub applied: CorrectionPolicy,
pub light_time_iters: u8,
}
impl AppliedCorrections {
pub fn from_request(requested: CorrectionPolicy) -> Self {
Self {
requested,
applied: CorrectionPolicy::GEOMETRIC,
light_time_iters: 0,
}
}
pub fn record(&mut self, stage: CorrectionPolicy) {
self.applied |= stage;
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn default_policy_is_geometric() {
assert_eq!(CorrectionPolicy::default(), CorrectionPolicy::GEOMETRIC);
}
#[test]
fn apparent_policy_includes_all_stages() {
let p = CorrectionPolicy::APPARENT;
for stage in CORRECTION_ORDER {
assert!(p.contains(stage), "{stage:?} missing from APPARENT");
}
}
#[test]
fn record_accumulates_applied_stages() {
let mut r = AppliedCorrections::from_request(CorrectionPolicy::APPARENT);
assert_eq!(r.applied, CorrectionPolicy::GEOMETRIC);
r.record(CorrectionPolicy::ABERRATION);
r.record(CorrectionPolicy::LIGHT_TIME);
assert!(r.applied.contains(CorrectionPolicy::ABERRATION));
assert!(r.applied.contains(CorrectionPolicy::LIGHT_TIME));
assert!(!r.applied.contains(CorrectionPolicy::LIGHT_DEFLECTION));
}
#[test]
fn correction_order_is_canonical_and_complete() {
assert_eq!(CORRECTION_ORDER[0], CorrectionPolicy::PROPER_MOTION);
assert_eq!(CORRECTION_ORDER[1], CorrectionPolicy::LIGHT_TIME);
assert_eq!(CORRECTION_ORDER[2], CorrectionPolicy::ABERRATION);
assert_eq!(CORRECTION_ORDER[3], CorrectionPolicy::LIGHT_DEFLECTION);
}
}