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