1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
//! Available energy (base unit joule per kilogram, m² · s⁻²).

quantity! {
    /// Available energy (base unit joule per kilogram, m² · s⁻²).
    quantity: AvailableEnergy; "available energy";
    /// Dimension of available energy, L²T⁻² (base unit joule per kilogram, m² · s⁻²).
    dimension: ISQ<
        P2,     // length
        Z0,     // mass
        N2,     // time
        Z0,     // electric current
        Z0,     // thermodynamic temperature
        Z0,     // amount of substance
        Z0>;    // luminous intensity
    units {
        @yottajoule_per_kilogram: prefix!(yotta); "YJ/kg", "yottajoule per kilogram",
            "yottajoules per kilogram";
        @zettajoule_per_kilogram: prefix!(zetta); "ZJ/kg", "zettajoule per kilogram",
            "zettajoules per kilogram";
        @exajoule_per_kilogram: prefix!(exa); "EJ/kg", "exajoule per kilogram",
            "exajoules per kilogram";
        @petajoule_per_kilogram: prefix!(peta); "PJ/kg", "petajoule per kilogram",
            "petajoules per kilogram";
        @terajoule_per_kilogram: prefix!(tera); "TJ/kg", "terajoule per kilogram",
            "terajoules per kilogram";
        @gigajoule_per_kilogram: prefix!(giga); "GJ/kg", "gigajoule per kilogram",
            "gigajoules per kilogram";
        @megajoule_per_kilogram: prefix!(mega); "MJ/kg", "megajoule per kilogram",
            "megajoules per kilogram";
        @kilojoule_per_kilogram: prefix!(kilo); "kJ/kg", "kilojoule per kilogram",
            "kilojoules per kilogram";
        @hectojoule_per_kilogram: prefix!(hecto); "hJ/kg", "hectojoule per kilogram",
            "hectojoules per kilogram";
        @decajoule_per_kilogram: prefix!(deca); "daJ/kg", "decajoule per kilogram",
            "decajoules per kilogram";
        /// Derived unit of available energy.
        @joule_per_kilogram: prefix!(none); "J/kg", "joule per kilogram", "joules per kilogram";
        @decijoule_per_kilogram: prefix!(deci); "dJ/kg", "decijoule per kilogram",
            "decijoules per kilogram";
        @centijoule_per_kilogram: prefix!(centi); "cJ/kg", "centijoule per kilogram",
            "centijoules per kilogram";
        @millijoule_per_kilogram: prefix!(milli); "mJ/kg", "millijoule per kilogram",
            "millijoules per kilogram";
        @microjoule_per_kilogram: prefix!(micro); "µJ/kg", "microjoule per kilogram",
            "microjoules per kilogram";
        @nanojoule_per_kilogram: prefix!(nano); "nJ/kg", "nanojoule per kilogram",
            "nanojoules per kilogram";
        @picojoule_per_kilogram: prefix!(pico); "pJ/kg", "picojoule per kilogram",
            "picojoules per kilogram";
        @femtojoule_per_kilogram: prefix!(femto); "fJ/kg", "femtojoule per kilogram",
            "femtojoules per kilogram";
        @attojoule_per_kilogram: prefix!(atto); "aJ/kg", "attojoule per kilogram",
            "attojoules per kilogram";
        @zeptojoule_per_kilogram: prefix!(zepto); "zJ/kg", "zeptojoule per kilogram",
            "zeptojoules per kilogram";
        @yoctojoule_per_kilogram: prefix!(yocto); "yJ/kg", "yoctojoule per kilogram",
            "yoctojoules per kilogram";

        @joule_per_zeptogram: prefix!(yotta); "J/zg", "joule per zeptogram",
            "joules per zeptogram";
        @joule_per_attogram: prefix!(zetta); "J/ag", "joule per attogram", "joules per attogram";
        @joule_per_femtogram: prefix!(exa); "J/fg", "joule per femtogram", "joules per femtogram";
        @joule_per_picogram: prefix!(peta); "J/pg", "joule per picogram", "joules per picogram";
        @joule_per_nanogram: prefix!(tera); "J/ng", "joule per nanogram", "joules per nanogram";
        @joule_per_microgram: prefix!(giga); "J/µg", "joule per microgram", "joules per microgram";
        @joule_per_milligram: prefix!(mega); "J/mg", "joule per milligram", "joules per milligram";
        @joule_per_gram: prefix!(kilo); "J/g", "joule per gram", "joules per gram";
        @joule_per_megagram: prefix!(milli); "J/Mg", "joule per megagram", "joules per megagram";
        @joule_per_gigagram: prefix!(micro); "J/Gg", "joule per gigagram", "joules per gigagram";
        @joule_per_teragram: prefix!(nano); "J/Tg", "joule per teragram", "joules per teragram";
        @joule_per_petagram: prefix!(pico); "J/Pg", "joule per petagram", "joules per petagram";
        @joule_per_exagram: prefix!(femto); "J/Eg", "joule per exagram", "joules per exagram";
        @joule_per_zettagram: prefix!(atto); "J/Zg", "joule per zettagram", "joules per zettagram";
        @joule_per_yottagram: prefix!(zepto); "J/Yg", "joule per yottagram",
            "joules per yottagram";

        @btu_it_per_pound: 2.326_000_171_078_704_E3; "Btu (IT)/lb",
            "British thermal unit (IT) per pound", "British thermal units (IT) per pound";
        @btu_per_pound: 2.324_443_707_610_621_E3; "Btu/lb", "British thermal unit per pound",
            "British thermal units per pound";
        @calorie_it_per_gram: 4.186_8_E3; "cal (IT)/lb", "calorie (IT) per gram",
            "calories (IT) per gram";
        @calorie_per_gram: 4.184_E3; "cal/lb", "calorie per gram", "calories per gram";
    }
}

#[cfg(test)]
mod tests {
    storage_types! {
        use crate::num::One;
        use crate::si::available_energy as v;
        use crate::si::energy as e;
        use crate::si::mass as m;
        use crate::si::quantities::*;
        use crate::tests::Test;

        #[test]
        fn check_dimension() {
            let _: AvailableEnergy<V> = Energy::new::<e::joule>(V::one())
                / Mass::new::<m::kilogram>(V::one());
        }

        #[test]
        fn check_units() {
            test::<e::yottajoule, m::kilogram, v::yottajoule_per_kilogram>();
            test::<e::exajoule, m::kilogram, v::exajoule_per_kilogram>();
            test::<e::terajoule, m::kilogram, v::terajoule_per_kilogram>();
            test::<e::megajoule, m::kilogram, v::megajoule_per_kilogram>();
            test::<e::joule, m::kilogram, v::joule_per_kilogram>();
            test::<e::microjoule, m::kilogram, v::microjoule_per_kilogram>();
            test::<e::picojoule, m::kilogram, v::picojoule_per_kilogram>();
            test::<e::attojoule, m::kilogram, v::attojoule_per_kilogram>();
            test::<e::yoctojoule, m::kilogram, v::yoctojoule_per_kilogram>();

            test::<e::joule, m::zeptogram, v::joule_per_zeptogram>();
            test::<e::joule, m::femtogram, v::joule_per_femtogram>();
            test::<e::joule, m::nanogram, v::joule_per_nanogram>();
            test::<e::joule, m::milligram, v::joule_per_milligram>();
            test::<e::joule, m::gigagram, v::joule_per_gigagram>();
            test::<e::joule, m::petagram, v::joule_per_petagram>();
            test::<e::joule, m::zettagram, v::joule_per_zettagram>();

            test::<e::btu_it, m::pound, v::btu_it_per_pound>();
            test::<e::btu, m::pound, v::btu_per_pound>();
            test::<e::calorie_it, m::gram, v::calorie_it_per_gram>();
            test::<e::calorie, m::gram, v::calorie_per_gram>();

            fn test<E: e::Conversion<V>, M: m::Conversion<V>, A: v::Conversion<V>>() {
                Test::assert_approx_eq(&AvailableEnergy::new::<A>(V::one()),
                    &(Energy::new::<E>(V::one()) / Mass::new::<M>(V::one())));
            }
        }
    }
}