1use crate::{Quantity, Unit};
36use qtty_derive::Unit;
37
38pub use crate::dimension::Power;
40
41pub trait PowerUnit: Unit<Dim = Power> {}
43impl<T: Unit<Dim = Power>> PowerUnit for T {}
44
45#[cfg(feature = "fundamental-physics")]
46mod fundamental_physics;
47#[cfg(feature = "fundamental-physics")]
48pub use fundamental_physics::*;
49#[cfg(feature = "customary")]
50mod customary;
51#[cfg(feature = "customary")]
52pub use customary::*;
53#[cfg(feature = "astro")]
54mod astro;
55#[cfg(feature = "astro")]
56pub use astro::*;
57
58#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
60#[unit(symbol = "W", dimension = Power, ratio = 1.0)]
61pub struct Watt;
62pub type W = Watt;
64pub type Watts = Quantity<W>;
66pub const WATT: Watts = Watts::new(1.0);
68
69macro_rules! si_watt {
70 ($name:ident, $sym:literal, $ratio:expr, $alias:ident, $qty:ident, $one:ident) => {
71 #[doc = concat!("SI-prefixed watt unit (", stringify!($ratio), " W).")]
72 #[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
73 #[unit(symbol = $sym, dimension = Power, ratio = $ratio)]
74 pub struct $name;
75 #[doc = concat!("Type alias shorthand for [`", stringify!($name), "`].")]
76 pub type $alias = $name;
77 #[doc = concat!("A quantity measured in ", stringify!($name), "s.")]
78 pub type $qty = Quantity<$alias>;
79 #[doc = concat!("One ", stringify!($name), ".")]
80 pub const $one: $qty = $qty::new(1.0);
81 };
82}
83
84si_watt!(Yoctowatt, "yW", 1e-24, Yw, Yoctowatts, YW);
86si_watt!(Zeptowatt, "zW", 1e-21, Zw, Zeptowatts, ZW);
87si_watt!(Attowatt, "aW", 1e-18, Aw, Attowatts, AW);
88si_watt!(Femtowatt, "fW", 1e-15, Fw, Femtowatts, FW);
89si_watt!(Picowatt, "pW", 1e-12, Pw, Picowatts, PW);
90si_watt!(Nanowatt, "nW", 1e-9, Nw, Nanowatts, NW);
91si_watt!(Microwatt, "µW", 1e-6, Uw, Microwatts, UW);
92si_watt!(Milliwatt, "mW", 1e-3, Mw, Milliwatts, MW_1);
93
94si_watt!(Deciwatt, "dW", 1e-1, Dw, Deciwatts, DW);
95si_watt!(Decawatt, "daW", 1e1, Daw, Decawatts, DAW);
96si_watt!(Hectowatt, "hW", 1e2, Hw, Hectowatts, HW);
97si_watt!(Kilowatt, "kW", 1e3, Kw, Kilowatts, KW);
98si_watt!(Megawatt, "MW", 1e6, MW, Megawatts, MEGAWATT);
99si_watt!(Gigawatt, "GW", 1e9, GW, Gigawatts, GW_1);
100si_watt!(Terawatt, "TW", 1e12, TW, Terawatts, TW_1);
101si_watt!(Petawatt, "PW", 1e15, PW, Petawatts, PETAWATT);
102si_watt!(Exawatt, "EW", 1e18, EW, Exawatts, EW_1);
103si_watt!(Zettawatt, "ZW", 1e21, ZW, Zettawatts, ZW_1);
104si_watt!(Yottawatt, "YW", 1e24, YW, Yottawatts, YW_1);
105
106#[macro_export]
112#[doc(hidden)]
113macro_rules! power_units {
114 ($cb:path) => {
115 $cb!(
116 Watt, Yoctowatt, Zeptowatt, Attowatt, Femtowatt, Picowatt, Nanowatt, Microwatt,
117 Milliwatt, Deciwatt, Decawatt, Hectowatt, Kilowatt, Megawatt, Gigawatt, Terawatt,
118 Petawatt, Exawatt, Zettawatt, Yottawatt
119 );
120 };
121}
122
123power_units!(crate::impl_unit_from_conversions);
125
126#[cfg(feature = "cross-unit-ops")]
130power_units!(crate::impl_unit_cross_unit_ops);
131
132#[cfg(all(feature = "astro", feature = "customary"))]
134crate::__impl_from_each_extra_to_bases!(
135 {SolarLuminosity}
136 HorsepowerMetric, HorsepowerElectric
137);
138#[cfg(all(feature = "astro", feature = "customary", feature = "cross-unit-ops"))]
139crate::__impl_cross_ops_each_extra_to_bases!(
140 {SolarLuminosity}
141 HorsepowerMetric, HorsepowerElectric
142);
143
144#[cfg(all(feature = "astro", feature = "fundamental-physics"))]
145crate::__impl_from_each_extra_to_bases!(
146 {SolarLuminosity}
147 ErgPerSecond
148);
149#[cfg(all(
150 feature = "astro",
151 feature = "fundamental-physics",
152 feature = "cross-unit-ops"
153))]
154crate::__impl_cross_ops_each_extra_to_bases!(
155 {SolarLuminosity}
156 ErgPerSecond
157);
158
159#[cfg(all(feature = "customary", feature = "fundamental-physics"))]
160crate::__impl_from_each_extra_to_bases!(
161 {HorsepowerMetric, HorsepowerElectric}
162 ErgPerSecond
163);
164#[cfg(all(
165 feature = "customary",
166 feature = "fundamental-physics",
167 feature = "cross-unit-ops"
168))]
169crate::__impl_cross_ops_each_extra_to_bases!(
170 {HorsepowerMetric, HorsepowerElectric}
171 ErgPerSecond
172);
173
174#[cfg(test)]
176power_units!(crate::assert_units_are_builtin);
177
178#[cfg(all(test, feature = "std"))]
179mod tests {
180 use super::*;
181 use approx::assert_relative_eq;
182 use proptest::prelude::*;
183
184 #[test]
189 #[cfg(feature = "astro")]
190 fn solar_luminosity_to_watts() {
191 let sol = SolarLuminosities::new(1.0);
192 let w = sol.to::<Watt>();
193 assert_relative_eq!(w.value(), 3.828e26, max_relative = 1e-9);
195 }
196
197 #[test]
198 #[cfg(feature = "astro")]
199 fn watts_to_solar_luminosity() {
200 let w = Watts::new(3.828e26);
201 let sol = w.to::<SolarLuminosity>();
202 assert_relative_eq!(sol.value(), 1.0, max_relative = 1e-9);
203 }
204
205 #[test]
206 #[cfg(feature = "astro")]
207 fn multiple_solar_luminosities() {
208 let sol = SolarLuminosities::new(3.0);
209 let w = sol.to::<Watt>();
210 assert_relative_eq!(w.value(), 3.0 * 3.828e26, max_relative = 1e-9);
211 }
212
213 #[test]
218 #[cfg(feature = "astro")]
219 fn solar_luminosity_ratio_sanity() {
220 assert_relative_eq!(SolarLuminosity::RATIO, 3.828e26, max_relative = 1e-9);
222 }
223
224 #[test]
225 #[cfg(feature = "astro")]
226 fn solar_luminosity_order_of_magnitude() {
227 let sun = SolarLuminosities::new(1.0);
228 let w = sun.to::<Watt>();
229 assert!(w.value() > 1e26);
231 assert!(w.value() < 1e27);
232 }
233
234 #[test]
239 #[cfg(feature = "astro")]
240 fn roundtrip_w_sol() {
241 let original = Watts::new(1e26);
242 let converted = original.to::<SolarLuminosity>();
243 let back = converted.to::<Watt>();
244 assert_relative_eq!(back.value(), original.value(), max_relative = 1e-12);
245 }
246
247 proptest! {
252 #[test]
253 #[cfg(feature = "astro")]
254 fn prop_roundtrip_w_sol(w in 1e20..1e30f64) {
255 let original = Watts::new(w);
256 let converted = original.to::<SolarLuminosity>();
257 let back = converted.to::<Watt>();
258 prop_assert!((back.value() - original.value()).abs() / original.value() < 1e-12);
259 }
260 }
261
262 #[test]
265 fn kilowatt_to_watt() {
266 let kw = Kilowatts::new(1.0);
267 let w = kw.to::<Watt>();
268 assert_relative_eq!(w.value(), 1_000.0, max_relative = 1e-12);
269 }
270
271 #[test]
272 fn megawatt_to_kilowatt() {
273 let mw = Megawatts::new(1.0);
274 let kw = mw.to::<Kilowatt>();
275 assert_relative_eq!(kw.value(), 1_000.0, max_relative = 1e-12);
276 }
277
278 #[test]
279 fn milliwatt_to_watt() {
280 let mw = Milliwatts::new(1000.0);
281 let w = mw.to::<Watt>();
282 assert_relative_eq!(w.value(), 1.0, max_relative = 1e-12);
283 }
284
285 #[test]
288 #[cfg(feature = "fundamental-physics")]
289 fn erg_per_second_to_watt() {
290 let erg_s = Quantity::<ErgPerSecond>::new(1e7);
291 let w = erg_s.to::<Watt>();
292 assert_relative_eq!(w.value(), 1.0, max_relative = 1e-9);
294 }
295
296 #[test]
297 #[cfg(feature = "customary")]
298 fn metric_horsepower_to_watt() {
299 let ps = HorsepowerMetrics::new(1.0);
300 let w = ps.to::<Watt>();
301 assert_relative_eq!(w.value(), 735.498_75, max_relative = 1e-9);
303 }
304
305 #[test]
306 #[cfg(feature = "customary")]
307 fn electric_horsepower_to_watt() {
308 let hp = HorsepowerElectrics::new(1.0);
309 let w = hp.to::<Watt>();
310 assert_relative_eq!(w.value(), 746.0, max_relative = 1e-12);
312 }
313
314 #[test]
315 fn symbols_are_correct() {
316 assert_eq!(Watt::SYMBOL, "W");
317 assert_eq!(Kilowatt::SYMBOL, "kW");
318 assert_eq!(Megawatt::SYMBOL, "MW");
319 #[cfg(feature = "customary")]
320 assert_eq!(HorsepowerMetric::SYMBOL, "PS");
321 #[cfg(feature = "fundamental-physics")]
322 assert_eq!(ErgPerSecond::SYMBOL, "erg/s");
323 }
324}