1use crate::{Dimension, Quantity, Unit};
19use qtty_derive::Unit;
20
21pub enum Power {}
23impl Dimension for Power {}
24
25pub trait PowerUnit: Unit<Dim = Power> {}
27impl<T: Unit<Dim = Power>> PowerUnit for T {}
28
29#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
31#[unit(symbol = "W", dimension = Power, ratio = 1.0)]
32pub struct Watt;
33pub type W = Watt;
35pub type Watts = Quantity<W>;
37pub const WATT: Watts = Watts::new(1.0);
39
40macro_rules! si_watt {
41 ($name:ident, $sym:literal, $ratio:expr, $alias:ident, $qty:ident, $one:ident) => {
42 #[doc = concat!("SI-prefixed watt unit (", stringify!($ratio), " W).")]
43 #[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
44 #[unit(symbol = $sym, dimension = Power, ratio = $ratio)]
45 pub struct $name;
46 #[doc = concat!("Type alias shorthand for [`", stringify!($name), "`].")]
47 pub type $alias = $name;
48 #[doc = concat!("A quantity measured in ", stringify!($name), "s.")]
49 pub type $qty = Quantity<$alias>;
50 #[doc = concat!("One ", stringify!($name), ".")]
51 pub const $one: $qty = $qty::new(1.0);
52 };
53}
54
55si_watt!(Yoctowatt, "yW", 1e-24, Yw, Yoctowatts, YW);
57si_watt!(Zeptowatt, "zW", 1e-21, Zw, Zeptowatts, ZW);
58si_watt!(Attowatt, "aW", 1e-18, Aw, Attowatts, AW);
59si_watt!(Femtowatt, "fW", 1e-15, Fw, Femtowatts, FW);
60si_watt!(Picowatt, "pW", 1e-12, Pw, Picowatts, PW);
61si_watt!(Nanowatt, "nW", 1e-9, Nw, Nanowatts, NW);
62si_watt!(Microwatt, "µW", 1e-6, Uw, Microwatts, UW);
63si_watt!(Milliwatt, "mW", 1e-3, Mw, Milliwatts, MW_1);
64
65si_watt!(Deciwatt, "dW", 1e-1, Dw, Deciwatts, DW);
66si_watt!(Decawatt, "daW", 1e1, Daw, Decawatts, DAW);
67si_watt!(Hectowatt, "hW", 1e2, Hw, Hectowatts, HW);
68si_watt!(Kilowatt, "kW", 1e3, Kw, Kilowatts, KW);
69si_watt!(Megawatt, "MW", 1e6, MW, Megawatts, MEGAWATT);
70si_watt!(Gigawatt, "GW", 1e9, GW, Gigawatts, GW_1);
71si_watt!(Terawatt, "TW", 1e12, TW, Terawatts, TW_1);
72si_watt!(Petawatt, "PW", 1e15, PW, Petawatts, PETAWATT);
73si_watt!(Exawatt, "EW", 1e18, EW, Exawatts, EW_1);
74si_watt!(Zettawatt, "ZW", 1e21, ZW, Zettawatts, ZW_1);
75si_watt!(Yottawatt, "YW", 1e24, YW, Yottawatts, YW_1);
76
77#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
81#[unit(symbol = "erg/s", dimension = Power, ratio = 1e-7)]
82pub struct ErgPerSecond;
83pub const ERG_PER_S: Quantity<ErgPerSecond> = Quantity::new(1.0);
85
86#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
88#[unit(symbol = "PS", dimension = Power, ratio = 73_549_875.0 / 100_000.0)]
89pub struct HorsepowerMetric;
90pub type HorsepowerMetrics = Quantity<HorsepowerMetric>;
92pub const PS: HorsepowerMetrics = HorsepowerMetrics::new(1.0);
94
95#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
97#[unit(symbol = "hp_e", dimension = Power, ratio = 746.0)]
98pub struct HorsepowerElectric;
99pub type HorsepowerElectrics = Quantity<HorsepowerElectric>;
101pub const HP_E: HorsepowerElectrics = HorsepowerElectrics::new(1.0);
103
104#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
108#[unit(symbol = "L☉", dimension = Power, ratio = 3.828e26)]
109pub struct SolarLuminosity;
110pub type SolarLuminosities = Quantity<SolarLuminosity>;
112pub const L_SUN: SolarLuminosities = SolarLuminosities::new(1.0);
114
115crate::impl_unit_conversions!(
117 Watt,
118 Yoctowatt,
119 Zeptowatt,
120 Attowatt,
121 Femtowatt,
122 Picowatt,
123 Nanowatt,
124 Microwatt,
125 Milliwatt,
126 Deciwatt,
127 Decawatt,
128 Hectowatt,
129 Kilowatt,
130 Megawatt,
131 Gigawatt,
132 Terawatt,
133 Petawatt,
134 Exawatt,
135 Zettawatt,
136 Yottawatt,
137 ErgPerSecond,
138 HorsepowerMetric,
139 HorsepowerElectric,
140 SolarLuminosity
141);
142
143#[cfg(test)]
144mod tests {
145 use super::*;
146 use approx::assert_relative_eq;
147 use proptest::prelude::*;
148
149 #[test]
154 fn solar_luminosity_to_watts() {
155 let sol = SolarLuminosities::new(1.0);
156 let w = sol.to::<Watt>();
157 assert_relative_eq!(w.value(), 3.828e26, max_relative = 1e-9);
159 }
160
161 #[test]
162 fn watts_to_solar_luminosity() {
163 let w = Watts::new(3.828e26);
164 let sol = w.to::<SolarLuminosity>();
165 assert_relative_eq!(sol.value(), 1.0, max_relative = 1e-9);
166 }
167
168 #[test]
169 fn multiple_solar_luminosities() {
170 let sol = SolarLuminosities::new(3.0);
171 let w = sol.to::<Watt>();
172 assert_relative_eq!(w.value(), 3.0 * 3.828e26, max_relative = 1e-9);
173 }
174
175 #[test]
180 fn solar_luminosity_ratio_sanity() {
181 assert_relative_eq!(SolarLuminosity::RATIO, 3.828e26, max_relative = 1e-9);
183 }
184
185 #[test]
186 fn solar_luminosity_order_of_magnitude() {
187 let sun = SolarLuminosities::new(1.0);
188 let w = sun.to::<Watt>();
189 assert!(w.value() > 1e26);
191 assert!(w.value() < 1e27);
192 }
193
194 #[test]
199 fn roundtrip_w_sol() {
200 let original = Watts::new(1e26);
201 let converted = original.to::<SolarLuminosity>();
202 let back = converted.to::<Watt>();
203 assert_relative_eq!(back.value(), original.value(), max_relative = 1e-12);
204 }
205
206 proptest! {
211 #[test]
212 fn prop_roundtrip_w_sol(w in 1e20..1e30f64) {
213 let original = Watts::new(w);
214 let converted = original.to::<SolarLuminosity>();
215 let back = converted.to::<Watt>();
216 prop_assert!((back.value() - original.value()).abs() / original.value() < 1e-12);
217 }
218 }
219}