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//!
27//! ## All volume units
28//!
29//! ```rust
30//! use qtty_core::volume::*;
31//!
32//! macro_rules! touch {
33//!     ($T:ty, $v:expr) => {{ let q = <$T>::new($v); let _c = q; assert!(q == q); }};
34//! }
35//!
36//! touch!(CubicMeters, 1.0);    touch!(CubicKilometers, 1.0);
37//! touch!(CubicCentimeters, 1.0); touch!(CubicMillimeters, 1.0);
38//! touch!(Liters, 1.0);         touch!(Milliliters, 1.0);
39//! touch!(Microliters, 1.0);    touch!(Centiliters, 1.0);
40//! touch!(Deciliters, 1.0);     touch!(CubicInches, 1.0);
41//! touch!(CubicFeet, 1.0);      touch!(UsGallons, 1.0);
42//! touch!(UsFluidOunces, 1.0);
43//! ```
44
45use crate::{Quantity, Unit};
46use qtty_derive::Unit;
47
48/// Re-export the volume dimension from the dimension module.
49pub use crate::dimension::Volume;
50
51/// Marker trait for any [`Unit`] whose dimension is [`Volume`].
52pub trait VolumeUnit: Unit<Dim = Volume> {}
53impl<T: Unit<Dim = Volume>> VolumeUnit for T {}
54
55// ─────────────────────────────────────────────────────────────────────────────
56// SI / metric volume units
57// ─────────────────────────────────────────────────────────────────────────────
58
59/// Cubic metre (SI derived unit of volume).
60#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
61#[unit(symbol = "m³", dimension = Volume, ratio = 1.0)]
62pub struct CubicMeter;
63/// A quantity measured in cubic metres.
64pub type CubicMeters = Quantity<CubicMeter>;
65
66/// Cubic kilometre (`1e9 m³`).
67#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
68#[unit(symbol = "km³", dimension = Volume, ratio = 1e9)]
69pub struct CubicKilometer;
70/// A quantity measured in cubic kilometres.
71pub type CubicKilometers = Quantity<CubicKilometer>;
72
73/// Cubic centimetre (`1e-6 m³`).
74#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
75#[unit(symbol = "cm³", dimension = Volume, ratio = 1e-6)]
76pub struct CubicCentimeter;
77/// A quantity measured in cubic centimetres.
78pub type CubicCentimeters = Quantity<CubicCentimeter>;
79
80/// Cubic millimetre (`1e-9 m³`).
81#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
82#[unit(symbol = "mm³", dimension = Volume, ratio = 1e-9)]
83pub struct CubicMillimeter;
84/// A quantity measured in cubic millimetres.
85pub type CubicMillimeters = Quantity<CubicMillimeter>;
86
87// ─────────────────────────────────────────────────────────────────────────────
88// Litre family
89// ─────────────────────────────────────────────────────────────────────────────
90
91/// Litre (`1e-3 m³`, exact).
92#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
93#[unit(symbol = "L", dimension = Volume, ratio = 1e-3)]
94pub struct Liter;
95/// A quantity measured in litres.
96pub type Liters = Quantity<Liter>;
97
98/// Millilitre (`1e-6 m³`, exact).
99#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
100#[unit(symbol = "mL", dimension = Volume, ratio = 1e-6)]
101pub struct Milliliter;
102/// A quantity measured in millilitres.
103pub type Milliliters = Quantity<Milliliter>;
104
105/// Microlitre (`1e-9 m³`, exact).
106#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
107#[unit(symbol = "µL", dimension = Volume, ratio = 1e-9)]
108pub struct Microliter;
109/// A quantity measured in microlitres.
110pub type Microliters = Quantity<Microliter>;
111
112/// Centilitre (`1e-5 m³`, exact).
113#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
114#[unit(symbol = "cL", dimension = Volume, ratio = 1e-5)]
115pub struct Centiliter;
116/// A quantity measured in centilitres.
117pub type Centiliters = Quantity<Centiliter>;
118
119/// Decilitre (`1e-4 m³`, exact).
120#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
121#[unit(symbol = "dL", dimension = Volume, ratio = 1e-4)]
122pub struct Deciliter;
123/// A quantity measured in decilitres.
124pub type Deciliters = Quantity<Deciliter>;
125
126// ─────────────────────────────────────────────────────────────────────────────
127// Imperial / US customary volume units
128// ─────────────────────────────────────────────────────────────────────────────
129
130/// Cubic inch (`1.6387064e-5 m³`, exact: `0.0254³ m³`).
131#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
132#[unit(symbol = "in³", dimension = Volume, ratio = 1.638_706_4e-5)]
133pub struct CubicInch;
134/// A quantity measured in cubic inches.
135pub type CubicInches = Quantity<CubicInch>;
136
137/// Cubic foot (`0.028316846592 m³`, exact: `0.3048³ m³`).
138#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
139#[unit(symbol = "ft³", dimension = Volume, ratio = 0.028_316_846_592)]
140pub struct CubicFoot;
141/// A quantity measured in cubic feet.
142pub type CubicFeet = Quantity<CubicFoot>;
143
144/// US liquid gallon (`0.003785411784 m³`, exact: `231 in³`).
145#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
146#[unit(symbol = "gal", dimension = Volume, ratio = 0.003_785_411_784)]
147pub struct UsGallon;
148/// A quantity measured in US gallons.
149pub type UsGallons = Quantity<UsGallon>;
150
151/// US fluid ounce (`2.95735295625e-5 m³`, exact: `gal / 128`).
152#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
153#[unit(symbol = "fl oz", dimension = Volume, ratio = 2.957_352_956_25e-5)]
154pub struct UsFluidOunce;
155/// A quantity measured in US fluid ounces.
156pub type UsFluidOunces = Quantity<UsFluidOunce>;
157
158#[cfg(test)]
159mod tests {
160    use super::*;
161    use approx::assert_abs_diff_eq;
162
163    #[test]
164    fn liter_to_cubic_meter() {
165        let l = Liters::new(1.0);
166        let m: CubicMeters = l.to();
167        assert_abs_diff_eq!(m.value(), 0.001, epsilon = 1e-15);
168    }
169
170    #[test]
171    fn milliliter_to_liter() {
172        let ml = Milliliters::new(1000.0);
173        let l: Liters = ml.to();
174        assert_abs_diff_eq!(l.value(), 1.0, epsilon = 1e-12);
175    }
176
177    #[test]
178    fn cubic_cm_to_ml() {
179        let cc = CubicCentimeters::new(1.0);
180        let ml: Milliliters = cc.to();
181        assert_abs_diff_eq!(ml.value(), 1.0, epsilon = 1e-12);
182    }
183
184    #[test]
185    fn us_gallon_to_liter() {
186        let g = UsGallons::new(1.0);
187        let l: Liters = g.to();
188        assert_abs_diff_eq!(l.value(), 3.785_411_784, epsilon = 1e-6);
189    }
190
191    #[test]
192    fn cubic_foot_to_liter() {
193        let cf = CubicFeet::new(1.0);
194        let l: Liters = cf.to();
195        assert_abs_diff_eq!(l.value(), 28.316_846_592, epsilon = 1e-6);
196    }
197
198    #[test]
199    fn length_times_area_to_volume() {
200        use crate::area::{SquareMeter, SquareMeters};
201        use crate::length::{Meter, Meters};
202        use crate::Prod;
203
204        let side = Meters::new(3.0);
205        let face: SquareMeters = (side * side).to();
206        let vol_prod: Quantity<Prod<SquareMeter, Meter>> = face * side;
207        let vol: CubicMeters = vol_prod.to();
208        assert_abs_diff_eq!(vol.value(), 27.0, epsilon = 1e-12);
209    }
210
211    #[test]
212    fn cubic_km_to_liter() {
213        let ckm = CubicKilometers::new(1.0);
214        let l: Liters = ckm.to();
215        assert_abs_diff_eq!(l.value(), 1e12, epsilon = 1e3);
216    }
217
218    #[test]
219    fn cubic_mm_to_cubic_cm() {
220        let mm3 = CubicMillimeters::new(1000.0);
221        let cm3: CubicCentimeters = mm3.to();
222        assert_abs_diff_eq!(cm3.value(), 1.0, epsilon = 1e-12);
223    }
224
225    #[test]
226    fn microliter_to_milliliter() {
227        let ul = Microliters::new(1000.0);
228        let ml: Milliliters = ul.to();
229        assert_abs_diff_eq!(ml.value(), 1.0, epsilon = 1e-12);
230    }
231
232    #[test]
233    fn centiliter_to_liter() {
234        let cl = Centiliters::new(100.0);
235        let l: Liters = cl.to();
236        assert_abs_diff_eq!(l.value(), 1.0, epsilon = 1e-12);
237    }
238
239    #[test]
240    fn deciliter_to_liter() {
241        let dl = Deciliters::new(10.0);
242        let l: Liters = dl.to();
243        assert_abs_diff_eq!(l.value(), 1.0, epsilon = 1e-12);
244    }
245
246    #[test]
247    fn cubic_inch_to_cubic_cm() {
248        let cin = CubicInches::new(1.0);
249        let cc: CubicCentimeters = cin.to();
250        // 1 in³ = 16.387064 cm³
251        assert_abs_diff_eq!(cc.value(), 16.387_064, epsilon = 1e-4);
252    }
253
254    #[test]
255    fn us_fluid_ounce_to_milliliter() {
256        let floz = UsFluidOunces::new(1.0);
257        let ml: Milliliters = floz.to();
258        // 1 US fl oz ≈ 29.5735 mL
259        assert_abs_diff_eq!(ml.value(), 29.573_529_562_5, epsilon = 1e-6);
260    }
261
262    #[test]
263    fn symbols_are_correct() {
264        assert_eq!(CubicMeter::SYMBOL, "m³");
265        assert_eq!(Liter::SYMBOL, "L");
266        assert_eq!(Milliliter::SYMBOL, "mL");
267        assert_eq!(UsGallon::SYMBOL, "gal");
268    }
269}