Skip to content

Commit

Permalink
Merge pull request #65 from telus-agcg/feature/NAUM-6-to-fraction
Browse files Browse the repository at this point in the history
NAUM-6 Add v2::ToFraction
  • Loading branch information
turboladen authored May 14, 2024
2 parents c876b4f + db808b2 commit daede18
Show file tree
Hide file tree
Showing 17 changed files with 427 additions and 43 deletions.
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,12 @@ This feature is disabled by default. To enable it:
wise_units = { version = "0.22", features = ["serde"] }
```
### Feature `v2`
The `v2` feature makes some new traits available--traits that are "fixed" versions of existing
traits. Putting these behind this feature flag allows us to try out these new traits in downstream
crates before switching them to be the main traits in `wise_units`.
## Examples
A `Measurement` is made up of some quantifier, the `value`, and the unit of measure,
Expand Down
8 changes: 7 additions & 1 deletion crates/api/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,15 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
- PLCC-287: `impl num_traits::NumCast for Measurement`.
- PLCC-287: `impl num_traits::Pow<i32> for Measurement`, `Unit`, `Term`.
- PLCC-287: `impl std::ops::Neg for Measurement`.
- NAUM-5: Added `crate::Term::as_cow_str()`.
- NAUM-4: Derive `PartialOrd` for `Composition`
- NAUM-4: `impl From<Dimension> for Composition`
- NAUM-4: Derive `Hash` for `Property`
- NAUM-4: `impl PartialOrd for Term`
- NAUM-5: Added `crate::Term::as_cow_str()`.
- NAUM-6
- Add new `"v2"` feature.
- Add `v2::convert::ToFraction` trait.
- Implemented `v2::convert::ToFraction` trait for `Unit`, `Measurement`.
- Added `Unit::into_terms()` for cases where you only need the `Term`s of the `Unit`.
- Added `unit` constant: `UNITY`
- Added `term` constants: `UNITY`, `UNITY_ARRAY`, and `UNITY_ARRAY_REF`.
Expand Down Expand Up @@ -51,6 +55,8 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
- `ucum_symbol`
- (Internal) Moved `crate::parser` to `crate::unit::parser`.
- NAUM-5: (Internal) `Display` implementation for `Unit` now uses `Term::as_cow_str()` logic.
- NAUM-6: Updated `AsFraction::as_fraction()` implementation to iterate through `Term`s once instead
of twice for building the numerator and denominator.

### Deprecated

Expand Down
3 changes: 2 additions & 1 deletion crates/api/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ thiserror = "1.0"
[dev-dependencies]
bincode = "1.3"
criterion = "0.5"
lazy_static.workspace = true
rmp-serde = "1.0"
serde_json = "1.0"

Expand All @@ -31,6 +30,8 @@ default = []
# additional ffi module will be generated for each supported resource type.
cffi = ["ffi_common"]

v2 = []

[[bench]]
name = "measurements_benchmarks"
harness = false
Expand Down
2 changes: 1 addition & 1 deletion crates/api/src/composition.rs
Original file line number Diff line number Diff line change
Expand Up @@ -356,7 +356,7 @@ fn push_display_expression(
// ╰──────────╯
/// Used for combining two `Compositions`.
///
#[cfg_attr(feature = "cargo-clippy", allow(clippy::suspicious_arithmetic_impl))]
#[allow(clippy::suspicious_arithmetic_impl)]
impl Mul for Composition {
type Output = Self;

Expand Down
17 changes: 11 additions & 6 deletions crates/api/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,27 +21,32 @@
#[macro_use]
mod macros;

pub(crate) mod annotation_composition;
pub mod as_fraction;
pub mod atom;
pub mod classification;
mod composable;
pub mod composition;
pub mod convertible;
mod dimension;
pub mod error;
pub mod field_eq;
pub mod invert;
pub mod is_compatible_with;
pub mod measurement;
mod prefix;
pub mod property;
pub mod reduce;
pub(crate) mod term;
mod ucum_symbol;
pub mod unit;
#[cfg(feature = "v2")]
pub mod v2;

pub(crate) mod annotation_composition;
pub(crate) mod term;

mod composable;
mod dimension;
mod prefix;
mod reducible;
#[cfg(test)]
mod testing;
mod ucum_symbol;
mod ucum_unit;

pub use crate::{
Expand Down
2 changes: 1 addition & 1 deletion crates/api/src/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ macro_rules! terms {

#[cfg(test)]
mod tests {
use crate::{Term, Atom, Prefix};
use crate::{Atom, Prefix, Term};

#[test]
fn validate_term_macro() {
Expand Down
2 changes: 2 additions & 0 deletions crates/api/src/measurement.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ mod partial_ord;
mod reducible;
mod to_reduced;
mod ucum_unit;
#[cfg(feature = "v2")]
mod v2;

use crate::{reducible::Reducible, ucum_unit::UcumUnit, unit::Unit};

Expand Down
1 change: 1 addition & 0 deletions crates/api/src/measurement/v2.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
mod convert;
99 changes: 99 additions & 0 deletions crates/api/src/measurement/v2/convert.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
use crate::{unit, v2::convert::ToFraction, Measurement, Unit};

impl ToFraction<Self, Option<Unit>> for Measurement {
fn to_fraction(&self) -> (Self, Option<Unit>) {
let unit_parts = self.unit.to_fraction();

(
Self {
value: self.value,
unit: unit_parts.0.unwrap_or(unit::UNITY),
},
unit_parts.1,
)
}

fn to_numerator(&self) -> Self {
Self {
value: self.value,
unit: self.unit.to_numerator().unwrap_or(unit::UNITY),
}
}

fn to_denominator(&self) -> Option<Unit> {
self.unit.to_denominator()
}
}

#[cfg(test)]
mod tests {
use crate::{
testing::const_units::{GRAM_METER, METER, METER_PER_SECOND, PER_SECOND, SECOND},
unit::UNITY,
Measurement,
};

use super::*;

macro_rules! validate_fraction_parts {
(
$measurement:expr,
expected_numerator => $expected_numerator:expr,
expected_denominator => $expected_denominator:expr
) => {
let fraction = $measurement.to_fraction();
assert_eq!(&fraction.0, &$expected_numerator);
assert_eq!(fraction.1, $expected_denominator);

let numerator = $measurement.to_numerator();
assert_eq!(numerator, $expected_numerator);

let denominator = $measurement.to_denominator();
assert_eq!(denominator, $expected_denominator);
};
}

#[test]
fn validate_one_numerator_term() {
let measurement = Measurement::new(42.0, METER);

validate_fraction_parts!(
measurement,
expected_numerator => measurement,
expected_denominator => None
);
}

#[test]
fn validate_two_numerator_terms() {
let measurement = Measurement::new(42.0, GRAM_METER);

validate_fraction_parts!(
measurement,
expected_numerator => measurement,
expected_denominator => None
);
}

#[test]
fn validate_one_numerator_term_one_denominator_term() {
let measurement = Measurement::new(42.0, METER_PER_SECOND);

validate_fraction_parts!(
measurement,
expected_numerator => Measurement::new(42.0, METER),
expected_denominator => Some(SECOND)
);
}

#[test]
fn validate_one_denominator_term() {
let measurement = Measurement::new(42.0, PER_SECOND);

validate_fraction_parts!(
measurement,
expected_numerator => Measurement::new(42.0, UNITY),
expected_denominator => Some(SECOND)
);
}
}
112 changes: 112 additions & 0 deletions crates/api/src/testing.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
pub(crate) mod const_units {
use std::borrow::Cow;

use crate::{Atom, Prefix, Term, Unit};

pub(crate) const METER: Unit = Unit {
terms: Cow::Borrowed(&[Term {
factor: None,
prefix: None,
atom: Some(Atom::Meter),
exponent: None,
annotation: None,
}]),
};

pub(crate) const KILOMETER: Unit = Unit {
terms: Cow::Borrowed(&[Term {
factor: None,
prefix: Some(Prefix::Kilo),
atom: Some(Atom::Meter),
exponent: None,
annotation: None,
}]),
};

pub(crate) const GRAM_METER: Unit = Unit {
terms: Cow::Borrowed(&[
Term {
factor: None,
prefix: None,
atom: Some(Atom::Gram),
exponent: None,
annotation: None,
},
Term {
factor: None,
prefix: None,
atom: Some(Atom::Meter),
exponent: None,
annotation: None,
},
]),
};

pub(crate) const PER_GRAM_METER: Unit = Unit {
terms: Cow::Borrowed(&[
Term {
factor: None,
prefix: None,
atom: Some(Atom::Gram),
exponent: Some(-1),
annotation: None,
},
Term {
factor: None,
prefix: None,
atom: Some(Atom::Meter),
exponent: Some(-1),
annotation: None,
},
]),
};

pub(crate) const SECOND: Unit = Unit {
terms: Cow::Borrowed(&[Term {
factor: None,
prefix: None,
atom: Some(Atom::Second),
exponent: None,
annotation: None,
}]),
};

pub(crate) const PER_SECOND: Unit = Unit {
terms: Cow::Borrowed(&[Term {
factor: None,
prefix: None,
atom: Some(Atom::Second),
exponent: Some(-1),
annotation: None,
}]),
};

pub(crate) const METER_PER_SECOND: Unit = Unit {
terms: Cow::Borrowed(&[
Term {
factor: None,
prefix: None,
atom: Some(Atom::Meter),
exponent: None,
annotation: None,
},
Term {
factor: None,
prefix: None,
atom: Some(Atom::Second),
exponent: Some(-1),
annotation: None,
},
]),
};

pub(crate) const ACRE: Unit = Unit {
terms: Cow::Borrowed(&[Term {
factor: None,
prefix: None,
atom: Some(Atom::AcreUS),
exponent: None,
annotation: None,
}]),
};
}
4 changes: 3 additions & 1 deletion crates/api/src/unit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ mod partial_ord;
mod reducible;
mod term_reducing;
mod to_reduced;
#[cfg(feature = "v2")]
mod v2;

#[allow(clippy::module_name_repetitions)]
mod ucum_unit;
Expand Down Expand Up @@ -48,7 +50,7 @@ pub const UNITY: Unit = Unit {
)]
#[derive(Clone, Debug)]
pub struct Unit {
terms: Cow<'static, [Term]>,
pub(crate) terms: Cow<'static, [Term]>,
}

/// A `Unit` is the piece of data that represents a *valid* UCUM unit or
Expand Down
Loading

0 comments on commit daede18

Please sign in to comment.