Skip to content

Commit 61afa50

Browse files
authored
Use constants instead of types from typenum to describe units (#96)
1 parent b4b15ad commit 61afa50

File tree

10 files changed

+542
-188
lines changed

10 files changed

+542
-188
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
66

77
## [Unreleased]
88

9+
## [0.13.0] - 2026-01-06
10+
### Changed
11+
- Use const generics instead of types from `typenum` to represent units. [#95](https://github.com/itt-ustutt/quantity/pull/95)
12+
913
## [0.12.2] - 2025-12-04
1014
### Fixed
1115
- Also updated `num-dual` dependency to 0.13 to fix incorrect dependency resolution for downstream crates. [#95](https://github.com/itt-ustutt/quantity/pull/95)

Cargo.toml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "quantity"
3-
version = "0.12.2"
3+
version = "0.13.0"
44
authors = [
55
"Philipp Rehner <[email protected]>",
66
"Gernot Bauer <[email protected]>",
@@ -24,7 +24,6 @@ rustdoc-args = ["--html-in-header", "./src/docs-header.html"]
2424
members = ["si-units", "example/extend_quantity"]
2525

2626
[dependencies]
27-
typenum = "1.17"
2827
num-traits = "0.2"
2928
document-features = "0.2"
3029
## Use N-dimensional arrays from the [ndarray] crate as value of a quantity.

README.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ Add this to your `Cargo.toml`:
1515

1616
```
1717
[dependencies]
18-
quantity = "0.12"
18+
quantity = "0.13"
1919
```
2020

2121
## Examples
@@ -24,7 +24,7 @@ Calculate pressure of an ideal gas.
2424

2525
```rust
2626
let temperature = 25.0 * CELSIUS;
27-
let volume = 1.5 * METER.powi::<P3>();
27+
let volume = 1.5 * METER.powi::<3>();
2828
let moles = 75.0 * MOL;
2929
let pressure = moles * RGAS * temperature / volume;
3030
println!("{:.5}", pressure); // 123.94785 kPa
@@ -36,15 +36,15 @@ Calculate the gravitational pull of the moon on the earth.
3636
let mass_earth = 5.9724e24 * KILOGRAM;
3737
let mass_moon = 7.346e22 * KILOGRAM;
3838
let distance = 383.398 * KILO * METER;
39-
let force = G * mass_earth * mass_moon / distance.powi::<P2>();
39+
let force = G * mass_earth * mass_moon / distance.powi::<2>();
4040
println!("{:.5e}", force); // 1.99208e26 N
4141
```
4242

4343
Calculate the pressure distribution in the atmosphere using the barometric formula.
4444

4545
```rust
4646
let z = Quantity::linspace(1.0 * METER, 70.0 * KILO * METER, 10);
47-
let g = 9.81 * METER / SECOND.powi::<P2>();
47+
let g = 9.81 * METER / SECOND.powi::<2>();
4848
let m = 28.949 * GRAM / MOL;
4949
let t = 10.0 * CELSIUS;
5050
let p0 = BAR;

build.rs

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
use std::env;
2+
use std::fmt::Write;
3+
use std::fs;
4+
use std::path::Path;
5+
6+
fn main() {
7+
// Generate Neg, Add, Mul, Div, Sub impls for Const<const N: i8>
8+
// Limiting results of operations to values within [min, max]
9+
10+
// range of exponents
11+
// use i32 for results that would overflow i8, we will limit to min/max in loop
12+
let min: i32 = -20;
13+
let max: i32 = 20;
14+
15+
let out_dir = env::var_os("OUT_DIR").unwrap();
16+
let dest_path = Path::new(&out_dir).join("const_impls.rs");
17+
let mut out = String::new();
18+
19+
// go over all exponent combinations
20+
// for each operation, limit results to min/max
21+
for a in min..=max {
22+
// negation
23+
let neg = -a;
24+
if neg >= min && neg <= max {
25+
writeln!(
26+
&mut out,
27+
"impl Neg for Const<{a}> {{ type Output = Const<{neg}>; fn neg(self) -> Self::Output {{ Const }} }}"
28+
).unwrap();
29+
}
30+
31+
for b in min..=max {
32+
// addition
33+
let sum = a + b;
34+
if sum >= min && sum <= max {
35+
writeln!(
36+
&mut out,
37+
"impl Add<Const<{b}>> for Const<{a}> {{ type Output = Const<{sum}>; fn add(self, _: Const<{b}>) -> Self::Output {{ Const }} }}"
38+
).unwrap();
39+
}
40+
41+
// subtraction
42+
let diff = a - b;
43+
if diff >= min && diff <= max {
44+
writeln!(
45+
&mut out,
46+
"impl Sub<Const<{b}>> for Const<{a}> {{ type Output = Const<{diff}>; fn sub(self, _: Const<{b}>) -> Self::Output {{ Const }} }}"
47+
).unwrap();
48+
}
49+
50+
// multiplication
51+
let mul = a * b;
52+
if mul >= min && mul <= max {
53+
writeln!(
54+
&mut out,
55+
"impl Mul<Const<{b}>> for Const<{a}> {{ type Output = Const<{mul}>; fn mul(self, _: Const<{b}>) -> Self::Output {{ Const }} }}"
56+
).unwrap();
57+
}
58+
59+
// division
60+
// check: don't divide by 0 and only allow for integer results
61+
if b != 0 && a % b == 0 {
62+
let div = a / b;
63+
if div >= min && div <= max {
64+
writeln!(
65+
&mut out,
66+
"impl Div<Const<{b}>> for Const<{a}> {{ type Output = Const<{div}>; fn div(self, _: Const<{b}>) -> Self::Output {{ Const }} }}"
67+
).unwrap();
68+
}
69+
}
70+
}
71+
}
72+
73+
fs::write(&dest_path, out).unwrap();
74+
println!("cargo:rerun-if-changed=build.rs");
75+
}

src/ad.rs

Lines changed: 11 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
1-
use super::Quantity;
1+
use super::{Diff, Quantity};
22
use nalgebra::{DefaultAllocator, Dim, OMatrix, OVector, U1, allocator::Allocator};
33
use num_dual::{
44
Dual, Dual2, Dual2Vec, Dual3, DualNum, DualStruct, DualVec, Gradients, HyperDual, HyperDualVec,
55
HyperHyperDual, Real,
66
};
77
use std::ops::Sub;
8-
use typenum::Diff;
98

109
impl<D, F, T: DualStruct<D, F>, U> DualStruct<D, F> for Quantity<T, U> {
1110
type Real = Quantity<T::Real, U>;
@@ -338,32 +337,10 @@ where
338337
#[cfg(test)]
339338
mod test_num_dual {
340339
use super::*;
341-
use crate::{Area, Length, METER, Temperature, Volume};
340+
use crate::{Area, Length, METER, Volume};
342341
use approx::assert_relative_eq;
343342
use nalgebra::{SMatrix, SVector, vector};
344343
use num_dual::{Dual64, ImplicitDerivative, ImplicitFunction};
345-
use typenum::{P2, P3};
346-
347-
struct MyArgs<D> {
348-
temperature: Temperature<D>,
349-
}
350-
351-
impl<D: DualNum<f64> + Copy> DualStruct<D, f64> for MyArgs<D> {
352-
type Real = MyArgs<f64>;
353-
type Inner = MyArgs<D::Inner>;
354-
355-
fn re(&self) -> Self::Real {
356-
MyArgs {
357-
temperature: self.temperature.re(),
358-
}
359-
}
360-
361-
fn from_inner(inner: &Self::Inner) -> Self {
362-
MyArgs {
363-
temperature: Temperature::from_inner(&inner.temperature),
364-
}
365-
}
366-
}
367344

368345
struct AreaImplicit;
369346
impl ImplicitFunction<f64> for AreaImplicit {
@@ -403,27 +380,27 @@ mod test_num_dual {
403380
fn test_derivative() {
404381
let (v, dv) = first_derivative(volume, 5.0 * METER);
405382
println!("{v}\t{dv:3}");
406-
assert_eq!(v, 125.0 * METER.powi::<P3>());
407-
assert_eq!(dv, 75.0 * METER.powi::<P2>());
383+
assert_eq!(v, 125.0 * METER.powi::<3>());
384+
assert_eq!(dv, 75.0 * METER.powi::<2>());
408385

409386
let (v, dv, d2v) = second_derivative(volume, 5.0 * METER);
410387
println!("{v}\t{dv:3}\t\t{d2v}");
411-
assert_eq!(v, 125.0 * METER.powi::<P3>(),);
412-
assert_eq!(dv, 75.0 * METER.powi::<P2>(),);
388+
assert_eq!(v, 125.0 * METER.powi::<3>(),);
389+
assert_eq!(dv, 75.0 * METER.powi::<2>(),);
413390
assert_eq!(d2v, 30.0 * METER);
414391

415392
let (v, dv_dx, dv_dh, d2v) =
416393
second_partial_derivative(volume2, (5.0 * METER, 20.0 * METER));
417394
println!("{v}\t{dv_dx:3}\t{dv_dh:3}\t{d2v}");
418-
assert_eq!(v, 500.0 * METER.powi::<P3>(),);
419-
assert_eq!(dv_dx, 200.0 * METER.powi::<P2>(),);
420-
assert_eq!(dv_dh, 25.0 * METER.powi::<P2>(),);
395+
assert_eq!(v, 500.0 * METER.powi::<3>(),);
396+
assert_eq!(dv_dx, 200.0 * METER.powi::<2>(),);
397+
assert_eq!(dv_dh, 25.0 * METER.powi::<2>(),);
421398
assert_eq!(d2v, 10.0 * METER);
422399

423400
let (v, dv, d2v, d3v) = third_derivative(volume, 5.0 * METER);
424401
println!("{v}\t{dv:3}\t\t{d2v}\t{d3v}");
425-
assert_eq!(v, 125.0 * METER.powi::<P3>(),);
426-
assert_eq!(dv, 75.0 * METER.powi::<P2>(),);
402+
assert_eq!(v, 125.0 * METER.powi::<3>(),);
403+
assert_eq!(dv, 75.0 * METER.powi::<2>(),);
427404
assert_eq!(d2v, 30.0 * METER);
428405
assert_eq!(d3v.into_value(), 6.0);
429406
}

0 commit comments

Comments
 (0)