Skip to main content

qtty_core/units/
volume.rs

1//! Volume units.
2//!
3//! The canonical scaling unit for this dimension is the **cubic metre** (`CubicMeter::RATIO == 1.0`).
4//! All other volume units are expressed as exact ratios to cubic metres.
5//!
6//! This module provides:
7//!
8//! - **Metric cubes**: cubic millimetre, cubic centimetre, cubic metre, cubic kilometre.
9//! - **Litre family**: microlitre, millilitre, centilitre, decilitre, litre.
10//! - **Imperial/US**: cubic inch, cubic foot, US gallon, US fluid ounce.
11//!
12//! Volume units can also arise *automatically* from multiplying length × area quantities:
13//!
14//! ```rust
15//! use qtty_core::length::{Meter, Meters};
16//! use qtty_core::area::{SquareMeter, SquareMeters};
17//! use qtty_core::volume::{CubicMeters, CubicMeter};
18//! use qtty_core::Prod;
19//!
20//! let side = Meters::new(3.0);
21//! let face: SquareMeters = (side * side).to();
22//! let vol_prod = face * side;                       // Quantity<Prod<SquareMeter, Meter>>
23//! let vol: CubicMeters = vol_prod.to();
24//! assert!((vol.value() - 27.0).abs() < 1e-12);
25//! ```
26
27use crate::{Quantity, Unit};
28use qtty_derive::Unit;
29
30/// Re-export the volume dimension from the dimension module.
31pub use crate::dimension::Volume;
32
33/// Marker trait for any [`Unit`] whose dimension is [`Volume`].
34pub trait VolumeUnit: Unit<Dim = Volume> {}
35impl<T: Unit<Dim = Volume>> VolumeUnit for T {}
36
37// ─────────────────────────────────────────────────────────────────────────────
38// SI / metric volume units
39// ─────────────────────────────────────────────────────────────────────────────
40
41/// Cubic metre (SI derived unit of volume).
42#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
43#[unit(symbol = "m³", dimension = Volume, ratio = 1.0)]
44pub struct CubicMeter;
45/// A quantity measured in cubic metres.
46pub type CubicMeters = Quantity<CubicMeter>;
47
48/// Cubic kilometre (`1e9 m³`).
49#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
50#[unit(symbol = "km³", dimension = Volume, ratio = 1e9)]
51pub struct CubicKilometer;
52/// A quantity measured in cubic kilometres.
53pub type CubicKilometers = Quantity<CubicKilometer>;
54
55/// Cubic centimetre (`1e-6 m³`).
56#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
57#[unit(symbol = "cm³", dimension = Volume, ratio = 1e-6)]
58pub struct CubicCentimeter;
59/// A quantity measured in cubic centimetres.
60pub type CubicCentimeters = Quantity<CubicCentimeter>;
61
62/// Cubic millimetre (`1e-9 m³`).
63#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
64#[unit(symbol = "mm³", dimension = Volume, ratio = 1e-9)]
65pub struct CubicMillimeter;
66/// A quantity measured in cubic millimetres.
67pub type CubicMillimeters = Quantity<CubicMillimeter>;
68
69// ─────────────────────────────────────────────────────────────────────────────
70// Litre family
71// ─────────────────────────────────────────────────────────────────────────────
72
73/// Litre (`1e-3 m³`, exact).
74#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
75#[unit(symbol = "L", dimension = Volume, ratio = 1e-3)]
76pub struct Liter;
77/// A quantity measured in litres.
78pub type Liters = Quantity<Liter>;
79
80/// Millilitre (`1e-6 m³`, exact).
81#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
82#[unit(symbol = "mL", dimension = Volume, ratio = 1e-6)]
83pub struct Milliliter;
84/// A quantity measured in millilitres.
85pub type Milliliters = Quantity<Milliliter>;
86
87/// Microlitre (`1e-9 m³`, exact).
88#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
89#[unit(symbol = "µL", dimension = Volume, ratio = 1e-9)]
90pub struct Microliter;
91/// A quantity measured in microlitres.
92pub type Microliters = Quantity<Microliter>;
93
94/// Centilitre (`1e-5 m³`, exact).
95#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
96#[unit(symbol = "cL", dimension = Volume, ratio = 1e-5)]
97pub struct Centiliter;
98/// A quantity measured in centilitres.
99pub type Centiliters = Quantity<Centiliter>;
100
101/// Decilitre (`1e-4 m³`, exact).
102#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
103#[unit(symbol = "dL", dimension = Volume, ratio = 1e-4)]
104pub struct Deciliter;
105/// A quantity measured in decilitres.
106pub type Deciliters = Quantity<Deciliter>;
107
108// ─────────────────────────────────────────────────────────────────────────────
109// Imperial / US customary volume units
110// ─────────────────────────────────────────────────────────────────────────────
111
112/// Cubic inch (`1.6387064e-5 m³`, exact: `0.0254³ m³`).
113#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
114#[unit(symbol = "in³", dimension = Volume, ratio = 1.638_706_4e-5)]
115pub struct CubicInch;
116/// A quantity measured in cubic inches.
117pub type CubicInches = Quantity<CubicInch>;
118
119/// Cubic foot (`0.028316846592 m³`, exact: `0.3048³ m³`).
120#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
121#[unit(symbol = "ft³", dimension = Volume, ratio = 0.028_316_846_592)]
122pub struct CubicFoot;
123/// A quantity measured in cubic feet.
124pub type CubicFeet = Quantity<CubicFoot>;
125
126/// US liquid gallon (`0.003785411784 m³`, exact: `231 in³`).
127#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
128#[unit(symbol = "gal", dimension = Volume, ratio = 0.003_785_411_784)]
129pub struct UsGallon;
130/// A quantity measured in US gallons.
131pub type UsGallons = Quantity<UsGallon>;
132
133/// US fluid ounce (`2.95735295625e-5 m³`, exact: `gal / 128`).
134#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
135#[unit(symbol = "fl oz", dimension = Volume, ratio = 2.957_352_956_25e-5)]
136pub struct UsFluidOunce;
137/// A quantity measured in US fluid ounces.
138pub type UsFluidOunces = Quantity<UsFluidOunce>;
139
140#[cfg(test)]
141mod tests {
142    use super::*;
143    use approx::assert_abs_diff_eq;
144
145    #[test]
146    fn liter_to_cubic_meter() {
147        let l = Liters::new(1.0);
148        let m: CubicMeters = l.to();
149        assert_abs_diff_eq!(m.value(), 0.001, epsilon = 1e-15);
150    }
151
152    #[test]
153    fn milliliter_to_liter() {
154        let ml = Milliliters::new(1000.0);
155        let l: Liters = ml.to();
156        assert_abs_diff_eq!(l.value(), 1.0, epsilon = 1e-12);
157    }
158
159    #[test]
160    fn cubic_cm_to_ml() {
161        let cc = CubicCentimeters::new(1.0);
162        let ml: Milliliters = cc.to();
163        assert_abs_diff_eq!(ml.value(), 1.0, epsilon = 1e-12);
164    }
165
166    #[test]
167    fn us_gallon_to_liter() {
168        let g = UsGallons::new(1.0);
169        let l: Liters = g.to();
170        assert_abs_diff_eq!(l.value(), 3.785_411_784, epsilon = 1e-6);
171    }
172
173    #[test]
174    fn cubic_foot_to_liter() {
175        let cf = CubicFeet::new(1.0);
176        let l: Liters = cf.to();
177        assert_abs_diff_eq!(l.value(), 28.316_846_592, epsilon = 1e-6);
178    }
179
180    #[test]
181    fn length_times_area_to_volume() {
182        use crate::area::{SquareMeter, SquareMeters};
183        use crate::length::{Meter, Meters};
184        use crate::Prod;
185
186        let side = Meters::new(3.0);
187        let face: SquareMeters = (side * side).to();
188        let vol_prod: Quantity<Prod<SquareMeter, Meter>> = face * side;
189        let vol: CubicMeters = vol_prod.to();
190        assert_abs_diff_eq!(vol.value(), 27.0, epsilon = 1e-12);
191    }
192
193    #[test]
194    fn cubic_km_to_liter() {
195        let ckm = CubicKilometers::new(1.0);
196        let l: Liters = ckm.to();
197        assert_abs_diff_eq!(l.value(), 1e12, epsilon = 1e3);
198    }
199}