Hi, I've just done one of the exercises from exercism: https://exercism.org/tracks/rust/exercises/space-age
Basically, given a time period in seconds, calculate the equivalent number of years for planets other than Earth based on their orbital period.
Since the only thing that really changes with each planet is that single variable, I tried solving it with the help of a macro, and was wondering what I could improve/do differently.
My solution
#[derive(Debug)]
pub struct Duration {
seconds: u64,
}
impl From<u64> for Duration {
fn from(s: u64) -> Self {
Self { seconds: s }
}
}
pub trait Planet {
fn orbital_period_in_earth_years() -> f64;
fn years_during(d: &Duration) -> f64 {
const DAYS_PER_EARTH_YEAR: f64 = 365.25;
const SECONDS_PER_DAY: f64 = 60.0 * 60.0 * 24.0;
const SECONDS_PER_YEAR: f64 = SECONDS_PER_DAY * DAYS_PER_EARTH_YEAR;
return d.seconds as f64 / SECONDS_PER_YEAR / Self::orbital_period_in_earth_years();
}
}
macro_rules! planet {
($name:ident, $period:expr) => {
pub struct $name;
impl $name {}
impl Planet for $name {
fn orbital_period_in_earth_years() -> f64 {
return $period;
}
}
};
}
planet!(Mercury, 0.2408467);
planet!(Venus, 0.61519726);
planet!(Earth, 1.0);
planet!(Mars, 1.8808158);
planet!(Jupiter, 11.862615);
planet!(Saturn, 29.447498);
planet!(Uranus, 84.016846);
planet!(Neptune, 164.79132);
The given test cases:
use space_age::*;
fn assert_in_delta(expected: f64, actual: f64) {
let diff: f64 = (expected - actual).abs();
let delta: f64 = 0.01;
if diff > delta {
panic!("Your result of {actual} should be within {delta} of the expected result {expected}")
}
}
#[test]
fn age_on_earth() {
let seconds = 1_000_000_000;
let duration = Duration::from(seconds);
let output = Earth::years_during(&duration);
let expected = 31.69;
assert_in_delta(expected, output);
}
#[test]
fn age_on_mercury() {
let seconds = 2_134_835_688;
let duration = Duration::from(seconds);
let output = Mercury::years_during(&duration);
let expected = 280.88;
assert_in_delta(expected, output);
}
#[test]
fn age_on_venus() {
let seconds = 189_839_836;
let duration = Duration::from(seconds);
let output = Venus::years_during(&duration);
let expected = 9.78;
assert_in_delta(expected, output);
}
#[test]
fn age_on_mars() {
let seconds = 2_129_871_239;
let duration = Duration::from(seconds);
let output = Mars::years_during(&duration);
let expected = 35.88;
assert_in_delta(expected, output);
}
#[test]
fn age_on_jupiter() {
let seconds = 901_876_382;
let duration = Duration::from(seconds);
let output = Jupiter::years_during(&duration);
let expected = 2.41;
assert_in_delta(expected, output);
}
#[test]
fn age_on_saturn() {
let seconds = 2_000_000_000;
let duration = Duration::from(seconds);
let output = Saturn::years_during(&duration);
let expected = 2.15;
assert_in_delta(expected, output);
}
#[test]
fn age_on_uranus() {
let seconds = 1_210_123_456;
let duration = Duration::from(seconds);
let output = Uranus::years_during(&duration);
let expected = 0.46;
assert_in_delta(expected, output);
}
#[test]
fn age_on_neptune() {
let seconds = 1_821_023_456;
let duration = Duration::from(seconds);
let output = Neptune::years_during(&duration);
let expected = 0.35;
assert_in_delta(expected, output);
}