1use crate::{Quantity, Unit};
25use qtty_derive::Unit;
26
27pub use crate::dimension::Energy;
29
30pub trait EnergyUnit: Unit<Dim = Energy> {}
32impl<T: Unit<Dim = Energy>> EnergyUnit for T {}
33
34#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
40#[unit(symbol = "J", dimension = Energy, ratio = 1.0)]
41pub struct Joule;
42pub type Joules = Quantity<Joule>;
44pub const JOULE: Joules = Joules::new(1.0);
46
47macro_rules! si_joule {
48 ($name:ident, $sym:literal, $ratio:expr, $qty:ident, $one:ident) => {
49 #[doc = concat!("SI-prefixed joule unit (", stringify!($ratio), " J).")]
50 #[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
51 #[unit(symbol = $sym, dimension = Energy, ratio = $ratio)]
52 pub struct $name;
53 #[doc = concat!("A quantity measured in ", stringify!($name), "s.")]
54 pub type $qty = Quantity<$name>;
55 #[doc = concat!("One ", stringify!($name), ".")]
56 pub const $one: $qty = $qty::new(1.0);
57 };
58}
59
60si_joule!(Nanojoule, "nJ", 1e-9, Nanojoules, NANOJOULE);
61si_joule!(Picojoule, "pJ", 1e-12, Picojoules, PICOJOULE);
62si_joule!(Microjoule, "µJ", 1e-6, Microjoules, MICROJOULE);
63si_joule!(Millijoule, "mJ", 1e-3, Millijoules, MILLIJOULE);
64si_joule!(Kilojoule, "kJ", 1e3, Kilojoules, KILOJOULE);
65si_joule!(Megajoule, "MJ", 1e6, Megajoules, MEGAJOULE);
66si_joule!(Gigajoule, "GJ", 1e9, Gigajoules, GIGAJOULE);
67si_joule!(Terajoule, "TJ", 1e12, Terajoules, TERAJOULE);
68
69#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
71#[unit(symbol = "Wh", dimension = Energy, ratio = 3_600.0)]
72pub struct WattHour;
73pub type WattHours = Quantity<WattHour>;
75pub const WATT_HOUR: WattHours = WattHours::new(1.0);
77
78#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
80#[unit(symbol = "kWh", dimension = Energy, ratio = 3_600_000.0)]
81pub struct KilowattHour;
82pub type KilowattHours = Quantity<KilowattHour>;
84pub const KILOWATT_HOUR: KilowattHours = KilowattHours::new(1.0);
86
87#[cfg(feature = "fundamental-physics")]
93#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
94#[unit(symbol = "erg", dimension = Energy, ratio = 1e-7)]
95pub struct Erg;
96#[cfg(feature = "fundamental-physics")]
98pub type Ergs = Quantity<Erg>;
99
100#[cfg(feature = "fundamental-physics")]
102#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
103#[unit(symbol = "eV", dimension = Energy, ratio = 1.602_176_634e-19)]
104pub struct Electronvolt;
105#[cfg(feature = "fundamental-physics")]
107pub type Electronvolts = Quantity<Electronvolt>;
108
109#[cfg(feature = "fundamental-physics")]
111#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
112#[unit(symbol = "keV", dimension = Energy, ratio = 1.602_176_634e-16)]
113pub struct Kiloelectronvolt;
114#[cfg(feature = "fundamental-physics")]
116pub type Kiloelectronvolts = Quantity<Kiloelectronvolt>;
117
118#[cfg(feature = "fundamental-physics")]
120#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
121#[unit(symbol = "MeV", dimension = Energy, ratio = 1.602_176_634e-13)]
122pub struct Megaelectronvolt;
123#[cfg(feature = "fundamental-physics")]
125pub type Megaelectronvolts = Quantity<Megaelectronvolt>;
126
127#[cfg(feature = "customary")]
129#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
130#[unit(symbol = "cal", dimension = Energy, ratio = 4.184)]
131pub struct Calorie;
132#[cfg(feature = "customary")]
134pub type Calories = Quantity<Calorie>;
135
136#[cfg(feature = "customary")]
138#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
139#[unit(symbol = "kcal", dimension = Energy, ratio = 4184.0)]
140pub struct Kilocalorie;
141#[cfg(feature = "customary")]
143pub type Kilocalories = Quantity<Kilocalorie>;
144
145#[cfg(feature = "customary")]
147#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
148#[unit(symbol = "BTU", dimension = Energy, ratio = 1_055.05585262)]
149pub struct BritishThermalUnit;
150#[cfg(feature = "customary")]
152pub type BritishThermalUnits = Quantity<BritishThermalUnit>;
153
154#[cfg(feature = "customary")]
156#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
157#[unit(symbol = "therm", dimension = Energy, ratio = 105_505_585.262)]
158pub struct Therm;
159#[cfg(feature = "customary")]
161pub type Therms = Quantity<Therm>;
162
163#[macro_export]
169#[doc(hidden)]
170macro_rules! energy_units {
171 ($cb:path) => {
172 $cb!(
173 Joule,
174 Picojoule,
175 Nanojoule,
176 Microjoule,
177 Millijoule,
178 Kilojoule,
179 Megajoule,
180 Gigajoule,
181 Terajoule,
182 WattHour,
183 KilowattHour
184 );
185 };
186}
187
188energy_units!(crate::impl_unit_from_conversions);
190
191#[cfg(feature = "cross-unit-ops")]
192energy_units!(crate::impl_unit_cross_unit_ops);
193
194#[cfg(all(feature = "customary", feature = "fundamental-physics"))]
196crate::__impl_from_each_extra_to_bases!(
197 {Calorie, Kilocalorie, BritishThermalUnit, Therm}
198 Erg, Electronvolt, Kiloelectronvolt, Megaelectronvolt
199);
200#[cfg(all(
201 feature = "customary",
202 feature = "fundamental-physics",
203 feature = "cross-unit-ops"
204))]
205crate::__impl_cross_ops_each_extra_to_bases!(
206 {Calorie, Kilocalorie, BritishThermalUnit, Therm}
207 Erg, Electronvolt, Kiloelectronvolt, Megaelectronvolt
208);
209
210#[cfg(test)]
212energy_units!(crate::assert_units_are_builtin);
213
214#[cfg(feature = "fundamental-physics")]
216#[macro_export]
217#[doc(hidden)]
218macro_rules! energy_fundamental_physics_units {
219 ($cb:path) => {
220 $cb!(Erg, Electronvolt, Kiloelectronvolt, Megaelectronvolt);
221 };
222}
223
224#[cfg(feature = "customary")]
226#[macro_export]
227#[doc(hidden)]
228macro_rules! energy_customary_units {
229 ($cb:path) => {
230 $cb!(Calorie, Kilocalorie, BritishThermalUnit, Therm);
231 };
232}
233
234#[cfg(all(test, feature = "std"))]
235mod tests {
236 use super::*;
237 use approx::assert_abs_diff_eq;
238
239 #[test]
240 fn kilojoule_to_joule() {
241 let kj = Kilojoules::new(1.0);
242 let j: Joules = kj.to();
243 assert_abs_diff_eq!(j.value(), 1_000.0, epsilon = 1e-12);
244 }
245
246 #[test]
247 fn joule_to_millijoule() {
248 let j = Joules::new(1.0);
249 let mj: Millijoules = j.to();
250 assert_abs_diff_eq!(mj.value(), 1_000.0, epsilon = 1e-12);
251 }
252
253 #[test]
254 fn megajoule_to_kilojoule() {
255 let mj = Megajoules::new(1.0);
256 let kj: Kilojoules = mj.to();
257 assert_abs_diff_eq!(kj.value(), 1_000.0, epsilon = 1e-12);
258 }
259
260 #[test]
261 #[cfg(feature = "fundamental-physics")]
262 fn joule_to_erg() {
263 let j = Joules::new(1.0);
264 let e: Ergs = j.to();
265 assert_abs_diff_eq!(e.value(), 1e7, epsilon = 1e-5);
266 }
267
268 #[test]
269 #[cfg(feature = "fundamental-physics")]
270 fn ev_to_joule() {
271 let ev = Electronvolts::new(1.0);
272 let j: Joules = ev.to();
273 assert_abs_diff_eq!(j.value(), 1.602_176_634e-19, epsilon = 1e-30);
274 }
275
276 #[test]
277 #[cfg(feature = "customary")]
278 fn calorie_to_joule() {
279 let cal = Calories::new(1.0);
280 let j: Joules = cal.to();
281 assert_abs_diff_eq!(j.value(), 4.184, epsilon = 1e-12);
282 }
283
284 #[test]
285 #[cfg(feature = "customary")]
286 fn kilocalorie_to_joule() {
287 let kcal = Kilocalories::new(1.0);
288 let j: Joules = kcal.to();
289 assert_abs_diff_eq!(j.value(), 4184.0, epsilon = 1e-9);
290 }
291
292 #[test]
293 fn watt_hour_to_joule() {
294 let wh = WattHours::new(1.0);
295 let j: Joules = wh.to();
296 assert_abs_diff_eq!(j.value(), 3_600.0, epsilon = 1e-10);
297 }
298
299 #[test]
300 fn kilowatt_hour_to_joule() {
301 let kwh = KilowattHours::new(1.0);
302 let j: Joules = kwh.to();
303 assert_abs_diff_eq!(j.value(), 3_600_000.0, epsilon = 1e-6);
304 }
305
306 #[test]
307 fn nanojoule_to_picojoule() {
308 let nj = Nanojoules::new(1.0);
309 let pj: Picojoules = nj.to();
310 assert_abs_diff_eq!(pj.value(), 1_000.0, epsilon = 1e-9);
311 }
312
313 #[test]
314 #[cfg(feature = "customary")]
315 fn btu_to_joule() {
316 let btu = BritishThermalUnits::new(1.0);
317 let j: Joules = btu.to();
318 assert_abs_diff_eq!(j.value(), 1_055.05585262, epsilon = 1e-6);
319 }
320
321 #[test]
322 #[cfg(feature = "customary")]
323 fn therm_to_btu() {
324 let therm = Therms::new(1.0);
325 let btu: BritishThermalUnits = therm.to();
326 assert_abs_diff_eq!(btu.value(), 100_000.0, epsilon = 1e-3);
327 }
328}