Skip to content

Commit

Permalink
Fix compilation failures and partially test
Browse files Browse the repository at this point in the history
  • Loading branch information
AngusGMorrison committed Jan 20, 2024
1 parent e77c922 commit 5ddee45
Show file tree
Hide file tree
Showing 9 changed files with 712 additions and 270 deletions.
17 changes: 8 additions & 9 deletions crates/lox_core/src/earth/nutation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use crate::earth::nutation::iau2000::nutation_iau2000a;
use crate::earth::nutation::iau2000::nutation_iau2000b;
use crate::earth::nutation::iau2006::nutation_iau2006a;
use crate::math::RADIANS_IN_ARCSECOND;
use crate::time::continuous::Time;
use crate::time::continuous::ContinuousTime;
use crate::time::intervals::tdb_julian_centuries_since_j2000;
use crate::types::Radians;

Expand Down Expand Up @@ -64,7 +64,7 @@ impl Add<&Self> for Nutation {
}

/// Calculate nutation coefficients at `epoch` using the given [Model].
pub fn nutation(model: Model, epoch: Time) -> Nutation {
pub fn nutation(model: Model, epoch: ContinuousTime) -> Nutation {
let t = tdb_julian_centuries_since_j2000(epoch);
match model {
Model::IAU1980 => nutation_iau1980(t),
Expand Down Expand Up @@ -98,17 +98,16 @@ fn point1_microarcsec_to_rad(p1_uas: Point1Microarcsec) -> Radians {

#[cfg(test)]
mod tests {
use crate::time::continuous::ContinuousTimeScale;
use float_eq::assert_float_eq;

use crate::time::scales::TimeScale;


use super::*;

const TOLERANCE: f64 = 1e-12;

#[test]
fn test_nutation_iau1980() {
let epoch = Time::j2000(TimeScale::TT);
let epoch = ContinuousTime::j2000(ContinuousTimeScale::TT);
let expected = Nutation {
longitude: -0.00006750247617532478,
obliquity: -0.00002799221238377013,
Expand All @@ -119,7 +118,7 @@ mod tests {
}
#[test]
fn test_nutation_iau2000a() {
let epoch = Time::j2000(TimeScale::TT);
let epoch = ContinuousTime::j2000(ContinuousTimeScale::TT);
let expected = Nutation {
longitude: -0.00006754422426417299,
obliquity: -0.00002797083119237414,
Expand All @@ -131,7 +130,7 @@ mod tests {

#[test]
fn test_nutation_iau2000b() {
let epoch = Time::j2000(TimeScale::TT);
let epoch = ContinuousTime::j2000(ContinuousTimeScale::TT);
let expected = Nutation {
longitude: -0.00006754261253992235,
obliquity: -0.00002797092331098565,
Expand All @@ -143,7 +142,7 @@ mod tests {

#[test]
fn test_nutation_iau2006a() {
let epoch = Time::j2000(TimeScale::TT);
let epoch = ContinuousTime::j2000(ContinuousTimeScale::TT);
let expected = Nutation {
longitude: -0.00006754425598969513,
obliquity: -0.00002797083119237414,
Expand Down
4 changes: 2 additions & 2 deletions crates/lox_core/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ pub enum LoxError {
InvalidTime(u8, u8, u8),
#[error("seconds must be in the range [0.0, 60.0], but was `{0}`")]
InvalidSeconds(f64),
#[error("thousandths must be in the range [0, 999], but was `{0}`")]
InvalidThousandths(u16),
#[error("PerMille value must be in the range [0, 999], but was `{0}`")]
InvalidPerMille(u16),
#[error("day of year cannot be 366 for a non-leap year")]
NonLeapYear,
}
90 changes: 57 additions & 33 deletions crates/lox_core/src/time.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,84 +7,108 @@
*/

use crate::errors::LoxError;
use crate::time::dates::Date;
use crate::time::scales::TimeScale;
use std::fmt::Display;
use std::fmt;
use std::fmt::{Display, Formatter};

pub mod constants;
pub mod continuous;
pub mod dates;
pub mod intervals;
pub mod leap_seconds;
pub mod scales;
pub mod utc;

/// The time scales supported by Lox.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum TimeScale {
TAI,
TCB,
TCG,
TDB,
TT,
UT1,
UTC,
}

impl Display for TimeScale {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self {
TimeScale::TAI => write!(f, "TAI"),
TimeScale::TCB => write!(f, "TCB"),
TimeScale::TCG => write!(f, "TCG"),
TimeScale::TDB => write!(f, "TDB"),
TimeScale::TT => write!(f, "TT"),
TimeScale::UT1 => write!(f, "UT1"),
TimeScale::UTC => write!(f, "UTC"),
}
}
}

/// `WallClock` is the trait by which high-precision time representations expose human-readable time components.
///
/// The components returned by a `WallClock` must be interpreted in terms of its [TimeScale]. For example, a UTC
/// `WallClock` will have a `second` component of 60 during a leap second.
pub trait WallClock {
fn scale(&self) -> TimeScale;
fn hour(&self) -> u8;
fn minute(&self) -> u8;
fn second(&self) -> u8;
fn millisecond(&self) -> Thousandths;
fn microsecond(&self) -> Thousandths;
fn nanosecond(&self) -> Thousandths;
fn picosecond(&self) -> Thousandths;
fn femtosecond(&self) -> Thousandths;
fn attosecond(&self) -> Thousandths;
fn hour(&self) -> i64;
fn minute(&self) -> i64;
fn second(&self) -> i64;
fn millisecond(&self) -> i64;
fn microsecond(&self) -> i64;
fn nanosecond(&self) -> i64;
fn picosecond(&self) -> i64;
fn femtosecond(&self) -> i64;
fn attosecond(&self) -> i64;
}

/// Newtype wrapper for thousandths of an SI-prefixed subsecond (milli, micro, nano, etc.).
#[repr(transparent)]
#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct Thousandths(u16);
pub struct PerMille(u16);

impl Thousandths {
pub fn new(thousandths: u16) -> Result<Self, LoxError> {
if !(0..1000).contains(&thousandths) {
Err(LoxError::InvalidThousandths(thousandths))
impl PerMille {
pub fn new(per_mille: u16) -> Result<Self, LoxError> {
if !(0..1000).contains(&per_mille) {
Err(LoxError::InvalidPerMille(per_mille))
} else {
Ok(Self(thousandths))
Ok(Self(per_mille))
}
}
}

impl Display for Thousandths {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
impl Display for PerMille {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "{:03}", self.0)
}
}

impl TryFrom<u16> for Thousandths {
impl TryFrom<u16> for PerMille {
type Error = LoxError;

fn try_from(thousandths: u16) -> Result<Self, Self::Error> {
Self::new(thousandths)
fn try_from(per_mille: u16) -> Result<Self, Self::Error> {
Self::new(per_mille)
}
}

#[allow(clippy::from_over_into)] // the Into conversion is infallible, but From is not
impl Into<u64> for Thousandths {
fn into(self) -> u64 {
self.0 as u64
impl Into<i64> for PerMille {
fn into(self) -> i64 {
self.0 as i64
}
}

#[cfg(test)]
mod thousandths_tests {
use crate::time::Thousandths;
mod per_mille_tests {
use crate::time::PerMille;

#[test]
fn test_new_valid() {
assert!(Thousandths::new(0).is_ok());
assert!(Thousandths::new(999).is_ok());
assert!(PerMille::new(0).is_ok());
assert!(PerMille::new(999).is_ok());
}

#[test]
fn test_new_invalid() {
assert!(Thousandths::new(1000).is_err());
assert!(Thousandths::new(1001).is_err());
assert!(PerMille::new(1000).is_err());
assert!(PerMille::new(1001).is_err());
}
}
Loading

0 comments on commit 5ddee45

Please sign in to comment.