siderust-js 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/ci.yml +166 -0
- package/.gitmodules +9 -0
- package/CHANGELOG.md +26 -0
- package/LICENSE +661 -0
- package/README.md +138 -0
- package/package.json +12 -0
- package/qtty-js/.github/workflows/ci.yml +151 -0
- package/qtty-js/.gitmodules +3 -0
- package/qtty-js/CHANGELOG.md +31 -0
- package/qtty-js/LICENSE +661 -0
- package/qtty-js/README.md +132 -0
- package/qtty-js/package.json +20 -0
- package/qtty-js/qtty/.github/workflows/ci.yml +155 -0
- package/qtty-js/qtty/CHANGELOG.md +120 -0
- package/qtty-js/qtty/Cargo.lock +1462 -0
- package/qtty-js/qtty/Cargo.toml +12 -0
- package/qtty-js/qtty/LICENSE +661 -0
- package/qtty-js/qtty/README.md +9 -0
- package/qtty-js/qtty/qtty/Cargo.toml +41 -0
- package/qtty-js/qtty/qtty/README.md +8 -0
- package/qtty-js/qtty/qtty/examples/angles.rs +14 -0
- package/qtty-js/qtty/qtty/examples/astronomy.rs +17 -0
- package/qtty-js/qtty/qtty/examples/dimensional_arithmetic.rs +83 -0
- package/qtty-js/qtty/qtty/examples/python_integration.rs +61 -0
- package/qtty-js/qtty/qtty/examples/quickstart.rs +15 -0
- package/qtty-js/qtty/qtty/examples/ratios.rs +12 -0
- package/qtty-js/qtty/qtty/examples/serde_with_unit.rs +234 -0
- package/qtty-js/qtty/qtty/examples/serialization.rs +141 -0
- package/qtty-js/qtty/qtty/examples/serialization_advanced.rs +155 -0
- package/qtty-js/qtty/qtty/src/f32.rs +108 -0
- package/qtty-js/qtty/qtty/src/f64.rs +30 -0
- package/qtty-js/qtty/qtty/src/i128.rs +111 -0
- package/qtty-js/qtty/qtty/src/i16.rs +111 -0
- package/qtty-js/qtty/qtty/src/i32.rs +111 -0
- package/qtty-js/qtty/qtty/src/i64.rs +111 -0
- package/qtty-js/qtty/qtty/src/i8.rs +111 -0
- package/qtty-js/qtty/qtty/src/lib.rs +238 -0
- package/qtty-js/qtty/qtty/tests/fixtures/qtty-vec-no-std/Cargo.lock +83 -0
- package/qtty-js/qtty/qtty/tests/fixtures/qtty-vec-no-std/Cargo.toml +10 -0
- package/qtty-js/qtty/qtty/tests/fixtures/qtty-vec-no-std/src/lib.rs +7 -0
- package/qtty-js/qtty/qtty/tests/fixtures/qtty-vec-no-std-alloc/Cargo.lock +83 -0
- package/qtty-js/qtty/qtty/tests/fixtures/qtty-vec-no-std-alloc/Cargo.toml +10 -0
- package/qtty-js/qtty/qtty/tests/fixtures/qtty-vec-no-std-alloc/src/lib.rs +7 -0
- package/qtty-js/qtty/qtty/tests/fixtures/qtty-vec-std/Cargo.lock +83 -0
- package/qtty-js/qtty/qtty/tests/fixtures/qtty-vec-std/Cargo.toml +10 -0
- package/qtty-js/qtty/qtty/tests/fixtures/qtty-vec-std/src/lib.rs +5 -0
- package/qtty-js/qtty/qtty/tests/integration_tests.rs +529 -0
- package/qtty-js/qtty/qtty/tests/qtty_vec_feature_matrix.rs +58 -0
- package/qtty-js/qtty/qtty-core/Cargo.toml +41 -0
- package/qtty-js/qtty/qtty-core/README.md +8 -0
- package/qtty-js/qtty/qtty-core/examples/diesel_integration.rs +145 -0
- package/qtty-js/qtty/qtty-core/examples/quantity_db_serde.rs +215 -0
- package/qtty-js/qtty/qtty-core/src/dimension.rs +249 -0
- package/qtty-js/qtty/qtty-core/src/feature_diesel.rs +318 -0
- package/qtty-js/qtty/qtty-core/src/feature_pyo3.rs +27 -0
- package/qtty-js/qtty/qtty-core/src/feature_serde.rs +203 -0
- package/qtty-js/qtty/qtty-core/src/feature_tiberius.rs +28 -0
- package/qtty-js/qtty/qtty-core/src/lib.rs +744 -0
- package/qtty-js/qtty/qtty-core/src/macros.rs +93 -0
- package/qtty-js/qtty/qtty-core/src/quantity.rs +810 -0
- package/qtty-js/qtty/qtty-core/src/scalar.rs +1742 -0
- package/qtty-js/qtty/qtty-core/src/unit.rs +332 -0
- package/qtty-js/qtty/qtty-core/src/units/angular.rs +1228 -0
- package/qtty-js/qtty/qtty-core/src/units/area.rs +243 -0
- package/qtty-js/qtty/qtty-core/src/units/frequency.rs +179 -0
- package/qtty-js/qtty/qtty-core/src/units/length.rs +1270 -0
- package/qtty-js/qtty/qtty-core/src/units/mass.rs +488 -0
- package/qtty-js/qtty/qtty-core/src/units/mod.rs +26 -0
- package/qtty-js/qtty/qtty-core/src/units/power.rs +324 -0
- package/qtty-js/qtty/qtty-core/src/units/time.rs +667 -0
- package/qtty-js/qtty/qtty-core/src/units/unitless.rs +212 -0
- package/qtty-js/qtty/qtty-core/src/units/velocity.rs +210 -0
- package/qtty-js/qtty/qtty-core/src/units/volume.rs +269 -0
- package/qtty-js/qtty/qtty-core/tests/core.rs +628 -0
- package/qtty-js/qtty/qtty-core/tests/diesel.rs +461 -0
- package/qtty-js/qtty/qtty-core/tests/integers.rs +632 -0
- package/qtty-js/qtty/qtty-core/tests/no_cross_unit_ops.rs +35 -0
- package/qtty-js/qtty/qtty-core/tests/pyo3.rs +334 -0
- package/qtty-js/qtty/qtty-core/tests/quantity_f32.rs +276 -0
- package/qtty-js/qtty/qtty-core/tests/scalar_decimal.rs +258 -0
- package/qtty-js/qtty/qtty-core/tests/scalar_f32.rs +286 -0
- package/qtty-js/qtty/qtty-core/tests/scalar_f64_real.rs +287 -0
- package/qtty-js/qtty/qtty-core/tests/scalar_rational.rs +260 -0
- package/qtty-js/qtty/qtty-core/tests/serde.rs +256 -0
- package/qtty-js/qtty/qtty-core/tests/tiberius.rs +208 -0
- package/qtty-js/qtty/qtty-derive/Cargo.toml +23 -0
- package/qtty-js/qtty/qtty-derive/README.md +8 -0
- package/qtty-js/qtty/qtty-derive/src/lib.rs +340 -0
- package/qtty-js/qtty/qtty-ffi/ARCHITECTURE.md +3 -0
- package/qtty-js/qtty/qtty-ffi/Cargo.toml +31 -0
- package/qtty-js/qtty/qtty-ffi/README.md +9 -0
- package/qtty-js/qtty/qtty-ffi/build.rs +326 -0
- package/qtty-js/qtty/qtty-ffi/cbindgen.toml +105 -0
- package/qtty-js/qtty/qtty-ffi/include/qtty_ffi.h +1126 -0
- package/qtty-js/qtty/qtty-ffi/src/ffi.rs +1251 -0
- package/qtty-js/qtty/qtty-ffi/src/ffi_serde.rs +294 -0
- package/qtty-js/qtty/qtty-ffi/src/helpers.rs +310 -0
- package/qtty-js/qtty/qtty-ffi/src/lib.rs +229 -0
- package/qtty-js/qtty/qtty-ffi/src/macros.rs +121 -0
- package/qtty-js/qtty/qtty-ffi/src/registry.rs +274 -0
- package/qtty-js/qtty/qtty-ffi/src/types.rs +620 -0
- package/qtty-js/qtty/qtty-ffi/tests/integration_tests.rs +842 -0
- package/qtty-js/qtty/qtty-ffi/units.csv +156 -0
- package/qtty-js/qtty/qtty-ffi/units.csv.md +3 -0
- package/qtty-js/qtty-node/.prettierignore +6 -0
- package/qtty-js/qtty-node/.prettierrc.json +6 -0
- package/qtty-js/qtty-node/README.md +250 -0
- package/qtty-js/qtty-node/c8.config.json +11 -0
- package/qtty-js/qtty-node/eslint.config.js +31 -0
- package/qtty-js/qtty-node/examples/arithmetic.mjs +64 -0
- package/qtty-js/qtty-node/examples/astronomy.mjs +90 -0
- package/qtty-js/qtty-node/examples/quickstart.mjs +36 -0
- package/qtty-js/qtty-node/examples/serialization.mjs +125 -0
- package/qtty-js/qtty-node/examples/unit_factories.mjs +74 -0
- package/qtty-js/qtty-node/index.d.ts +219 -0
- package/qtty-js/qtty-node/index.js +323 -0
- package/qtty-js/qtty-node/lib/DerivedQuantity.js +122 -0
- package/qtty-js/qtty-node/lib/Quantity.js +151 -0
- package/qtty-js/qtty-node/lib/backend.js +25 -0
- package/qtty-js/qtty-node/native.cjs +306 -0
- package/qtty-js/qtty-node/package-lock.json +3223 -0
- package/qtty-js/qtty-node/package.json +70 -0
- package/qtty-js/qtty-node/units.d.ts +299 -0
- package/qtty-js/qtty-node/units.js +210 -0
- package/qtty-js/qtty-web/Cargo.lock +767 -0
- package/qtty-js/qtty-web/Cargo.toml +21 -0
- package/qtty-js/qtty-web/index.d.ts +140 -0
- package/qtty-js/qtty-web/index.js +20 -0
- package/qtty-js/qtty-web/lib/DerivedQuantity.js +58 -0
- package/qtty-js/qtty-web/lib/Quantity.js +75 -0
- package/qtty-js/qtty-web/lib/backend.js +80 -0
- package/qtty-js/qtty-web/package.json +45 -0
- package/qtty-js/qtty-web/src/lib.rs +111 -0
- package/qtty-js/scripts/ci.sh +73 -0
- package/scripts/ci.sh +123 -0
- package/siderust-core/Cargo.lock +787 -0
- package/siderust-core/Cargo.toml +18 -0
- package/siderust-core/DEDUPLICATION.md +124 -0
- package/siderust-core/src/body.rs +120 -0
- package/siderust-core/src/events.rs +184 -0
- package/siderust-core/src/lib.rs +20 -0
- package/siderust-core/src/observer.rs +55 -0
- package/siderust-core/src/position.rs +213 -0
- package/siderust-node/.prettierignore +7 -0
- package/siderust-node/.prettierrc.json +6 -0
- package/siderust-node/Cargo.lock +906 -0
- package/siderust-node/Cargo.toml +29 -0
- package/siderust-node/README.md +109 -0
- package/siderust-node/__test__/index.test.mjs +248 -0
- package/siderust-node/build.rs +5 -0
- package/siderust-node/c8.config.json +3 -0
- package/siderust-node/eslint.config.js +31 -0
- package/siderust-node/examples/01_basic_coordinates.mjs +24 -0
- package/siderust-node/examples/02_coordinate_transformations.mjs +25 -0
- package/siderust-node/examples/03_all_frames_conversions.mjs +26 -0
- package/siderust-node/examples/04_all_center_conversions.mjs +24 -0
- package/siderust-node/examples/05_target_tracking.mjs +22 -0
- package/siderust-node/examples/06_night_events.mjs +18 -0
- package/siderust-node/examples/07_moon_properties.mjs +21 -0
- package/siderust-node/examples/08_solar_system.mjs +19 -0
- package/siderust-node/examples/09_star_observability.mjs +22 -0
- package/siderust-node/examples/10_time_periods.mjs +9 -0
- package/siderust-node/examples/11_serialization.mjs +31 -0
- package/siderust-node/examples/12_runtime_ephemeris.mjs +27 -0
- package/siderust-node/examples/13_coordinate_operations.mjs +20 -0
- package/siderust-node/index.d.ts +623 -0
- package/siderust-node/index.js +79 -0
- package/siderust-node/lib/Observer.js +112 -0
- package/siderust-node/lib/Star.js +118 -0
- package/siderust-node/lib/backend.js +63 -0
- package/siderust-node/lib/wrappers.js +566 -0
- package/siderust-node/main.js +20 -0
- package/siderust-node/native.cjs +360 -0
- package/siderust-node/package-lock.json +3261 -0
- package/siderust-node/package.json +71 -0
- package/siderust-node/src/body.rs +74 -0
- package/siderust-node/src/coordinates.rs +372 -0
- package/siderust-node/src/ephemeris.rs +462 -0
- package/siderust-node/src/events.rs +577 -0
- package/siderust-node/src/lib.rs +43 -0
- package/siderust-node/src/observer.rs +132 -0
- package/siderust-node/src/phase.rs +218 -0
- package/siderust-node/src/position.rs +292 -0
- package/siderust-node/src/star.rs +200 -0
- package/siderust-web/Cargo.lock +855 -0
- package/siderust-web/Cargo.toml +34 -0
- package/siderust-web/README.md +100 -0
- package/siderust-web/__test__/index.test.mjs +118 -0
- package/siderust-web/examples/github-pages/README.md +31 -0
- package/siderust-web/examples/github-pages/index.html +135 -0
- package/siderust-web/index.d.ts +311 -0
- package/siderust-web/index.js +66 -0
- package/siderust-web/lib/Observer.js +103 -0
- package/siderust-web/lib/Star.js +116 -0
- package/siderust-web/lib/backend.js +400 -0
- package/siderust-web/lib/wrappers.js +512 -0
- package/siderust-web/package.json +55 -0
- package/siderust-web/src/body.rs +69 -0
- package/siderust-web/src/coordinates.rs +302 -0
- package/siderust-web/src/ephemeris.rs +456 -0
- package/siderust-web/src/events.rs +520 -0
- package/siderust-web/src/lib.rs +51 -0
- package/siderust-web/src/observer.rs +117 -0
- package/siderust-web/src/phase.rs +190 -0
- package/siderust-web/src/position.rs +291 -0
- package/siderust-web/src/star.rs +178 -0
- package/tempoch-js/.github/workflows/ci.yml +142 -0
- package/tempoch-js/.gitmodules +3 -0
- package/tempoch-js/CHANGELOG.md +25 -0
- package/tempoch-js/LICENSE +661 -0
- package/tempoch-js/README.md +126 -0
- package/tempoch-js/package.json +20 -0
- package/tempoch-js/scripts/ci.sh +73 -0
- package/tempoch-js/tempoch/.github/workflows/ci.yml +113 -0
- package/tempoch-js/tempoch/CHANGELOG.md +82 -0
- package/tempoch-js/tempoch/Cargo.lock +947 -0
- package/tempoch-js/tempoch/Cargo.toml +3 -0
- package/tempoch-js/tempoch/LICENSE +661 -0
- package/tempoch-js/tempoch/README.md +76 -0
- package/tempoch-js/tempoch/tempoch/Cargo.toml +27 -0
- package/tempoch-js/tempoch/tempoch/examples/periods.rs +45 -0
- package/tempoch-js/tempoch/tempoch/examples/quickstart.rs +13 -0
- package/tempoch-js/tempoch/tempoch/src/lib.rs +49 -0
- package/tempoch-js/tempoch/tempoch/tests/integration.rs +57 -0
- package/tempoch-js/tempoch/tempoch-core/Cargo.toml +24 -0
- package/tempoch-js/tempoch/tempoch-core/src/delta_t.rs +345 -0
- package/tempoch-js/tempoch/tempoch-core/src/instant.rs +811 -0
- package/tempoch-js/tempoch/tempoch-core/src/julian_date_ext.rs +142 -0
- package/tempoch-js/tempoch/tempoch-core/src/lib.rs +81 -0
- package/tempoch-js/tempoch/tempoch-core/src/period.rs +1168 -0
- package/tempoch-js/tempoch/tempoch-core/src/scales.rs +779 -0
- package/tempoch-js/tempoch/tempoch-ffi/Cargo.lock +889 -0
- package/tempoch-js/tempoch/tempoch-ffi/Cargo.toml +26 -0
- package/tempoch-js/tempoch/tempoch-ffi/build.rs +24 -0
- package/tempoch-js/tempoch/tempoch-ffi/cbindgen.toml +30 -0
- package/tempoch-js/tempoch/tempoch-ffi/src/error.rs +19 -0
- package/tempoch-js/tempoch/tempoch-ffi/src/lib.rs +82 -0
- package/tempoch-js/tempoch/tempoch-ffi/src/period.rs +101 -0
- package/tempoch-js/tempoch/tempoch-ffi/src/time.rs +711 -0
- package/tempoch-js/tempoch/tempoch-ffi/tests/ffi.rs +265 -0
- package/tempoch-js/tempoch-node/.prettierignore +6 -0
- package/tempoch-js/tempoch-node/.prettierrc.json +6 -0
- package/tempoch-js/tempoch-node/Cargo.lock +496 -0
- package/tempoch-js/tempoch-node/Cargo.toml +29 -0
- package/tempoch-js/tempoch-node/README.md +265 -0
- package/tempoch-js/tempoch-node/__test__/index.test.mjs +598 -0
- package/tempoch-js/tempoch-node/build.rs +5 -0
- package/tempoch-js/tempoch-node/c8.config.json +3 -0
- package/tempoch-js/tempoch-node/eslint.config.js +31 -0
- package/tempoch-js/tempoch-node/examples/periods.mjs +79 -0
- package/tempoch-js/tempoch-node/examples/quickstart.mjs +71 -0
- package/tempoch-js/tempoch-node/examples/timescales.mjs +92 -0
- package/tempoch-js/tempoch-node/index.d.ts +280 -0
- package/tempoch-js/tempoch-node/index.js +32 -0
- package/tempoch-js/tempoch-node/lib/JulianDate.js +176 -0
- package/tempoch-js/tempoch-node/lib/ModifiedJulianDate.js +156 -0
- package/tempoch-js/tempoch-node/lib/Period.js +133 -0
- package/tempoch-js/tempoch-node/lib/backend.js +38 -0
- package/tempoch-js/tempoch-node/lib/qttyCompat.js +92 -0
- package/tempoch-js/tempoch-node/native.cjs +317 -0
- package/tempoch-js/tempoch-node/package-lock.json +3223 -0
- package/tempoch-js/tempoch-node/package.json +56 -0
- package/tempoch-js/tempoch-node/src/lib.rs +573 -0
- package/tempoch-js/tempoch-web/Cargo.toml +23 -0
- package/tempoch-js/tempoch-web/index.d.ts +95 -0
- package/tempoch-js/tempoch-web/index.js +27 -0
- package/tempoch-js/tempoch-web/lib/JulianDate.js +170 -0
- package/tempoch-js/tempoch-web/lib/ModifiedJulianDate.js +145 -0
- package/tempoch-js/tempoch-web/lib/Period.js +121 -0
- package/tempoch-js/tempoch-web/lib/backend.js +118 -0
- package/tempoch-js/tempoch-web/package.json +46 -0
- package/tempoch-js/tempoch-web/src/lib.rs +184 -0
|
@@ -0,0 +1,332 @@
|
|
|
1
|
+
//! Unit types and traits.
|
|
2
|
+
|
|
3
|
+
use crate::dimension::{DimDiv, DimMul, Dimension, Dimensionless};
|
|
4
|
+
use crate::scalar::Scalar;
|
|
5
|
+
use crate::Quantity;
|
|
6
|
+
use core::fmt::{Debug, Display, Formatter, LowerExp, Result, UpperExp};
|
|
7
|
+
use core::marker::PhantomData;
|
|
8
|
+
|
|
9
|
+
/// Trait implemented by every **unit** type.
|
|
10
|
+
///
|
|
11
|
+
/// * `RATIO` is the conversion factor from this unit to the *canonical scaling unit* of the same dimension.
|
|
12
|
+
/// Example: if metres are canonical (`Meter::RATIO == 1.0`), then kilometres use `Kilometer::RATIO == 1000.0`
|
|
13
|
+
/// because `1 km = 1000 m`.
|
|
14
|
+
///
|
|
15
|
+
/// * `SYMBOL` is the printable string (e.g. `"m"` or `"km"`).
|
|
16
|
+
///
|
|
17
|
+
/// * `Dim` ties the unit to its underlying [`Dimension`].
|
|
18
|
+
///
|
|
19
|
+
/// # Invariants
|
|
20
|
+
///
|
|
21
|
+
/// - Implementations should be zero-sized marker types (this crate's built-in units are unit structs with no fields).
|
|
22
|
+
/// - `RATIO` should be finite and non-zero.
|
|
23
|
+
pub trait Unit: Copy + PartialEq + Debug + 'static {
|
|
24
|
+
/// Unit-to-canonical conversion factor.
|
|
25
|
+
const RATIO: f64;
|
|
26
|
+
|
|
27
|
+
/// Dimension to which this unit belongs.
|
|
28
|
+
type Dim: Dimension;
|
|
29
|
+
|
|
30
|
+
/// Printable symbol, shown by [`core::fmt::Display`].
|
|
31
|
+
const SYMBOL: &'static str;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/// Unit representing the division of two other units.
|
|
35
|
+
///
|
|
36
|
+
/// `Per<N, D>` corresponds to `N / D` and carries both the
|
|
37
|
+
/// dimensional information and the scaling ratio between the
|
|
38
|
+
/// constituent units. It is generic over any numerator and
|
|
39
|
+
/// denominator units, which allows implementing arithmetic
|
|
40
|
+
/// generically for all pairs without bespoke macros.
|
|
41
|
+
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
|
|
42
|
+
pub struct Per<N: Unit, D: Unit>(PhantomData<(N, D)>);
|
|
43
|
+
|
|
44
|
+
impl<N: Unit, D: Unit> Unit for Per<N, D>
|
|
45
|
+
where
|
|
46
|
+
N::Dim: DimDiv<D::Dim>,
|
|
47
|
+
<N::Dim as DimDiv<D::Dim>>::Output: Dimension,
|
|
48
|
+
{
|
|
49
|
+
const RATIO: f64 = N::RATIO / D::RATIO;
|
|
50
|
+
type Dim = <N::Dim as DimDiv<D::Dim>>::Output;
|
|
51
|
+
const SYMBOL: &'static str = "";
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
impl<N: Unit, D: Unit, S: Scalar + Display> Display for Quantity<Per<N, D>, S>
|
|
55
|
+
where
|
|
56
|
+
N::Dim: DimDiv<D::Dim>,
|
|
57
|
+
<N::Dim as DimDiv<D::Dim>>::Output: Dimension,
|
|
58
|
+
{
|
|
59
|
+
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
|
|
60
|
+
Display::fmt(&self.value(), f)?;
|
|
61
|
+
write!(f, " {}/{}", N::SYMBOL, D::SYMBOL)
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
impl<N: Unit, D: Unit, S: Scalar + LowerExp> LowerExp for Quantity<Per<N, D>, S>
|
|
66
|
+
where
|
|
67
|
+
N::Dim: DimDiv<D::Dim>,
|
|
68
|
+
<N::Dim as DimDiv<D::Dim>>::Output: Dimension,
|
|
69
|
+
{
|
|
70
|
+
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
|
|
71
|
+
LowerExp::fmt(&self.value(), f)?;
|
|
72
|
+
write!(f, " {}/{}", N::SYMBOL, D::SYMBOL)
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
impl<N: Unit, D: Unit, S: Scalar + UpperExp> UpperExp for Quantity<Per<N, D>, S>
|
|
77
|
+
where
|
|
78
|
+
N::Dim: DimDiv<D::Dim>,
|
|
79
|
+
<N::Dim as DimDiv<D::Dim>>::Output: Dimension,
|
|
80
|
+
{
|
|
81
|
+
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
|
|
82
|
+
UpperExp::fmt(&self.value(), f)?;
|
|
83
|
+
write!(f, " {}/{}", N::SYMBOL, D::SYMBOL)
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/// Unit representing the product of two other units.
|
|
88
|
+
///
|
|
89
|
+
/// `Prod<A, B>` corresponds to `A * B` and carries both the
|
|
90
|
+
/// dimensional information and the scaling ratio between the
|
|
91
|
+
/// constituent units.
|
|
92
|
+
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
|
|
93
|
+
pub struct Prod<A: Unit, B: Unit>(PhantomData<(A, B)>);
|
|
94
|
+
|
|
95
|
+
impl<A: Unit, B: Unit> Unit for Prod<A, B>
|
|
96
|
+
where
|
|
97
|
+
A::Dim: DimMul<B::Dim>,
|
|
98
|
+
<A::Dim as DimMul<B::Dim>>::Output: Dimension,
|
|
99
|
+
{
|
|
100
|
+
const RATIO: f64 = A::RATIO * B::RATIO;
|
|
101
|
+
type Dim = <A::Dim as DimMul<B::Dim>>::Output;
|
|
102
|
+
const SYMBOL: &'static str = "";
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
impl<A: Unit, B: Unit, S: Scalar + Display> Display for Quantity<Prod<A, B>, S>
|
|
106
|
+
where
|
|
107
|
+
A::Dim: DimMul<B::Dim>,
|
|
108
|
+
<A::Dim as DimMul<B::Dim>>::Output: Dimension,
|
|
109
|
+
{
|
|
110
|
+
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
|
|
111
|
+
Display::fmt(&self.value(), f)?;
|
|
112
|
+
write!(f, " {}·{}", A::SYMBOL, B::SYMBOL)
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
impl<A: Unit, B: Unit, S: Scalar + LowerExp> LowerExp for Quantity<Prod<A, B>, S>
|
|
117
|
+
where
|
|
118
|
+
A::Dim: DimMul<B::Dim>,
|
|
119
|
+
<A::Dim as DimMul<B::Dim>>::Output: Dimension,
|
|
120
|
+
{
|
|
121
|
+
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
|
|
122
|
+
LowerExp::fmt(&self.value(), f)?;
|
|
123
|
+
write!(f, " {}·{}", A::SYMBOL, B::SYMBOL)
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
impl<A: Unit, B: Unit, S: Scalar + UpperExp> UpperExp for Quantity<Prod<A, B>, S>
|
|
128
|
+
where
|
|
129
|
+
A::Dim: DimMul<B::Dim>,
|
|
130
|
+
<A::Dim as DimMul<B::Dim>>::Output: Dimension,
|
|
131
|
+
{
|
|
132
|
+
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
|
|
133
|
+
UpperExp::fmt(&self.value(), f)?;
|
|
134
|
+
write!(f, " {}·{}", A::SYMBOL, B::SYMBOL)
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/// Zero-sized marker type for dimensionless quantities.
|
|
139
|
+
///
|
|
140
|
+
/// `Unitless` represents a dimensionless unit with a conversion ratio of 1.0
|
|
141
|
+
/// and an empty symbol. It is used to model the result of simplifying same-unit
|
|
142
|
+
/// ratios (e.g., `Meters / Meters`) into a plain "number-like" `Quantity<Unitless>`.
|
|
143
|
+
///
|
|
144
|
+
/// Unlike a type alias to `f64`, this is a proper zero-sized type, which ensures
|
|
145
|
+
/// that only explicitly constructed `Quantity<Unitless>` values are treated as
|
|
146
|
+
/// dimensionless, not bare `f64` primitives.
|
|
147
|
+
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
|
|
148
|
+
pub struct Unitless;
|
|
149
|
+
|
|
150
|
+
impl Unit for Unitless {
|
|
151
|
+
const RATIO: f64 = 1.0;
|
|
152
|
+
type Dim = Dimensionless;
|
|
153
|
+
const SYMBOL: &'static str = "";
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
impl<S: Scalar + Display> Display for Quantity<Unitless, S> {
|
|
157
|
+
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
|
|
158
|
+
Display::fmt(&self.value(), f)
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
impl<S: Scalar + LowerExp> LowerExp for Quantity<Unitless, S> {
|
|
163
|
+
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
|
|
164
|
+
LowerExp::fmt(&self.value(), f)
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
impl<S: Scalar + UpperExp> UpperExp for Quantity<Unitless, S> {
|
|
169
|
+
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
|
|
170
|
+
UpperExp::fmt(&self.value(), f)
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/// Trait for simplifying composite unit types.
|
|
175
|
+
///
|
|
176
|
+
/// This allows reducing complex unit expressions to simpler forms,
|
|
177
|
+
/// such as `Per<U, U>` to `Unitless` or `Per<N, Per<N, D>>` to `D`.
|
|
178
|
+
pub trait Simplify {
|
|
179
|
+
/// The scalar type of this quantity.
|
|
180
|
+
type Scalar: Scalar;
|
|
181
|
+
/// The simplified unit type.
|
|
182
|
+
type Out: Unit;
|
|
183
|
+
/// Convert this quantity to its simplified unit.
|
|
184
|
+
fn simplify(self) -> Quantity<Self::Out, Self::Scalar>;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
impl<U: Unit, S: Scalar> Simplify for Quantity<Per<U, U>, S>
|
|
188
|
+
where
|
|
189
|
+
U::Dim: DimDiv<U::Dim>,
|
|
190
|
+
<U::Dim as DimDiv<U::Dim>>::Output: Dimension,
|
|
191
|
+
{
|
|
192
|
+
type Scalar = S;
|
|
193
|
+
type Out = Unitless;
|
|
194
|
+
/// ```rust
|
|
195
|
+
/// use qtty_core::length::Meters;
|
|
196
|
+
/// use qtty_core::{Quantity, Simplify, Unitless};
|
|
197
|
+
///
|
|
198
|
+
/// let ratio = Meters::new(1.0) / Meters::new(2.0);
|
|
199
|
+
/// let unitless: Quantity<Unitless> = ratio.simplify();
|
|
200
|
+
/// assert!((unitless.value() - 0.5).abs() < 1e-12);
|
|
201
|
+
/// ```
|
|
202
|
+
fn simplify(self) -> Quantity<Unitless, S> {
|
|
203
|
+
Quantity::new(self.value())
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
impl<N: Unit, D: Unit, S: Scalar> Simplify for Quantity<Per<N, Per<N, D>>, S>
|
|
208
|
+
where
|
|
209
|
+
N::Dim: DimDiv<D::Dim>,
|
|
210
|
+
<N::Dim as DimDiv<D::Dim>>::Output: Dimension,
|
|
211
|
+
N::Dim: DimDiv<<N::Dim as DimDiv<D::Dim>>::Output>,
|
|
212
|
+
<N::Dim as DimDiv<<N::Dim as DimDiv<D::Dim>>::Output>>::Output: Dimension,
|
|
213
|
+
{
|
|
214
|
+
type Scalar = S;
|
|
215
|
+
type Out = D;
|
|
216
|
+
fn simplify(self) -> Quantity<D, S> {
|
|
217
|
+
Quantity::new(self.value())
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
#[cfg(test)]
|
|
222
|
+
mod tests {
|
|
223
|
+
use super::*;
|
|
224
|
+
use crate::units::length::{Kilometer, Meter, Meters};
|
|
225
|
+
use crate::units::time::{Hour, Second};
|
|
226
|
+
use crate::Quantity;
|
|
227
|
+
|
|
228
|
+
// ── Per: Display, LowerExp, UpperExp ──────────────────────────────────────
|
|
229
|
+
|
|
230
|
+
#[test]
|
|
231
|
+
fn per_display_formats_value_and_symbol() {
|
|
232
|
+
// 10 m/s with Display
|
|
233
|
+
let qty: Quantity<Per<Meter, Second>> = Quantity::new(10.0);
|
|
234
|
+
let s = format!("{qty}");
|
|
235
|
+
assert_eq!(s, "10 m/s");
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
#[test]
|
|
239
|
+
fn per_display_with_precision() {
|
|
240
|
+
let qty: Quantity<Per<Meter, Second>> = Quantity::new(1.5);
|
|
241
|
+
let s = format!("{qty:.2}");
|
|
242
|
+
assert_eq!(s, "1.50 m/s");
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
#[test]
|
|
246
|
+
fn per_lower_exp_formats_correctly() {
|
|
247
|
+
let qty: Quantity<Per<Meter, Second>> = Quantity::new(1000.0);
|
|
248
|
+
let s = format!("{qty:e}");
|
|
249
|
+
assert!(s.contains("e"), "Expected scientific notation, got: {s}");
|
|
250
|
+
assert!(s.ends_with("m/s"), "Expected 'm/s' suffix, got: {s}");
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
#[test]
|
|
254
|
+
fn per_upper_exp_formats_correctly() {
|
|
255
|
+
let qty: Quantity<Per<Meter, Second>> = Quantity::new(1000.0);
|
|
256
|
+
let s = format!("{qty:E}");
|
|
257
|
+
assert!(s.contains("E"), "Expected uppercase-E notation, got: {s}");
|
|
258
|
+
assert!(s.ends_with("m/s"), "Expected 'm/s' suffix, got: {s}");
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
// ── Prod: Display, LowerExp, UpperExp ─────────────────────────────────────
|
|
262
|
+
|
|
263
|
+
#[test]
|
|
264
|
+
fn prod_display_formats_value_and_symbol() {
|
|
265
|
+
let qty: Quantity<Prod<Meter, Second>> = Quantity::new(3.0);
|
|
266
|
+
let s = format!("{qty}");
|
|
267
|
+
assert_eq!(s, "3 m·s");
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
#[test]
|
|
271
|
+
fn prod_display_with_precision() {
|
|
272
|
+
let qty: Quantity<Prod<Meter, Second>> = Quantity::new(2.5);
|
|
273
|
+
let s = format!("{qty:.3}");
|
|
274
|
+
assert_eq!(s, "2.500 m·s");
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
#[test]
|
|
278
|
+
fn prod_lower_exp_formats_correctly() {
|
|
279
|
+
let qty: Quantity<Prod<Kilometer, Second>> = Quantity::new(5000.0);
|
|
280
|
+
let s = format!("{qty:.2e}");
|
|
281
|
+
assert!(s.contains("e"), "Expected scientific notation, got: {s}");
|
|
282
|
+
assert!(s.ends_with("km·s"), "Expected 'km·s' suffix, got: {s}");
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
#[test]
|
|
286
|
+
fn prod_upper_exp_formats_correctly() {
|
|
287
|
+
let qty: Quantity<Prod<Kilometer, Second>> = Quantity::new(5000.0);
|
|
288
|
+
let s = format!("{qty:.2E}");
|
|
289
|
+
assert!(s.contains("E"), "Expected uppercase-E notation, got: {s}");
|
|
290
|
+
assert!(s.ends_with("km·s"), "Expected 'km·s' suffix, got: {s}");
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
// ── Unitless: LowerExp, UpperExp ──────────────────────────────────────────
|
|
294
|
+
|
|
295
|
+
#[test]
|
|
296
|
+
fn unitless_lower_exp_formats_correctly() {
|
|
297
|
+
let qty: Quantity<Unitless> = Quantity::new(0.5);
|
|
298
|
+
let s = format!("{qty:e}");
|
|
299
|
+
assert!(s.contains("e"), "Expected scientific notation, got: {s}");
|
|
300
|
+
// No unit symbol for Unitless
|
|
301
|
+
assert!(
|
|
302
|
+
!s.contains(' '),
|
|
303
|
+
"Unitless should not have a space, got: {s}"
|
|
304
|
+
);
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
#[test]
|
|
308
|
+
fn unitless_upper_exp_formats_correctly() {
|
|
309
|
+
let qty: Quantity<Unitless> = Quantity::new(0.5);
|
|
310
|
+
let s = format!("{qty:E}");
|
|
311
|
+
assert!(s.contains("E"), "Expected uppercase-E notation, got: {s}");
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
// ── Simplify: Per<U, U> → Unitless ────────────────────────────────────────
|
|
315
|
+
|
|
316
|
+
#[test]
|
|
317
|
+
fn simplify_per_u_u_gives_unitless() {
|
|
318
|
+
let ratio = Meters::new(3.0) / Meters::new(6.0);
|
|
319
|
+
let unitless: Quantity<Unitless> = ratio.simplify();
|
|
320
|
+
assert!((unitless.value() - 0.5).abs() < 1e-12);
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
// ── Simplify: Per<N, Per<N, D>> → D ──────────────────────────────────────
|
|
324
|
+
|
|
325
|
+
#[test]
|
|
326
|
+
fn simplify_per_n_per_n_d_gives_d() {
|
|
327
|
+
// Quantity<Per<Meter, Per<Meter, Hour>>> should simplify to Quantity<Hour>
|
|
328
|
+
let q: Quantity<Per<Meter, Per<Meter, Hour>>> = Quantity::new(42.0);
|
|
329
|
+
let simplified: Quantity<Hour> = q.simplify();
|
|
330
|
+
assert!((simplified.value() - 42.0).abs() < 1e-12);
|
|
331
|
+
}
|
|
332
|
+
}
|