1use crate::{Prod, Quantity, Unit};
45use qtty_derive::Unit;
46
47pub use crate::dimension::Volume;
49
50pub trait VolumeUnit: Unit<Dim = Volume> {}
52impl<T: Unit<Dim = Volume>> VolumeUnit for T {}
53
54pub type CubeOf<L> = Quantity<Prod<Prod<L, L>, L>>;
76
77#[cfg(feature = "customary")]
78mod customary;
79#[cfg(feature = "customary")]
80pub use customary::*;
81
82#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
88#[unit(symbol = "m³", dimension = Volume, ratio = 1.0)]
89pub struct CubicMeter;
90pub type CubicMeters = Quantity<CubicMeter>;
92
93#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
95#[unit(symbol = "km³", dimension = Volume, ratio = 1e9)]
96pub struct CubicKilometer;
97pub type CubicKilometers = Quantity<CubicKilometer>;
99
100#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
102#[unit(symbol = "cm³", dimension = Volume, ratio = 1e-6)]
103pub struct CubicCentimeter;
104pub type CubicCentimeters = Quantity<CubicCentimeter>;
106
107#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
109#[unit(symbol = "mm³", dimension = Volume, ratio = 1e-9)]
110pub struct CubicMillimeter;
111pub type CubicMillimeters = Quantity<CubicMillimeter>;
113
114#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
120#[unit(symbol = "L", dimension = Volume, ratio = 1e-3)]
121pub struct Liter;
122pub type Liters = Quantity<Liter>;
124
125#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
127#[unit(symbol = "mL", dimension = Volume, ratio = 1e-6)]
128pub struct Milliliter;
129pub type Milliliters = Quantity<Milliliter>;
131
132#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
134#[unit(symbol = "µL", dimension = Volume, ratio = 1e-9)]
135pub struct Microliter;
136pub type Microliters = Quantity<Microliter>;
138
139#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
141#[unit(symbol = "cL", dimension = Volume, ratio = 1e-5)]
142pub struct Centiliter;
143pub type Centiliters = Quantity<Centiliter>;
145
146#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
148#[unit(symbol = "dL", dimension = Volume, ratio = 1e-4)]
149pub struct Deciliter;
150pub type Deciliters = Quantity<Deciliter>;
152
153#[macro_export]
169#[doc(hidden)]
170macro_rules! volume_units {
171 ($cb:path) => {
172 $cb!(
173 CubicMeter,
174 CubicKilometer,
175 CubicCentimeter,
176 CubicMillimeter,
177 Liter,
178 Milliliter,
179 Microliter,
180 Centiliter,
181 Deciliter
182 );
183 };
184}
185
186volume_units!(crate::impl_unit_from_conversions);
188
189#[cfg(feature = "cross-unit-ops")]
191volume_units!(crate::impl_unit_cross_unit_ops);
192
193#[cfg(test)]
195volume_units!(crate::assert_units_are_builtin);
196
197#[cfg(test)]
198mod tests {
199 use super::*;
200 use approx::assert_abs_diff_eq;
201
202 #[test]
203 fn liter_to_cubic_meter() {
204 let l = Liters::new(1.0);
205 let m: CubicMeters = l.to();
206 assert_abs_diff_eq!(m.value(), 0.001, epsilon = 1e-15);
207 }
208
209 #[test]
210 fn milliliter_to_liter() {
211 let ml = Milliliters::new(1000.0);
212 let l: Liters = ml.to();
213 assert_abs_diff_eq!(l.value(), 1.0, epsilon = 1e-12);
214 }
215
216 #[test]
217 fn cubic_cm_to_ml() {
218 let cc = CubicCentimeters::new(1.0);
219 let ml: Milliliters = cc.to();
220 assert_abs_diff_eq!(ml.value(), 1.0, epsilon = 1e-12);
221 }
222
223 #[test]
224 #[cfg(feature = "customary")]
225 fn us_gallon_to_liter() {
226 let g = UsGallons::new(1.0);
227 let l: Liters = g.to();
228 assert_abs_diff_eq!(l.value(), 3.785_411_784, epsilon = 1e-6);
229 }
230
231 #[test]
232 #[cfg(feature = "customary")]
233 fn cubic_foot_to_liter() {
234 let cf = CubicFeet::new(1.0);
235 let l: Liters = cf.to();
236 assert_abs_diff_eq!(l.value(), 28.316_846_592, epsilon = 1e-6);
237 }
238
239 #[test]
240 fn length_times_area_to_volume() {
241 use crate::area::{SquareMeter, SquareMeters};
242 use crate::length::{Meter, Meters};
243 use crate::Prod;
244
245 let side = Meters::new(3.0);
246 let face: SquareMeters = (side * side).to();
247 let vol_prod: Quantity<Prod<SquareMeter, Meter>> = face * side;
248 let vol: CubicMeters = vol_prod.to();
249 assert_abs_diff_eq!(vol.value(), 27.0, epsilon = 1e-12);
250 }
251
252 #[test]
253 fn cubic_km_to_liter() {
254 let ckm = CubicKilometers::new(1.0);
255 let l: Liters = ckm.to();
256 assert_abs_diff_eq!(l.value(), 1e12, epsilon = 1e3);
257 }
258
259 #[test]
260 fn cubic_mm_to_cubic_cm() {
261 let mm3 = CubicMillimeters::new(1000.0);
262 let cm3: CubicCentimeters = mm3.to();
263 assert_abs_diff_eq!(cm3.value(), 1.0, epsilon = 1e-12);
264 }
265
266 #[test]
267 fn microliter_to_milliliter() {
268 let ul = Microliters::new(1000.0);
269 let ml: Milliliters = ul.to();
270 assert_abs_diff_eq!(ml.value(), 1.0, epsilon = 1e-12);
271 }
272
273 #[test]
274 fn centiliter_to_liter() {
275 let cl = Centiliters::new(100.0);
276 let l: Liters = cl.to();
277 assert_abs_diff_eq!(l.value(), 1.0, epsilon = 1e-12);
278 }
279
280 #[test]
281 fn deciliter_to_liter() {
282 let dl = Deciliters::new(10.0);
283 let l: Liters = dl.to();
284 assert_abs_diff_eq!(l.value(), 1.0, epsilon = 1e-12);
285 }
286
287 #[test]
288 #[cfg(feature = "customary")]
289 fn cubic_inch_to_cubic_cm() {
290 let cin = CubicInches::new(1.0);
291 let cc: CubicCentimeters = cin.to();
292 assert_abs_diff_eq!(cc.value(), 16.387_064, epsilon = 1e-4);
294 }
295
296 #[test]
297 #[cfg(feature = "customary")]
298 fn us_fluid_ounce_to_milliliter() {
299 let floz = UsFluidOunces::new(1.0);
300 let ml: Milliliters = floz.to();
301 assert_abs_diff_eq!(ml.value(), 29.573_529_562_5, epsilon = 1e-6);
303 }
304
305 #[test]
306 fn symbols_are_correct() {
307 assert_eq!(CubicMeter::SYMBOL, "m³");
308 assert_eq!(Liter::SYMBOL, "L");
309 assert_eq!(Milliliter::SYMBOL, "mL");
310 #[cfg(feature = "customary")]
311 assert_eq!(UsGallon::SYMBOL, "gal");
312 }
313}