rpn_cli/calc/
meaning.rs

1use crate::calc::meaning::AreaKind::*;
2use crate::calc::meaning::DataKind::*;
3use crate::calc::meaning::DeltaKind::*;
4use crate::calc::meaning::LengthKind::*;
5use crate::calc::meaning::MassKind::*;
6use crate::calc::meaning::Meaning::*;
7use crate::calc::meaning::PrefixKind::*;
8use crate::calc::meaning::SpeedKind::*;
9use crate::calc::meaning::TempKind::*;
10use crate::calc::meaning::VolumeKind::*;
11use crate::core::interface::Meanings;
12use crate::error::{EngineError, MyResult};
13use crate::util::number::create_ratio;
14use num::{BigRational, CheckedAdd, CheckedDiv, CheckedMul, CheckedSub, One, Zero};
15use std::borrow::Cow;
16use std::cell::RefCell;
17use std::fmt::{Display, Formatter};
18use std::ops::{DerefMut, Div, Mul};
19
20#[macro_export]
21macro_rules! combine_inner {
22    ($lhs:expr, $rhs:expr) => {
23        None
24    };
25    ($lhs:expr, $rhs:expr, $head:ident) => {
26        Meaning::$head($lhs, $rhs)
27    };
28    ($lhs:expr, $rhs:expr, $head:ident, $($tail:ident),+) => {
29        Meaning::$head($lhs, $rhs).or_else(|| combine_inner!($lhs, $rhs, $($tail),*))
30    };
31}
32
33#[macro_export]
34macro_rules! combine_cast {
35    ($input:expr, $output:expr, $($tail:ident),+ $(,)?) => {
36        {
37            let input = $input;
38            let output = $output;
39            let result = combine_inner!(input, output, $($tail),*);
40            result.ok_or_else(|| MyError::Engine(EngineError::BadCastOp(input, output)))
41        }
42    };
43}
44
45#[macro_export]
46macro_rules! combine_binary {
47    ($lhs:expr, $rhs:expr, $($tail:ident),+ $(,)?) => {
48        {
49            let lhs = $lhs;
50            let rhs = $rhs;
51            let result = combine_inner!(lhs, rhs, $($tail),*);
52            result.ok_or_else(|| MyError::Engine(EngineError::BadCastOp(rhs, lhs)))
53        }
54    };
55}
56
57// Definitions: https://en.wikipedia.org/wiki/List_of_conversion_factors
58// Unit tests:  https://www.digitaldutch.com/unitconverter/length.htm
59
60pub trait UnitInfo {
61    fn walk_values<F: FnMut(Self) -> MyResult<()>>(
62        multiply: bool,
63        divide: bool,
64        function: F,
65    ) -> MyResult<()> where Self: Sized;
66
67    fn get_factor(&self) -> BigRational {
68        BigRational::one()
69    }
70
71    fn get_offset(&self) -> BigRational {
72        BigRational::zero()
73    }
74
75    fn get_name(&self) -> Option<String>;
76
77    fn get_symbol(&self) -> Option<String>;
78}
79
80#[derive(Clone, Copy, Debug, PartialEq)]
81pub enum PrefixKind {
82    Quetta,
83    Ronna,
84    Yotta,
85    Zetta,
86    Exa,
87    Peta,
88    Tera,
89    Giga,
90    Mega,
91    Kilo,
92    Hecto,
93    Deca,
94    Unit,
95    Deci,
96    Centi,
97    Milli,
98    Micro,
99    Nano,
100    Pico,
101    Femto,
102    Atto,
103    Zepto,
104    Yocto,
105    Ronto,
106    Quecto,
107}
108
109#[derive(Clone, Copy, Debug, PartialEq)]
110pub enum DeltaKind {
111    Second(PrefixKind),
112    Minute,
113    Hour,
114    Day,
115    Week,
116    Month,
117    Year,
118    HMS,
119}
120
121#[derive(Clone, Copy, Debug, PartialEq)]
122pub enum LengthKind {
123    Metre(PrefixKind),
124    Inch,
125    Foot,
126    Yard,
127    Mile,
128}
129
130#[derive(Clone, Copy, Debug, PartialEq)]
131pub enum AreaKind {
132    Square(LengthKind),
133    Hectare,
134    Acre,
135}
136
137#[derive(Clone, Copy, Debug, PartialEq)]
138pub enum VolumeKind {
139    Cubic(LengthKind),
140    Litre(PrefixKind),
141    Tsp,
142    Tbsp,
143    Floz,
144    Pint,
145    Quart,
146    Gallon,
147    Barrel,
148    USTsp,
149    USTbsp,
150    USFloz,
151    USCup,
152    USPint,
153    USQuart,
154    USGallon,
155    USBarrel,
156}
157
158#[derive(Clone, Copy, Debug, PartialEq)]
159pub enum SpeedKind {
160    Ratio(LengthKind, DeltaKind),
161    Mach,
162    Light,
163}
164
165#[derive(Clone, Copy, Debug, PartialEq)]
166pub enum MassKind {
167    Gram(PrefixKind),
168    Ounce,
169    Pound,
170    Stone,
171    Ton,
172}
173
174#[derive(Clone, Copy, Debug, PartialEq)]
175pub enum TempKind {
176    Kelvin(PrefixKind),
177    Celsius,
178    Fahrenheit,
179    Rankine,
180}
181
182#[derive(Clone, Copy, Debug, PartialEq)]
183pub enum DataKind {
184    Byte(PrefixKind),
185    Bit,
186}
187
188#[derive(Clone, Copy, Debug, PartialEq)]
189pub enum Meaning {
190    Plain,
191    Delta(DeltaKind),
192    Time,
193    Length(LengthKind),
194    Area(AreaKind),
195    Volume(VolumeKind),
196    Speed(SpeedKind),
197    Mass(MassKind),
198    Temp(TempKind),
199    Data(DataKind),
200}
201
202impl PrefixKind {
203    pub fn walk_values<F: FnMut(Self) -> MyResult<()>>(
204        multiply: bool,
205        divide: bool,
206        mut function: F,
207    ) -> MyResult<()> {
208        if multiply {
209            function(Quetta)?;
210            function(Ronna)?;
211            function(Yotta)?;
212            function(Zetta)?;
213            function(Exa)?;
214            function(Peta)?;
215            function(Tera)?;
216            function(Giga)?;
217            function(Mega)?;
218            function(Kilo)?;
219            function(Hecto)?;
220            function(Deca)?;
221        }
222        function(Unit)?;
223        if divide {
224            function(Deci)?;
225            function(Centi)?;
226            function(Milli)?;
227            function(Micro)?;
228            function(Nano)?;
229            function(Pico)?;
230            function(Femto)?;
231            function(Atto)?;
232            function(Zepto)?;
233            function(Yocto)?;
234            function(Ronto)?;
235            function(Quecto)?;
236        }
237        Ok(())
238    }
239}
240
241impl PrefixKind {
242    fn get_factor(&self) -> BigRational {
243        let power = self.get_power();
244        create_ratio(10, 1).pow(power)
245    }
246
247    pub fn get_power(&self) -> i32 {
248        match self {
249            Quetta => 30,
250            Ronna => 27,
251            Yotta => 24,
252            Zetta => 21,
253            Exa => 18,
254            Peta => 15,
255            Tera => 12,
256            Giga => 9,
257            Mega => 6,
258            Kilo => 3,
259            Hecto => 2,
260            Deca => 1,
261            Unit => 0,
262            Deci => -1,
263            Centi => -2,
264            Milli => -3,
265            Micro => -6,
266            Nano => -9,
267            Pico => -12,
268            Femto => -15,
269            Atto => -18,
270            Zepto => -21,
271            Yocto => -24,
272            Ronto => -27,
273            Quecto => -30,
274        }
275    }
276
277    pub fn get_name(&self) -> &'static str {
278        match self {
279            Quetta => "quetta",
280            Ronna => "ronna",
281            Yotta => "yotta",
282            Zetta => "zetta",
283            Exa => "exa",
284            Peta => "peta",
285            Tera => "tera",
286            Giga => "giga",
287            Mega => "mega",
288            Kilo => "kilo",
289            Hecto => "hecto",
290            Deca => "deca",
291            Unit => "",
292            Deci => "deci",
293            Centi => "centi",
294            Milli => "milli",
295            Micro => "micro",
296            Nano => "nano",
297            Pico => "pico",
298            Femto => "femto",
299            Atto => "atto",
300            Zepto => "zepto",
301            Yocto => "yocto",
302            Ronto => "ronto",
303            Quecto => "quecto",
304        }
305    }
306
307    pub fn get_symbol(&self) -> &'static str {
308        match self {
309            Quetta => "Q",
310            Ronna => "R",
311            Yotta => "Y",
312            Zetta => "Z",
313            Exa => "E",
314            Peta => "P",
315            Tera => "T",
316            Giga => "G",
317            Mega => "M",
318            Kilo => "k",
319            Hecto => "h",
320            Deca => "da",
321            Unit => "",
322            Deci => "d",
323            Centi => "c",
324            Milli => "m",
325            Micro => "u",
326            Nano => "n",
327            Pico => "p",
328            Femto => "f",
329            Atto => "a",
330            Zepto => "z",
331            Yocto => "y",
332            Ronto => "r",
333            Quecto => "q",
334        }
335    }
336}
337
338impl UnitInfo for DeltaKind {
339    fn walk_values<F: FnMut(Self) -> MyResult<()>>(
340        multiply: bool,
341        divide: bool,
342        mut function: F,
343    ) -> MyResult<()> {
344        PrefixKind::walk_values(multiply, divide, |prefix| function(Second(prefix)))?;
345        function(Minute)?;
346        function(Hour)?;
347        function(Day)?;
348        function(Week)?;
349        function(Month)?;
350        function(Year)?;
351        function(HMS)?;
352        Ok(())
353    }
354
355    fn get_factor(&self) -> BigRational {
356        match self {
357            Second(prefix) => prefix.get_factor(),
358            Minute => create_ratio(60, 1), // 60
359            Hour => create_ratio(3600, 1), // 60 * 60
360            Day => create_ratio(86400, 1), // 60 * 60 * 24
361            Week => create_ratio(604800, 1), // 60 * 60 * 24 * 7
362            Month => create_ratio(2592000, 1), // 60 * 60 * 24 * 30
363            Year => create_ratio(31557600, 1), // 60 * 60 * 24 * 365.25
364            HMS => create_ratio(1, 1),
365        }
366    }
367
368    fn get_name(&self) -> Option<String> {
369        match self {
370            Second(prefix) => Some(format!("{}second", prefix.get_name())),
371            Minute => Some(String::from("minute")),
372            Hour => Some(String::from("hour")),
373            Day => Some(String::from("day")),
374            Week => Some(String::from("week")),
375            Month => Some(String::from("month")),
376            Year => Some(String::from("year")),
377            HMS => None,
378        }
379    }
380
381    fn get_symbol(&self) -> Option<String> {
382        match self {
383            Second(prefix) => Some(format!("{}s", prefix.get_symbol())),
384            _ => None,
385        }
386    }
387}
388
389impl UnitInfo for LengthKind {
390    fn walk_values<F: FnMut(Self) -> MyResult<()>>(
391        multiply: bool,
392        divide: bool,
393        mut function: F,
394    ) -> MyResult<()> {
395        PrefixKind::walk_values(multiply, divide, |prefix| function(Metre(prefix)))?;
396        function(Inch)?;
397        function(Foot)?;
398        function(Yard)?;
399        function(Mile)?;
400        Ok(())
401    }
402
403    fn get_factor(&self) -> BigRational {
404        match self {
405            Metre(prefix) => prefix.get_factor(),
406            Inch => create_ratio(254, 10000), // inch (international) # in # = 2.54 cm = 1/36 yd = 1/12 ft # = 0.0254 m
407            Foot => create_ratio(3048, 10000), // foot (international) # ft # = 0.3048 m = 1/3 yd = 12 inches # = 0.3048 m
408            Yard => create_ratio(9144, 10000), // yard (international) # yd # = 0.9144 m = 3 ft = 36 in # = 0.9144 m
409            Mile => create_ratio(16093440, 10000), // mile (international) # mi # = 80 chains = 5280 ft = 1760 yd # = 1609.344 m
410        }
411    }
412
413    fn get_name(&self) -> Option<String> {
414        match self {
415            Metre(prefix) => Some(format!("{}metre", prefix.get_name())),
416            Inch => Some(String::from("inch")),
417            Foot => Some(String::from("foot")),
418            Yard => Some(String::from("yard")),
419            Mile => Some(String::from("mile")),
420        }
421    }
422
423    fn get_symbol(&self) -> Option<String> {
424        match self {
425            Metre(prefix) => Some(format!("{}m", prefix.get_symbol())),
426            _ => None,
427        }
428    }
429}
430
431impl UnitInfo for AreaKind {
432    fn walk_values<F: FnMut(Self) -> MyResult<()>>(
433        multiply: bool,
434        divide: bool,
435        mut function: F,
436    ) -> MyResult<()> {
437        LengthKind::walk_values(multiply, divide, |length| function(Square(length)))?;
438        function(Hectare)?;
439        function(Acre)?;
440        Ok(())
441    }
442
443    fn get_factor(&self) -> BigRational {
444        match self {
445            Square(length) => length.get_factor().pow(2),
446            Hectare => create_ratio(10000, 1),
447            Acre => create_ratio(40468564224, 10000000), // acre (international) # ac # = 1 ch x 10 ch = 4840 sq yd # = 4046.8564224 m2
448        }
449    }
450
451    fn get_name(&self) -> Option<String> {
452        match self {
453            Square(length) => length.get_name().map(|x| format!("square-{}", x)),
454            Hectare => Some(String::from("hectare")),
455            Acre => Some(String::from("acre")),
456        }
457    }
458
459    fn get_symbol(&self) -> Option<String> {
460        match self {
461            Square(length) => length.get_symbol()
462                .or_else(|| length.get_name())
463                .map(|x| format!("{}^2", x)),
464            _ => None,
465        }
466    }
467}
468
469impl UnitInfo for VolumeKind {
470    fn walk_values<F: FnMut(Self) -> MyResult<()>>(
471        multiply: bool,
472        divide: bool,
473        mut function: F,
474    ) -> MyResult<()> {
475        LengthKind::walk_values(multiply, divide, |length| function(Cubic(length)))?;
476        PrefixKind::walk_values(multiply, divide, |prefix| function(Litre(prefix)))?;
477        function(Tsp)?;
478        function(Tbsp)?;
479        function(Floz)?;
480        function(Pint)?;
481        function(Quart)?;
482        function(Gallon)?;
483        function(Barrel)?;
484        function(USTsp)?;
485        function(USTbsp)?;
486        function(USFloz)?;
487        function(USCup)?;
488        function(USPint)?;
489        function(USQuart)?;
490        function(USGallon)?;
491        function(USBarrel)?;
492        Ok(())
493    }
494
495    fn get_factor(&self) -> BigRational {
496        match self {
497            Cubic(length) => length.get_factor().pow(3),
498            Litre(prefix) => prefix.get_factor().mul(create_ratio(1, 1000)),
499            Tsp => create_ratio(5_919_388_020_830, 1_000_000_000_000_000_000), // teaspoon (imperial) # tsp # = 1/24 gi (imp) # = 5.91938802083x10-6 m3
500            Tbsp => create_ratio(17_758_164_062_500, 1_000_000_000_000_000_000), // tablespoon (imperial) # tbsp # = 5/8 fl oz (imp) # = 17.7581640625x10-6 m3
501            Floz => create_ratio(28_413_062_500_000, 1_000_000_000_000_000_000), // ounce (fluid imperial) # fl oz (imp) # = 1/160 gal (imp) # = 28.4130625x10-6 m3
502            Pint => create_ratio(568_261_250_000_000, 1_000_000_000_000_000_000), // pint (imperial) # pt (imp) # = 1/8 gal (imp) # = 568.26125x10-6 m3
503            Quart => create_ratio(1_136_522_500_000_000, 1_000_000_000_000_000_000), // quart (imperial) # qt (imp) # = 1/4 gal (imp) # = 1.1365225x10-3 m3
504            Gallon => create_ratio(4_546_090_000_000_000, 1_000_000_000_000_000_000), // gallon (imperial) # gal (imp) # = 4.54609 L # = 4.54609x10-3 m3
505            Barrel => create_ratio(163_659_240_000_000_000, 1_000_000_000_000_000_000), // barrel (imperial) # bl (imp) # = 36 gal (imp) # = 0.16365924 m3
506            USTsp => create_ratio(4_928_921_593_750, 1_000_000_000_000_000_000), // teaspoon (US customary) # tsp # = 1/6 US fl oz # = 4.92892159375x10-6 m3
507            USTbsp => create_ratio(14_786_764_781_250, 1_000_000_000_000_000_000), // tablespoon (US customary) # tbsp # = 1/2 US fl oz # = 14.78676478125x10-6 m3
508            USFloz => create_ratio(29_573_529_562_500, 1_000_000_000_000_000_000), // ounce (fluid US customary) # US fl oz # = 1/128 gal (US) # = 29.5735295625x10-6 m3
509            USCup => create_ratio(236_588_236_500_000, 1_000_000_000_000_000_000), // cup (US customary) # c (US) # = 8 US fl oz = 1/16 gal (US) # = 236.5882365x10-6 m3
510            USPint => create_ratio(473_176_473_000_000, 1_000_000_000_000_000_000), // pint (US fluid) # pt (US fl) # = 1/8 gal (US) # = 473.176473x10-6 m3
511            USQuart => create_ratio(946_352_946_000_000, 1_000_000_000_000_000_000), // quart (US fluid) # qt (US) # = 1/4 gal (US fl) # = 946.352946x10-6 m3
512            USGallon => create_ratio(3_785_411_784_000_000, 1_000_000_000_000_000_000), // gallon (US fluid; Wine) # gal (US) # = 231 cu in # = 3.785411784x10-3 m3
513            USBarrel => create_ratio(119_240_471_196_000_000, 1_000_000_000_000_000_000), // barrel (US fluid) # fl bl (US) # = 31+1/2 gal (US) # = 0.119240471196 m3
514        }
515    }
516
517    fn get_name(&self) -> Option<String> {
518        match self {
519            Cubic(length) => length.get_name().map(|x| format!("cubic-{}", x)),
520            Litre(prefix) => Some(format!("{}litre", prefix.get_name())),
521            Tsp => Some(String::from("tsp")),
522            Tbsp => Some(String::from("tbsp")),
523            Floz => Some(String::from("floz")),
524            Pint => Some(String::from("pint")),
525            Quart => Some(String::from("quart")),
526            Gallon => Some(String::from("gallon")),
527            Barrel => Some(String::from("barrel")),
528            USTsp => Some(String::from("ustsp")),
529            USTbsp => Some(String::from("ustbsp")),
530            USFloz => Some(String::from("usfloz")),
531            USCup => Some(String::from("uscup")),
532            USPint => Some(String::from("uspint")),
533            USQuart => Some(String::from("usquart")),
534            USGallon => Some(String::from("usgallon")),
535            USBarrel => Some(String::from("usbarrel")),
536        }
537    }
538
539    fn get_symbol(&self) -> Option<String> {
540        match self {
541            Cubic(length) => length.get_symbol()
542                .or_else(|| length.get_name())
543                .map(|x| format!("{}^3", x)),
544            Litre(prefix) => Some(format!("{}l", prefix.get_symbol())),
545            _ => None,
546        }
547    }
548}
549
550impl UnitInfo for SpeedKind {
551    fn walk_values<F: FnMut(Self) -> MyResult<()>>(
552        multiply: bool,
553        divide: bool,
554        mut function: F,
555    ) -> MyResult<()> {
556        LengthKind::walk_values(multiply, divide, |length| {
557            DeltaKind::walk_values(false, false, |delta| function(Ratio(length, delta)))
558        })?;
559        function(Mach)?;
560        function(Light)?;
561        Ok(())
562    }
563
564    fn get_factor(&self) -> BigRational {
565        match self {
566            Ratio(length, delta) => length.get_factor().div(delta.get_factor()),
567            Mach => create_ratio(340, 1), // mach number # M # ratio to the speed of sound in air at sea level # ≈ 340 m/s
568            Light => create_ratio(299792458, 1), // speed of light in vacuum # c # = 299792458 m/s # = 299792458 m/s
569        }
570    }
571
572    fn get_name(&self) -> Option<String> {
573        match self {
574            Ratio(length, delta) => format_speed_name(*length, *delta),
575            Mach => Some(String::from("mach")),
576            Light => Some(String::from("light")),
577        }
578    }
579
580    fn get_symbol(&self) -> Option<String> {
581        match self {
582            Ratio(length, delta) => format_speed_symbol(*length, *delta),
583            _ => None,
584        }
585    }
586}
587
588fn format_speed_name(length: LengthKind, delta: DeltaKind) -> Option<String> {
589    if let Some(length) = length.get_name() {
590        if let Some(delta) = delta.get_name() {
591            return Some(format!("{}/{}", length, delta));
592        }
593    }
594    None
595}
596
597fn format_speed_symbol(length: LengthKind, delta: DeltaKind) -> Option<String> {
598    if let Some(length) = length.get_symbol().or_else(|| length.get_name()) {
599        if let Some(delta) = delta.get_symbol().or_else(|| delta.get_name()) {
600            return Some(format!("{}/{}", length, delta));
601        }
602    }
603    None
604}
605
606impl UnitInfo for MassKind {
607    fn walk_values<F: FnMut(Self) -> MyResult<()>>(
608        multiply: bool,
609        divide: bool,
610        mut function: F,
611    ) -> MyResult<()> {
612        PrefixKind::walk_values(multiply, divide, |prefix| function(Gram(prefix)))?;
613        function(Ounce)?;
614        function(Pound)?;
615        function(Stone)?;
616        function(Ton)?;
617        Ok(())
618    }
619
620    fn get_factor(&self) -> BigRational {
621        match self {
622            Gram(prefix) => prefix.get_factor(),
623            Ounce => create_ratio(28_349_523_125, 1_000_000_000), // ounce (avoirdupois) # oz av # = 1/16 lb # = 28.349523125 g
624            Pound => create_ratio(453_592_370_000, 1_000_000_000), // pound (avoirdupois) # lb av # = 0.45359237 kg = 7000 grains # = 0.45359237 kg
625            Stone => create_ratio(6_350_293_180_000, 1_000_000_000), // stone # st # = 14 lb av # = 6.35029318 kg
626            Ton => create_ratio(1_016_046_908_800_000, 1_000_000_000), // ton, long # long tn or ton # = 2240 lb # = 1016.0469088 kg
627        }
628    }
629
630    fn get_name(&self) -> Option<String> {
631        match self {
632            Gram(prefix) => Some(format!("{}gram", prefix.get_name())),
633            Ounce => Some(String::from("ounce")),
634            Pound => Some(String::from("pound")),
635            Stone => Some(String::from("stone")),
636            Ton => Some(String::from("ton")),
637        }
638    }
639
640    fn get_symbol(&self) -> Option<String> {
641        match self {
642            Gram(prefix) => Some(format!("{}g", prefix.get_symbol())),
643            _ => None,
644        }
645    }
646}
647
648impl UnitInfo for TempKind {
649    fn walk_values<F: FnMut(Self) -> MyResult<()>>(
650        multiply: bool,
651        divide: bool,
652        mut function: F,
653    ) -> MyResult<()> {
654        PrefixKind::walk_values(multiply, divide, |prefix| function(Kelvin(prefix)))?;
655        function(Celsius)?;
656        function(Fahrenheit)?;
657        function(Rankine)?;
658        Ok(())
659    }
660
661    fn get_factor(&self) -> BigRational {
662        match self {
663            Kelvin(_) => create_ratio(1, 1),
664            Celsius => create_ratio(1, 1),
665            Fahrenheit => create_ratio(5, 9),
666            Rankine => create_ratio(5, 9),
667        }
668    }
669
670    fn get_offset(&self) -> BigRational {
671        match self {
672            Kelvin(_) => create_ratio(0, 1),
673            Celsius => create_ratio(27315, 100), // 273.15
674            Fahrenheit => create_ratio(229835, 900), // 255.372222
675            Rankine => create_ratio(0, 1),
676        }
677    }
678
679    fn get_name(&self) -> Option<String> {
680        match self {
681            Kelvin(prefix) => Some(format!("{}kelvin", prefix.get_name())),
682            Celsius => Some(String::from("celsius")),
683            Fahrenheit => Some(String::from("fahrenheit")),
684            Rankine => Some(String::from("rankine")),
685        }
686    }
687
688    fn get_symbol(&self) -> Option<String> {
689        match self {
690            Kelvin(prefix) => Some(format!("{}K", prefix.get_symbol())),
691            Celsius => Some(String::from("C")),
692            Fahrenheit => Some(String::from("F")),
693            Rankine => Some(String::from("R")),
694        }
695    }
696}
697
698impl UnitInfo for DataKind {
699    fn walk_values<F: FnMut(Self) -> MyResult<()>>(
700        multiply: bool,
701        _divide: bool,
702        mut function: F,
703    ) -> MyResult<()> {
704        PrefixKind::walk_values(multiply, false, |prefix| function(Byte(prefix)))?;
705        function(Bit)?;
706        Ok(())
707    }
708
709    fn get_factor(&self) -> BigRational {
710        match self {
711            Byte(prefix) => prefix.get_factor(),
712            Bit => create_ratio(1, 8),
713        }
714    }
715
716    fn get_name(&self) -> Option<String> {
717        match self {
718            Byte(prefix) => Some(format!("{}byte", prefix.get_name())),
719            Bit => Some(String::from("bit")),
720        }
721    }
722
723    fn get_symbol(&self) -> Option<String> {
724        match self {
725            Byte(prefix) => Some(format!("{}B", prefix.get_symbol())),
726            _ => None,
727        }
728    }
729}
730
731impl Meaning {
732    pub fn get_meanings() -> MyResult<Meanings> {
733        let meanings = RefCell::new(Meanings::new());
734        DeltaKind::walk_values(true, true, |unit| Self::insert_meaning(meanings.borrow_mut().deref_mut(), Delta(unit), unit))?;
735        LengthKind::walk_values(true, true, |unit| Self::insert_meaning(meanings.borrow_mut().deref_mut(), Length(unit), unit))?;
736        AreaKind::walk_values(true, true, |unit| Self::insert_meaning(meanings.borrow_mut().deref_mut(), Area(unit), unit))?;
737        VolumeKind::walk_values(true, true, |unit| Self::insert_meaning(meanings.borrow_mut().deref_mut(), Volume(unit), unit))?;
738        SpeedKind::walk_values(true, true, |unit| Self::insert_meaning(meanings.borrow_mut().deref_mut(), Speed(unit), unit))?;
739        MassKind::walk_values(true, true, |unit| Self::insert_meaning(meanings.borrow_mut().deref_mut(), Mass(unit), unit))?;
740        TempKind::walk_values(true, true, |unit| Self::insert_meaning(meanings.borrow_mut().deref_mut(), Temp(unit), unit))?;
741        DataKind::walk_values(true, true, |unit| Self::insert_meaning(meanings.borrow_mut().deref_mut(), Data(unit), unit))?;
742        Ok(meanings.into_inner())
743    }
744
745    fn insert_meaning<U: UnitInfo>(
746        meanings: &mut Meanings,
747        meaning: Self,
748        unit: U,
749    ) -> MyResult<()> {
750        if let Some(name) = unit.get_name() {
751            meanings.insert(name, meaning);
752        }
753        if let Some(symbol) = unit.get_symbol() {
754            meanings.insert(symbol, meaning);
755        }
756        Ok(())
757    }
758
759    pub fn get_symbol(&self) -> Option<String> {
760        match self {
761            Delta(unit) => unit.get_symbol().or_else(|| unit.get_name()),
762            Length(unit) => unit.get_symbol().or_else(|| unit.get_name()),
763            Area(unit) => unit.get_symbol().or_else(|| unit.get_name()),
764            Volume(unit) => unit.get_symbol().or_else(|| unit.get_name()),
765            Speed(unit) => unit.get_symbol().or_else(|| unit.get_name()),
766            Mass(unit) => unit.get_symbol().or_else(|| unit.get_name()),
767            Temp(unit) => unit.get_symbol().or_else(|| unit.get_name()),
768            Data(unit) => unit.get_symbol().or_else(|| unit.get_name()),
769            _ => None,
770        }
771    }
772
773    pub fn undo_meaning(self, number: &BigRational) -> Cow<BigRational> {
774        match self {
775            Delta(unit) => Self::undo_unit(number, unit),
776            Length(unit) => Self::undo_unit(number, unit),
777            Area(unit) => Self::undo_unit(number, unit),
778            Volume(unit) => Self::undo_unit(number, unit),
779            Speed(unit) => Self::undo_unit(number, unit),
780            Mass(unit) => Self::undo_unit(number, unit),
781            Temp(unit) => Self::undo_unit(number, unit),
782            Data(unit) => Self::undo_unit(number, unit),
783            _ => Cow::Borrowed(number),
784        }
785    }
786
787    pub fn redo_meaning(self, number: &BigRational) -> Cow<BigRational> {
788        match self {
789            Delta(unit) => Self::redo_unit(number, unit),
790            Length(unit) => Self::redo_unit(number, unit),
791            Area(unit) => Self::redo_unit(number, unit),
792            Volume(unit) => Self::redo_unit(number, unit),
793            Speed(unit) => Self::redo_unit(number, unit),
794            Mass(unit) => Self::redo_unit(number, unit),
795            Temp(unit) => Self::redo_unit(number, unit),
796            Data(unit) => Self::redo_unit(number, unit),
797            _ => Cow::Borrowed(number),
798        }
799    }
800
801    fn undo_unit<U: UnitInfo>(number: &BigRational, unit: U) -> Cow<BigRational> {
802        let factor = unit.get_factor();
803        let offset = unit.get_offset();
804        if let Some(result) = number.checked_mul(&factor).and_then(|n| n.checked_add(&offset)) {
805            Cow::Owned(result)
806        } else {
807            Cow::Borrowed(number)
808        }
809    }
810
811    fn redo_unit<U: UnitInfo>(number: &BigRational, unit: U) -> Cow<BigRational> {
812        let factor = unit.get_factor();
813        let offset = unit.get_offset();
814        if let Some(result) = number.checked_sub(&offset).and_then(|n| n.checked_div(&factor)) {
815            Cow::Owned(result)
816        } else {
817            Cow::Borrowed(number)
818        }
819    }
820
821    fn display_unit<U: UnitInfo>(f: &mut Formatter<'_>, unit: U, default: &str) -> std::fmt::Result {
822        if let Some(name) = unit.get_name() {
823            write!(f, "{}", name)
824        } else {
825            write!(f, "{}", default)
826        }
827    }
828
829    pub fn select_only_plain(self) -> Result<(), EngineError> {
830        if self == Plain {
831            Ok(())
832        } else {
833            Err(EngineError::BadCastOp(self, Plain))
834        }
835    }
836
837    pub fn select_not_time(self) -> Result<(), EngineError> {
838        if self != Time {
839            Ok(())
840        } else {
841            Err(EngineError::BadCastOp(Time, Time))
842        }
843    }
844
845    // Cast  | Plain Delta Time  | Len   Area  Vol   Speed | Mass  Temp  Data
846    // ------+-------------------+-------------------------+------------------
847    // Plain | Plain Delta Time  | Len   Area  Vol   Speed | Mass  Temp  Data
848    // Delta | Plain Delta -     | -     -     -     -     | -     -     -
849    // Time  | Plain -     Time  | -     -     -     -     | -     -     -
850    // ------+-------------------+-------------------------+------------------
851    // Len   | Plain -     -     | Len   -     -     -     | -     -     -
852    // Area  | Plain -     -     | -     Area  -     -     | -     -     -
853    // Vol   | Plain -     -     | -     -     Vol   -     | -     -     -
854    // Speed | Plain -     -     | -     -     -     Speed | -     -     -
855    // ------+-------------------+-------------------------+------------------
856    // Mass  | Plain -     -     | -     -     -     -     | Mass  -     -
857    // Temp  | Plain -     -     | -     -     -     -     | -     Temp  -
858    // Data  | Plain -     -     | -     -     -     -     | -     -     Data
859
860    pub fn combine_cast_value(lhs: Self, rhs: Self) -> Option<Self> {
861        match (lhs, rhs) {
862            (_, Plain) => Some(Plain),
863            (Plain, rhs) => Some(rhs),
864            (Time, Time) => Some(Time),
865            (Delta(_), Delta(rhs)) => Some(Delta(rhs)),
866            (Length(_), Length(rhs)) => Some(Length(rhs)),
867            (Area(_), Area(rhs)) => Some(Area(rhs)),
868            (Volume(_), Volume(rhs)) => Some(Volume(rhs)),
869            (Speed(_), Speed(rhs)) => Some(Speed(rhs)),
870            (Mass(_), Mass(rhs)) => Some(Mass(rhs)),
871            (Temp(_), Temp(rhs)) => Some(Temp(rhs)),
872            (Data(_), Data(rhs)) => Some(Data(rhs)),
873            _ => None,
874        }
875    }
876
877    // Add   | Plain Delta Time
878    // ------+------------------
879    // Plain | Plain Delta Time
880    // Delta | Delta Delta Time
881    // Time  | Time  Time  -
882
883    pub fn combine_add_time(lhs: Self, rhs: Self) -> Option<Self> {
884        match (lhs, rhs) {
885            (Plain, Plain) => Some(Plain),
886            (Plain, Delta(rhs)) => Some(Delta(rhs)),
887            (Plain, Time) => Some(Time),
888            (Delta(lhs), Plain) => Some(Delta(lhs)),
889            (Delta(lhs), Delta(_)) => Some(Delta(lhs)),
890            (Delta(_), Time) => Some(Time),
891            (Time, Plain) => Some(Time),
892            (Time, Delta(_)) => Some(Time),
893            _ => None,
894        }
895    }
896
897    // Sub   | Plain Delta Time
898    // ------+------------------
899    // Plain | Plain Delta -
900    // Delta | Delta Delta -
901    // Time  | Time  Time  Delta
902
903    pub fn combine_sub_time(lhs: Self, rhs: Self) -> Option<Self> {
904        match (lhs, rhs) {
905            (Plain, Plain) => Some(Plain),
906            (Plain, Delta(rhs)) => Some(Delta(rhs)),
907            (Delta(lhs), Plain) => Some(Delta(lhs)),
908            (Delta(lhs), Delta(_)) => Some(Delta(lhs)),
909            (Time, Plain) => Some(Time),
910            (Time, Delta(_)) => Some(Time),
911            (Time, Time) => Some(Delta(HMS)),
912            _ => None,
913        }
914    }
915
916    // Mul   | Plain Delta Time  | Len   Area  Vol   Speed
917    // ------+-------------------+-------------------------
918    // Plain | Plain Delta -     | -     -     -     -
919    // Delta | Delta -     -     | -     -     -     Len
920    // Time  | -     -     -     | -     -     -     -
921    // ------+-------------------+-------------------------
922    // Len   | -     -     -     | Area  Vol   -     -
923    // Area  | -     -     -     | Vol   -     -     -
924    // Vol   | -     -     -     | -     -     -     -
925    // Speed | -     Len   -     | -     -     -     -
926
927    pub fn combine_mul_unit(lhs: Self, rhs: Self) -> Option<Self> {
928        match (lhs, rhs) {
929            (Plain, Plain) => Some(Plain),
930            (Plain, Delta(rhs)) => Some(Delta(rhs)),
931            (Delta(lhs), Plain) => Some(Delta(lhs)),
932            (Speed(Ratio(lhs, _)), Delta(_)) => Some(Length(lhs)),
933            (Length(lhs), Length(_)) => Some(Area(Square(lhs))),
934            (Length(lhs), Area(_)) => Some(Volume(Cubic(lhs))),
935            (Area(Square(lhs)), Length(_)) => Some(Volume(Cubic(lhs))),
936            (Delta(_), Speed(_)) => Some(Length(Metre(Unit))),
937            (Speed(_), Delta(_)) => Some(Length(Metre(Unit))),
938            (Area(_), Length(_)) => Some(Volume(Cubic(Metre(Unit)))),
939            _ => None,
940        }
941    }
942
943    // Div   | Plain Delta Time  | Len   Area  Vol   Speed | Mass  Temp  Data
944    // ------+-------------------+-------------------------+------------------
945    // Plain | Plain -     -     | -     -     -     -     | -     -     -
946    // Delta | Delta Plain -     | -     -     -     -     | -     -     -
947    // Time  | -     -     -     | -     -     -     -     | -     -     -
948    // ------+-------------------+-------------------------+------------------
949    // Len   | -     -     -     | Plain -     -     Delta | -     -     -
950    // Area  | -     -     -     | Len   Plain -     -     | -     -     -
951    // Vol   | -     -     -     | Area  Len   Plain -     | -     -     -
952    // Speed | -     -     -     | -     -     -     Plain | -     -     -
953    // ------+-------------------+-------------------------+------------------
954    // Mass  | -     -     -     | -     -     -     -     | Plain -     -
955    // Temp  | -     -     -     | -     -     -     -     | -     Plain -
956    // Data  | -     -     -     | -     -     -     -     | -     -     Plain
957
958    pub fn combine_div_unit(lhs: Self, rhs: Self) -> Option<Self> {
959        match (lhs, rhs) {
960            (Plain, Plain) => Some(Plain),
961            (Delta(lhs), Plain) => Some(Delta(lhs)),
962            (Delta(_), Delta(_)) => Some(Plain),
963            (Length(_), Length(_)) => Some(Plain),
964            (Area(_), Area(_)) => Some(Plain),
965            (Volume(_), Volume(_)) => Some(Plain),
966            (Speed(_), Speed(_)) => Some(Plain),
967            (Mass(_), Mass(_)) => Some(Plain),
968            (Temp(_), Temp(_)) => Some(Plain),
969            (Data(_), Data(_)) => Some(Plain),
970            (Area(Square(lhs)), Length(_)) => Some(Length(lhs)),
971            (Volume(Cubic(lhs)), Length(_)) => Some(Area(Square(lhs))),
972            (Volume(Cubic(lhs)), Area(_)) => Some(Length(lhs)),
973            (Length(_), Speed(_)) => Some(Delta(Second(Unit))),
974            (Area(_), Length(_)) => Some(Length(Metre(Unit))),
975            (Volume(_), Length(_)) => Some(Area(Square(Metre(Unit)))),
976            (Volume(_), Area(_)) => Some(Length(Metre(Unit))),
977            _ => None,
978        }
979    }
980
981    // XXX   | Plain Other
982    // ------+-------------
983    // Plain | -     -
984    // Delta | -     -
985    // Time  | -     -
986    // ------+-------------
987    // Len   | Len   -
988    // Area  | Area  -
989    // Vol   | Vol   -
990    // Speed | Speed -
991    // ------+-------------
992    // Mass  | Mass  -
993    // Temp  | Temp  -
994    // Data  | Data  -
995
996    pub fn combine_copy_left(lhs: Self, rhs: Self) -> Option<Self> {
997        match (lhs, rhs) {
998            (Plain, _) => None,
999            (Delta(_), _) => None,
1000            (Time, _) => None,
1001            (lhs, Plain) => Some(lhs),
1002            _ => None,
1003        }
1004    }
1005
1006    // XXX   | Plain Delta Time  | Len   Area  Vol   Speed | Mass  Temp  Data
1007    // ------+-------------------+-------------------------+------------------
1008    // Plain | -     -     -     | Len   Area  Vol   Speed | Mass  Temp  Data
1009    // Other | -     -     -     | -     -     -     -     | -     -     -
1010
1011    pub fn combine_copy_right(lhs: Self, rhs: Self) -> Option<Self> {
1012        match (lhs, rhs) {
1013            (_, Plain) => None,
1014            (_, Delta(_)) => None,
1015            (_, Time) => None,
1016            (Plain, rhs) => Some(rhs),
1017            _ => None,
1018        }
1019    }
1020
1021    // XXX   | Plain Delta Time  | Len   Area  Vol   Speed | Mass  Temp  Data
1022    // ------+-------------------+-------------------------+------------------
1023    // Plain | -     -     -     | -     -     -     -     | -     -     -
1024    // Delta | -     -     -     | -     -     -     -     | -     -     -
1025    // Time  | -     -     -     | -     -     -     -     | -     -     -
1026    // ------+-------------------+-------------------------+------------------
1027    // Len   | -     -     -     | Len   -     -     -     | -     -     -
1028    // Area  | -     -     -     | -     Area  -     -     | -     -     -
1029    // Vol   | -     -     -     | -     -     Vol   -     | -     -     -
1030    // Speed | -     -     -     | -     -     -     Speed | -     -     -
1031    // ------+-------------------+-------------------------+------------------
1032    // Mass  | -     -     -     | -     -     -     -     | Mass  -     -
1033    // Temp  | -     -     -     | -     -     -     -     | -     Temp  -
1034    // Data  | -     -     -     | -     -     -     -     | -     -     Data
1035
1036    pub fn combine_copy_same(lhs: Self, rhs: Self) -> Option<Self> {
1037        match (lhs, rhs) {
1038            (Length(lhs), Length(_)) => Some(Length(lhs)),
1039            (Area(lhs), Area(_)) => Some(Area(lhs)),
1040            (Volume(lhs), Volume(_)) => Some(Volume(lhs)),
1041            (Speed(lhs), Speed(_)) => Some(Speed(lhs)),
1042            (Mass(lhs), Mass(_)) => Some(Mass(lhs)),
1043            (Temp(lhs), Temp(_)) => Some(Temp(lhs)),
1044            (Data(lhs), Data(_)) => Some(Data(lhs)),
1045            _ => None,
1046        }
1047    }
1048
1049    // XXX   | Plain Other
1050    // ------+-------------
1051    // Plain | Plain -
1052    // Other | -     -
1053
1054    pub fn combine_only_plain(lhs: Self, rhs: Self) -> Option<Self> {
1055        if (lhs, rhs) == (Plain, Plain) {
1056            Some(Plain)
1057        } else {
1058            None
1059        }
1060    }
1061}
1062
1063impl Display for Meaning {
1064    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1065        match self {
1066            Plain => write!(f, "plain"),
1067            Time => write!(f, "time"),
1068            Delta(unit) => Self::display_unit(f, *unit, "delta"),
1069            Length(unit) => Self::display_unit(f, *unit, "length"),
1070            Area(unit) => Self::display_unit(f, *unit, "area"),
1071            Volume(unit) => Self::display_unit(f, *unit, "volume"),
1072            Speed(unit) => Self::display_unit(f, *unit, "speed"),
1073            Mass(unit) => Self::display_unit(f, *unit, "mass"),
1074            Temp(unit) => Self::display_unit(f, *unit, "temp"),
1075            Data(unit) => Self::display_unit(f, *unit, "data"),
1076        }
1077    }
1078}
1079
1080// noinspection DuplicatedCode
1081#[cfg(test)]
1082mod tests {
1083    use crate::calc::context::Context;
1084    use crate::calc::meaning::AreaKind::*;
1085    use crate::calc::meaning::DataKind::*;
1086    use crate::calc::meaning::DeltaKind::*;
1087    use crate::calc::meaning::LengthKind::*;
1088    use crate::calc::meaning::MassKind::*;
1089    use crate::calc::meaning::Meaning;
1090    use crate::calc::meaning::Meaning::*;
1091    use crate::calc::meaning::PrefixKind::*;
1092    use crate::calc::meaning::SpeedKind::*;
1093    use crate::calc::meaning::TempKind::*;
1094    use crate::calc::meaning::VolumeKind::*;
1095    use crate::calc::value::tests::create_value;
1096    use crate::calc::value::{Value, ValueRef};
1097    use crate::error::EngineError::BadCastOp;
1098    use crate::error::{EngineError, MyError, MyResult};
1099    use crate::regex;
1100    use itertools::Itertools;
1101    use pretty_assertions::assert_eq;
1102    use std::cell::RefCell;
1103    use std::rc::Rc;
1104
1105    macro_rules! count_regex {
1106        ($meanings:ident, $regex:literal) => {
1107            {
1108                let regex = regex!($regex);
1109                $meanings.iter().filter(|x| regex.is_match(x)).count()
1110            }
1111        };
1112    }
1113
1114    #[test]
1115    fn test_meanings_are_collected_for_interface() {
1116        let meanings = get_meanings();
1117        assert_eq!(814, meanings.len());
1118    }
1119
1120    #[test]
1121    fn test_meanings_are_collected_with_multiplier_prefix() {
1122        let meanings = get_meanings();
1123        assert_eq!(6, count_regex!(meanings, r"^giga\w+$"));
1124        assert_eq!(6, count_regex!(meanings, r"^mega\w+$"));
1125        assert_eq!(6, count_regex!(meanings, r"^kilo\w+$"));
1126        assert_eq!(6, count_regex!(meanings, r"^G\w$"));
1127        assert_eq!(6, count_regex!(meanings, r"^M\w$"));
1128        assert_eq!(6, count_regex!(meanings, r"^k\w$"));
1129    }
1130
1131    #[test]
1132    fn test_meanings_are_collected_with_divider_prefix() {
1133        let meanings = get_meanings();
1134        assert_eq!(5, count_regex!(meanings, r"^milli\w+$"));
1135        assert_eq!(5, count_regex!(meanings, r"^micro\w+$"));
1136        assert_eq!(5, count_regex!(meanings, r"^nano\w+$"));
1137        assert_eq!(5, count_regex!(meanings, r"^m\w$"));
1138        assert_eq!(5, count_regex!(meanings, r"^u\w$"));
1139        assert_eq!(5, count_regex!(meanings, r"^n\w$"));
1140    }
1141
1142    #[test]
1143    fn test_meanings_are_collected_with_unit_measurement() {
1144        let meanings = get_meanings();
1145        assert_eq!(25, count_regex!(meanings, r"^\w*second$"));
1146        assert_eq!(25, count_regex!(meanings, r"^\w*metre$"));
1147        assert_eq!(25, count_regex!(meanings, r"^\w*litre$"));
1148        assert_eq!(25, count_regex!(meanings, r"^\w*gram$"));
1149        assert_eq!(25, count_regex!(meanings, r"^\w*kelvin$"));
1150        assert_eq!(13, count_regex!(meanings, r"^\w*byte$"));
1151        assert_eq!(25, count_regex!(meanings, r"^\w{0,2}s$"));
1152        assert_eq!(25, count_regex!(meanings, r"^\w{0,2}m$"));
1153        assert_eq!(25, count_regex!(meanings, r"^\w{0,2}l$"));
1154        assert_eq!(25, count_regex!(meanings, r"^\w{0,2}g$"));
1155        assert_eq!(25, count_regex!(meanings, r"^\w{0,2}K$"));
1156        assert_eq!(13, count_regex!(meanings, r"^\w{0,2}B$"));
1157    }
1158
1159    #[test]
1160    fn test_meanings_are_collected_with_square_measurement() {
1161        let meanings = get_meanings();
1162        assert_eq!(25, count_regex!(meanings, r"^square-\w*metre$"));
1163        assert_eq!(29, count_regex!(meanings, r"^square-\w+$"));
1164        assert_eq!(25, count_regex!(meanings, r"^\w{0,2}m\^2$"));
1165        assert_eq!(29, count_regex!(meanings, r"^\w+\^2$"));
1166    }
1167
1168    #[test]
1169    fn test_meanings_are_collected_with_cubic_measurement() {
1170        let meanings = get_meanings();
1171        assert_eq!(25, count_regex!(meanings, r"^cubic-\w*metre$"));
1172        assert_eq!(29, count_regex!(meanings, r"^cubic-\w+$"));
1173        assert_eq!(25, count_regex!(meanings, r"^\w{0,2}m\^3$"));
1174        assert_eq!(29, count_regex!(meanings, r"^\w+\^3$"));
1175    }
1176
1177    #[test]
1178    fn test_meanings_are_collected_with_ratio_measurement() {
1179        let meanings = get_meanings();
1180        assert_eq!(25, count_regex!(meanings, r"^\w*metre/\w*second$"));
1181        assert_eq!(25, count_regex!(meanings, r"^\w*metre/minute$"));
1182        assert_eq!(25, count_regex!(meanings, r"^\w*metre/hour$"));
1183        assert_eq!(25, count_regex!(meanings, r"^\w*metre/day$"));
1184        assert_eq!(25, count_regex!(meanings, r"^\w*metre/week$"));
1185        assert_eq!(25, count_regex!(meanings, r"^\w*metre/month$"));
1186        assert_eq!(25, count_regex!(meanings, r"^\w*metre/year$"));
1187        assert_eq!(25, count_regex!(meanings, r"^\w{0,2}m/\w*s$"));
1188        assert_eq!(25, count_regex!(meanings, r"^\w{0,2}m/minute$"));
1189        assert_eq!(25, count_regex!(meanings, r"^\w{0,2}m/hour$"));
1190        assert_eq!(25, count_regex!(meanings, r"^\w{0,2}m/day$"));
1191        assert_eq!(25, count_regex!(meanings, r"^\w{0,2}m/week$"));
1192        assert_eq!(25, count_regex!(meanings, r"^\w{0,2}m/month$"));
1193        assert_eq!(25, count_regex!(meanings, r"^\w{0,2}m/year$"));
1194        assert_eq!(29, count_regex!(meanings, r"^\w+/\w*s$"));
1195        assert_eq!(29, count_regex!(meanings, r"^\w+/\w*second$"));
1196        assert_eq!(54, count_regex!(meanings, r"^\w+/minute$"));
1197        assert_eq!(54, count_regex!(meanings, r"^\w+/hour$"));
1198        assert_eq!(54, count_regex!(meanings, r"^\w+/day$"));
1199        assert_eq!(54, count_regex!(meanings, r"^\w+/week$"));
1200        assert_eq!(54, count_regex!(meanings, r"^\w+/month$"));
1201        assert_eq!(54, count_regex!(meanings, r"^\w+/year$"));
1202    }
1203
1204    fn get_meanings() -> Vec<String> {
1205        let meanings = Meaning::get_meanings().unwrap_or_default();
1206        meanings.keys().map(String::from).sorted().collect::<Vec<_>>()
1207    }
1208
1209    // Cast  | Plain Delta Time  | Len   Area  Vol   Speed | Mass  Temp  Data
1210    // ------+-------------------+-------------------------+------------------
1211    // Plain | Plain Delta Time  | Len   Area  Vol   Speed | Mass  Temp  Data
1212    // Delta | Plain Delta -     | -     -     -     -     | -     -     -
1213    // Time  | Plain -     Time  | -     -     -     -     | -     -     -
1214    // ------+-------------------+-------------------------+------------------
1215    // Len   | Plain -     -     | Len   -     -     -     | -     -     -
1216    // Area  | Plain -     -     | -     Area  -     -     | -     -     -
1217    // Vol   | Plain -     -     | -     -     Vol   -     | -     -     -
1218    // Speed | Plain -     -     | -     -     -     Speed | -     -     -
1219    // ------+-------------------+-------------------------+------------------
1220    // Mass  | Plain -     -     | -     -     -     -     | Mass  -     -
1221    // Temp  | Plain -     -     | -     -     -     -     | -     Temp  -
1222    // Data  | Plain -     -     | -     -     -     -     | -     -     Data
1223
1224    #[test]
1225    fn test_unit_meanings_are_combined_on_cast() {
1226        assert_eq!(perform_cast_ok(Plain, Plain), Some(Plain));
1227        assert_eq!(perform_cast_ok(Plain, Delta(Hour)), Some(Delta(Hour)));
1228        assert_eq!(perform_cast_ok(Plain, Time), Some(Time));
1229        assert_eq!(perform_cast_ok(Plain, Length(Mile)), Some(Length(Mile)));
1230        assert_eq!(perform_cast_ok(Plain, Area(Acre)), Some(Area(Acre)));
1231        assert_eq!(perform_cast_ok(Plain, Volume(Pint)), Some(Volume(Pint)));
1232        assert_eq!(perform_cast_ok(Plain, Speed(Light)), Some(Speed(Light)));
1233        assert_eq!(perform_cast_ok(Plain, Mass(Ounce)), Some(Mass(Ounce)));
1234        assert_eq!(perform_cast_ok(Plain, Temp(Rankine)), Some(Temp(Rankine)));
1235        assert_eq!(perform_cast_ok(Plain, Data(Bit)), Some(Data(Bit)));
1236
1237        assert_eq!(perform_cast_ok(Delta(Hour), Plain), Some(Plain));
1238        assert_eq!(perform_cast_ok(Delta(Hour), Delta(Hour)), Some(Delta(Hour)));
1239        assert_eq!(perform_cast_err(Delta(Hour), Time), Some(BadCastOp(Delta(Hour), Time)));
1240        assert_eq!(perform_cast_err(Delta(Hour), Length(Mile)), Some(BadCastOp(Delta(Hour), Length(Mile))));
1241        assert_eq!(perform_cast_err(Delta(Hour), Area(Acre)), Some(BadCastOp(Delta(Hour), Area(Acre))));
1242        assert_eq!(perform_cast_err(Delta(Hour), Volume(Pint)), Some(BadCastOp(Delta(Hour), Volume(Pint))));
1243        assert_eq!(perform_cast_err(Delta(Hour), Speed(Light)), Some(BadCastOp(Delta(Hour), Speed(Light))));
1244        assert_eq!(perform_cast_err(Delta(Hour), Mass(Ounce)), Some(BadCastOp(Delta(Hour), Mass(Ounce))));
1245        assert_eq!(perform_cast_err(Delta(Hour), Temp(Rankine)), Some(BadCastOp(Delta(Hour), Temp(Rankine))));
1246        assert_eq!(perform_cast_err(Delta(Hour), Data(Bit)), Some(BadCastOp(Delta(Hour), Data(Bit))));
1247
1248        assert_eq!(perform_cast_ok(Time, Plain), Some(Plain));
1249        assert_eq!(perform_cast_err(Time, Delta(Hour)), Some(BadCastOp(Time, Delta(Hour))));
1250        assert_eq!(perform_cast_ok(Time, Time), Some(Time));
1251        assert_eq!(perform_cast_err(Time, Length(Mile)), Some(BadCastOp(Time, Length(Mile))));
1252        assert_eq!(perform_cast_err(Time, Area(Acre)), Some(BadCastOp(Time, Area(Acre))));
1253        assert_eq!(perform_cast_err(Time, Volume(Pint)), Some(BadCastOp(Time, Volume(Pint))));
1254        assert_eq!(perform_cast_err(Time, Speed(Light)), Some(BadCastOp(Time, Speed(Light))));
1255        assert_eq!(perform_cast_err(Time, Mass(Ounce)), Some(BadCastOp(Time, Mass(Ounce))));
1256        assert_eq!(perform_cast_err(Time, Temp(Rankine)), Some(BadCastOp(Time, Temp(Rankine))));
1257        assert_eq!(perform_cast_err(Time, Data(Bit)), Some(BadCastOp(Time, Data(Bit))));
1258
1259        assert_eq!(perform_cast_ok(Length(Mile), Plain), Some(Plain));
1260        assert_eq!(perform_cast_err(Length(Mile), Delta(Hour)), Some(BadCastOp(Length(Mile), Delta(Hour))));
1261        assert_eq!(perform_cast_err(Length(Mile), Time), Some(BadCastOp(Length(Mile), Time)));
1262        assert_eq!(perform_cast_ok(Length(Mile), Length(Mile)), Some(Length(Mile)));
1263        assert_eq!(perform_cast_err(Length(Mile), Area(Acre)), Some(BadCastOp(Length(Mile), Area(Acre))));
1264        assert_eq!(perform_cast_err(Length(Mile), Volume(Pint)), Some(BadCastOp(Length(Mile), Volume(Pint))));
1265        assert_eq!(perform_cast_err(Length(Mile), Speed(Light)), Some(BadCastOp(Length(Mile), Speed(Light))));
1266        assert_eq!(perform_cast_err(Length(Mile), Mass(Ounce)), Some(BadCastOp(Length(Mile), Mass(Ounce))));
1267        assert_eq!(perform_cast_err(Length(Mile), Temp(Rankine)), Some(BadCastOp(Length(Mile), Temp(Rankine))));
1268        assert_eq!(perform_cast_err(Length(Mile), Data(Bit)), Some(BadCastOp(Length(Mile), Data(Bit))));
1269
1270        assert_eq!(perform_cast_ok(Area(Acre), Plain), Some(Plain));
1271        assert_eq!(perform_cast_err(Area(Acre), Delta(Hour)), Some(BadCastOp(Area(Acre), Delta(Hour))));
1272        assert_eq!(perform_cast_err(Area(Acre), Time), Some(BadCastOp(Area(Acre), Time)));
1273        assert_eq!(perform_cast_err(Area(Acre), Length(Mile)), Some(BadCastOp(Area(Acre), Length(Mile))));
1274        assert_eq!(perform_cast_ok(Area(Acre), Area(Acre)), Some(Area(Acre)));
1275        assert_eq!(perform_cast_err(Area(Acre), Volume(Pint)), Some(BadCastOp(Area(Acre), Volume(Pint))));
1276        assert_eq!(perform_cast_err(Area(Acre), Speed(Light)), Some(BadCastOp(Area(Acre), Speed(Light))));
1277        assert_eq!(perform_cast_err(Area(Acre), Mass(Ounce)), Some(BadCastOp(Area(Acre), Mass(Ounce))));
1278        assert_eq!(perform_cast_err(Area(Acre), Temp(Rankine)), Some(BadCastOp(Area(Acre), Temp(Rankine))));
1279        assert_eq!(perform_cast_err(Area(Acre), Data(Bit)), Some(BadCastOp(Area(Acre), Data(Bit))));
1280
1281        assert_eq!(perform_cast_ok(Volume(Pint), Plain), Some(Plain));
1282        assert_eq!(perform_cast_err(Volume(Pint), Delta(Hour)), Some(BadCastOp(Volume(Pint), Delta(Hour))));
1283        assert_eq!(perform_cast_err(Volume(Pint), Time), Some(BadCastOp(Volume(Pint), Time)));
1284        assert_eq!(perform_cast_err(Volume(Pint), Length(Mile)), Some(BadCastOp(Volume(Pint), Length(Mile))));
1285        assert_eq!(perform_cast_err(Volume(Pint), Area(Acre)), Some(BadCastOp(Volume(Pint), Area(Acre))));
1286        assert_eq!(perform_cast_ok(Volume(Pint), Volume(Pint)), Some(Volume(Pint)));
1287        assert_eq!(perform_cast_err(Volume(Pint), Speed(Light)), Some(BadCastOp(Volume(Pint), Speed(Light))));
1288        assert_eq!(perform_cast_err(Volume(Pint), Mass(Ounce)), Some(BadCastOp(Volume(Pint), Mass(Ounce))));
1289        assert_eq!(perform_cast_err(Volume(Pint), Temp(Rankine)), Some(BadCastOp(Volume(Pint), Temp(Rankine))));
1290        assert_eq!(perform_cast_err(Volume(Pint), Data(Bit)), Some(BadCastOp(Volume(Pint), Data(Bit))));
1291
1292        assert_eq!(perform_cast_ok(Speed(Light), Plain), Some(Plain));
1293        assert_eq!(perform_cast_err(Speed(Light), Delta(Hour)), Some(BadCastOp(Speed(Light), Delta(Hour))));
1294        assert_eq!(perform_cast_err(Speed(Light), Time), Some(BadCastOp(Speed(Light), Time)));
1295        assert_eq!(perform_cast_err(Speed(Light), Length(Mile)), Some(BadCastOp(Speed(Light), Length(Mile))));
1296        assert_eq!(perform_cast_err(Speed(Light), Area(Acre)), Some(BadCastOp(Speed(Light), Area(Acre))));
1297        assert_eq!(perform_cast_err(Speed(Light), Volume(Pint)), Some(BadCastOp(Speed(Light), Volume(Pint))));
1298        assert_eq!(perform_cast_ok(Speed(Light), Speed(Light)), Some(Speed(Light)));
1299        assert_eq!(perform_cast_err(Speed(Light), Mass(Ounce)), Some(BadCastOp(Speed(Light), Mass(Ounce))));
1300        assert_eq!(perform_cast_err(Speed(Light), Temp(Rankine)), Some(BadCastOp(Speed(Light), Temp(Rankine))));
1301        assert_eq!(perform_cast_err(Speed(Light), Data(Bit)), Some(BadCastOp(Speed(Light), Data(Bit))));
1302
1303        assert_eq!(perform_cast_ok(Mass(Ounce), Plain), Some(Plain));
1304        assert_eq!(perform_cast_err(Mass(Ounce), Delta(Hour)), Some(BadCastOp(Mass(Ounce), Delta(Hour))));
1305        assert_eq!(perform_cast_err(Mass(Ounce), Time), Some(BadCastOp(Mass(Ounce), Time)));
1306        assert_eq!(perform_cast_err(Mass(Ounce), Length(Mile)), Some(BadCastOp(Mass(Ounce), Length(Mile))));
1307        assert_eq!(perform_cast_err(Mass(Ounce), Area(Acre)), Some(BadCastOp(Mass(Ounce), Area(Acre))));
1308        assert_eq!(perform_cast_err(Mass(Ounce), Volume(Pint)), Some(BadCastOp(Mass(Ounce), Volume(Pint))));
1309        assert_eq!(perform_cast_err(Mass(Ounce), Speed(Light)), Some(BadCastOp(Mass(Ounce), Speed(Light))));
1310        assert_eq!(perform_cast_ok(Mass(Ounce), Mass(Ounce)), Some(Mass(Ounce)));
1311        assert_eq!(perform_cast_err(Mass(Ounce), Temp(Rankine)), Some(BadCastOp(Mass(Ounce), Temp(Rankine))));
1312        assert_eq!(perform_cast_err(Mass(Ounce), Data(Bit)), Some(BadCastOp(Mass(Ounce), Data(Bit))));
1313
1314        assert_eq!(perform_cast_ok(Temp(Rankine), Plain), Some(Plain));
1315        assert_eq!(perform_cast_err(Temp(Rankine), Delta(Hour)), Some(BadCastOp(Temp(Rankine), Delta(Hour))));
1316        assert_eq!(perform_cast_err(Temp(Rankine), Time), Some(BadCastOp(Temp(Rankine), Time)));
1317        assert_eq!(perform_cast_err(Temp(Rankine), Length(Mile)), Some(BadCastOp(Temp(Rankine), Length(Mile))));
1318        assert_eq!(perform_cast_err(Temp(Rankine), Area(Acre)), Some(BadCastOp(Temp(Rankine), Area(Acre))));
1319        assert_eq!(perform_cast_err(Temp(Rankine), Volume(Pint)), Some(BadCastOp(Temp(Rankine), Volume(Pint))));
1320        assert_eq!(perform_cast_err(Temp(Rankine), Speed(Light)), Some(BadCastOp(Temp(Rankine), Speed(Light))));
1321        assert_eq!(perform_cast_err(Temp(Rankine), Mass(Ounce)), Some(BadCastOp(Temp(Rankine), Mass(Ounce))));
1322        assert_eq!(perform_cast_ok(Temp(Rankine), Temp(Rankine)), Some(Temp(Rankine)));
1323        assert_eq!(perform_cast_err(Temp(Rankine), Data(Bit)), Some(BadCastOp(Temp(Rankine), Data(Bit))));
1324
1325        assert_eq!(perform_cast_ok(Data(Bit), Plain), Some(Plain));
1326        assert_eq!(perform_cast_err(Data(Bit), Delta(Hour)), Some(BadCastOp(Data(Bit), Delta(Hour))));
1327        assert_eq!(perform_cast_err(Data(Bit), Time), Some(BadCastOp(Data(Bit), Time)));
1328        assert_eq!(perform_cast_err(Data(Bit), Length(Mile)), Some(BadCastOp(Data(Bit), Length(Mile))));
1329        assert_eq!(perform_cast_err(Data(Bit), Area(Acre)), Some(BadCastOp(Data(Bit), Area(Acre))));
1330        assert_eq!(perform_cast_err(Data(Bit), Volume(Pint)), Some(BadCastOp(Data(Bit), Volume(Pint))));
1331        assert_eq!(perform_cast_err(Data(Bit), Speed(Light)), Some(BadCastOp(Data(Bit), Speed(Light))));
1332        assert_eq!(perform_cast_err(Data(Bit), Mass(Ounce)), Some(BadCastOp(Data(Bit), Mass(Ounce))));
1333        assert_eq!(perform_cast_err(Data(Bit), Temp(Rankine)), Some(BadCastOp(Data(Bit), Temp(Rankine))));
1334        assert_eq!(perform_cast_ok(Data(Bit), Data(Bit)), Some(Data(Bit)));
1335    }
1336
1337    #[test]
1338    fn test_delta_values_are_scaled_on_cast() {
1339        assert_eq!(perform_cast_value(Delta(Second(Unit)), Delta(Second(Unit))), Some((Delta(Second(Unit)), String::from("1.0"))));
1340        assert_eq!(perform_cast_value(Delta(Minute), Delta(Second(Unit))), Some((Delta(Second(Unit)), String::from("60.0"))));
1341        assert_eq!(perform_cast_value(Delta(Hour), Delta(Second(Unit))), Some((Delta(Second(Unit)), String::from("3600.0"))));
1342        assert_eq!(perform_cast_value(Delta(Day), Delta(Second(Unit))), Some((Delta(Second(Unit)), String::from("86400.0"))));
1343        assert_eq!(perform_cast_value(Delta(Week), Delta(Second(Unit))), Some((Delta(Second(Unit)), String::from("604800.0"))));
1344        assert_eq!(perform_cast_value(Delta(Month), Delta(Second(Unit))), Some((Delta(Second(Unit)), String::from("2592000.0"))));
1345        assert_eq!(perform_cast_value(Delta(Year), Delta(Second(Unit))), Some((Delta(Second(Unit)), String::from("31557600.0"))));
1346        assert_eq!(perform_cast_value(Delta(HMS), Delta(Second(Unit))), Some((Delta(Second(Unit)), String::from("1.0"))));
1347
1348        assert_eq!(perform_cast_value(Delta(Second(Milli)), Delta(Second(Milli))), Some((Delta(Second(Milli)), String::from("1.0"))));
1349        assert_eq!(perform_cast_value(Delta(Second(Milli)), Delta(Minute)), Some((Delta(Minute), String::from("0.000016667"))));
1350        assert_eq!(perform_cast_value(Delta(Second(Milli)), Delta(HMS)), Some((Delta(HMS), String::from("00.001"))));
1351
1352        assert_eq!(perform_cast_value(Delta(Minute), Delta(Second(Milli))), Some((Delta(Second(Milli)), String::from("60000.0"))));
1353        assert_eq!(perform_cast_value(Delta(Minute), Delta(Minute)), Some((Delta(Minute), String::from("1.0"))));
1354        assert_eq!(perform_cast_value(Delta(Minute), Delta(HMS)), Some((Delta(HMS), String::from("01:00.000"))));
1355
1356        assert_eq!(perform_cast_value(Delta(HMS), Delta(Second(Milli))), Some((Delta(Second(Milli)), String::from("1000.0"))));
1357        assert_eq!(perform_cast_value(Delta(HMS), Delta(Minute)), Some((Delta(Minute), String::from("0.016666667"))));
1358        assert_eq!(perform_cast_value(Delta(HMS), Delta(HMS)), Some((Delta(HMS), String::from("01.000"))));
1359    }
1360
1361    #[test]
1362    fn test_length_values_are_scaled_on_cast() {
1363        assert_eq!(perform_cast_value(Length(Metre(Unit)), Length(Metre(Unit))), Some((Length(Metre(Unit)), String::from("1.0"))));
1364        assert_eq!(perform_cast_value(Length(Inch), Length(Metre(Unit))), Some((Length(Metre(Unit)), String::from("0.0254"))));
1365        assert_eq!(perform_cast_value(Length(Foot), Length(Metre(Unit))), Some((Length(Metre(Unit)), String::from("0.3048"))));
1366        assert_eq!(perform_cast_value(Length(Yard), Length(Metre(Unit))), Some((Length(Metre(Unit)), String::from("0.9144"))));
1367        assert_eq!(perform_cast_value(Length(Mile), Length(Metre(Unit))), Some((Length(Metre(Unit)), String::from("1609.344"))));
1368
1369        assert_eq!(perform_cast_value(Length(Metre(Kilo)), Length(Metre(Kilo))), Some((Length(Metre(Kilo)), String::from("1.0"))));
1370        assert_eq!(perform_cast_value(Length(Metre(Kilo)), Length(Mile)), Some((Length(Mile), String::from("0.621371192"))));
1371
1372        assert_eq!(perform_cast_value(Length(Mile), Length(Metre(Kilo))), Some((Length(Metre(Kilo)), String::from("1.609344"))));
1373        assert_eq!(perform_cast_value(Length(Mile), Length(Mile)), Some((Length(Mile), String::from("1.0"))));
1374    }
1375
1376    #[test]
1377    fn test_area_values_are_scaled_on_cast() {
1378        assert_eq!(perform_cast_value(Area(Square(Metre(Unit))), Area(Square(Metre(Unit)))), Some((Area(Square(Metre(Unit))), String::from("1.0"))));
1379        assert_eq!(perform_cast_value(Area(Hectare), Area(Square(Metre(Unit)))), Some((Area(Square(Metre(Unit))), String::from("10000.0"))));
1380        assert_eq!(perform_cast_value(Area(Acre), Area(Square(Metre(Unit)))), Some((Area(Square(Metre(Unit))), String::from("4046.8564224"))));
1381
1382        assert_eq!(perform_cast_value(Area(Square(Metre(Kilo))), Area(Square(Metre(Kilo)))), Some((Area(Square(Metre(Kilo))), String::from("1.0"))));
1383        assert_eq!(perform_cast_value(Area(Square(Metre(Kilo))), Area(Square(Mile))), Some((Area(Square(Mile)), String::from("0.386102159"))));
1384        assert_eq!(perform_cast_value(Area(Square(Metre(Kilo))), Area(Acre)), Some((Area(Acre), String::from("247.105381467"))));
1385
1386        assert_eq!(perform_cast_value(Area(Square(Mile)), Area(Square(Metre(Kilo)))), Some((Area(Square(Metre(Kilo))), String::from("2.58998811"))));
1387        assert_eq!(perform_cast_value(Area(Square(Mile)), Area(Square(Mile))), Some((Area(Square(Mile)), String::from("1.0"))));
1388        assert_eq!(perform_cast_value(Area(Square(Mile)), Area(Acre)), Some((Area(Acre), String::from("640.0"))));
1389
1390        assert_eq!(perform_cast_value(Area(Acre), Area(Square(Metre(Kilo)))), Some((Area(Square(Metre(Kilo))), String::from("0.004046856"))));
1391        assert_eq!(perform_cast_value(Area(Acre), Area(Square(Mile))), Some((Area(Square(Mile)), String::from("0.0015625"))));
1392        assert_eq!(perform_cast_value(Area(Acre), Area(Acre)), Some((Area(Acre), String::from("1.0"))));
1393    }
1394
1395    #[test]
1396    fn test_volume_values_are_scaled_on_cast() {
1397        assert_eq!(perform_cast_value(Volume(Cubic(Metre(Unit))), Volume(Cubic(Metre(Unit)))), Some((Volume(Cubic(Metre(Unit))), String::from("1.0"))));
1398        assert_eq!(perform_cast_value(Volume(Litre(Unit)), Volume(Cubic(Metre(Unit)))), Some((Volume(Cubic(Metre(Unit))), String::from("0.001"))));
1399        assert_eq!(perform_cast_value(Volume(Tsp), Volume(Cubic(Metre(Unit)))), Some((Volume(Cubic(Metre(Unit))), String::from("0.000005919"))));
1400        assert_eq!(perform_cast_value(Volume(Tbsp), Volume(Cubic(Metre(Unit)))), Some((Volume(Cubic(Metre(Unit))), String::from("0.000017758"))));
1401        assert_eq!(perform_cast_value(Volume(Floz), Volume(Cubic(Metre(Unit)))), Some((Volume(Cubic(Metre(Unit))), String::from("0.000028413"))));
1402        assert_eq!(perform_cast_value(Volume(Pint), Volume(Cubic(Metre(Unit)))), Some((Volume(Cubic(Metre(Unit))), String::from("0.000568261"))));
1403        assert_eq!(perform_cast_value(Volume(Quart), Volume(Cubic(Metre(Unit)))), Some((Volume(Cubic(Metre(Unit))), String::from("0.001136523"))));
1404        assert_eq!(perform_cast_value(Volume(Gallon), Volume(Cubic(Metre(Unit)))), Some((Volume(Cubic(Metre(Unit))), String::from("0.00454609"))));
1405        assert_eq!(perform_cast_value(Volume(Barrel), Volume(Cubic(Metre(Unit)))), Some((Volume(Cubic(Metre(Unit))), String::from("0.16365924"))));
1406        assert_eq!(perform_cast_value(Volume(USTsp), Volume(Cubic(Metre(Unit)))), Some((Volume(Cubic(Metre(Unit))), String::from("0.000004929"))));
1407        assert_eq!(perform_cast_value(Volume(USTbsp), Volume(Cubic(Metre(Unit)))), Some((Volume(Cubic(Metre(Unit))), String::from("0.000014787"))));
1408        assert_eq!(perform_cast_value(Volume(USFloz), Volume(Cubic(Metre(Unit)))), Some((Volume(Cubic(Metre(Unit))), String::from("0.000029574"))));
1409        assert_eq!(perform_cast_value(Volume(USCup), Volume(Cubic(Metre(Unit)))), Some((Volume(Cubic(Metre(Unit))), String::from("0.000236588"))));
1410        assert_eq!(perform_cast_value(Volume(USPint), Volume(Cubic(Metre(Unit)))), Some((Volume(Cubic(Metre(Unit))), String::from("0.000473176"))));
1411        assert_eq!(perform_cast_value(Volume(USQuart), Volume(Cubic(Metre(Unit)))), Some((Volume(Cubic(Metre(Unit))), String::from("0.000946353"))));
1412        assert_eq!(perform_cast_value(Volume(USGallon), Volume(Cubic(Metre(Unit)))), Some((Volume(Cubic(Metre(Unit))), String::from("0.003785412"))));
1413        assert_eq!(perform_cast_value(Volume(USBarrel), Volume(Cubic(Metre(Unit)))), Some((Volume(Cubic(Metre(Unit))), String::from("0.119240471"))));
1414
1415        assert_eq!(perform_cast_value(Volume(Cubic(Metre(Unit))), Volume(Cubic(Metre(Unit)))), Some((Volume(Cubic(Metre(Unit))), String::from("1.0"))));
1416        assert_eq!(perform_cast_value(Volume(Cubic(Metre(Unit))), Volume(Cubic(Yard))), Some((Volume(Cubic(Yard)), String::from("1.307950619"))));
1417        assert_eq!(perform_cast_value(Volume(Cubic(Metre(Unit))), Volume(Litre(Unit))), Some((Volume(Litre(Unit)), String::from("1000.0"))));
1418        assert_eq!(perform_cast_value(Volume(Cubic(Metre(Unit))), Volume(Pint)), Some((Volume(Pint), String::from("1759.753986393"))));
1419
1420        assert_eq!(perform_cast_value(Volume(Cubic(Yard)), Volume(Cubic(Metre(Unit)))), Some((Volume(Cubic(Metre(Unit))), String::from("0.764554858"))));
1421        assert_eq!(perform_cast_value(Volume(Cubic(Yard)), Volume(Cubic(Yard))), Some((Volume(Cubic(Yard)), String::from("1.0"))));
1422        assert_eq!(perform_cast_value(Volume(Cubic(Yard)), Volume(Litre(Unit))), Some((Volume(Litre(Unit)), String::from("764.554857984"))));
1423        assert_eq!(perform_cast_value(Volume(Cubic(Yard)), Volume(Pint)), Some((Volume(Pint), String::from("1345.428459153"))));
1424
1425        assert_eq!(perform_cast_value(Volume(Litre(Unit)), Volume(Cubic(Metre(Unit)))), Some((Volume(Cubic(Metre(Unit))), String::from("0.001"))));
1426        assert_eq!(perform_cast_value(Volume(Litre(Unit)), Volume(Cubic(Yard))), Some((Volume(Cubic(Yard)), String::from("0.001307951"))));
1427        assert_eq!(perform_cast_value(Volume(Litre(Unit)), Volume(Litre(Unit))), Some((Volume(Litre(Unit)), String::from("1.0"))));
1428        assert_eq!(perform_cast_value(Volume(Litre(Unit)), Volume(Pint)), Some((Volume(Pint), String::from("1.759753986"))));
1429
1430        assert_eq!(perform_cast_value(Volume(Pint), Volume(Cubic(Metre(Unit)))), Some((Volume(Cubic(Metre(Unit))), String::from("0.000568261"))));
1431        assert_eq!(perform_cast_value(Volume(Pint), Volume(Cubic(Yard))), Some((Volume(Cubic(Yard)), String::from("0.000743258"))));
1432        assert_eq!(perform_cast_value(Volume(Pint), Volume(Litre(Unit))), Some((Volume(Litre(Unit)), String::from("0.56826125"))));
1433        assert_eq!(perform_cast_value(Volume(Pint), Volume(Pint)), Some((Volume(Pint), String::from("1.0"))));
1434    }
1435
1436    #[test]
1437    fn test_speed_values_are_scaled_on_cast() {
1438        assert_eq!(perform_cast_value(Speed(Ratio(Metre(Unit), Second(Unit))), Speed(Ratio(Metre(Unit), Second(Unit)))), Some((Speed(Ratio(Metre(Unit), Second(Unit))), String::from("1.0"))));
1439        assert_eq!(perform_cast_value(Speed(Mach), Speed(Ratio(Metre(Unit), Second(Unit)))), Some((Speed(Ratio(Metre(Unit), Second(Unit))), String::from("340.0"))));
1440        assert_eq!(perform_cast_value(Speed(Light), Speed(Ratio(Metre(Unit), Second(Unit)))), Some((Speed(Ratio(Metre(Unit), Second(Unit))), String::from("299792458.0"))));
1441
1442        assert_eq!(perform_cast_value(Speed(Ratio(Metre(Kilo), Hour)), Speed(Ratio(Metre(Kilo), Hour))), Some((Speed(Ratio(Metre(Kilo), Hour)), String::from("1.0"))));
1443        assert_eq!(perform_cast_value(Speed(Ratio(Metre(Kilo), Hour)), Speed(Ratio(Mile, Hour))), Some((Speed(Ratio(Mile, Hour)), String::from("0.621371192"))));
1444        assert_eq!(perform_cast_value(Speed(Ratio(Metre(Kilo), Hour)), Speed(Mach)), Some((Speed(Mach), String::from("0.000816993"))));
1445
1446        assert_eq!(perform_cast_value(Speed(Ratio(Mile, Hour)), Speed(Ratio(Metre(Kilo), Hour))), Some((Speed(Ratio(Metre(Kilo), Hour)), String::from("1.609344"))));
1447        assert_eq!(perform_cast_value(Speed(Ratio(Mile, Hour)), Speed(Ratio(Mile, Hour))), Some((Speed(Ratio(Mile, Hour)), String::from("1.0"))));
1448        assert_eq!(perform_cast_value(Speed(Ratio(Mile, Hour)), Speed(Mach)), Some((Speed(Mach), String::from("0.001314824"))));
1449
1450        assert_eq!(perform_cast_value(Speed(Mach), Speed(Ratio(Metre(Kilo), Hour))), Some((Speed(Ratio(Metre(Kilo), Hour)), String::from("1224.0"))));
1451        assert_eq!(perform_cast_value(Speed(Mach), Speed(Ratio(Mile, Hour))), Some((Speed(Ratio(Mile, Hour)), String::from("760.558339298"))));
1452        assert_eq!(perform_cast_value(Speed(Mach), Speed(Mach)), Some((Speed(Mach), String::from("1.0"))));
1453    }
1454
1455    #[test]
1456    fn test_mass_values_are_scaled_on_cast() {
1457        assert_eq!(perform_cast_value(Mass(Gram(Unit)), Mass(Gram(Unit))), Some((Mass(Gram(Unit)), String::from("1.0"))));
1458        assert_eq!(perform_cast_value(Mass(Ounce), Mass(Gram(Unit))), Some((Mass(Gram(Unit)), String::from("28.349523125"))));
1459        assert_eq!(perform_cast_value(Mass(Pound), Mass(Gram(Unit))), Some((Mass(Gram(Unit)), String::from("453.59237"))));
1460        assert_eq!(perform_cast_value(Mass(Stone), Mass(Gram(Unit))), Some((Mass(Gram(Unit)), String::from("6350.29318"))));
1461        assert_eq!(perform_cast_value(Mass(Ton), Mass(Gram(Unit))), Some((Mass(Gram(Unit)), String::from("1016046.9088"))));
1462
1463        assert_eq!(perform_cast_value(Mass(Gram(Kilo)), Mass(Gram(Kilo))), Some((Mass(Gram(Kilo)), String::from("1.0"))));
1464        assert_eq!(perform_cast_value(Mass(Gram(Kilo)), Mass(Ton)), Some((Mass(Ton), String::from("0.000984207"))));
1465
1466        assert_eq!(perform_cast_value(Mass(Ton), Mass(Gram(Kilo))), Some((Mass(Gram(Kilo)), String::from("1016.0469088"))));
1467        assert_eq!(perform_cast_value(Mass(Ton), Mass(Ton)), Some((Mass(Ton), String::from("1.0"))));
1468    }
1469
1470    #[test]
1471    fn test_temp_values_are_scaled_on_cast() {
1472        assert_eq!(perform_cast_temp(Temp(Kelvin(Unit)), Temp(Kelvin(Unit)), "0.0"), Some((Temp(Kelvin(Unit)), String::from("0.0"))));
1473        assert_eq!(perform_cast_temp(Temp(Kelvin(Unit)), Temp(Kelvin(Unit)), "50.0"), Some((Temp(Kelvin(Unit)), String::from("50.0"))));
1474        assert_eq!(perform_cast_temp(Temp(Kelvin(Unit)), Temp(Kelvin(Unit)), "100.0"), Some((Temp(Kelvin(Unit)), String::from("100.0"))));
1475
1476        assert_eq!(perform_cast_temp(Temp(Kelvin(Unit)), Temp(Celsius), "0.0"), Some((Temp(Celsius), String::from("-273.15"))));
1477        assert_eq!(perform_cast_temp(Temp(Kelvin(Unit)), Temp(Celsius), "50.0"), Some((Temp(Celsius), String::from("-223.15"))));
1478        assert_eq!(perform_cast_temp(Temp(Kelvin(Unit)), Temp(Celsius), "100.0"), Some((Temp(Celsius), String::from("-173.15"))));
1479
1480        assert_eq!(perform_cast_temp(Temp(Kelvin(Unit)), Temp(Fahrenheit), "0.0"), Some((Temp(Fahrenheit), String::from("-459.67"))));
1481        assert_eq!(perform_cast_temp(Temp(Kelvin(Unit)), Temp(Fahrenheit), "50.0"), Some((Temp(Fahrenheit), String::from("-369.67"))));
1482        assert_eq!(perform_cast_temp(Temp(Kelvin(Unit)), Temp(Fahrenheit), "100.0"), Some((Temp(Fahrenheit), String::from("-279.67"))));
1483
1484        assert_eq!(perform_cast_temp(Temp(Kelvin(Unit)), Temp(Rankine), "0.0"), Some((Temp(Rankine), String::from("0.0"))));
1485        assert_eq!(perform_cast_temp(Temp(Kelvin(Unit)), Temp(Rankine), "50.0"), Some((Temp(Rankine), String::from("90.0"))));
1486        assert_eq!(perform_cast_temp(Temp(Kelvin(Unit)), Temp(Rankine), "100.0"), Some((Temp(Rankine), String::from("180.0"))));
1487
1488        assert_eq!(perform_cast_temp(Temp(Celsius), Temp(Kelvin(Unit)), "0.0"), Some((Temp(Kelvin(Unit)), String::from("273.15"))));
1489        assert_eq!(perform_cast_temp(Temp(Celsius), Temp(Kelvin(Unit)), "50.0"), Some((Temp(Kelvin(Unit)), String::from("323.15"))));
1490        assert_eq!(perform_cast_temp(Temp(Celsius), Temp(Kelvin(Unit)), "100.0"), Some((Temp(Kelvin(Unit)), String::from("373.15"))));
1491
1492        assert_eq!(perform_cast_temp(Temp(Celsius), Temp(Celsius), "0.0"), Some((Temp(Celsius), String::from("0.0"))));
1493        assert_eq!(perform_cast_temp(Temp(Celsius), Temp(Celsius), "50.0"), Some((Temp(Celsius), String::from("50.0"))));
1494        assert_eq!(perform_cast_temp(Temp(Celsius), Temp(Celsius), "100.0"), Some((Temp(Celsius), String::from("100.0"))));
1495
1496        assert_eq!(perform_cast_temp(Temp(Celsius), Temp(Fahrenheit), "0.0"), Some((Temp(Fahrenheit), String::from("32.0"))));
1497        assert_eq!(perform_cast_temp(Temp(Celsius), Temp(Fahrenheit), "50.0"), Some((Temp(Fahrenheit), String::from("122.0"))));
1498        assert_eq!(perform_cast_temp(Temp(Celsius), Temp(Fahrenheit), "100.0"), Some((Temp(Fahrenheit), String::from("212.0"))));
1499
1500        assert_eq!(perform_cast_temp(Temp(Celsius), Temp(Rankine), "0.0"), Some((Temp(Rankine), String::from("491.67"))));
1501        assert_eq!(perform_cast_temp(Temp(Celsius), Temp(Rankine), "50.0"), Some((Temp(Rankine), String::from("581.67"))));
1502        assert_eq!(perform_cast_temp(Temp(Celsius), Temp(Rankine), "100.0"), Some((Temp(Rankine), String::from("671.67"))));
1503
1504        assert_eq!(perform_cast_temp(Temp(Fahrenheit), Temp(Kelvin(Unit)), "0.0"), Some((Temp(Kelvin(Unit)), String::from("255.372222222"))));
1505        assert_eq!(perform_cast_temp(Temp(Fahrenheit), Temp(Kelvin(Unit)), "50.0"), Some((Temp(Kelvin(Unit)), String::from("283.15"))));
1506        assert_eq!(perform_cast_temp(Temp(Fahrenheit), Temp(Kelvin(Unit)), "100.0"), Some((Temp(Kelvin(Unit)), String::from("310.927777778"))));
1507
1508        assert_eq!(perform_cast_temp(Temp(Fahrenheit), Temp(Celsius), "0.0"), Some((Temp(Celsius), String::from("-17.777777778"))));
1509        assert_eq!(perform_cast_temp(Temp(Fahrenheit), Temp(Celsius), "50.0"), Some((Temp(Celsius), String::from("10.0"))));
1510        assert_eq!(perform_cast_temp(Temp(Fahrenheit), Temp(Celsius), "100.0"), Some((Temp(Celsius), String::from("37.777777778"))));
1511
1512        assert_eq!(perform_cast_temp(Temp(Fahrenheit), Temp(Fahrenheit), "0.0"), Some((Temp(Fahrenheit), String::from("0.0"))));
1513        assert_eq!(perform_cast_temp(Temp(Fahrenheit), Temp(Fahrenheit), "50.0"), Some((Temp(Fahrenheit), String::from("50.0"))));
1514        assert_eq!(perform_cast_temp(Temp(Fahrenheit), Temp(Fahrenheit), "100.0"), Some((Temp(Fahrenheit), String::from("100.0"))));
1515
1516        assert_eq!(perform_cast_temp(Temp(Fahrenheit), Temp(Rankine), "0.0"), Some((Temp(Rankine), String::from("459.67"))));
1517        assert_eq!(perform_cast_temp(Temp(Fahrenheit), Temp(Rankine), "50.0"), Some((Temp(Rankine), String::from("509.67"))));
1518        assert_eq!(perform_cast_temp(Temp(Fahrenheit), Temp(Rankine), "100.0"), Some((Temp(Rankine), String::from("559.67"))));
1519
1520        assert_eq!(perform_cast_temp(Temp(Rankine), Temp(Kelvin(Unit)), "0.0"), Some((Temp(Kelvin(Unit)), String::from("0.0"))));
1521        assert_eq!(perform_cast_temp(Temp(Rankine), Temp(Kelvin(Unit)), "50.0"), Some((Temp(Kelvin(Unit)), String::from("27.777777778"))));
1522        assert_eq!(perform_cast_temp(Temp(Rankine), Temp(Kelvin(Unit)), "100.0"), Some((Temp(Kelvin(Unit)), String::from("55.555555556"))));
1523
1524        assert_eq!(perform_cast_temp(Temp(Rankine), Temp(Celsius), "0.0"), Some((Temp(Celsius), String::from("-273.15"))));
1525        assert_eq!(perform_cast_temp(Temp(Rankine), Temp(Celsius), "50.0"), Some((Temp(Celsius), String::from("-245.372222222"))));
1526        assert_eq!(perform_cast_temp(Temp(Rankine), Temp(Celsius), "100.0"), Some((Temp(Celsius), String::from("-217.594444444"))));
1527
1528        assert_eq!(perform_cast_temp(Temp(Rankine), Temp(Fahrenheit), "0.0"), Some((Temp(Fahrenheit), String::from("-459.67"))));
1529        assert_eq!(perform_cast_temp(Temp(Rankine), Temp(Fahrenheit), "50.0"), Some((Temp(Fahrenheit), String::from("-409.67"))));
1530        assert_eq!(perform_cast_temp(Temp(Rankine), Temp(Fahrenheit), "100.0"), Some((Temp(Fahrenheit), String::from("-359.67"))));
1531
1532        assert_eq!(perform_cast_temp(Temp(Rankine), Temp(Rankine), "0.0"), Some((Temp(Rankine), String::from("0.0"))));
1533        assert_eq!(perform_cast_temp(Temp(Rankine), Temp(Rankine), "50.0"), Some((Temp(Rankine), String::from("50.0"))));
1534        assert_eq!(perform_cast_temp(Temp(Rankine), Temp(Rankine), "100.0"), Some((Temp(Rankine), String::from("100.0"))));
1535    }
1536
1537    #[test]
1538    fn test_data_values_are_scaled_on_cast() {
1539        assert_eq!(perform_cast_value(Data(Byte(Unit)), Data(Byte(Unit))), Some((Data(Byte(Unit)), String::from("1.0"))));
1540        assert_eq!(perform_cast_value(Data(Bit), Data(Byte(Unit))), Some((Data(Byte(Unit)), String::from("0.125"))));
1541
1542        assert_eq!(perform_cast_value(Data(Byte(Kilo)), Data(Byte(Kilo))), Some((Data(Byte(Kilo)), String::from("1.0"))));
1543        assert_eq!(perform_cast_value(Data(Byte(Kilo)), Data(Bit)), Some((Data(Bit), String::from("8000.0"))));
1544
1545        assert_eq!(perform_cast_value(Data(Bit), Data(Byte(Kilo))), Some((Data(Byte(Kilo)), String::from("0.000125"))));
1546        assert_eq!(perform_cast_value(Data(Bit), Data(Bit)), Some((Data(Bit), String::from("1.0"))));
1547    }
1548
1549    // Add   | Plain Delta Time  | Len   Area  Vol   Speed | Mass  Temp  Data
1550    // ------+-------------------+-------------------------+------------------
1551    // Plain | Plain Delta Time  | Len   Area  Vol   Speed | Mass  Temp  Data
1552    // Delta | Delta Delta Time  | -     -     -     -     | -     -     -
1553    // Time  | Time  Time  -     | -     -     -     -     | -     -     -
1554    // ------+-------------------+-------------------------+------------------
1555    // Len   | Len   -     -     | Len   -     -     -     | -     -     -
1556    // Area  | Area  -     -     | -     Area  -     -     | -     -     -
1557    // Vol   | Vol   -     -     | -     -     Vol   -     | -     -     -
1558    // Speed | Speed -     -     | -     -     -     Speed | -     -     -
1559    // ------+-------------------+-------------------------+------------------
1560    // Mass  | Mass  -     -     | -     -     -     -     | Mass  -     -
1561    // Temp  | Temp  -     -     | -     -     -     -     | -     Temp  -
1562    // Data  | Data  -     -     | -     -     -     -     | -     -     Data
1563
1564    #[test]
1565    fn test_unit_values_are_added_by_meaning() {
1566        assert_eq!(perform_binary_ok(Value::calc_add, Plain, Plain), Some(Plain));
1567        assert_eq!(perform_binary_ok(Value::calc_add, Plain, Delta(Hour)), Some(Delta(Hour)));
1568        assert_eq!(perform_binary_ok(Value::calc_add, Plain, Time), Some(Time));
1569        assert_eq!(perform_binary_ok(Value::calc_add, Plain, Length(Mile)), Some(Length(Mile)));
1570        assert_eq!(perform_binary_ok(Value::calc_add, Plain, Area(Acre)), Some(Area(Acre)));
1571        assert_eq!(perform_binary_ok(Value::calc_add, Plain, Volume(Pint)), Some(Volume(Pint)));
1572        assert_eq!(perform_binary_ok(Value::calc_add, Plain, Speed(Light)), Some(Speed(Light)));
1573        assert_eq!(perform_binary_ok(Value::calc_add, Plain, Mass(Ounce)), Some(Mass(Ounce)));
1574        assert_eq!(perform_binary_ok(Value::calc_add, Plain, Temp(Rankine)), Some(Temp(Rankine)));
1575        assert_eq!(perform_binary_ok(Value::calc_add, Plain, Data(Bit)), Some(Data(Bit)));
1576
1577        assert_eq!(perform_binary_ok(Value::calc_add, Delta(Hour), Plain), Some(Delta(Hour)));
1578        assert_eq!(perform_binary_ok(Value::calc_add, Delta(Hour), Delta(Hour)), Some(Delta(Hour)));
1579        assert_eq!(perform_binary_ok(Value::calc_add, Delta(Hour), Time), Some(Time));
1580        assert_eq!(perform_binary_err(Value::calc_add, Delta(Hour), Length(Mile)), Some(BadCastOp(Length(Mile), Delta(Hour))));
1581        assert_eq!(perform_binary_err(Value::calc_add, Delta(Hour), Area(Acre)), Some(BadCastOp(Area(Acre), Delta(Hour))));
1582        assert_eq!(perform_binary_err(Value::calc_add, Delta(Hour), Volume(Pint)), Some(BadCastOp(Volume(Pint), Delta(Hour))));
1583        assert_eq!(perform_binary_err(Value::calc_add, Delta(Hour), Speed(Light)), Some(BadCastOp(Speed(Light), Delta(Hour))));
1584        assert_eq!(perform_binary_err(Value::calc_add, Delta(Hour), Mass(Ounce)), Some(BadCastOp(Mass(Ounce), Delta(Hour))));
1585        assert_eq!(perform_binary_err(Value::calc_add, Delta(Hour), Temp(Rankine)), Some(BadCastOp(Temp(Rankine), Delta(Hour))));
1586        assert_eq!(perform_binary_err(Value::calc_add, Delta(Hour), Data(Bit)), Some(BadCastOp(Data(Bit), Delta(Hour))));
1587
1588        assert_eq!(perform_binary_ok(Value::calc_add, Time, Plain), Some(Time));
1589        assert_eq!(perform_binary_ok(Value::calc_add, Time, Delta(Hour)), Some(Time));
1590        assert_eq!(perform_binary_err(Value::calc_add, Time, Time), Some(BadCastOp(Time, Time)));
1591        assert_eq!(perform_binary_err(Value::calc_add, Time, Length(Mile)), Some(BadCastOp(Length(Mile), Time)));
1592        assert_eq!(perform_binary_err(Value::calc_add, Time, Area(Acre)), Some(BadCastOp(Area(Acre), Time)));
1593        assert_eq!(perform_binary_err(Value::calc_add, Time, Volume(Pint)), Some(BadCastOp(Volume(Pint), Time)));
1594        assert_eq!(perform_binary_err(Value::calc_add, Time, Speed(Light)), Some(BadCastOp(Speed(Light), Time)));
1595        assert_eq!(perform_binary_err(Value::calc_add, Time, Mass(Ounce)), Some(BadCastOp(Mass(Ounce), Time)));
1596        assert_eq!(perform_binary_err(Value::calc_add, Time, Temp(Rankine)), Some(BadCastOp(Temp(Rankine), Time)));
1597        assert_eq!(perform_binary_err(Value::calc_add, Time, Data(Bit)), Some(BadCastOp(Data(Bit), Time)));
1598
1599        assert_eq!(perform_binary_ok(Value::calc_add, Length(Mile), Plain), Some(Length(Mile)));
1600        assert_eq!(perform_binary_err(Value::calc_add, Length(Mile), Delta(Hour)), Some(BadCastOp(Delta(Hour), Length(Mile))));
1601        assert_eq!(perform_binary_err(Value::calc_add, Length(Mile), Time), Some(BadCastOp(Time, Length(Mile))));
1602        assert_eq!(perform_binary_ok(Value::calc_add, Length(Mile), Length(Mile)), Some(Length(Mile)));
1603        assert_eq!(perform_binary_err(Value::calc_add, Length(Mile), Area(Acre)), Some(BadCastOp(Area(Acre), Length(Mile))));
1604        assert_eq!(perform_binary_err(Value::calc_add, Length(Mile), Volume(Pint)), Some(BadCastOp(Volume(Pint), Length(Mile))));
1605        assert_eq!(perform_binary_err(Value::calc_add, Length(Mile), Speed(Light)), Some(BadCastOp(Speed(Light), Length(Mile))));
1606        assert_eq!(perform_binary_err(Value::calc_add, Length(Mile), Mass(Ounce)), Some(BadCastOp(Mass(Ounce), Length(Mile))));
1607        assert_eq!(perform_binary_err(Value::calc_add, Length(Mile), Temp(Rankine)), Some(BadCastOp(Temp(Rankine), Length(Mile))));
1608        assert_eq!(perform_binary_err(Value::calc_add, Length(Mile), Data(Bit)), Some(BadCastOp(Data(Bit), Length(Mile))));
1609
1610        assert_eq!(perform_binary_ok(Value::calc_add, Area(Acre), Plain), Some(Area(Acre)));
1611        assert_eq!(perform_binary_err(Value::calc_add, Area(Acre), Delta(Hour)), Some(BadCastOp(Delta(Hour), Area(Acre))));
1612        assert_eq!(perform_binary_err(Value::calc_add, Area(Acre), Time), Some(BadCastOp(Time, Area(Acre))));
1613        assert_eq!(perform_binary_err(Value::calc_add, Area(Acre), Length(Mile)), Some(BadCastOp(Length(Mile), Area(Acre))));
1614        assert_eq!(perform_binary_ok(Value::calc_add, Area(Acre), Area(Acre)), Some(Area(Acre)));
1615        assert_eq!(perform_binary_err(Value::calc_add, Area(Acre), Volume(Pint)), Some(BadCastOp(Volume(Pint), Area(Acre))));
1616        assert_eq!(perform_binary_err(Value::calc_add, Area(Acre), Speed(Light)), Some(BadCastOp(Speed(Light), Area(Acre))));
1617        assert_eq!(perform_binary_err(Value::calc_add, Area(Acre), Mass(Ounce)), Some(BadCastOp(Mass(Ounce), Area(Acre))));
1618        assert_eq!(perform_binary_err(Value::calc_add, Area(Acre), Temp(Rankine)), Some(BadCastOp(Temp(Rankine), Area(Acre))));
1619        assert_eq!(perform_binary_err(Value::calc_add, Area(Acre), Data(Bit)), Some(BadCastOp(Data(Bit), Area(Acre))));
1620
1621        assert_eq!(perform_binary_ok(Value::calc_add, Volume(Pint), Plain), Some(Volume(Pint)));
1622        assert_eq!(perform_binary_err(Value::calc_add, Volume(Pint), Delta(Hour)), Some(BadCastOp(Delta(Hour), Volume(Pint))));
1623        assert_eq!(perform_binary_err(Value::calc_add, Volume(Pint), Time), Some(BadCastOp(Time, Volume(Pint))));
1624        assert_eq!(perform_binary_err(Value::calc_add, Volume(Pint), Length(Mile)), Some(BadCastOp(Length(Mile), Volume(Pint))));
1625        assert_eq!(perform_binary_err(Value::calc_add, Volume(Pint), Area(Acre)), Some(BadCastOp(Area(Acre), Volume(Pint))));
1626        assert_eq!(perform_binary_ok(Value::calc_add, Volume(Pint), Volume(Pint)), Some(Volume(Pint)));
1627        assert_eq!(perform_binary_err(Value::calc_add, Volume(Pint), Speed(Light)), Some(BadCastOp(Speed(Light), Volume(Pint))));
1628        assert_eq!(perform_binary_err(Value::calc_add, Volume(Pint), Mass(Ounce)), Some(BadCastOp(Mass(Ounce), Volume(Pint))));
1629        assert_eq!(perform_binary_err(Value::calc_add, Volume(Pint), Temp(Rankine)), Some(BadCastOp(Temp(Rankine), Volume(Pint))));
1630        assert_eq!(perform_binary_err(Value::calc_add, Volume(Pint), Data(Bit)), Some(BadCastOp(Data(Bit), Volume(Pint))));
1631
1632        assert_eq!(perform_binary_ok(Value::calc_add, Speed(Light), Plain), Some(Speed(Light)));
1633        assert_eq!(perform_binary_err(Value::calc_add, Speed(Light), Delta(Hour)), Some(BadCastOp(Delta(Hour), Speed(Light))));
1634        assert_eq!(perform_binary_err(Value::calc_add, Speed(Light), Time), Some(BadCastOp(Time, Speed(Light))));
1635        assert_eq!(perform_binary_err(Value::calc_add, Speed(Light), Length(Mile)), Some(BadCastOp(Length(Mile), Speed(Light))));
1636        assert_eq!(perform_binary_err(Value::calc_add, Speed(Light), Area(Acre)), Some(BadCastOp(Area(Acre), Speed(Light))));
1637        assert_eq!(perform_binary_err(Value::calc_add, Speed(Light), Volume(Pint)), Some(BadCastOp(Volume(Pint), Speed(Light))));
1638        assert_eq!(perform_binary_ok(Value::calc_add, Speed(Light), Speed(Light)), Some(Speed(Light)));
1639        assert_eq!(perform_binary_err(Value::calc_add, Speed(Light), Mass(Ounce)), Some(BadCastOp(Mass(Ounce), Speed(Light))));
1640        assert_eq!(perform_binary_err(Value::calc_add, Speed(Light), Temp(Rankine)), Some(BadCastOp(Temp(Rankine), Speed(Light))));
1641        assert_eq!(perform_binary_err(Value::calc_add, Speed(Light), Data(Bit)), Some(BadCastOp(Data(Bit), Speed(Light))));
1642
1643        assert_eq!(perform_binary_ok(Value::calc_add, Mass(Ounce), Plain), Some(Mass(Ounce)));
1644        assert_eq!(perform_binary_err(Value::calc_add, Mass(Ounce), Delta(Hour)), Some(BadCastOp(Delta(Hour), Mass(Ounce))));
1645        assert_eq!(perform_binary_err(Value::calc_add, Mass(Ounce), Time), Some(BadCastOp(Time, Mass(Ounce))));
1646        assert_eq!(perform_binary_err(Value::calc_add, Mass(Ounce), Length(Mile)), Some(BadCastOp(Length(Mile), Mass(Ounce))));
1647        assert_eq!(perform_binary_err(Value::calc_add, Mass(Ounce), Area(Acre)), Some(BadCastOp(Area(Acre), Mass(Ounce))));
1648        assert_eq!(perform_binary_err(Value::calc_add, Mass(Ounce), Volume(Pint)), Some(BadCastOp(Volume(Pint), Mass(Ounce))));
1649        assert_eq!(perform_binary_err(Value::calc_add, Mass(Ounce), Speed(Light)), Some(BadCastOp(Speed(Light), Mass(Ounce))));
1650        assert_eq!(perform_binary_ok(Value::calc_add, Mass(Ounce), Mass(Ounce)), Some(Mass(Ounce)));
1651        assert_eq!(perform_binary_err(Value::calc_add, Mass(Ounce), Temp(Rankine)), Some(BadCastOp(Temp(Rankine), Mass(Ounce))));
1652        assert_eq!(perform_binary_err(Value::calc_add, Mass(Ounce), Data(Bit)), Some(BadCastOp(Data(Bit), Mass(Ounce))));
1653
1654        assert_eq!(perform_binary_ok(Value::calc_add, Temp(Rankine), Plain), Some(Temp(Rankine)));
1655        assert_eq!(perform_binary_err(Value::calc_add, Temp(Rankine), Delta(Hour)), Some(BadCastOp(Delta(Hour), Temp(Rankine))));
1656        assert_eq!(perform_binary_err(Value::calc_add, Temp(Rankine), Time), Some(BadCastOp(Time, Temp(Rankine))));
1657        assert_eq!(perform_binary_err(Value::calc_add, Temp(Rankine), Length(Mile)), Some(BadCastOp(Length(Mile), Temp(Rankine))));
1658        assert_eq!(perform_binary_err(Value::calc_add, Temp(Rankine), Area(Acre)), Some(BadCastOp(Area(Acre), Temp(Rankine))));
1659        assert_eq!(perform_binary_err(Value::calc_add, Temp(Rankine), Volume(Pint)), Some(BadCastOp(Volume(Pint), Temp(Rankine))));
1660        assert_eq!(perform_binary_err(Value::calc_add, Temp(Rankine), Speed(Light)), Some(BadCastOp(Speed(Light), Temp(Rankine))));
1661        assert_eq!(perform_binary_err(Value::calc_add, Temp(Rankine), Mass(Ounce)), Some(BadCastOp(Mass(Ounce), Temp(Rankine))));
1662        assert_eq!(perform_binary_ok(Value::calc_add, Temp(Rankine), Temp(Rankine)), Some(Temp(Rankine)));
1663        assert_eq!(perform_binary_err(Value::calc_add, Temp(Rankine), Data(Bit)), Some(BadCastOp(Data(Bit), Temp(Rankine))));
1664
1665        assert_eq!(perform_binary_ok(Value::calc_add, Data(Bit), Plain), Some(Data(Bit)));
1666        assert_eq!(perform_binary_err(Value::calc_add, Data(Bit), Delta(Hour)), Some(BadCastOp(Delta(Hour), Data(Bit))));
1667        assert_eq!(perform_binary_err(Value::calc_add, Data(Bit), Time), Some(BadCastOp(Time, Data(Bit))));
1668        assert_eq!(perform_binary_err(Value::calc_add, Data(Bit), Length(Mile)), Some(BadCastOp(Length(Mile), Data(Bit))));
1669        assert_eq!(perform_binary_err(Value::calc_add, Data(Bit), Area(Acre)), Some(BadCastOp(Area(Acre), Data(Bit))));
1670        assert_eq!(perform_binary_err(Value::calc_add, Data(Bit), Volume(Pint)), Some(BadCastOp(Volume(Pint), Data(Bit))));
1671        assert_eq!(perform_binary_err(Value::calc_add, Data(Bit), Speed(Light)), Some(BadCastOp(Speed(Light), Data(Bit))));
1672        assert_eq!(perform_binary_err(Value::calc_add, Data(Bit), Mass(Ounce)), Some(BadCastOp(Mass(Ounce), Data(Bit))));
1673        assert_eq!(perform_binary_err(Value::calc_add, Data(Bit), Temp(Rankine)), Some(BadCastOp(Temp(Rankine), Data(Bit))));
1674        assert_eq!(perform_binary_ok(Value::calc_add, Data(Bit), Data(Bit)), Some(Data(Bit)));
1675    }
1676
1677    #[test]
1678    fn test_time_values_are_added_by_meaning() {
1679        assert_eq!(perform_binary_value(Value::calc_add, Delta(Second(Unit)), Delta(Second(Unit))), Some((Delta(Second(Unit)), String::from("2.0"))));
1680        assert_eq!(perform_binary_value(Value::calc_add, Delta(Second(Unit)), Delta(Minute)), Some((Delta(Second(Unit)), String::from("61.0"))));
1681        assert_eq!(perform_binary_value(Value::calc_add, Delta(Second(Unit)), Delta(HMS)), Some((Delta(Second(Unit)), String::from("2.0"))));
1682        assert_eq!(perform_binary_value(Value::calc_add, Delta(Second(Unit)), Time), Some((Time, String::from("1970-01-01T00:00:02.000Z"))));
1683
1684        assert_eq!(perform_binary_value(Value::calc_add, Delta(Minute), Delta(Second(Unit))), Some((Delta(Minute), String::from("1.016666667"))));
1685        assert_eq!(perform_binary_value(Value::calc_add, Delta(Minute), Delta(Minute)), Some((Delta(Minute), String::from("2.0"))));
1686        assert_eq!(perform_binary_value(Value::calc_add, Delta(Minute), Delta(HMS)), Some((Delta(Minute), String::from("1.016666667"))));
1687        assert_eq!(perform_binary_value(Value::calc_add, Delta(Minute), Time), Some((Time, String::from("1970-01-01T00:01:01.000Z"))));
1688
1689        assert_eq!(perform_binary_value(Value::calc_add, Delta(HMS), Delta(Second(Unit))), Some((Delta(HMS), String::from("02.000"))));
1690        assert_eq!(perform_binary_value(Value::calc_add, Delta(HMS), Delta(Minute)), Some((Delta(HMS), String::from("01:01.000"))));
1691        assert_eq!(perform_binary_value(Value::calc_add, Delta(HMS), Delta(HMS)), Some((Delta(HMS), String::from("02.000"))));
1692        assert_eq!(perform_binary_value(Value::calc_add, Delta(HMS), Time), Some((Time, String::from("1970-01-01T00:00:02.000Z"))));
1693
1694        assert_eq!(perform_binary_value(Value::calc_add, Time, Delta(Second(Unit))), Some((Time, String::from("1970-01-01T00:00:02.000Z"))));
1695        assert_eq!(perform_binary_value(Value::calc_add, Time, Delta(Minute)), Some((Time, String::from("1970-01-01T00:01:01.000Z"))));
1696        assert_eq!(perform_binary_value(Value::calc_add, Time, Delta(HMS)), Some((Time, String::from("1970-01-01T00:00:02.000Z"))));
1697        assert_eq!(perform_binary_err(Value::calc_add, Time, Time), Some(BadCastOp(Time, Time)));
1698    }
1699
1700    // Sub   | Plain Delta Time  | Len   Area  Vol   Speed | Mass  Temp  Data
1701    // ------+-------------------+-------------------------+------------------
1702    // Plain | Plain Delta -     | Len   Area  Vol   Speed | Mass  Temp  Data
1703    // Delta | Delta Delta -     | -     -     -     -     | -     -     -
1704    // Time  | Time  Time  Delta | -     -     -     -     | -     -     -
1705    // ------+-------------------+-------------------------+------------------
1706    // Len   | Len   -     -     | Len   -     -     -     | -     -     -
1707    // Area  | Area  -     -     | -     Area  -     -     | -     -     -
1708    // Vol   | Vol   -     -     | -     -     Vol   -     | -     -     -
1709    // Speed | Speed -     -     | -     -     -     Speed | -     -     -
1710    // ------+-------------------+-------------------------+------------------
1711    // Mass  | Mass  -     -     | -     -     -     -     | Mass  -     -
1712    // Temp  | Temp  -     -     | -     -     -     -     | -     Temp  -
1713    // Data  | Data  -     -     | -     -     -     -     | -     -     Data
1714
1715    #[test]
1716    fn test_unit_values_are_subtracted_by_meaning() {
1717        assert_eq!(perform_binary_ok(Value::calc_sub, Plain, Plain), Some(Plain));
1718        assert_eq!(perform_binary_ok(Value::calc_sub, Plain, Delta(Hour)), Some(Delta(Hour)));
1719        assert_eq!(perform_binary_err(Value::calc_sub, Plain, Time), Some(BadCastOp(Time, Plain)));
1720        assert_eq!(perform_binary_ok(Value::calc_sub, Plain, Length(Mile)), Some(Length(Mile)));
1721        assert_eq!(perform_binary_ok(Value::calc_sub, Plain, Area(Acre)), Some(Area(Acre)));
1722        assert_eq!(perform_binary_ok(Value::calc_sub, Plain, Volume(Pint)), Some(Volume(Pint)));
1723        assert_eq!(perform_binary_ok(Value::calc_sub, Plain, Speed(Light)), Some(Speed(Light)));
1724        assert_eq!(perform_binary_ok(Value::calc_sub, Plain, Mass(Ounce)), Some(Mass(Ounce)));
1725        assert_eq!(perform_binary_ok(Value::calc_sub, Plain, Temp(Rankine)), Some(Temp(Rankine)));
1726        assert_eq!(perform_binary_ok(Value::calc_sub, Plain, Data(Bit)), Some(Data(Bit)));
1727
1728        assert_eq!(perform_binary_ok(Value::calc_sub, Delta(Hour), Plain), Some(Delta(Hour)));
1729        assert_eq!(perform_binary_ok(Value::calc_sub, Delta(Hour), Delta(Hour)), Some(Delta(Hour)));
1730        assert_eq!(perform_binary_err(Value::calc_sub, Delta(Hour), Time), Some(BadCastOp(Time, Delta(Hour))));
1731        assert_eq!(perform_binary_err(Value::calc_sub, Delta(Hour), Length(Mile)), Some(BadCastOp(Length(Mile), Delta(Hour))));
1732        assert_eq!(perform_binary_err(Value::calc_sub, Delta(Hour), Area(Acre)), Some(BadCastOp(Area(Acre), Delta(Hour))));
1733        assert_eq!(perform_binary_err(Value::calc_sub, Delta(Hour), Volume(Pint)), Some(BadCastOp(Volume(Pint), Delta(Hour))));
1734        assert_eq!(perform_binary_err(Value::calc_sub, Delta(Hour), Speed(Light)), Some(BadCastOp(Speed(Light), Delta(Hour))));
1735        assert_eq!(perform_binary_err(Value::calc_sub, Delta(Hour), Mass(Ounce)), Some(BadCastOp(Mass(Ounce), Delta(Hour))));
1736        assert_eq!(perform_binary_err(Value::calc_sub, Delta(Hour), Temp(Rankine)), Some(BadCastOp(Temp(Rankine), Delta(Hour))));
1737        assert_eq!(perform_binary_err(Value::calc_sub, Delta(Hour), Data(Bit)), Some(BadCastOp(Data(Bit), Delta(Hour))));
1738
1739        assert_eq!(perform_binary_ok(Value::calc_sub, Time, Plain), Some(Time));
1740        assert_eq!(perform_binary_ok(Value::calc_sub, Time, Delta(Hour)), Some(Time));
1741        assert_eq!(perform_binary_ok(Value::calc_sub, Time, Time), Some(Delta(HMS)));
1742        assert_eq!(perform_binary_err(Value::calc_sub, Time, Length(Mile)), Some(BadCastOp(Length(Mile), Time)));
1743        assert_eq!(perform_binary_err(Value::calc_sub, Time, Area(Acre)), Some(BadCastOp(Area(Acre), Time)));
1744        assert_eq!(perform_binary_err(Value::calc_sub, Time, Volume(Pint)), Some(BadCastOp(Volume(Pint), Time)));
1745        assert_eq!(perform_binary_err(Value::calc_sub, Time, Speed(Light)), Some(BadCastOp(Speed(Light), Time)));
1746        assert_eq!(perform_binary_err(Value::calc_sub, Time, Mass(Ounce)), Some(BadCastOp(Mass(Ounce), Time)));
1747        assert_eq!(perform_binary_err(Value::calc_sub, Time, Temp(Rankine)), Some(BadCastOp(Temp(Rankine), Time)));
1748        assert_eq!(perform_binary_err(Value::calc_sub, Time, Data(Bit)), Some(BadCastOp(Data(Bit), Time)));
1749
1750        assert_eq!(perform_binary_ok(Value::calc_sub, Length(Mile), Plain), Some(Length(Mile)));
1751        assert_eq!(perform_binary_err(Value::calc_sub, Length(Mile), Delta(Hour)), Some(BadCastOp(Delta(Hour), Length(Mile))));
1752        assert_eq!(perform_binary_err(Value::calc_sub, Length(Mile), Time), Some(BadCastOp(Time, Length(Mile))));
1753        assert_eq!(perform_binary_ok(Value::calc_sub, Length(Mile), Length(Mile)), Some(Length(Mile)));
1754        assert_eq!(perform_binary_err(Value::calc_sub, Length(Mile), Area(Acre)), Some(BadCastOp(Area(Acre), Length(Mile))));
1755        assert_eq!(perform_binary_err(Value::calc_sub, Length(Mile), Volume(Pint)), Some(BadCastOp(Volume(Pint), Length(Mile))));
1756        assert_eq!(perform_binary_err(Value::calc_sub, Length(Mile), Speed(Light)), Some(BadCastOp(Speed(Light), Length(Mile))));
1757        assert_eq!(perform_binary_err(Value::calc_sub, Length(Mile), Mass(Ounce)), Some(BadCastOp(Mass(Ounce), Length(Mile))));
1758        assert_eq!(perform_binary_err(Value::calc_sub, Length(Mile), Temp(Rankine)), Some(BadCastOp(Temp(Rankine), Length(Mile))));
1759        assert_eq!(perform_binary_err(Value::calc_sub, Length(Mile), Data(Bit)), Some(BadCastOp(Data(Bit), Length(Mile))));
1760
1761        assert_eq!(perform_binary_ok(Value::calc_sub, Area(Acre), Plain), Some(Area(Acre)));
1762        assert_eq!(perform_binary_err(Value::calc_sub, Area(Acre), Delta(Hour)), Some(BadCastOp(Delta(Hour), Area(Acre))));
1763        assert_eq!(perform_binary_err(Value::calc_sub, Area(Acre), Time), Some(BadCastOp(Time, Area(Acre))));
1764        assert_eq!(perform_binary_err(Value::calc_sub, Area(Acre), Length(Mile)), Some(BadCastOp(Length(Mile), Area(Acre))));
1765        assert_eq!(perform_binary_ok(Value::calc_sub, Area(Acre), Area(Acre)), Some(Area(Acre)));
1766        assert_eq!(perform_binary_err(Value::calc_sub, Area(Acre), Volume(Pint)), Some(BadCastOp(Volume(Pint), Area(Acre))));
1767        assert_eq!(perform_binary_err(Value::calc_sub, Area(Acre), Speed(Light)), Some(BadCastOp(Speed(Light), Area(Acre))));
1768        assert_eq!(perform_binary_err(Value::calc_sub, Area(Acre), Mass(Ounce)), Some(BadCastOp(Mass(Ounce), Area(Acre))));
1769        assert_eq!(perform_binary_err(Value::calc_sub, Area(Acre), Temp(Rankine)), Some(BadCastOp(Temp(Rankine), Area(Acre))));
1770        assert_eq!(perform_binary_err(Value::calc_sub, Area(Acre), Data(Bit)), Some(BadCastOp(Data(Bit), Area(Acre))));
1771
1772        assert_eq!(perform_binary_ok(Value::calc_sub, Volume(Pint), Plain), Some(Volume(Pint)));
1773        assert_eq!(perform_binary_err(Value::calc_sub, Volume(Pint), Delta(Hour)), Some(BadCastOp(Delta(Hour), Volume(Pint))));
1774        assert_eq!(perform_binary_err(Value::calc_sub, Volume(Pint), Time), Some(BadCastOp(Time, Volume(Pint))));
1775        assert_eq!(perform_binary_err(Value::calc_sub, Volume(Pint), Length(Mile)), Some(BadCastOp(Length(Mile), Volume(Pint))));
1776        assert_eq!(perform_binary_err(Value::calc_sub, Volume(Pint), Area(Acre)), Some(BadCastOp(Area(Acre), Volume(Pint))));
1777        assert_eq!(perform_binary_ok(Value::calc_sub, Volume(Pint), Volume(Pint)), Some(Volume(Pint)));
1778        assert_eq!(perform_binary_err(Value::calc_sub, Volume(Pint), Speed(Light)), Some(BadCastOp(Speed(Light), Volume(Pint))));
1779        assert_eq!(perform_binary_err(Value::calc_sub, Volume(Pint), Mass(Ounce)), Some(BadCastOp(Mass(Ounce), Volume(Pint))));
1780        assert_eq!(perform_binary_err(Value::calc_sub, Volume(Pint), Temp(Rankine)), Some(BadCastOp(Temp(Rankine), Volume(Pint))));
1781        assert_eq!(perform_binary_err(Value::calc_sub, Volume(Pint), Data(Bit)), Some(BadCastOp(Data(Bit), Volume(Pint))));
1782
1783        assert_eq!(perform_binary_ok(Value::calc_sub, Speed(Light), Plain), Some(Speed(Light)));
1784        assert_eq!(perform_binary_err(Value::calc_sub, Speed(Light), Delta(Hour)), Some(BadCastOp(Delta(Hour), Speed(Light))));
1785        assert_eq!(perform_binary_err(Value::calc_sub, Speed(Light), Time), Some(BadCastOp(Time, Speed(Light))));
1786        assert_eq!(perform_binary_err(Value::calc_sub, Speed(Light), Length(Mile)), Some(BadCastOp(Length(Mile), Speed(Light))));
1787        assert_eq!(perform_binary_err(Value::calc_sub, Speed(Light), Area(Acre)), Some(BadCastOp(Area(Acre), Speed(Light))));
1788        assert_eq!(perform_binary_err(Value::calc_sub, Speed(Light), Volume(Pint)), Some(BadCastOp(Volume(Pint), Speed(Light))));
1789        assert_eq!(perform_binary_ok(Value::calc_sub, Speed(Light), Speed(Light)), Some(Speed(Light)));
1790        assert_eq!(perform_binary_err(Value::calc_sub, Speed(Light), Mass(Ounce)), Some(BadCastOp(Mass(Ounce), Speed(Light))));
1791        assert_eq!(perform_binary_err(Value::calc_sub, Speed(Light), Temp(Rankine)), Some(BadCastOp(Temp(Rankine), Speed(Light))));
1792        assert_eq!(perform_binary_err(Value::calc_sub, Speed(Light), Data(Bit)), Some(BadCastOp(Data(Bit), Speed(Light))));
1793
1794        assert_eq!(perform_binary_ok(Value::calc_sub, Mass(Ounce), Plain), Some(Mass(Ounce)));
1795        assert_eq!(perform_binary_err(Value::calc_sub, Mass(Ounce), Delta(Hour)), Some(BadCastOp(Delta(Hour), Mass(Ounce))));
1796        assert_eq!(perform_binary_err(Value::calc_sub, Mass(Ounce), Time), Some(BadCastOp(Time, Mass(Ounce))));
1797        assert_eq!(perform_binary_err(Value::calc_sub, Mass(Ounce), Length(Mile)), Some(BadCastOp(Length(Mile), Mass(Ounce))));
1798        assert_eq!(perform_binary_err(Value::calc_sub, Mass(Ounce), Area(Acre)), Some(BadCastOp(Area(Acre), Mass(Ounce))));
1799        assert_eq!(perform_binary_err(Value::calc_sub, Mass(Ounce), Volume(Pint)), Some(BadCastOp(Volume(Pint), Mass(Ounce))));
1800        assert_eq!(perform_binary_err(Value::calc_sub, Mass(Ounce), Speed(Light)), Some(BadCastOp(Speed(Light), Mass(Ounce))));
1801        assert_eq!(perform_binary_ok(Value::calc_sub, Mass(Ounce), Mass(Ounce)), Some(Mass(Ounce)));
1802        assert_eq!(perform_binary_err(Value::calc_sub, Mass(Ounce), Temp(Rankine)), Some(BadCastOp(Temp(Rankine), Mass(Ounce))));
1803        assert_eq!(perform_binary_err(Value::calc_sub, Mass(Ounce), Data(Bit)), Some(BadCastOp(Data(Bit), Mass(Ounce))));
1804
1805        assert_eq!(perform_binary_ok(Value::calc_sub, Temp(Rankine), Plain), Some(Temp(Rankine)));
1806        assert_eq!(perform_binary_err(Value::calc_sub, Temp(Rankine), Delta(Hour)), Some(BadCastOp(Delta(Hour), Temp(Rankine))));
1807        assert_eq!(perform_binary_err(Value::calc_sub, Temp(Rankine), Time), Some(BadCastOp(Time, Temp(Rankine))));
1808        assert_eq!(perform_binary_err(Value::calc_sub, Temp(Rankine), Length(Mile)), Some(BadCastOp(Length(Mile), Temp(Rankine))));
1809        assert_eq!(perform_binary_err(Value::calc_sub, Temp(Rankine), Area(Acre)), Some(BadCastOp(Area(Acre), Temp(Rankine))));
1810        assert_eq!(perform_binary_err(Value::calc_sub, Temp(Rankine), Volume(Pint)), Some(BadCastOp(Volume(Pint), Temp(Rankine))));
1811        assert_eq!(perform_binary_err(Value::calc_sub, Temp(Rankine), Speed(Light)), Some(BadCastOp(Speed(Light), Temp(Rankine))));
1812        assert_eq!(perform_binary_err(Value::calc_sub, Temp(Rankine), Mass(Ounce)), Some(BadCastOp(Mass(Ounce), Temp(Rankine))));
1813        assert_eq!(perform_binary_ok(Value::calc_sub, Temp(Rankine), Temp(Rankine)), Some(Temp(Rankine)));
1814        assert_eq!(perform_binary_err(Value::calc_sub, Temp(Rankine), Data(Bit)), Some(BadCastOp(Data(Bit), Temp(Rankine))));
1815
1816        assert_eq!(perform_binary_ok(Value::calc_sub, Data(Bit), Plain), Some(Data(Bit)));
1817        assert_eq!(perform_binary_err(Value::calc_sub, Data(Bit), Delta(Hour)), Some(BadCastOp(Delta(Hour), Data(Bit))));
1818        assert_eq!(perform_binary_err(Value::calc_sub, Data(Bit), Time), Some(BadCastOp(Time, Data(Bit))));
1819        assert_eq!(perform_binary_err(Value::calc_sub, Data(Bit), Length(Mile)), Some(BadCastOp(Length(Mile), Data(Bit))));
1820        assert_eq!(perform_binary_err(Value::calc_sub, Data(Bit), Area(Acre)), Some(BadCastOp(Area(Acre), Data(Bit))));
1821        assert_eq!(perform_binary_err(Value::calc_sub, Data(Bit), Volume(Pint)), Some(BadCastOp(Volume(Pint), Data(Bit))));
1822        assert_eq!(perform_binary_err(Value::calc_sub, Data(Bit), Speed(Light)), Some(BadCastOp(Speed(Light), Data(Bit))));
1823        assert_eq!(perform_binary_err(Value::calc_sub, Data(Bit), Mass(Ounce)), Some(BadCastOp(Mass(Ounce), Data(Bit))));
1824        assert_eq!(perform_binary_err(Value::calc_sub, Data(Bit), Temp(Rankine)), Some(BadCastOp(Temp(Rankine), Data(Bit))));
1825        assert_eq!(perform_binary_ok(Value::calc_sub, Data(Bit), Data(Bit)), Some(Data(Bit)));
1826    }
1827
1828    #[test]
1829    fn test_time_values_are_subtracted_by_meaning() {
1830        assert_eq!(perform_binary_value(Value::calc_sub, Delta(Second(Unit)), Delta(Second(Unit))), Some((Delta(Second(Unit)), String::from("0.0"))));
1831        assert_eq!(perform_binary_value(Value::calc_sub, Delta(Second(Unit)), Delta(Minute)), Some((Delta(Second(Unit)), String::from("-59.0"))));
1832        assert_eq!(perform_binary_value(Value::calc_sub, Delta(Second(Unit)), Delta(HMS)), Some((Delta(Second(Unit)), String::from("0.0"))));
1833        assert_eq!(perform_binary_err(Value::calc_sub, Delta(Second(Unit)), Time), Some(BadCastOp(Time, Delta(Second(Unit)))));
1834
1835        assert_eq!(perform_binary_value(Value::calc_sub, Delta(Minute), Delta(Second(Unit))), Some((Delta(Minute), String::from("0.983333333"))));
1836        assert_eq!(perform_binary_value(Value::calc_sub, Delta(Minute), Delta(Minute)), Some((Delta(Minute), String::from("0.0"))));
1837        assert_eq!(perform_binary_value(Value::calc_sub, Delta(Minute), Delta(HMS)), Some((Delta(Minute), String::from("0.983333333"))));
1838        assert_eq!(perform_binary_err(Value::calc_sub, Delta(Minute), Time), Some(BadCastOp(Time, Delta(Minute))));
1839
1840        assert_eq!(perform_binary_value(Value::calc_sub, Delta(HMS), Delta(Second(Unit))), Some((Delta(HMS), String::from("00.000"))));
1841        assert_eq!(perform_binary_value(Value::calc_sub, Delta(HMS), Delta(Minute)), Some((Delta(HMS), String::from("-59.000"))));
1842        assert_eq!(perform_binary_value(Value::calc_sub, Delta(HMS), Delta(HMS)), Some((Delta(HMS), String::from("00.000"))));
1843        assert_eq!(perform_binary_err(Value::calc_sub, Delta(HMS), Time), Some(BadCastOp(Time, Delta(HMS))));
1844
1845        assert_eq!(perform_binary_value(Value::calc_sub, Time, Delta(Second(Unit))), Some((Time, String::from("1970-01-01T00:00:00.000Z"))));
1846        assert_eq!(perform_binary_value(Value::calc_sub, Time, Delta(Minute)), Some((Time, String::from("1969-12-31T23:59:01.000Z"))));
1847        assert_eq!(perform_binary_value(Value::calc_sub, Time, Delta(HMS)), Some((Time, String::from("1970-01-01T00:00:00.000Z"))));
1848        assert_eq!(perform_binary_value(Value::calc_sub, Time, Time), Some((Delta(HMS), String::from("00.000"))));
1849    }
1850
1851    // Mul   | Plain Delta Time  | Len   Area  Vol   Speed | Mass  Temp  Data
1852    // ------+-------------------+-------------------------+------------------
1853    // Plain | Plain Delta -     | Len   Area  Vol   Speed | Mass  Temp  Data
1854    // Delta | Delta -     -     | -     -     -     Len   | -     -     -
1855    // Time  | -     -     -     | -     -     -     -     | -     -     -
1856    // ------+-------------------+-------------------------+------------------
1857    // Len   | Len   -     -     | Area  Vol   -     -     | -     -     -
1858    // Area  | Area  -     -     | Vol   -     -     -     | -     -     -
1859    // Vol   | Vol   -     -     | -     -     -     -     | -     -     -
1860    // Speed | Speed Len   -     | -     -     -     -     | -     -     -
1861    // ------+-------------------+-------------------------+------------------
1862    // Mass  | Mass  -     -     | -     -     -     -     | -     -     -
1863    // Temp  | Temp  -     -     | -     -     -     -     | -     -     -
1864    // Data  | Data  -     -     | -     -     -     -     | -     -     -
1865
1866    #[test]
1867    fn test_unit_values_are_multiplied_by_meaning() {
1868        assert_eq!(perform_binary_ok(Value::calc_mul, Plain, Plain), Some(Plain));
1869        assert_eq!(perform_binary_ok(Value::calc_mul, Plain, Delta(Hour)), Some(Delta(Hour)));
1870        assert_eq!(perform_binary_err(Value::calc_mul, Plain, Time), Some(BadCastOp(Time, Plain)));
1871        assert_eq!(perform_binary_ok(Value::calc_mul, Plain, Length(Mile)), Some(Length(Mile)));
1872        assert_eq!(perform_binary_ok(Value::calc_mul, Plain, Area(Acre)), Some(Area(Acre)));
1873        assert_eq!(perform_binary_ok(Value::calc_mul, Plain, Volume(Pint)), Some(Volume(Pint)));
1874        assert_eq!(perform_binary_ok(Value::calc_mul, Plain, Speed(Light)), Some(Speed(Light)));
1875        assert_eq!(perform_binary_ok(Value::calc_mul, Plain, Mass(Ounce)), Some(Mass(Ounce)));
1876        assert_eq!(perform_binary_ok(Value::calc_mul, Plain, Temp(Rankine)), Some(Temp(Rankine)));
1877        assert_eq!(perform_binary_ok(Value::calc_mul, Plain, Data(Bit)), Some(Data(Bit)));
1878
1879        assert_eq!(perform_binary_ok(Value::calc_mul, Delta(Hour), Plain), Some(Delta(Hour)));
1880        assert_eq!(perform_binary_err(Value::calc_mul, Delta(Hour), Delta(Hour)), Some(BadCastOp(Delta(Hour), Delta(Hour))));
1881        assert_eq!(perform_binary_err(Value::calc_mul, Delta(Hour), Time), Some(BadCastOp(Time, Delta(Hour))));
1882        assert_eq!(perform_binary_err(Value::calc_mul, Delta(Hour), Length(Mile)), Some(BadCastOp(Length(Mile), Delta(Hour))));
1883        assert_eq!(perform_binary_err(Value::calc_mul, Delta(Hour), Area(Acre)), Some(BadCastOp(Area(Acre), Delta(Hour))));
1884        assert_eq!(perform_binary_err(Value::calc_mul, Delta(Hour), Volume(Pint)), Some(BadCastOp(Volume(Pint), Delta(Hour))));
1885        assert_eq!(perform_binary_ok(Value::calc_mul, Delta(Hour), Speed(Light)), Some(Length(Metre(Unit))));
1886        assert_eq!(perform_binary_err(Value::calc_mul, Delta(Hour), Mass(Ounce)), Some(BadCastOp(Mass(Ounce), Delta(Hour))));
1887        assert_eq!(perform_binary_err(Value::calc_mul, Delta(Hour), Temp(Rankine)), Some(BadCastOp(Temp(Rankine), Delta(Hour))));
1888        assert_eq!(perform_binary_err(Value::calc_mul, Delta(Hour), Data(Bit)), Some(BadCastOp(Data(Bit), Delta(Hour))));
1889
1890        assert_eq!(perform_binary_err(Value::calc_mul, Time, Plain), Some(BadCastOp(Plain, Time)));
1891        assert_eq!(perform_binary_err(Value::calc_mul, Time, Delta(Hour)), Some(BadCastOp(Delta(Hour), Time)));
1892        assert_eq!(perform_binary_err(Value::calc_mul, Time, Time), Some(BadCastOp(Time, Time)));
1893        assert_eq!(perform_binary_err(Value::calc_mul, Time, Length(Mile)), Some(BadCastOp(Length(Mile), Time)));
1894        assert_eq!(perform_binary_err(Value::calc_mul, Time, Area(Acre)), Some(BadCastOp(Area(Acre), Time)));
1895        assert_eq!(perform_binary_err(Value::calc_mul, Time, Volume(Pint)), Some(BadCastOp(Volume(Pint), Time)));
1896        assert_eq!(perform_binary_err(Value::calc_mul, Time, Speed(Light)), Some(BadCastOp(Speed(Light), Time)));
1897        assert_eq!(perform_binary_err(Value::calc_mul, Time, Mass(Ounce)), Some(BadCastOp(Mass(Ounce), Time)));
1898        assert_eq!(perform_binary_err(Value::calc_mul, Time, Temp(Rankine)), Some(BadCastOp(Temp(Rankine), Time)));
1899        assert_eq!(perform_binary_err(Value::calc_mul, Time, Data(Bit)), Some(BadCastOp(Data(Bit), Time)));
1900
1901        assert_eq!(perform_binary_ok(Value::calc_mul, Length(Mile), Plain), Some(Length(Mile)));
1902        assert_eq!(perform_binary_err(Value::calc_mul, Length(Mile), Delta(Hour)), Some(BadCastOp(Delta(Hour), Length(Mile))));
1903        assert_eq!(perform_binary_err(Value::calc_mul, Length(Mile), Time), Some(BadCastOp(Time, Length(Mile))));
1904        assert_eq!(perform_binary_ok(Value::calc_mul, Length(Mile), Length(Mile)), Some(Area(Square(Mile))));
1905        assert_eq!(perform_binary_ok(Value::calc_mul, Length(Mile), Area(Acre)), Some(Volume(Cubic(Mile))));
1906        assert_eq!(perform_binary_err(Value::calc_mul, Length(Mile), Volume(Pint)), Some(BadCastOp(Volume(Pint), Length(Mile))));
1907        assert_eq!(perform_binary_err(Value::calc_mul, Length(Mile), Speed(Light)), Some(BadCastOp(Speed(Light), Length(Mile))));
1908        assert_eq!(perform_binary_err(Value::calc_mul, Length(Mile), Mass(Ounce)), Some(BadCastOp(Mass(Ounce), Length(Mile))));
1909        assert_eq!(perform_binary_err(Value::calc_mul, Length(Mile), Temp(Rankine)), Some(BadCastOp(Temp(Rankine), Length(Mile))));
1910        assert_eq!(perform_binary_err(Value::calc_mul, Length(Mile), Data(Bit)), Some(BadCastOp(Data(Bit), Length(Mile))));
1911
1912        assert_eq!(perform_binary_ok(Value::calc_mul, Area(Acre), Plain), Some(Area(Acre)));
1913        assert_eq!(perform_binary_err(Value::calc_mul, Area(Acre), Delta(Hour)), Some(BadCastOp(Delta(Hour), Area(Acre))));
1914        assert_eq!(perform_binary_err(Value::calc_mul, Area(Acre), Time), Some(BadCastOp(Time, Area(Acre))));
1915        assert_eq!(perform_binary_ok(Value::calc_mul, Area(Acre), Length(Mile)), Some(Volume(Cubic(Metre(Unit)))));
1916        assert_eq!(perform_binary_err(Value::calc_mul, Area(Acre), Area(Acre)), Some(BadCastOp(Area(Acre), Area(Acre))));
1917        assert_eq!(perform_binary_err(Value::calc_mul, Area(Acre), Volume(Pint)), Some(BadCastOp(Volume(Pint), Area(Acre))));
1918        assert_eq!(perform_binary_err(Value::calc_mul, Area(Acre), Speed(Light)), Some(BadCastOp(Speed(Light), Area(Acre))));
1919        assert_eq!(perform_binary_err(Value::calc_mul, Area(Acre), Mass(Ounce)), Some(BadCastOp(Mass(Ounce), Area(Acre))));
1920        assert_eq!(perform_binary_err(Value::calc_mul, Area(Acre), Temp(Rankine)), Some(BadCastOp(Temp(Rankine), Area(Acre))));
1921        assert_eq!(perform_binary_err(Value::calc_mul, Area(Acre), Data(Bit)), Some(BadCastOp(Data(Bit), Area(Acre))));
1922
1923        assert_eq!(perform_binary_ok(Value::calc_mul, Volume(Pint), Plain), Some(Volume(Pint)));
1924        assert_eq!(perform_binary_err(Value::calc_mul, Volume(Pint), Delta(Hour)), Some(BadCastOp(Delta(Hour), Volume(Pint))));
1925        assert_eq!(perform_binary_err(Value::calc_mul, Volume(Pint), Time), Some(BadCastOp(Time, Volume(Pint))));
1926        assert_eq!(perform_binary_err(Value::calc_mul, Volume(Pint), Length(Mile)), Some(BadCastOp(Length(Mile), Volume(Pint))));
1927        assert_eq!(perform_binary_err(Value::calc_mul, Volume(Pint), Area(Acre)), Some(BadCastOp(Area(Acre), Volume(Pint))));
1928        assert_eq!(perform_binary_err(Value::calc_mul, Volume(Pint), Volume(Pint)), Some(BadCastOp(Volume(Pint), Volume(Pint))));
1929        assert_eq!(perform_binary_err(Value::calc_mul, Volume(Pint), Speed(Light)), Some(BadCastOp(Speed(Light), Volume(Pint))));
1930        assert_eq!(perform_binary_err(Value::calc_mul, Volume(Pint), Mass(Ounce)), Some(BadCastOp(Mass(Ounce), Volume(Pint))));
1931        assert_eq!(perform_binary_err(Value::calc_mul, Volume(Pint), Temp(Rankine)), Some(BadCastOp(Temp(Rankine), Volume(Pint))));
1932        assert_eq!(perform_binary_err(Value::calc_mul, Volume(Pint), Data(Bit)), Some(BadCastOp(Data(Bit), Volume(Pint))));
1933
1934        assert_eq!(perform_binary_ok(Value::calc_mul, Speed(Light), Plain), Some(Speed(Light)));
1935        assert_eq!(perform_binary_ok(Value::calc_mul, Speed(Light), Delta(Hour)), Some(Length(Metre(Unit))));
1936        assert_eq!(perform_binary_err(Value::calc_mul, Speed(Light), Time), Some(BadCastOp(Time, Speed(Light))));
1937        assert_eq!(perform_binary_err(Value::calc_mul, Speed(Light), Length(Mile)), Some(BadCastOp(Length(Mile), Speed(Light))));
1938        assert_eq!(perform_binary_err(Value::calc_mul, Speed(Light), Area(Acre)), Some(BadCastOp(Area(Acre), Speed(Light))));
1939        assert_eq!(perform_binary_err(Value::calc_mul, Speed(Light), Volume(Pint)), Some(BadCastOp(Volume(Pint), Speed(Light))));
1940        assert_eq!(perform_binary_err(Value::calc_mul, Speed(Light), Speed(Light)), Some(BadCastOp(Speed(Light), Speed(Light))));
1941        assert_eq!(perform_binary_err(Value::calc_mul, Speed(Light), Mass(Ounce)), Some(BadCastOp(Mass(Ounce), Speed(Light))));
1942        assert_eq!(perform_binary_err(Value::calc_mul, Speed(Light), Temp(Rankine)), Some(BadCastOp(Temp(Rankine), Speed(Light))));
1943        assert_eq!(perform_binary_err(Value::calc_mul, Speed(Light), Data(Bit)), Some(BadCastOp(Data(Bit), Speed(Light))));
1944
1945        assert_eq!(perform_binary_ok(Value::calc_mul, Mass(Ounce), Plain), Some(Mass(Ounce)));
1946        assert_eq!(perform_binary_err(Value::calc_mul, Mass(Ounce), Delta(Hour)), Some(BadCastOp(Delta(Hour), Mass(Ounce))));
1947        assert_eq!(perform_binary_err(Value::calc_mul, Mass(Ounce), Time), Some(BadCastOp(Time, Mass(Ounce))));
1948        assert_eq!(perform_binary_err(Value::calc_mul, Mass(Ounce), Length(Mile)), Some(BadCastOp(Length(Mile), Mass(Ounce))));
1949        assert_eq!(perform_binary_err(Value::calc_mul, Mass(Ounce), Area(Acre)), Some(BadCastOp(Area(Acre), Mass(Ounce))));
1950        assert_eq!(perform_binary_err(Value::calc_mul, Mass(Ounce), Volume(Pint)), Some(BadCastOp(Volume(Pint), Mass(Ounce))));
1951        assert_eq!(perform_binary_err(Value::calc_mul, Mass(Ounce), Speed(Light)), Some(BadCastOp(Speed(Light), Mass(Ounce))));
1952        assert_eq!(perform_binary_err(Value::calc_mul, Mass(Ounce), Mass(Ounce)), Some(BadCastOp(Mass(Ounce), Mass(Ounce))));
1953        assert_eq!(perform_binary_err(Value::calc_mul, Mass(Ounce), Temp(Rankine)), Some(BadCastOp(Temp(Rankine), Mass(Ounce))));
1954        assert_eq!(perform_binary_err(Value::calc_mul, Mass(Ounce), Data(Bit)), Some(BadCastOp(Data(Bit), Mass(Ounce))));
1955
1956        assert_eq!(perform_binary_ok(Value::calc_mul, Temp(Rankine), Plain), Some(Temp(Rankine)));
1957        assert_eq!(perform_binary_err(Value::calc_mul, Temp(Rankine), Delta(Hour)), Some(BadCastOp(Delta(Hour), Temp(Rankine))));
1958        assert_eq!(perform_binary_err(Value::calc_mul, Temp(Rankine), Time), Some(BadCastOp(Time, Temp(Rankine))));
1959        assert_eq!(perform_binary_err(Value::calc_mul, Temp(Rankine), Length(Mile)), Some(BadCastOp(Length(Mile), Temp(Rankine))));
1960        assert_eq!(perform_binary_err(Value::calc_mul, Temp(Rankine), Area(Acre)), Some(BadCastOp(Area(Acre), Temp(Rankine))));
1961        assert_eq!(perform_binary_err(Value::calc_mul, Temp(Rankine), Volume(Pint)), Some(BadCastOp(Volume(Pint), Temp(Rankine))));
1962        assert_eq!(perform_binary_err(Value::calc_mul, Temp(Rankine), Speed(Light)), Some(BadCastOp(Speed(Light), Temp(Rankine))));
1963        assert_eq!(perform_binary_err(Value::calc_mul, Temp(Rankine), Mass(Ounce)), Some(BadCastOp(Mass(Ounce), Temp(Rankine))));
1964        assert_eq!(perform_binary_err(Value::calc_mul, Temp(Rankine), Temp(Rankine)), Some(BadCastOp(Temp(Rankine), Temp(Rankine))));
1965        assert_eq!(perform_binary_err(Value::calc_mul, Temp(Rankine), Data(Bit)), Some(BadCastOp(Data(Bit), Temp(Rankine))));
1966
1967        assert_eq!(perform_binary_ok(Value::calc_mul, Data(Bit), Plain), Some(Data(Bit)));
1968        assert_eq!(perform_binary_err(Value::calc_mul, Data(Bit), Delta(Hour)), Some(BadCastOp(Delta(Hour), Data(Bit))));
1969        assert_eq!(perform_binary_err(Value::calc_mul, Data(Bit), Time), Some(BadCastOp(Time, Data(Bit))));
1970        assert_eq!(perform_binary_err(Value::calc_mul, Data(Bit), Length(Mile)), Some(BadCastOp(Length(Mile), Data(Bit))));
1971        assert_eq!(perform_binary_err(Value::calc_mul, Data(Bit), Area(Acre)), Some(BadCastOp(Area(Acre), Data(Bit))));
1972        assert_eq!(perform_binary_err(Value::calc_mul, Data(Bit), Volume(Pint)), Some(BadCastOp(Volume(Pint), Data(Bit))));
1973        assert_eq!(perform_binary_err(Value::calc_mul, Data(Bit), Speed(Light)), Some(BadCastOp(Speed(Light), Data(Bit))));
1974        assert_eq!(perform_binary_err(Value::calc_mul, Data(Bit), Mass(Ounce)), Some(BadCastOp(Mass(Ounce), Data(Bit))));
1975        assert_eq!(perform_binary_err(Value::calc_mul, Data(Bit), Temp(Rankine)), Some(BadCastOp(Temp(Rankine), Data(Bit))));
1976        assert_eq!(perform_binary_err(Value::calc_mul, Data(Bit), Data(Bit)), Some(BadCastOp(Data(Bit), Data(Bit))));
1977    }
1978
1979    #[test]
1980    fn test_length_values_are_multiplied_by_meaning() {
1981        assert_eq!(perform_binary_value(Value::calc_mul, Length(Metre(Kilo)), Length(Metre(Kilo))), Some((Area(Square(Metre(Kilo))), String::from("1.0"))));
1982        assert_eq!(perform_binary_value(Value::calc_mul, Length(Metre(Kilo)), Length(Mile)), Some((Area(Square(Metre(Kilo))), String::from("1.609344"))));
1983        assert_eq!(perform_binary_value(Value::calc_mul, Length(Metre(Kilo)), Area(Square(Metre(Kilo)))), Some((Volume(Cubic(Metre(Kilo))), String::from("1.0"))));
1984        assert_eq!(perform_binary_value(Value::calc_mul, Length(Metre(Kilo)), Area(Square(Mile))), Some((Volume(Cubic(Metre(Kilo))), String::from("2.58998811"))));
1985        assert_eq!(perform_binary_value(Value::calc_mul, Length(Metre(Kilo)), Area(Acre)), Some((Volume(Cubic(Metre(Kilo))), String::from("0.004046856"))));
1986
1987        assert_eq!(perform_binary_value(Value::calc_mul, Length(Mile), Length(Metre(Kilo))), Some((Area(Square(Mile)), String::from("0.621371192"))));
1988        assert_eq!(perform_binary_value(Value::calc_mul, Length(Mile), Length(Mile)), Some((Area(Square(Mile)), String::from("1.0"))));
1989        assert_eq!(perform_binary_value(Value::calc_mul, Length(Mile), Area(Square(Metre(Kilo)))), Some((Volume(Cubic(Mile)), String::from("0.386102159"))));
1990        assert_eq!(perform_binary_value(Value::calc_mul, Length(Mile), Area(Square(Mile))), Some((Volume(Cubic(Mile)), String::from("1.0"))));
1991        assert_eq!(perform_binary_value(Value::calc_mul, Length(Mile), Area(Acre)), Some((Volume(Cubic(Mile)), String::from("0.0015625"))));
1992
1993        assert_eq!(perform_binary_value(Value::calc_mul, Area(Square(Metre(Kilo))), Length(Metre(Kilo))), Some((Volume(Cubic(Metre(Kilo))), String::from("1.0"))));
1994        assert_eq!(perform_binary_value(Value::calc_mul, Area(Square(Metre(Kilo))), Length(Mile)), Some((Volume(Cubic(Metre(Kilo))), String::from("1.609344"))));
1995        assert_eq!(perform_binary_err(Value::calc_mul, Area(Square(Metre(Kilo))), Area(Square(Metre(Kilo)))), Some(BadCastOp(Area(Square(Metre(Kilo))), Area(Square(Metre(Kilo))))));
1996        assert_eq!(perform_binary_err(Value::calc_mul, Area(Square(Metre(Kilo))), Area(Square(Mile))), Some(BadCastOp(Area(Square(Mile)), Area(Square(Metre(Kilo))))));
1997        assert_eq!(perform_binary_err(Value::calc_mul, Area(Square(Metre(Kilo))), Area(Acre)), Some(BadCastOp(Area(Acre), Area(Square(Metre(Kilo))))));
1998
1999        assert_eq!(perform_binary_value(Value::calc_mul, Area(Square(Mile)), Length(Metre(Kilo))), Some((Volume(Cubic(Mile)), String::from("0.621371192"))));
2000        assert_eq!(perform_binary_value(Value::calc_mul, Area(Square(Mile)), Length(Mile)), Some((Volume(Cubic(Mile)), String::from("1.0"))));
2001        assert_eq!(perform_binary_err(Value::calc_mul, Area(Square(Mile)), Area(Square(Metre(Kilo)))), Some(BadCastOp(Area(Square(Metre(Kilo))), Area(Square(Mile)))));
2002        assert_eq!(perform_binary_err(Value::calc_mul, Area(Square(Mile)), Area(Square(Mile))), Some(BadCastOp(Area(Square(Mile)), Area(Square(Mile)))));
2003        assert_eq!(perform_binary_err(Value::calc_mul, Area(Square(Mile)), Area(Acre)), Some(BadCastOp(Area(Acre), Area(Square(Mile)))));
2004
2005        assert_eq!(perform_binary_value(Value::calc_mul, Area(Acre), Length(Metre(Kilo))), Some((Volume(Cubic(Metre(Unit))), String::from("4046856.4224"))));
2006        assert_eq!(perform_binary_value(Value::calc_mul, Area(Acre), Length(Mile)), Some((Volume(Cubic(Metre(Unit))), String::from("6512784.102250906"))));
2007        assert_eq!(perform_binary_err(Value::calc_mul, Area(Acre), Area(Square(Metre(Kilo)))), Some(BadCastOp(Area(Square(Metre(Kilo))), Area(Acre))));
2008        assert_eq!(perform_binary_err(Value::calc_mul, Area(Acre), Area(Square(Mile))), Some(BadCastOp(Area(Square(Mile)), Area(Acre))));
2009        assert_eq!(perform_binary_err(Value::calc_mul, Area(Acre), Area(Acre)), Some(BadCastOp(Area(Acre), Area(Acre))));
2010    }
2011
2012    #[test]
2013    fn test_speed_values_are_multiplied_by_meaning() {
2014        assert_eq!(perform_binary_err(Value::calc_mul, Delta(Hour), Delta(Hour)), Some(BadCastOp(Delta(Hour), Delta(Hour))));
2015        assert_eq!(perform_binary_value(Value::calc_mul, Delta(Hour), Speed(Ratio(Metre(Kilo), Second(Unit)))), Some((Length(Metre(Unit)), String::from("3600000.0"))));
2016        assert_eq!(perform_binary_value(Value::calc_mul, Delta(Hour), Speed(Ratio(Mile, Hour))), Some((Length(Metre(Unit)), String::from("1609.344"))));
2017        assert_eq!(perform_binary_value(Value::calc_mul, Delta(Hour), Speed(Light)), Some((Length(Metre(Unit)), String::from("1079252848800.0"))));
2018
2019        assert_eq!(perform_binary_value(Value::calc_mul, Speed(Ratio(Metre(Kilo), Second(Unit))), Delta(Hour)), Some((Length(Metre(Kilo)), String::from("3600.0"))));
2020        assert_eq!(perform_binary_err(Value::calc_mul, Speed(Ratio(Metre(Kilo), Second(Unit))), Speed(Ratio(Metre(Kilo), Second(Unit)))), Some(BadCastOp(Speed(Ratio(Metre(Kilo), Second(Unit))), Speed(Ratio(Metre(Kilo), Second(Unit))))));
2021        assert_eq!(perform_binary_err(Value::calc_mul, Speed(Ratio(Metre(Kilo), Second(Unit))), Speed(Ratio(Mile, Hour))), Some(BadCastOp(Speed(Ratio(Mile, Hour)), Speed(Ratio(Metre(Kilo), Second(Unit))))));
2022        assert_eq!(perform_binary_err(Value::calc_mul, Speed(Ratio(Metre(Kilo), Second(Unit))), Speed(Light)), Some(BadCastOp(Speed(Light), Speed(Ratio(Metre(Kilo), Second(Unit))))));
2023
2024        assert_eq!(perform_binary_value(Value::calc_mul, Speed(Ratio(Mile, Hour)), Delta(Hour)), Some((Length(Mile), String::from("1.0"))));
2025        assert_eq!(perform_binary_err(Value::calc_mul, Speed(Ratio(Mile, Hour)), Speed(Ratio(Metre(Kilo), Second(Unit)))), Some(BadCastOp(Speed(Ratio(Metre(Kilo), Second(Unit))), Speed(Ratio(Mile, Hour)))));
2026        assert_eq!(perform_binary_err(Value::calc_mul, Speed(Ratio(Mile, Hour)), Speed(Ratio(Mile, Hour))), Some(BadCastOp(Speed(Ratio(Mile, Hour)), Speed(Ratio(Mile, Hour)))));
2027        assert_eq!(perform_binary_err(Value::calc_mul, Speed(Ratio(Mile, Hour)), Speed(Light)), Some(BadCastOp(Speed(Light), Speed(Ratio(Mile, Hour)))));
2028
2029        assert_eq!(perform_binary_value(Value::calc_mul, Speed(Light), Delta(Hour)), Some((Length(Metre(Unit)), String::from("1079252848800.0"))));
2030        assert_eq!(perform_binary_err(Value::calc_mul, Speed(Light), Speed(Ratio(Metre(Kilo), Second(Unit)))), Some(BadCastOp(Speed(Ratio(Metre(Kilo), Second(Unit))), Speed(Light))));
2031        assert_eq!(perform_binary_err(Value::calc_mul, Speed(Light), Speed(Ratio(Mile, Hour))), Some(BadCastOp(Speed(Ratio(Mile, Hour)), Speed(Light))));
2032        assert_eq!(perform_binary_err(Value::calc_mul, Speed(Light), Speed(Light)), Some(BadCastOp(Speed(Light), Speed(Light))));
2033    }
2034
2035    // Div   | Plain Delta Time  | Len   Area  Vol   Speed | Mass  Temp  Data
2036    // ------+-------------------+-------------------------+------------------
2037    // Plain | Plain -     -     | -     -     -     -     | -     -     -
2038    // Delta | Delta Plain -     | -     -     -     -     | -     -     -
2039    // Time  | -     -     -     | -     -     -     -     | -     -     -
2040    // ------+-------------------+-------------------------+------------------
2041    // Len   | Len   -     -     | Plain -     -     Delta | -     -     -
2042    // Area  | Area  -     -     | Len   Plain -     -     | -     -     -
2043    // Vol   | Vol   -     -     | Area  Len   Plain -     | -     -     -
2044    // Speed | Speed -     -     | -     -     -     Plain | -     -     -
2045    // ------+-------------------+-------------------------+------------------
2046    // Mass  | Mass  -     -     | -     -     -     -     | Plain -     -
2047    // Temp  | Temp  -     -     | -     -     -     -     | -     Plain -
2048    // Data  | Data  -     -     | -     -     -     -     | -     -     Plain
2049
2050    #[test]
2051    fn test_unit_values_are_divided_by_meaning() {
2052        assert_eq!(perform_binary_ok(Value::calc_div, Plain, Plain), Some(Plain));
2053        assert_eq!(perform_binary_err(Value::calc_div, Plain, Delta(Hour)), Some(BadCastOp(Delta(Hour), Plain)));
2054        assert_eq!(perform_binary_err(Value::calc_div, Plain, Time), Some(BadCastOp(Time, Plain)));
2055        assert_eq!(perform_binary_err(Value::calc_div, Plain, Length(Mile)), Some(BadCastOp(Length(Mile), Plain)));
2056        assert_eq!(perform_binary_err(Value::calc_div, Plain, Area(Acre)), Some(BadCastOp(Area(Acre), Plain)));
2057        assert_eq!(perform_binary_err(Value::calc_div, Plain, Volume(Pint)), Some(BadCastOp(Volume(Pint), Plain)));
2058        assert_eq!(perform_binary_err(Value::calc_div, Plain, Speed(Light)), Some(BadCastOp(Speed(Light), Plain)));
2059        assert_eq!(perform_binary_err(Value::calc_div, Plain, Mass(Ounce)), Some(BadCastOp(Mass(Ounce), Plain)));
2060        assert_eq!(perform_binary_err(Value::calc_div, Plain, Temp(Rankine)), Some(BadCastOp(Temp(Rankine), Plain)));
2061        assert_eq!(perform_binary_err(Value::calc_div, Plain, Data(Bit)), Some(BadCastOp(Data(Bit), Plain)));
2062
2063        assert_eq!(perform_binary_ok(Value::calc_div, Delta(Hour), Plain), Some(Delta(Hour)));
2064        assert_eq!(perform_binary_ok(Value::calc_div, Delta(Hour), Delta(Hour)), Some(Plain));
2065        assert_eq!(perform_binary_err(Value::calc_div, Delta(Hour), Time), Some(BadCastOp(Time, Delta(Hour))));
2066        assert_eq!(perform_binary_err(Value::calc_div, Delta(Hour), Length(Mile)), Some(BadCastOp(Length(Mile), Delta(Hour))));
2067        assert_eq!(perform_binary_err(Value::calc_div, Delta(Hour), Area(Acre)), Some(BadCastOp(Area(Acre), Delta(Hour))));
2068        assert_eq!(perform_binary_err(Value::calc_div, Delta(Hour), Volume(Pint)), Some(BadCastOp(Volume(Pint), Delta(Hour))));
2069        assert_eq!(perform_binary_err(Value::calc_div, Delta(Hour), Speed(Light)), Some(BadCastOp(Speed(Light), Delta(Hour))));
2070        assert_eq!(perform_binary_err(Value::calc_div, Delta(Hour), Mass(Ounce)), Some(BadCastOp(Mass(Ounce), Delta(Hour))));
2071        assert_eq!(perform_binary_err(Value::calc_div, Delta(Hour), Temp(Rankine)), Some(BadCastOp(Temp(Rankine), Delta(Hour))));
2072        assert_eq!(perform_binary_err(Value::calc_div, Delta(Hour), Data(Bit)), Some(BadCastOp(Data(Bit), Delta(Hour))));
2073
2074        assert_eq!(perform_binary_err(Value::calc_div, Time, Plain), Some(BadCastOp(Plain, Time)));
2075        assert_eq!(perform_binary_err(Value::calc_div, Time, Delta(Hour)), Some(BadCastOp(Delta(Hour), Time)));
2076        assert_eq!(perform_binary_err(Value::calc_div, Time, Time), Some(BadCastOp(Time, Time)));
2077        assert_eq!(perform_binary_err(Value::calc_div, Time, Length(Mile)), Some(BadCastOp(Length(Mile), Time)));
2078        assert_eq!(perform_binary_err(Value::calc_div, Time, Area(Acre)), Some(BadCastOp(Area(Acre), Time)));
2079        assert_eq!(perform_binary_err(Value::calc_div, Time, Volume(Pint)), Some(BadCastOp(Volume(Pint), Time)));
2080        assert_eq!(perform_binary_err(Value::calc_div, Time, Speed(Light)), Some(BadCastOp(Speed(Light), Time)));
2081        assert_eq!(perform_binary_err(Value::calc_div, Time, Mass(Ounce)), Some(BadCastOp(Mass(Ounce), Time)));
2082        assert_eq!(perform_binary_err(Value::calc_div, Time, Temp(Rankine)), Some(BadCastOp(Temp(Rankine), Time)));
2083        assert_eq!(perform_binary_err(Value::calc_div, Time, Data(Bit)), Some(BadCastOp(Data(Bit), Time)));
2084
2085        assert_eq!(perform_binary_ok(Value::calc_div, Length(Mile), Plain), Some(Length(Mile)));
2086        assert_eq!(perform_binary_err(Value::calc_div, Length(Mile), Delta(Hour)), Some(BadCastOp(Delta(Hour), Length(Mile))));
2087        assert_eq!(perform_binary_err(Value::calc_div, Length(Mile), Time), Some(BadCastOp(Time, Length(Mile))));
2088        assert_eq!(perform_binary_ok(Value::calc_div, Length(Mile), Length(Mile)), Some(Plain));
2089        assert_eq!(perform_binary_err(Value::calc_div, Length(Mile), Area(Acre)), Some(BadCastOp(Area(Acre), Length(Mile))));
2090        assert_eq!(perform_binary_err(Value::calc_div, Length(Mile), Volume(Pint)), Some(BadCastOp(Volume(Pint), Length(Mile))));
2091        assert_eq!(perform_binary_ok(Value::calc_div, Length(Mile), Speed(Light)), Some(Delta(Second(Unit))));
2092        assert_eq!(perform_binary_err(Value::calc_div, Length(Mile), Mass(Ounce)), Some(BadCastOp(Mass(Ounce), Length(Mile))));
2093        assert_eq!(perform_binary_err(Value::calc_div, Length(Mile), Temp(Rankine)), Some(BadCastOp(Temp(Rankine), Length(Mile))));
2094        assert_eq!(perform_binary_err(Value::calc_div, Length(Mile), Data(Bit)), Some(BadCastOp(Data(Bit), Length(Mile))));
2095
2096        assert_eq!(perform_binary_ok(Value::calc_div, Area(Acre), Plain), Some(Area(Acre)));
2097        assert_eq!(perform_binary_err(Value::calc_div, Area(Acre), Delta(Hour)), Some(BadCastOp(Delta(Hour), Area(Acre))));
2098        assert_eq!(perform_binary_err(Value::calc_div, Area(Acre), Time), Some(BadCastOp(Time, Area(Acre))));
2099        assert_eq!(perform_binary_ok(Value::calc_div, Area(Acre), Length(Mile)), Some(Length(Metre(Unit))));
2100        assert_eq!(perform_binary_ok(Value::calc_div, Area(Acre), Area(Acre)), Some(Plain));
2101        assert_eq!(perform_binary_err(Value::calc_div, Area(Acre), Volume(Pint)), Some(BadCastOp(Volume(Pint), Area(Acre))));
2102        assert_eq!(perform_binary_err(Value::calc_div, Area(Acre), Speed(Light)), Some(BadCastOp(Speed(Light), Area(Acre))));
2103        assert_eq!(perform_binary_err(Value::calc_div, Area(Acre), Mass(Ounce)), Some(BadCastOp(Mass(Ounce), Area(Acre))));
2104        assert_eq!(perform_binary_err(Value::calc_div, Area(Acre), Temp(Rankine)), Some(BadCastOp(Temp(Rankine), Area(Acre))));
2105        assert_eq!(perform_binary_err(Value::calc_div, Area(Acre), Data(Bit)), Some(BadCastOp(Data(Bit), Area(Acre))));
2106
2107        assert_eq!(perform_binary_ok(Value::calc_div, Volume(Pint), Plain), Some(Volume(Pint)));
2108        assert_eq!(perform_binary_err(Value::calc_div, Volume(Pint), Delta(Hour)), Some(BadCastOp(Delta(Hour), Volume(Pint))));
2109        assert_eq!(perform_binary_err(Value::calc_div, Volume(Pint), Time), Some(BadCastOp(Time, Volume(Pint))));
2110        assert_eq!(perform_binary_ok(Value::calc_div, Volume(Pint), Length(Mile)), Some(Area(Square(Metre(Unit)))));
2111        assert_eq!(perform_binary_ok(Value::calc_div, Volume(Pint), Area(Acre)), Some(Length(Metre(Unit))));
2112        assert_eq!(perform_binary_ok(Value::calc_div, Volume(Pint), Volume(Pint)), Some(Plain));
2113        assert_eq!(perform_binary_err(Value::calc_div, Volume(Pint), Speed(Light)), Some(BadCastOp(Speed(Light), Volume(Pint))));
2114        assert_eq!(perform_binary_err(Value::calc_div, Volume(Pint), Mass(Ounce)), Some(BadCastOp(Mass(Ounce), Volume(Pint))));
2115        assert_eq!(perform_binary_err(Value::calc_div, Volume(Pint), Temp(Rankine)), Some(BadCastOp(Temp(Rankine), Volume(Pint))));
2116        assert_eq!(perform_binary_err(Value::calc_div, Volume(Pint), Data(Bit)), Some(BadCastOp(Data(Bit), Volume(Pint))));
2117
2118        assert_eq!(perform_binary_ok(Value::calc_div, Speed(Light), Plain), Some(Speed(Light)));
2119        assert_eq!(perform_binary_err(Value::calc_div, Speed(Light), Delta(Hour)), Some(BadCastOp(Delta(Hour), Speed(Light))));
2120        assert_eq!(perform_binary_err(Value::calc_div, Speed(Light), Time), Some(BadCastOp(Time, Speed(Light))));
2121        assert_eq!(perform_binary_err(Value::calc_div, Speed(Light), Length(Mile)), Some(BadCastOp(Length(Mile), Speed(Light))));
2122        assert_eq!(perform_binary_err(Value::calc_div, Speed(Light), Area(Acre)), Some(BadCastOp(Area(Acre), Speed(Light))));
2123        assert_eq!(perform_binary_err(Value::calc_div, Speed(Light), Volume(Pint)), Some(BadCastOp(Volume(Pint), Speed(Light))));
2124        assert_eq!(perform_binary_ok(Value::calc_div, Speed(Light), Speed(Light)), Some(Plain));
2125        assert_eq!(perform_binary_err(Value::calc_div, Speed(Light), Mass(Ounce)), Some(BadCastOp(Mass(Ounce), Speed(Light))));
2126        assert_eq!(perform_binary_err(Value::calc_div, Speed(Light), Temp(Rankine)), Some(BadCastOp(Temp(Rankine), Speed(Light))));
2127        assert_eq!(perform_binary_err(Value::calc_div, Speed(Light), Data(Bit)), Some(BadCastOp(Data(Bit), Speed(Light))));
2128
2129        assert_eq!(perform_binary_ok(Value::calc_div, Mass(Ounce), Plain), Some(Mass(Ounce)));
2130        assert_eq!(perform_binary_err(Value::calc_div, Mass(Ounce), Delta(Hour)), Some(BadCastOp(Delta(Hour), Mass(Ounce))));
2131        assert_eq!(perform_binary_err(Value::calc_div, Mass(Ounce), Time), Some(BadCastOp(Time, Mass(Ounce))));
2132        assert_eq!(perform_binary_err(Value::calc_div, Mass(Ounce), Length(Mile)), Some(BadCastOp(Length(Mile), Mass(Ounce))));
2133        assert_eq!(perform_binary_err(Value::calc_div, Mass(Ounce), Area(Acre)), Some(BadCastOp(Area(Acre), Mass(Ounce))));
2134        assert_eq!(perform_binary_err(Value::calc_div, Mass(Ounce), Volume(Pint)), Some(BadCastOp(Volume(Pint), Mass(Ounce))));
2135        assert_eq!(perform_binary_err(Value::calc_div, Mass(Ounce), Speed(Light)), Some(BadCastOp(Speed(Light), Mass(Ounce))));
2136        assert_eq!(perform_binary_ok(Value::calc_div, Mass(Ounce), Mass(Ounce)), Some(Plain));
2137        assert_eq!(perform_binary_err(Value::calc_div, Mass(Ounce), Temp(Rankine)), Some(BadCastOp(Temp(Rankine), Mass(Ounce))));
2138        assert_eq!(perform_binary_err(Value::calc_div, Mass(Ounce), Data(Bit)), Some(BadCastOp(Data(Bit), Mass(Ounce))));
2139
2140        assert_eq!(perform_binary_ok(Value::calc_div, Temp(Rankine), Plain), Some(Temp(Rankine)));
2141        assert_eq!(perform_binary_err(Value::calc_div, Temp(Rankine), Delta(Hour)), Some(BadCastOp(Delta(Hour), Temp(Rankine))));
2142        assert_eq!(perform_binary_err(Value::calc_div, Temp(Rankine), Time), Some(BadCastOp(Time, Temp(Rankine))));
2143        assert_eq!(perform_binary_err(Value::calc_div, Temp(Rankine), Length(Mile)), Some(BadCastOp(Length(Mile), Temp(Rankine))));
2144        assert_eq!(perform_binary_err(Value::calc_div, Temp(Rankine), Area(Acre)), Some(BadCastOp(Area(Acre), Temp(Rankine))));
2145        assert_eq!(perform_binary_err(Value::calc_div, Temp(Rankine), Volume(Pint)), Some(BadCastOp(Volume(Pint), Temp(Rankine))));
2146        assert_eq!(perform_binary_err(Value::calc_div, Temp(Rankine), Speed(Light)), Some(BadCastOp(Speed(Light), Temp(Rankine))));
2147        assert_eq!(perform_binary_err(Value::calc_div, Temp(Rankine), Mass(Ounce)), Some(BadCastOp(Mass(Ounce), Temp(Rankine))));
2148        assert_eq!(perform_binary_ok(Value::calc_div, Temp(Rankine), Temp(Rankine)), Some(Plain));
2149        assert_eq!(perform_binary_err(Value::calc_div, Temp(Rankine), Data(Bit)), Some(BadCastOp(Data(Bit), Temp(Rankine))));
2150
2151        assert_eq!(perform_binary_ok(Value::calc_div, Data(Bit), Plain), Some(Data(Bit)));
2152        assert_eq!(perform_binary_err(Value::calc_div, Data(Bit), Delta(Hour)), Some(BadCastOp(Delta(Hour), Data(Bit))));
2153        assert_eq!(perform_binary_err(Value::calc_div, Data(Bit), Time), Some(BadCastOp(Time, Data(Bit))));
2154        assert_eq!(perform_binary_err(Value::calc_div, Data(Bit), Length(Mile)), Some(BadCastOp(Length(Mile), Data(Bit))));
2155        assert_eq!(perform_binary_err(Value::calc_div, Data(Bit), Area(Acre)), Some(BadCastOp(Area(Acre), Data(Bit))));
2156        assert_eq!(perform_binary_err(Value::calc_div, Data(Bit), Volume(Pint)), Some(BadCastOp(Volume(Pint), Data(Bit))));
2157        assert_eq!(perform_binary_err(Value::calc_div, Data(Bit), Speed(Light)), Some(BadCastOp(Speed(Light), Data(Bit))));
2158        assert_eq!(perform_binary_err(Value::calc_div, Data(Bit), Mass(Ounce)), Some(BadCastOp(Mass(Ounce), Data(Bit))));
2159        assert_eq!(perform_binary_err(Value::calc_div, Data(Bit), Temp(Rankine)), Some(BadCastOp(Temp(Rankine), Data(Bit))));
2160        assert_eq!(perform_binary_ok(Value::calc_div, Data(Bit), Data(Bit)), Some(Plain));
2161    }
2162
2163    #[test]
2164    fn test_length_values_are_divided_by_meaning() {
2165        assert_eq!(perform_binary_value(Value::calc_div, Length(Metre(Kilo)), Length(Metre(Kilo))), Some((Plain, String::from("1.0"))));
2166        assert_eq!(perform_binary_value(Value::calc_div, Length(Metre(Kilo)), Length(Mile)), Some((Plain, String::from("0.621371192"))));
2167        assert_eq!(perform_binary_err(Value::calc_div, Length(Metre(Kilo)), Area(Square(Metre(Kilo)))), Some(BadCastOp(Area(Square(Metre(Kilo))), Length(Metre(Kilo)))));
2168        assert_eq!(perform_binary_err(Value::calc_div, Length(Metre(Kilo)), Area(Square(Mile))), Some(BadCastOp(Area(Square(Mile)), Length(Metre(Kilo)))));
2169        assert_eq!(perform_binary_err(Value::calc_div, Length(Metre(Kilo)), Area(Acre)), Some(BadCastOp(Area(Acre), Length(Metre(Kilo)))));
2170        assert_eq!(perform_binary_err(Value::calc_div, Length(Metre(Kilo)), Volume(Cubic(Metre(Kilo)))), Some(BadCastOp(Volume(Cubic(Metre(Kilo))), Length(Metre(Kilo)))));
2171        assert_eq!(perform_binary_err(Value::calc_div, Length(Metre(Kilo)), Volume(Cubic(Mile))), Some(BadCastOp(Volume(Cubic(Mile)), Length(Metre(Kilo)))));
2172        assert_eq!(perform_binary_err(Value::calc_div, Length(Metre(Kilo)), Volume(Litre(Milli))), Some(BadCastOp(Volume(Litre(Milli)), Length(Metre(Kilo)))));
2173        assert_eq!(perform_binary_err(Value::calc_div, Length(Metre(Kilo)), Volume(Pint)), Some(BadCastOp(Volume(Pint), Length(Metre(Kilo)))));
2174
2175        assert_eq!(perform_binary_value(Value::calc_div, Length(Mile), Length(Metre(Kilo))), Some((Plain, String::from("1.609344"))));
2176        assert_eq!(perform_binary_value(Value::calc_div, Length(Mile), Length(Mile)), Some((Plain, String::from("1.0"))));
2177        assert_eq!(perform_binary_err(Value::calc_div, Length(Mile), Area(Square(Metre(Kilo)))), Some(BadCastOp(Area(Square(Metre(Kilo))), Length(Mile))));
2178        assert_eq!(perform_binary_err(Value::calc_div, Length(Mile), Area(Square(Mile))), Some(BadCastOp(Area(Square(Mile)), Length(Mile))));
2179        assert_eq!(perform_binary_err(Value::calc_div, Length(Mile), Area(Acre)), Some(BadCastOp(Area(Acre), Length(Mile))));
2180        assert_eq!(perform_binary_err(Value::calc_div, Length(Mile), Volume(Cubic(Metre(Kilo)))), Some(BadCastOp(Volume(Cubic(Metre(Kilo))), Length(Mile))));
2181        assert_eq!(perform_binary_err(Value::calc_div, Length(Mile), Volume(Cubic(Mile))), Some(BadCastOp(Volume(Cubic(Mile)), Length(Mile))));
2182        assert_eq!(perform_binary_err(Value::calc_div, Length(Mile), Volume(Litre(Milli))), Some(BadCastOp(Volume(Litre(Milli)), Length(Mile))));
2183        assert_eq!(perform_binary_err(Value::calc_div, Length(Mile), Volume(Pint)), Some(BadCastOp(Volume(Pint), Length(Mile))));
2184
2185        assert_eq!(perform_binary_value(Value::calc_div, Area(Square(Metre(Kilo))), Length(Metre(Kilo))), Some((Length(Metre(Kilo)), String::from("1.0"))));
2186        assert_eq!(perform_binary_value(Value::calc_div, Area(Square(Metre(Kilo))), Length(Mile)), Some((Length(Metre(Kilo)), String::from("0.621371192"))));
2187        assert_eq!(perform_binary_value(Value::calc_div, Area(Square(Metre(Kilo))), Area(Square(Metre(Kilo)))), Some((Plain, String::from("1.0"))));
2188        assert_eq!(perform_binary_value(Value::calc_div, Area(Square(Metre(Kilo))), Area(Square(Mile))), Some((Plain, String::from("0.386102159"))));
2189        assert_eq!(perform_binary_value(Value::calc_div, Area(Square(Metre(Kilo))), Area(Acre)), Some((Plain, String::from("247.105381467"))));
2190        assert_eq!(perform_binary_err(Value::calc_div, Area(Square(Metre(Kilo))), Volume(Cubic(Metre(Kilo)))), Some(BadCastOp(Volume(Cubic(Metre(Kilo))), Area(Square(Metre(Kilo))))));
2191        assert_eq!(perform_binary_err(Value::calc_div, Area(Square(Metre(Kilo))), Volume(Cubic(Mile))), Some(BadCastOp(Volume(Cubic(Mile)), Area(Square(Metre(Kilo))))));
2192        assert_eq!(perform_binary_err(Value::calc_div, Area(Square(Metre(Kilo))), Volume(Litre(Milli))), Some(BadCastOp(Volume(Litre(Milli)), Area(Square(Metre(Kilo))))));
2193        assert_eq!(perform_binary_err(Value::calc_div, Area(Square(Metre(Kilo))), Volume(Pint)), Some(BadCastOp(Volume(Pint), Area(Square(Metre(Kilo))))));
2194
2195        assert_eq!(perform_binary_value(Value::calc_div, Area(Square(Mile)), Length(Metre(Kilo))), Some((Length(Mile), String::from("1.609344"))));
2196        assert_eq!(perform_binary_value(Value::calc_div, Area(Square(Mile)), Length(Mile)), Some((Length(Mile), String::from("1.0"))));
2197        assert_eq!(perform_binary_value(Value::calc_div, Area(Square(Mile)), Area(Square(Metre(Kilo)))), Some((Plain, String::from("2.58998811"))));
2198        assert_eq!(perform_binary_value(Value::calc_div, Area(Square(Mile)), Area(Square(Mile))), Some((Plain, String::from("1.0"))));
2199        assert_eq!(perform_binary_value(Value::calc_div, Area(Square(Mile)), Area(Acre)), Some((Plain, String::from("640.0"))));
2200        assert_eq!(perform_binary_err(Value::calc_div, Area(Square(Mile)), Volume(Cubic(Metre(Kilo)))), Some(BadCastOp(Volume(Cubic(Metre(Kilo))), Area(Square(Mile)))));
2201        assert_eq!(perform_binary_err(Value::calc_div, Area(Square(Mile)), Volume(Cubic(Mile))), Some(BadCastOp(Volume(Cubic(Mile)), Area(Square(Mile)))));
2202        assert_eq!(perform_binary_err(Value::calc_div, Area(Square(Mile)), Volume(Litre(Milli))), Some(BadCastOp(Volume(Litre(Milli)), Area(Square(Mile)))));
2203        assert_eq!(perform_binary_err(Value::calc_div, Area(Square(Mile)), Volume(Pint)), Some(BadCastOp(Volume(Pint), Area(Square(Mile)))));
2204
2205        assert_eq!(perform_binary_value(Value::calc_div, Area(Acre), Length(Metre(Kilo))), Some((Length(Metre(Unit)), String::from("4.046856422"))));
2206        assert_eq!(perform_binary_value(Value::calc_div, Area(Acre), Length(Mile)), Some((Length(Metre(Unit)), String::from("2.5146"))));
2207        assert_eq!(perform_binary_value(Value::calc_div, Area(Acre), Area(Square(Metre(Kilo)))), Some((Plain, String::from("0.004046856"))));
2208        assert_eq!(perform_binary_value(Value::calc_div, Area(Acre), Area(Square(Mile))), Some((Plain, String::from("0.0015625"))));
2209        assert_eq!(perform_binary_value(Value::calc_div, Area(Acre), Area(Acre)), Some((Plain, String::from("1.0"))));
2210        assert_eq!(perform_binary_err(Value::calc_div, Area(Acre), Volume(Cubic(Metre(Kilo)))), Some(BadCastOp(Volume(Cubic(Metre(Kilo))), Area(Acre))));
2211        assert_eq!(perform_binary_err(Value::calc_div, Area(Acre), Volume(Cubic(Mile))), Some(BadCastOp(Volume(Cubic(Mile)), Area(Acre))));
2212        assert_eq!(perform_binary_err(Value::calc_div, Area(Acre), Volume(Litre(Milli))), Some(BadCastOp(Volume(Litre(Milli)), Area(Acre))));
2213        assert_eq!(perform_binary_err(Value::calc_div, Area(Acre), Volume(Pint)), Some(BadCastOp(Volume(Pint), Area(Acre))));
2214
2215        assert_eq!(perform_binary_value(Value::calc_div, Volume(Cubic(Metre(Kilo))), Length(Metre(Kilo))), Some((Area(Square(Metre(Kilo))), String::from("1.0"))));
2216        assert_eq!(perform_binary_value(Value::calc_div, Volume(Cubic(Metre(Kilo))), Length(Mile)), Some((Area(Square(Metre(Kilo))), String::from("0.621371192"))));
2217        assert_eq!(perform_binary_value(Value::calc_div, Volume(Cubic(Metre(Kilo))), Area(Square(Metre(Kilo)))), Some((Length(Metre(Kilo)), String::from("1.0"))));
2218        assert_eq!(perform_binary_value(Value::calc_div, Volume(Cubic(Metre(Kilo))), Area(Square(Mile))), Some((Length(Metre(Kilo)), String::from("0.386102159"))));
2219        assert_eq!(perform_binary_value(Value::calc_div, Volume(Cubic(Metre(Kilo))), Area(Acre)), Some((Length(Metre(Kilo)), String::from("247.105381467"))));
2220        assert_eq!(perform_binary_value(Value::calc_div, Volume(Cubic(Metre(Kilo))), Volume(Cubic(Metre(Kilo)))), Some((Plain, String::from("1.0"))));
2221        assert_eq!(perform_binary_value(Value::calc_div, Volume(Cubic(Metre(Kilo))), Volume(Cubic(Mile))), Some((Plain, String::from("0.239912759"))));
2222        assert_eq!(perform_binary_value(Value::calc_div, Volume(Cubic(Metre(Kilo))), Volume(Litre(Milli))), Some((Plain, String::from("1000000000000000.0"))));
2223        assert_eq!(perform_binary_value(Value::calc_div, Volume(Cubic(Metre(Kilo))), Volume(Pint)), Some((Plain, String::from("1759753986392.702300218"))));
2224
2225        assert_eq!(perform_binary_value(Value::calc_div, Volume(Cubic(Mile)), Length(Metre(Kilo))), Some((Area(Square(Mile)), String::from("1.609344"))));
2226        assert_eq!(perform_binary_value(Value::calc_div, Volume(Cubic(Mile)), Length(Mile)), Some((Area(Square(Mile)), String::from("1.0"))));
2227        assert_eq!(perform_binary_value(Value::calc_div, Volume(Cubic(Mile)), Area(Square(Metre(Kilo)))), Some((Length(Mile), String::from("2.58998811"))));
2228        assert_eq!(perform_binary_value(Value::calc_div, Volume(Cubic(Mile)), Area(Square(Mile))), Some((Length(Mile), String::from("1.0"))));
2229        assert_eq!(perform_binary_value(Value::calc_div, Volume(Cubic(Mile)), Area(Acre)), Some((Length(Mile), String::from("640.0"))));
2230        assert_eq!(perform_binary_value(Value::calc_div, Volume(Cubic(Mile)), Volume(Cubic(Metre(Kilo)))), Some((Plain, String::from("4.168181825"))));
2231        assert_eq!(perform_binary_value(Value::calc_div, Volume(Cubic(Mile)), Volume(Cubic(Mile))), Some((Plain, String::from("1.0"))));
2232        assert_eq!(perform_binary_value(Value::calc_div, Volume(Cubic(Mile)), Volume(Litre(Milli))), Some((Plain, String::from("4168181825440579.584"))));
2233        assert_eq!(perform_binary_value(Value::calc_div, Volume(Cubic(Mile)), Volume(Pint)), Some((Plain, String::from("7334974583328.670719673"))));
2234
2235        assert_eq!(perform_binary_value(Value::calc_div, Volume(Litre(Milli)), Length(Metre(Kilo))), Some((Area(Square(Metre(Unit))), String::from("0.000000001"))));
2236        assert_eq!(perform_binary_value(Value::calc_div, Volume(Litre(Milli)), Length(Mile)), Some((Area(Square(Metre(Unit))), String::from("0.000000001"))));
2237        assert_eq!(perform_binary_value(Value::calc_div, Volume(Litre(Milli)), Area(Square(Metre(Kilo)))), Some((Length(Metre(Unit)), String::from("0.0"))));
2238        assert_eq!(perform_binary_value(Value::calc_div, Volume(Litre(Milli)), Area(Square(Mile))), Some((Length(Metre(Unit)), String::from("0.0"))));
2239        assert_eq!(perform_binary_value(Value::calc_div, Volume(Litre(Milli)), Area(Acre)), Some((Length(Metre(Unit)), String::from("0.0"))));
2240        assert_eq!(perform_binary_value(Value::calc_div, Volume(Litre(Milli)), Volume(Cubic(Metre(Kilo)))), Some((Plain, String::from("0.0"))));
2241        assert_eq!(perform_binary_value(Value::calc_div, Volume(Litre(Milli)), Volume(Cubic(Mile))), Some((Plain, String::from("0.0"))));
2242        assert_eq!(perform_binary_value(Value::calc_div, Volume(Litre(Milli)), Volume(Litre(Milli))), Some((Plain, String::from("1.0"))));
2243        assert_eq!(perform_binary_value(Value::calc_div, Volume(Litre(Milli)), Volume(Pint)), Some((Plain, String::from("0.001759754"))));
2244
2245        assert_eq!(perform_binary_value(Value::calc_div, Volume(Pint), Length(Metre(Kilo))), Some((Area(Square(Metre(Unit))), String::from("0.000000568"))));
2246        assert_eq!(perform_binary_value(Value::calc_div, Volume(Pint), Length(Mile)), Some((Area(Square(Metre(Unit))), String::from("0.000000353"))));
2247        assert_eq!(perform_binary_value(Value::calc_div, Volume(Pint), Area(Square(Metre(Kilo)))), Some((Length(Metre(Unit)), String::from("0.000000001"))));
2248        assert_eq!(perform_binary_value(Value::calc_div, Volume(Pint), Area(Square(Mile))), Some((Length(Metre(Unit)), String::from("0.0"))));
2249        assert_eq!(perform_binary_value(Value::calc_div, Volume(Pint), Area(Acre)), Some((Length(Metre(Unit)), String::from("0.00000014"))));
2250        assert_eq!(perform_binary_value(Value::calc_div, Volume(Pint), Volume(Cubic(Metre(Kilo)))), Some((Plain, String::from("0.0"))));
2251        assert_eq!(perform_binary_value(Value::calc_div, Volume(Pint), Volume(Cubic(Mile))), Some((Plain, String::from("0.0"))));
2252        assert_eq!(perform_binary_value(Value::calc_div, Volume(Pint), Volume(Litre(Milli))), Some((Plain, String::from("568.26125"))));
2253        assert_eq!(perform_binary_value(Value::calc_div, Volume(Pint), Volume(Pint)), Some((Plain, String::from("1.0"))));
2254    }
2255
2256    #[test]
2257    fn test_unit_values_are_remaindered_by_meaning() {
2258        assert_eq!(perform_binary_ok(Value::calc_mod, Plain, Plain), Some(Plain));
2259        assert_eq!(perform_binary_err(Value::calc_mod, Plain, Delta(Hour)), Some(BadCastOp(Delta(Hour), Plain)));
2260        assert_eq!(perform_binary_err(Value::calc_mod, Plain, Time), Some(BadCastOp(Time, Plain)));
2261        assert_eq!(perform_binary_err(Value::calc_mod, Plain, Length(Mile)), Some(BadCastOp(Length(Mile), Plain)));
2262        assert_eq!(perform_binary_err(Value::calc_mod, Plain, Area(Acre)), Some(BadCastOp(Area(Acre), Plain)));
2263        assert_eq!(perform_binary_err(Value::calc_mod, Plain, Volume(Pint)), Some(BadCastOp(Volume(Pint), Plain)));
2264        assert_eq!(perform_binary_err(Value::calc_mod, Plain, Speed(Light)), Some(BadCastOp(Speed(Light), Plain)));
2265        assert_eq!(perform_binary_err(Value::calc_mod, Plain, Mass(Ounce)), Some(BadCastOp(Mass(Ounce), Plain)));
2266        assert_eq!(perform_binary_err(Value::calc_mod, Plain, Temp(Rankine)), Some(BadCastOp(Temp(Rankine), Plain)));
2267        assert_eq!(perform_binary_err(Value::calc_mod, Plain, Data(Bit)), Some(BadCastOp(Data(Bit), Plain)));
2268
2269        assert_eq!(perform_binary_ok(Value::calc_mod, Delta(Hour), Plain), Some(Delta(Hour)));
2270        assert_eq!(perform_binary_ok(Value::calc_mod, Delta(Hour), Delta(Hour)), Some(Plain));
2271        assert_eq!(perform_binary_err(Value::calc_mod, Delta(Hour), Time), Some(BadCastOp(Time, Delta(Hour))));
2272        assert_eq!(perform_binary_err(Value::calc_mod, Delta(Hour), Length(Mile)), Some(BadCastOp(Length(Mile), Delta(Hour))));
2273        assert_eq!(perform_binary_err(Value::calc_mod, Delta(Hour), Area(Acre)), Some(BadCastOp(Area(Acre), Delta(Hour))));
2274        assert_eq!(perform_binary_err(Value::calc_mod, Delta(Hour), Volume(Pint)), Some(BadCastOp(Volume(Pint), Delta(Hour))));
2275        assert_eq!(perform_binary_err(Value::calc_mod, Delta(Hour), Speed(Light)), Some(BadCastOp(Speed(Light), Delta(Hour))));
2276        assert_eq!(perform_binary_err(Value::calc_mod, Delta(Hour), Mass(Ounce)), Some(BadCastOp(Mass(Ounce), Delta(Hour))));
2277        assert_eq!(perform_binary_err(Value::calc_mod, Delta(Hour), Temp(Rankine)), Some(BadCastOp(Temp(Rankine), Delta(Hour))));
2278        assert_eq!(perform_binary_err(Value::calc_mod, Delta(Hour), Data(Bit)), Some(BadCastOp(Data(Bit), Delta(Hour))));
2279
2280        assert_eq!(perform_binary_err(Value::calc_mod, Time, Plain), Some(BadCastOp(Plain, Time)));
2281        assert_eq!(perform_binary_err(Value::calc_mod, Time, Delta(Hour)), Some(BadCastOp(Delta(Hour), Time)));
2282        assert_eq!(perform_binary_err(Value::calc_mod, Time, Time), Some(BadCastOp(Time, Time)));
2283        assert_eq!(perform_binary_err(Value::calc_mod, Time, Length(Mile)), Some(BadCastOp(Length(Mile), Time)));
2284        assert_eq!(perform_binary_err(Value::calc_mod, Time, Area(Acre)), Some(BadCastOp(Area(Acre), Time)));
2285        assert_eq!(perform_binary_err(Value::calc_mod, Time, Volume(Pint)), Some(BadCastOp(Volume(Pint), Time)));
2286        assert_eq!(perform_binary_err(Value::calc_mod, Time, Speed(Light)), Some(BadCastOp(Speed(Light), Time)));
2287        assert_eq!(perform_binary_err(Value::calc_mod, Time, Mass(Ounce)), Some(BadCastOp(Mass(Ounce), Time)));
2288        assert_eq!(perform_binary_err(Value::calc_mod, Time, Temp(Rankine)), Some(BadCastOp(Temp(Rankine), Time)));
2289        assert_eq!(perform_binary_err(Value::calc_mod, Time, Data(Bit)), Some(BadCastOp(Data(Bit), Time)));
2290
2291        assert_eq!(perform_binary_ok(Value::calc_mod, Length(Mile), Plain), Some(Length(Mile)));
2292        assert_eq!(perform_binary_err(Value::calc_mod, Length(Mile), Delta(Hour)), Some(BadCastOp(Delta(Hour), Length(Mile))));
2293        assert_eq!(perform_binary_err(Value::calc_mod, Length(Mile), Time), Some(BadCastOp(Time, Length(Mile))));
2294        assert_eq!(perform_binary_ok(Value::calc_mod, Length(Mile), Length(Mile)), Some(Plain));
2295        assert_eq!(perform_binary_err(Value::calc_mod, Length(Mile), Area(Acre)), Some(BadCastOp(Area(Acre), Length(Mile))));
2296        assert_eq!(perform_binary_err(Value::calc_mod, Length(Mile), Volume(Pint)), Some(BadCastOp(Volume(Pint), Length(Mile))));
2297        assert_eq!(perform_binary_ok(Value::calc_mod, Length(Mile), Speed(Light)), Some(Delta(Second(Unit))));
2298        assert_eq!(perform_binary_err(Value::calc_mod, Length(Mile), Mass(Ounce)), Some(BadCastOp(Mass(Ounce), Length(Mile))));
2299        assert_eq!(perform_binary_err(Value::calc_mod, Length(Mile), Temp(Rankine)), Some(BadCastOp(Temp(Rankine), Length(Mile))));
2300        assert_eq!(perform_binary_err(Value::calc_mod, Length(Mile), Data(Bit)), Some(BadCastOp(Data(Bit), Length(Mile))));
2301
2302        assert_eq!(perform_binary_ok(Value::calc_mod, Area(Acre), Plain), Some(Area(Acre)));
2303        assert_eq!(perform_binary_err(Value::calc_mod, Area(Acre), Delta(Hour)), Some(BadCastOp(Delta(Hour), Area(Acre))));
2304        assert_eq!(perform_binary_err(Value::calc_mod, Area(Acre), Time), Some(BadCastOp(Time, Area(Acre))));
2305        assert_eq!(perform_binary_ok(Value::calc_mod, Area(Acre), Length(Mile)), Some(Length(Metre(Unit))));
2306        assert_eq!(perform_binary_ok(Value::calc_mod, Area(Acre), Area(Acre)), Some(Plain));
2307        assert_eq!(perform_binary_err(Value::calc_mod, Area(Acre), Volume(Pint)), Some(BadCastOp(Volume(Pint), Area(Acre))));
2308        assert_eq!(perform_binary_err(Value::calc_mod, Area(Acre), Speed(Light)), Some(BadCastOp(Speed(Light), Area(Acre))));
2309        assert_eq!(perform_binary_err(Value::calc_mod, Area(Acre), Mass(Ounce)), Some(BadCastOp(Mass(Ounce), Area(Acre))));
2310        assert_eq!(perform_binary_err(Value::calc_mod, Area(Acre), Temp(Rankine)), Some(BadCastOp(Temp(Rankine), Area(Acre))));
2311        assert_eq!(perform_binary_err(Value::calc_mod, Area(Acre), Data(Bit)), Some(BadCastOp(Data(Bit), Area(Acre))));
2312
2313        assert_eq!(perform_binary_ok(Value::calc_mod, Volume(Pint), Plain), Some(Volume(Pint)));
2314        assert_eq!(perform_binary_err(Value::calc_mod, Volume(Pint), Delta(Hour)), Some(BadCastOp(Delta(Hour), Volume(Pint))));
2315        assert_eq!(perform_binary_err(Value::calc_mod, Volume(Pint), Time), Some(BadCastOp(Time, Volume(Pint))));
2316        assert_eq!(perform_binary_ok(Value::calc_mod, Volume(Pint), Length(Mile)), Some(Area(Square(Metre(Unit)))));
2317        assert_eq!(perform_binary_ok(Value::calc_mod, Volume(Pint), Area(Acre)), Some(Length(Metre(Unit))));
2318        assert_eq!(perform_binary_ok(Value::calc_mod, Volume(Pint), Volume(Pint)), Some(Plain));
2319        assert_eq!(perform_binary_err(Value::calc_mod, Volume(Pint), Speed(Light)), Some(BadCastOp(Speed(Light), Volume(Pint))));
2320        assert_eq!(perform_binary_err(Value::calc_mod, Volume(Pint), Mass(Ounce)), Some(BadCastOp(Mass(Ounce), Volume(Pint))));
2321        assert_eq!(perform_binary_err(Value::calc_mod, Volume(Pint), Temp(Rankine)), Some(BadCastOp(Temp(Rankine), Volume(Pint))));
2322        assert_eq!(perform_binary_err(Value::calc_mod, Volume(Pint), Data(Bit)), Some(BadCastOp(Data(Bit), Volume(Pint))));
2323
2324        assert_eq!(perform_binary_ok(Value::calc_mod, Speed(Light), Plain), Some(Speed(Light)));
2325        assert_eq!(perform_binary_err(Value::calc_mod, Speed(Light), Delta(Hour)), Some(BadCastOp(Delta(Hour), Speed(Light))));
2326        assert_eq!(perform_binary_err(Value::calc_mod, Speed(Light), Time), Some(BadCastOp(Time, Speed(Light))));
2327        assert_eq!(perform_binary_err(Value::calc_mod, Speed(Light), Length(Mile)), Some(BadCastOp(Length(Mile), Speed(Light))));
2328        assert_eq!(perform_binary_err(Value::calc_mod, Speed(Light), Area(Acre)), Some(BadCastOp(Area(Acre), Speed(Light))));
2329        assert_eq!(perform_binary_err(Value::calc_mod, Speed(Light), Volume(Pint)), Some(BadCastOp(Volume(Pint), Speed(Light))));
2330        assert_eq!(perform_binary_ok(Value::calc_mod, Speed(Light), Speed(Light)), Some(Plain));
2331        assert_eq!(perform_binary_err(Value::calc_mod, Speed(Light), Mass(Ounce)), Some(BadCastOp(Mass(Ounce), Speed(Light))));
2332        assert_eq!(perform_binary_err(Value::calc_mod, Speed(Light), Temp(Rankine)), Some(BadCastOp(Temp(Rankine), Speed(Light))));
2333        assert_eq!(perform_binary_err(Value::calc_mod, Speed(Light), Data(Bit)), Some(BadCastOp(Data(Bit), Speed(Light))));
2334
2335        assert_eq!(perform_binary_ok(Value::calc_mod, Mass(Ounce), Plain), Some(Mass(Ounce)));
2336        assert_eq!(perform_binary_err(Value::calc_mod, Mass(Ounce), Delta(Hour)), Some(BadCastOp(Delta(Hour), Mass(Ounce))));
2337        assert_eq!(perform_binary_err(Value::calc_mod, Mass(Ounce), Time), Some(BadCastOp(Time, Mass(Ounce))));
2338        assert_eq!(perform_binary_err(Value::calc_mod, Mass(Ounce), Length(Mile)), Some(BadCastOp(Length(Mile), Mass(Ounce))));
2339        assert_eq!(perform_binary_err(Value::calc_mod, Mass(Ounce), Area(Acre)), Some(BadCastOp(Area(Acre), Mass(Ounce))));
2340        assert_eq!(perform_binary_err(Value::calc_mod, Mass(Ounce), Volume(Pint)), Some(BadCastOp(Volume(Pint), Mass(Ounce))));
2341        assert_eq!(perform_binary_err(Value::calc_mod, Mass(Ounce), Speed(Light)), Some(BadCastOp(Speed(Light), Mass(Ounce))));
2342        assert_eq!(perform_binary_ok(Value::calc_mod, Mass(Ounce), Mass(Ounce)), Some(Plain));
2343        assert_eq!(perform_binary_err(Value::calc_mod, Mass(Ounce), Temp(Rankine)), Some(BadCastOp(Temp(Rankine), Mass(Ounce))));
2344        assert_eq!(perform_binary_err(Value::calc_mod, Mass(Ounce), Data(Bit)), Some(BadCastOp(Data(Bit), Mass(Ounce))));
2345
2346        assert_eq!(perform_binary_ok(Value::calc_mod, Temp(Rankine), Plain), Some(Temp(Rankine)));
2347        assert_eq!(perform_binary_err(Value::calc_mod, Temp(Rankine), Delta(Hour)), Some(BadCastOp(Delta(Hour), Temp(Rankine))));
2348        assert_eq!(perform_binary_err(Value::calc_mod, Temp(Rankine), Time), Some(BadCastOp(Time, Temp(Rankine))));
2349        assert_eq!(perform_binary_err(Value::calc_mod, Temp(Rankine), Length(Mile)), Some(BadCastOp(Length(Mile), Temp(Rankine))));
2350        assert_eq!(perform_binary_err(Value::calc_mod, Temp(Rankine), Area(Acre)), Some(BadCastOp(Area(Acre), Temp(Rankine))));
2351        assert_eq!(perform_binary_err(Value::calc_mod, Temp(Rankine), Volume(Pint)), Some(BadCastOp(Volume(Pint), Temp(Rankine))));
2352        assert_eq!(perform_binary_err(Value::calc_mod, Temp(Rankine), Speed(Light)), Some(BadCastOp(Speed(Light), Temp(Rankine))));
2353        assert_eq!(perform_binary_err(Value::calc_mod, Temp(Rankine), Mass(Ounce)), Some(BadCastOp(Mass(Ounce), Temp(Rankine))));
2354        assert_eq!(perform_binary_ok(Value::calc_mod, Temp(Rankine), Temp(Rankine)), Some(Plain));
2355        assert_eq!(perform_binary_err(Value::calc_mod, Temp(Rankine), Data(Bit)), Some(BadCastOp(Data(Bit), Temp(Rankine))));
2356
2357        assert_eq!(perform_binary_ok(Value::calc_mod, Data(Bit), Plain), Some(Data(Bit)));
2358        assert_eq!(perform_binary_err(Value::calc_mod, Data(Bit), Delta(Hour)), Some(BadCastOp(Delta(Hour), Data(Bit))));
2359        assert_eq!(perform_binary_err(Value::calc_mod, Data(Bit), Time), Some(BadCastOp(Time, Data(Bit))));
2360        assert_eq!(perform_binary_err(Value::calc_mod, Data(Bit), Length(Mile)), Some(BadCastOp(Length(Mile), Data(Bit))));
2361        assert_eq!(perform_binary_err(Value::calc_mod, Data(Bit), Area(Acre)), Some(BadCastOp(Area(Acre), Data(Bit))));
2362        assert_eq!(perform_binary_err(Value::calc_mod, Data(Bit), Volume(Pint)), Some(BadCastOp(Volume(Pint), Data(Bit))));
2363        assert_eq!(perform_binary_err(Value::calc_mod, Data(Bit), Speed(Light)), Some(BadCastOp(Speed(Light), Data(Bit))));
2364        assert_eq!(perform_binary_err(Value::calc_mod, Data(Bit), Mass(Ounce)), Some(BadCastOp(Mass(Ounce), Data(Bit))));
2365        assert_eq!(perform_binary_err(Value::calc_mod, Data(Bit), Temp(Rankine)), Some(BadCastOp(Temp(Rankine), Data(Bit))));
2366        assert_eq!(perform_binary_ok(Value::calc_mod, Data(Bit), Data(Bit)), Some(Plain));
2367    }
2368
2369    #[test]
2370    fn test_length_values_are_remaindered_by_meaning() {
2371        assert_eq!(perform_binary_value(Value::calc_mod, Length(Metre(Kilo)), Length(Metre(Kilo))), Some((Plain, String::from("0.0"))));
2372        assert_eq!(perform_binary_value(Value::calc_mod, Length(Metre(Kilo)), Length(Mile)), Some((Plain, String::from("1000.0"))));
2373        assert_eq!(perform_binary_err(Value::calc_mod, Length(Metre(Kilo)), Area(Square(Metre(Kilo)))), Some(BadCastOp(Area(Square(Metre(Kilo))), Length(Metre(Kilo)))));
2374        assert_eq!(perform_binary_err(Value::calc_mod, Length(Metre(Kilo)), Area(Square(Mile))), Some(BadCastOp(Area(Square(Mile)), Length(Metre(Kilo)))));
2375        assert_eq!(perform_binary_err(Value::calc_mod, Length(Metre(Kilo)), Area(Acre)), Some(BadCastOp(Area(Acre), Length(Metre(Kilo)))));
2376        assert_eq!(perform_binary_err(Value::calc_mod, Length(Metre(Kilo)), Volume(Cubic(Metre(Kilo)))), Some(BadCastOp(Volume(Cubic(Metre(Kilo))), Length(Metre(Kilo)))));
2377        assert_eq!(perform_binary_err(Value::calc_mod, Length(Metre(Kilo)), Volume(Cubic(Mile))), Some(BadCastOp(Volume(Cubic(Mile)), Length(Metre(Kilo)))));
2378        assert_eq!(perform_binary_err(Value::calc_mod, Length(Metre(Kilo)), Volume(Litre(Milli))), Some(BadCastOp(Volume(Litre(Milli)), Length(Metre(Kilo)))));
2379        assert_eq!(perform_binary_err(Value::calc_mod, Length(Metre(Kilo)), Volume(Pint)), Some(BadCastOp(Volume(Pint), Length(Metre(Kilo)))));
2380
2381        assert_eq!(perform_binary_value(Value::calc_mod, Length(Mile), Length(Metre(Kilo))), Some((Plain, String::from("609.344"))));
2382        assert_eq!(perform_binary_value(Value::calc_mod, Length(Mile), Length(Mile)), Some((Plain, String::from("0.0"))));
2383        assert_eq!(perform_binary_err(Value::calc_mod, Length(Mile), Area(Square(Metre(Kilo)))), Some(BadCastOp(Area(Square(Metre(Kilo))), Length(Mile))));
2384        assert_eq!(perform_binary_err(Value::calc_mod, Length(Mile), Area(Square(Mile))), Some(BadCastOp(Area(Square(Mile)), Length(Mile))));
2385        assert_eq!(perform_binary_err(Value::calc_mod, Length(Mile), Area(Acre)), Some(BadCastOp(Area(Acre), Length(Mile))));
2386        assert_eq!(perform_binary_err(Value::calc_mod, Length(Mile), Volume(Cubic(Metre(Kilo)))), Some(BadCastOp(Volume(Cubic(Metre(Kilo))), Length(Mile))));
2387        assert_eq!(perform_binary_err(Value::calc_mod, Length(Mile), Volume(Cubic(Mile))), Some(BadCastOp(Volume(Cubic(Mile)), Length(Mile))));
2388        assert_eq!(perform_binary_err(Value::calc_mod, Length(Mile), Volume(Litre(Milli))), Some(BadCastOp(Volume(Litre(Milli)), Length(Mile))));
2389        assert_eq!(perform_binary_err(Value::calc_mod, Length(Mile), Volume(Pint)), Some(BadCastOp(Volume(Pint), Length(Mile))));
2390
2391        assert_eq!(perform_binary_value(Value::calc_mod, Area(Square(Metre(Kilo))), Length(Metre(Kilo))), Some((Length(Metre(Kilo)), String::from("0.0"))));
2392        assert_eq!(perform_binary_value(Value::calc_mod, Area(Square(Metre(Kilo))), Length(Mile)), Some((Length(Metre(Kilo)), String::from("0.597376"))));
2393        assert_eq!(perform_binary_value(Value::calc_mod, Area(Square(Metre(Kilo))), Area(Square(Metre(Kilo)))), Some((Plain, String::from("0.0"))));
2394        assert_eq!(perform_binary_value(Value::calc_mod, Area(Square(Metre(Kilo))), Area(Square(Mile))), Some((Plain, String::from("1000000.0"))));
2395        assert_eq!(perform_binary_value(Value::calc_mod, Area(Square(Metre(Kilo))), Area(Acre)), Some((Plain, String::from("426.4636672"))));
2396        assert_eq!(perform_binary_err(Value::calc_mod, Area(Square(Metre(Kilo))), Volume(Cubic(Metre(Kilo)))), Some(BadCastOp(Volume(Cubic(Metre(Kilo))), Area(Square(Metre(Kilo))))));
2397        assert_eq!(perform_binary_err(Value::calc_mod, Area(Square(Metre(Kilo))), Volume(Cubic(Mile))), Some(BadCastOp(Volume(Cubic(Mile)), Area(Square(Metre(Kilo))))));
2398        assert_eq!(perform_binary_err(Value::calc_mod, Area(Square(Metre(Kilo))), Volume(Litre(Milli))), Some(BadCastOp(Volume(Litre(Milli)), Area(Square(Metre(Kilo))))));
2399        assert_eq!(perform_binary_err(Value::calc_mod, Area(Square(Metre(Kilo))), Volume(Pint)), Some(BadCastOp(Volume(Pint), Area(Square(Metre(Kilo))))));
2400
2401        assert_eq!(perform_binary_value(Value::calc_mod, Area(Square(Mile)), Length(Metre(Kilo))), Some((Length(Mile), String::from("0.613983298"))));
2402        assert_eq!(perform_binary_value(Value::calc_mod, Area(Square(Mile)), Length(Mile)), Some((Length(Mile), String::from("0.344"))));
2403        assert_eq!(perform_binary_value(Value::calc_mod, Area(Square(Mile)), Area(Square(Metre(Kilo)))), Some((Plain, String::from("589988.110336"))));
2404        assert_eq!(perform_binary_value(Value::calc_mod, Area(Square(Mile)), Area(Square(Mile))), Some((Plain, String::from("0.0"))));
2405        assert_eq!(perform_binary_value(Value::calc_mod, Area(Square(Mile)), Area(Acre)), Some((Plain, String::from("0.0"))));
2406        assert_eq!(perform_binary_err(Value::calc_mod, Area(Square(Mile)), Volume(Cubic(Metre(Kilo)))), Some(BadCastOp(Volume(Cubic(Metre(Kilo))), Area(Square(Mile)))));
2407        assert_eq!(perform_binary_err(Value::calc_mod, Area(Square(Mile)), Volume(Cubic(Mile))), Some(BadCastOp(Volume(Cubic(Mile)), Area(Square(Mile)))));
2408        assert_eq!(perform_binary_err(Value::calc_mod, Area(Square(Mile)), Volume(Litre(Milli))), Some(BadCastOp(Volume(Litre(Milli)), Area(Square(Mile)))));
2409        assert_eq!(perform_binary_err(Value::calc_mod, Area(Square(Mile)), Volume(Pint)), Some(BadCastOp(Volume(Pint), Area(Square(Mile)))));
2410
2411        assert_eq!(perform_binary_value(Value::calc_mod, Area(Acre), Length(Metre(Kilo))), Some((Length(Metre(Unit)), String::from("46.8564224"))));
2412        assert_eq!(perform_binary_value(Value::calc_mod, Area(Acre), Length(Mile)), Some((Length(Metre(Unit)), String::from("828.1684224"))));
2413        assert_eq!(perform_binary_value(Value::calc_mod, Area(Acre), Area(Square(Metre(Kilo)))), Some((Plain, String::from("4046.8564224"))));
2414        assert_eq!(perform_binary_value(Value::calc_mod, Area(Acre), Area(Square(Mile))), Some((Plain, String::from("4046.8564224"))));
2415        assert_eq!(perform_binary_value(Value::calc_mod, Area(Acre), Area(Acre)), Some((Plain, String::from("0.0"))));
2416        assert_eq!(perform_binary_err(Value::calc_mod, Area(Acre), Volume(Cubic(Metre(Kilo)))), Some(BadCastOp(Volume(Cubic(Metre(Kilo))), Area(Acre))));
2417        assert_eq!(perform_binary_err(Value::calc_mod, Area(Acre), Volume(Cubic(Mile))), Some(BadCastOp(Volume(Cubic(Mile)), Area(Acre))));
2418        assert_eq!(perform_binary_err(Value::calc_mod, Area(Acre), Volume(Litre(Milli))), Some(BadCastOp(Volume(Litre(Milli)), Area(Acre))));
2419        assert_eq!(perform_binary_err(Value::calc_mod, Area(Acre), Volume(Pint)), Some(BadCastOp(Volume(Pint), Area(Acre))));
2420
2421        assert_eq!(perform_binary_value(Value::calc_mod, Volume(Cubic(Metre(Kilo))), Length(Metre(Kilo))), Some((Area(Square(Metre(Kilo))), String::from("0.0"))));
2422        assert_eq!(perform_binary_value(Value::calc_mod, Volume(Cubic(Metre(Kilo))), Length(Mile)), Some((Area(Square(Metre(Kilo))), String::from("0.000309376"))));
2423        assert_eq!(perform_binary_value(Value::calc_mod, Volume(Cubic(Metre(Kilo))), Area(Square(Metre(Kilo)))), Some((Length(Metre(Kilo)), String::from("0.0"))));
2424        assert_eq!(perform_binary_value(Value::calc_mod, Volume(Cubic(Metre(Kilo))), Area(Square(Mile))), Some((Length(Metre(Kilo)), String::from("264.589410304"))));
2425        assert_eq!(perform_binary_value(Value::calc_mod, Volume(Cubic(Metre(Kilo))), Area(Acre)), Some((Length(Metre(Kilo)), String::from("1.543742848"))));
2426        assert_eq!(perform_binary_value(Value::calc_mod, Volume(Cubic(Metre(Kilo))), Volume(Cubic(Metre(Kilo)))), Some((Plain, String::from("0.0"))));
2427        assert_eq!(perform_binary_value(Value::calc_mod, Volume(Cubic(Metre(Kilo))), Volume(Cubic(Mile))), Some((Plain, String::from("1000000000.0"))));
2428        assert_eq!(perform_binary_value(Value::calc_mod, Volume(Cubic(Metre(Kilo))), Volume(Litre(Milli))), Some((Plain, String::from("0.0"))));
2429        assert_eq!(perform_binary_value(Value::calc_mod, Volume(Cubic(Metre(Kilo))), Volume(Pint)), Some((Plain, String::from("0.00039909"))));
2430
2431        assert_eq!(perform_binary_value(Value::calc_mod, Volume(Cubic(Mile)), Length(Metre(Kilo))), Some((Area(Square(Mile)), String::from("0.000318704"))));
2432        assert_eq!(perform_binary_value(Value::calc_mod, Volume(Cubic(Mile)), Length(Mile)), Some((Area(Square(Mile)), String::from("0.00006856"))));
2433        assert_eq!(perform_binary_value(Value::calc_mod, Volume(Cubic(Mile)), Area(Square(Metre(Kilo)))), Some((Length(Mile), String::from("112.981090792"))));
2434        assert_eq!(perform_binary_value(Value::calc_mod, Volume(Cubic(Mile)), Area(Square(Mile))), Some((Length(Mile), String::from("553.614336"))));
2435        assert_eq!(perform_binary_value(Value::calc_mod, Volume(Cubic(Mile)), Area(Acre)), Some((Length(Mile), String::from("0.402336"))));
2436        assert_eq!(perform_binary_value(Value::calc_mod, Volume(Cubic(Mile)), Volume(Cubic(Metre(Kilo)))), Some((Plain, String::from("168181825.440579584"))));
2437        assert_eq!(perform_binary_value(Value::calc_mod, Volume(Cubic(Mile)), Volume(Cubic(Mile))), Some((Plain, String::from("0.0"))));
2438        assert_eq!(perform_binary_value(Value::calc_mod, Volume(Cubic(Mile)), Volume(Litre(Milli))), Some((Plain, String::from("0.000000584"))));
2439        assert_eq!(perform_binary_value(Value::calc_mod, Volume(Cubic(Mile)), Volume(Pint)), Some((Plain, String::from("0.000381144"))));
2440
2441        assert_eq!(perform_binary_value(Value::calc_mod, Volume(Litre(Milli)), Length(Metre(Kilo))), Some((Area(Square(Metre(Unit))), String::from("0.000001"))));
2442        assert_eq!(perform_binary_value(Value::calc_mod, Volume(Litre(Milli)), Length(Mile)), Some((Area(Square(Metre(Unit))), String::from("0.000001"))));
2443        assert_eq!(perform_binary_value(Value::calc_mod, Volume(Litre(Milli)), Area(Square(Metre(Kilo)))), Some((Length(Metre(Unit)), String::from("0.000001"))));
2444        assert_eq!(perform_binary_value(Value::calc_mod, Volume(Litre(Milli)), Area(Square(Mile))), Some((Length(Metre(Unit)), String::from("0.000001"))));
2445        assert_eq!(perform_binary_value(Value::calc_mod, Volume(Litre(Milli)), Area(Acre)), Some((Length(Metre(Unit)), String::from("0.000001"))));
2446        assert_eq!(perform_binary_value(Value::calc_mod, Volume(Litre(Milli)), Volume(Cubic(Metre(Kilo)))), Some((Plain, String::from("0.000001"))));
2447        assert_eq!(perform_binary_value(Value::calc_mod, Volume(Litre(Milli)), Volume(Cubic(Mile))), Some((Plain, String::from("0.000001"))));
2448        assert_eq!(perform_binary_value(Value::calc_mod, Volume(Litre(Milli)), Volume(Litre(Milli))), Some((Plain, String::from("0.0"))));
2449        assert_eq!(perform_binary_value(Value::calc_mod, Volume(Litre(Milli)), Volume(Pint)), Some((Plain, String::from("0.000001"))));
2450
2451        assert_eq!(perform_binary_value(Value::calc_mod, Volume(Pint), Length(Metre(Kilo))), Some((Area(Square(Metre(Unit))), String::from("0.000568261"))));
2452        assert_eq!(perform_binary_value(Value::calc_mod, Volume(Pint), Length(Mile)), Some((Area(Square(Metre(Unit))), String::from("0.000568261"))));
2453        assert_eq!(perform_binary_value(Value::calc_mod, Volume(Pint), Area(Square(Metre(Kilo)))), Some((Length(Metre(Unit)), String::from("0.000568261"))));
2454        assert_eq!(perform_binary_value(Value::calc_mod, Volume(Pint), Area(Square(Mile))), Some((Length(Metre(Unit)), String::from("0.000568261"))));
2455        assert_eq!(perform_binary_value(Value::calc_mod, Volume(Pint), Area(Acre)), Some((Length(Metre(Unit)), String::from("0.000568261"))));
2456        assert_eq!(perform_binary_value(Value::calc_mod, Volume(Pint), Volume(Cubic(Metre(Kilo)))), Some((Plain, String::from("0.000568261"))));
2457        assert_eq!(perform_binary_value(Value::calc_mod, Volume(Pint), Volume(Cubic(Mile))), Some((Plain, String::from("0.000568261"))));
2458        assert_eq!(perform_binary_value(Value::calc_mod, Volume(Pint), Volume(Litre(Milli))), Some((Plain, String::from("0.000000261"))));
2459        assert_eq!(perform_binary_value(Value::calc_mod, Volume(Pint), Volume(Pint)), Some((Plain, String::from("0.0"))));
2460    }
2461
2462    // Neg   |
2463    // ------+-------
2464    // Plain | Plain
2465    // Delta | Delta
2466    // Time  | -
2467    // Other | Other
2468
2469    #[test]
2470    fn test_unit_values_are_negated_by_meaning() {
2471        assert_eq!(perform_unary_ok(Value::calc_neg, Plain), Some(Plain));
2472        assert_eq!(perform_unary_ok(Value::calc_neg, Delta(Hour)), Some(Delta(Hour)));
2473        assert_eq!(perform_unary_err(Value::calc_neg, Time), Some(BadCastOp(Time, Time)));
2474        assert_eq!(perform_unary_ok(Value::calc_neg, Length(Mile)), Some(Length(Mile)));
2475        assert_eq!(perform_unary_ok(Value::calc_neg, Area(Acre)), Some(Area(Acre)));
2476        assert_eq!(perform_unary_ok(Value::calc_neg, Volume(Pint)), Some(Volume(Pint)));
2477        assert_eq!(perform_unary_ok(Value::calc_neg, Speed(Light)), Some(Speed(Light)));
2478        assert_eq!(perform_unary_ok(Value::calc_neg, Mass(Ounce)), Some(Mass(Ounce)));
2479        assert_eq!(perform_unary_ok(Value::calc_neg, Temp(Rankine)), Some(Temp(Rankine)));
2480        assert_eq!(perform_unary_ok(Value::calc_neg, Data(Bit)), Some(Data(Bit)));
2481    }
2482
2483    // Inv   |
2484    // ------+-------
2485    // Plain | Plain
2486    // Delta | -
2487    // Time  | -
2488    // Other | -
2489
2490    #[test]
2491    fn test_unit_values_are_inverted_by_meaning() {
2492        assert_eq!(perform_unary_ok(Value::calc_inv, Plain), Some(Plain));
2493        assert_eq!(perform_unary_err(Value::calc_inv, Delta(Hour)), Some(BadCastOp(Delta(Hour), Plain)));
2494        assert_eq!(perform_unary_err(Value::calc_inv, Time), Some(BadCastOp(Time, Plain)));
2495        assert_eq!(perform_unary_err(Value::calc_inv, Length(Mile)), Some(BadCastOp(Length(Mile), Plain)));
2496        assert_eq!(perform_unary_err(Value::calc_inv, Area(Acre)), Some(BadCastOp(Area(Acre), Plain)));
2497        assert_eq!(perform_unary_err(Value::calc_inv, Volume(Pint)), Some(BadCastOp(Volume(Pint), Plain)));
2498        assert_eq!(perform_unary_err(Value::calc_inv, Speed(Light)), Some(BadCastOp(Speed(Light), Plain)));
2499        assert_eq!(perform_unary_err(Value::calc_inv, Mass(Ounce)), Some(BadCastOp(Mass(Ounce), Plain)));
2500        assert_eq!(perform_unary_err(Value::calc_inv, Temp(Rankine)), Some(BadCastOp(Temp(Rankine), Plain)));
2501        assert_eq!(perform_unary_err(Value::calc_inv, Data(Bit)), Some(BadCastOp(Data(Bit), Plain)));
2502    }
2503
2504    // Pow   | Plain Delta Time  | Other
2505    // ------+-------------------+-------
2506    // Plain | Plain -     -     | -
2507    // Delta | -     -     -     | -
2508    // Time  | -     -     -     | -
2509    // ------+-------------------+-------
2510    // Other | -     -     -     | -
2511
2512    #[test]
2513    fn test_unit_values_are_raised_by_meaning() {
2514        assert_eq!(perform_binary_ok(Value::calc_pow, Plain, Plain), Some(Plain));
2515        assert_eq!(perform_binary_err(Value::calc_pow, Plain, Delta(Hour)), Some(BadCastOp(Delta(Hour), Plain)));
2516        assert_eq!(perform_binary_err(Value::calc_pow, Plain, Time), Some(BadCastOp(Time, Plain)));
2517        assert_eq!(perform_binary_err(Value::calc_pow, Plain, Length(Mile)), Some(BadCastOp(Length(Mile), Plain)));
2518        assert_eq!(perform_binary_err(Value::calc_pow, Plain, Area(Acre)), Some(BadCastOp(Area(Acre), Plain)));
2519        assert_eq!(perform_binary_err(Value::calc_pow, Plain, Volume(Pint)), Some(BadCastOp(Volume(Pint), Plain)));
2520        assert_eq!(perform_binary_err(Value::calc_pow, Plain, Speed(Light)), Some(BadCastOp(Speed(Light), Plain)));
2521        assert_eq!(perform_binary_err(Value::calc_pow, Plain, Mass(Ounce)), Some(BadCastOp(Mass(Ounce), Plain)));
2522        assert_eq!(perform_binary_err(Value::calc_pow, Plain, Temp(Rankine)), Some(BadCastOp(Temp(Rankine), Plain)));
2523        assert_eq!(perform_binary_err(Value::calc_pow, Plain, Data(Bit)), Some(BadCastOp(Data(Bit), Plain)));
2524
2525        assert_eq!(perform_binary_err(Value::calc_pow, Delta(Hour), Plain), Some(BadCastOp(Plain, Delta(Hour))));
2526        assert_eq!(perform_binary_err(Value::calc_pow, Delta(Hour), Delta(Hour)), Some(BadCastOp(Delta(Hour), Delta(Hour))));
2527        assert_eq!(perform_binary_err(Value::calc_pow, Delta(Hour), Time), Some(BadCastOp(Time, Delta(Hour))));
2528        assert_eq!(perform_binary_err(Value::calc_pow, Delta(Hour), Length(Mile)), Some(BadCastOp(Length(Mile), Delta(Hour))));
2529        assert_eq!(perform_binary_err(Value::calc_pow, Delta(Hour), Area(Acre)), Some(BadCastOp(Area(Acre), Delta(Hour))));
2530        assert_eq!(perform_binary_err(Value::calc_pow, Delta(Hour), Volume(Pint)), Some(BadCastOp(Volume(Pint), Delta(Hour))));
2531        assert_eq!(perform_binary_err(Value::calc_pow, Delta(Hour), Speed(Light)), Some(BadCastOp(Speed(Light), Delta(Hour))));
2532        assert_eq!(perform_binary_err(Value::calc_pow, Delta(Hour), Mass(Ounce)), Some(BadCastOp(Mass(Ounce), Delta(Hour))));
2533        assert_eq!(perform_binary_err(Value::calc_pow, Delta(Hour), Temp(Rankine)), Some(BadCastOp(Temp(Rankine), Delta(Hour))));
2534        assert_eq!(perform_binary_err(Value::calc_pow, Delta(Hour), Data(Bit)), Some(BadCastOp(Data(Bit), Delta(Hour))));
2535
2536        assert_eq!(perform_binary_err(Value::calc_pow, Time, Plain), Some(BadCastOp(Plain, Time)));
2537        assert_eq!(perform_binary_err(Value::calc_pow, Time, Delta(Hour)), Some(BadCastOp(Delta(Hour), Time)));
2538        assert_eq!(perform_binary_err(Value::calc_pow, Time, Time), Some(BadCastOp(Time, Time)));
2539        assert_eq!(perform_binary_err(Value::calc_pow, Time, Length(Mile)), Some(BadCastOp(Length(Mile), Time)));
2540        assert_eq!(perform_binary_err(Value::calc_pow, Time, Area(Acre)), Some(BadCastOp(Area(Acre), Time)));
2541        assert_eq!(perform_binary_err(Value::calc_pow, Time, Volume(Pint)), Some(BadCastOp(Volume(Pint), Time)));
2542        assert_eq!(perform_binary_err(Value::calc_pow, Time, Speed(Light)), Some(BadCastOp(Speed(Light), Time)));
2543        assert_eq!(perform_binary_err(Value::calc_pow, Time, Mass(Ounce)), Some(BadCastOp(Mass(Ounce), Time)));
2544        assert_eq!(perform_binary_err(Value::calc_pow, Time, Temp(Rankine)), Some(BadCastOp(Temp(Rankine), Time)));
2545        assert_eq!(perform_binary_err(Value::calc_pow, Time, Data(Bit)), Some(BadCastOp(Data(Bit), Time)));
2546
2547        assert_eq!(perform_binary_err(Value::calc_pow, Length(Mile), Plain), Some(BadCastOp(Plain, Length(Mile))));
2548        assert_eq!(perform_binary_err(Value::calc_pow, Length(Mile), Delta(Hour)), Some(BadCastOp(Delta(Hour), Length(Mile))));
2549        assert_eq!(perform_binary_err(Value::calc_pow, Length(Mile), Time), Some(BadCastOp(Time, Length(Mile))));
2550        assert_eq!(perform_binary_err(Value::calc_pow, Length(Mile), Length(Mile)), Some(BadCastOp(Length(Mile), Length(Mile))));
2551        assert_eq!(perform_binary_err(Value::calc_pow, Length(Mile), Area(Acre)), Some(BadCastOp(Area(Acre), Length(Mile))));
2552        assert_eq!(perform_binary_err(Value::calc_pow, Length(Mile), Volume(Pint)), Some(BadCastOp(Volume(Pint), Length(Mile))));
2553        assert_eq!(perform_binary_err(Value::calc_pow, Length(Mile), Speed(Light)), Some(BadCastOp(Speed(Light), Length(Mile))));
2554        assert_eq!(perform_binary_err(Value::calc_pow, Length(Mile), Mass(Ounce)), Some(BadCastOp(Mass(Ounce), Length(Mile))));
2555        assert_eq!(perform_binary_err(Value::calc_pow, Length(Mile), Temp(Rankine)), Some(BadCastOp(Temp(Rankine), Length(Mile))));
2556        assert_eq!(perform_binary_err(Value::calc_pow, Length(Mile), Data(Bit)), Some(BadCastOp(Data(Bit), Length(Mile))));
2557
2558        assert_eq!(perform_binary_err(Value::calc_pow, Area(Acre), Plain), Some(BadCastOp(Plain, Area(Acre))));
2559        assert_eq!(perform_binary_err(Value::calc_pow, Area(Acre), Delta(Hour)), Some(BadCastOp(Delta(Hour), Area(Acre))));
2560        assert_eq!(perform_binary_err(Value::calc_pow, Area(Acre), Time), Some(BadCastOp(Time, Area(Acre))));
2561        assert_eq!(perform_binary_err(Value::calc_pow, Area(Acre), Length(Mile)), Some(BadCastOp(Length(Mile), Area(Acre))));
2562        assert_eq!(perform_binary_err(Value::calc_pow, Area(Acre), Area(Acre)), Some(BadCastOp(Area(Acre), Area(Acre))));
2563        assert_eq!(perform_binary_err(Value::calc_pow, Area(Acre), Volume(Pint)), Some(BadCastOp(Volume(Pint), Area(Acre))));
2564        assert_eq!(perform_binary_err(Value::calc_pow, Area(Acre), Speed(Light)), Some(BadCastOp(Speed(Light), Area(Acre))));
2565        assert_eq!(perform_binary_err(Value::calc_pow, Area(Acre), Mass(Ounce)), Some(BadCastOp(Mass(Ounce), Area(Acre))));
2566        assert_eq!(perform_binary_err(Value::calc_pow, Area(Acre), Temp(Rankine)), Some(BadCastOp(Temp(Rankine), Area(Acre))));
2567        assert_eq!(perform_binary_err(Value::calc_pow, Area(Acre), Data(Bit)), Some(BadCastOp(Data(Bit), Area(Acre))));
2568
2569        assert_eq!(perform_binary_err(Value::calc_pow, Volume(Pint), Plain), Some(BadCastOp(Plain, Volume(Pint))));
2570        assert_eq!(perform_binary_err(Value::calc_pow, Volume(Pint), Delta(Hour)), Some(BadCastOp(Delta(Hour), Volume(Pint))));
2571        assert_eq!(perform_binary_err(Value::calc_pow, Volume(Pint), Time), Some(BadCastOp(Time, Volume(Pint))));
2572        assert_eq!(perform_binary_err(Value::calc_pow, Volume(Pint), Length(Mile)), Some(BadCastOp(Length(Mile), Volume(Pint))));
2573        assert_eq!(perform_binary_err(Value::calc_pow, Volume(Pint), Area(Acre)), Some(BadCastOp(Area(Acre), Volume(Pint))));
2574        assert_eq!(perform_binary_err(Value::calc_pow, Volume(Pint), Volume(Pint)), Some(BadCastOp(Volume(Pint), Volume(Pint))));
2575        assert_eq!(perform_binary_err(Value::calc_pow, Volume(Pint), Speed(Light)), Some(BadCastOp(Speed(Light), Volume(Pint))));
2576        assert_eq!(perform_binary_err(Value::calc_pow, Volume(Pint), Mass(Ounce)), Some(BadCastOp(Mass(Ounce), Volume(Pint))));
2577        assert_eq!(perform_binary_err(Value::calc_pow, Volume(Pint), Temp(Rankine)), Some(BadCastOp(Temp(Rankine), Volume(Pint))));
2578        assert_eq!(perform_binary_err(Value::calc_pow, Volume(Pint), Data(Bit)), Some(BadCastOp(Data(Bit), Volume(Pint))));
2579
2580        assert_eq!(perform_binary_err(Value::calc_pow, Speed(Light), Plain), Some(BadCastOp(Plain, Speed(Light))));
2581        assert_eq!(perform_binary_err(Value::calc_pow, Speed(Light), Delta(Hour)), Some(BadCastOp(Delta(Hour), Speed(Light))));
2582        assert_eq!(perform_binary_err(Value::calc_pow, Speed(Light), Time), Some(BadCastOp(Time, Speed(Light))));
2583        assert_eq!(perform_binary_err(Value::calc_pow, Speed(Light), Length(Mile)), Some(BadCastOp(Length(Mile), Speed(Light))));
2584        assert_eq!(perform_binary_err(Value::calc_pow, Speed(Light), Area(Acre)), Some(BadCastOp(Area(Acre), Speed(Light))));
2585        assert_eq!(perform_binary_err(Value::calc_pow, Speed(Light), Volume(Pint)), Some(BadCastOp(Volume(Pint), Speed(Light))));
2586        assert_eq!(perform_binary_err(Value::calc_pow, Speed(Light), Speed(Light)), Some(BadCastOp(Speed(Light), Speed(Light))));
2587        assert_eq!(perform_binary_err(Value::calc_pow, Speed(Light), Mass(Ounce)), Some(BadCastOp(Mass(Ounce), Speed(Light))));
2588        assert_eq!(perform_binary_err(Value::calc_pow, Speed(Light), Temp(Rankine)), Some(BadCastOp(Temp(Rankine), Speed(Light))));
2589        assert_eq!(perform_binary_err(Value::calc_pow, Speed(Light), Data(Bit)), Some(BadCastOp(Data(Bit), Speed(Light))));
2590
2591        assert_eq!(perform_binary_err(Value::calc_pow, Mass(Ounce), Plain), Some(BadCastOp(Plain, Mass(Ounce))));
2592        assert_eq!(perform_binary_err(Value::calc_pow, Mass(Ounce), Delta(Hour)), Some(BadCastOp(Delta(Hour), Mass(Ounce))));
2593        assert_eq!(perform_binary_err(Value::calc_pow, Mass(Ounce), Time), Some(BadCastOp(Time, Mass(Ounce))));
2594        assert_eq!(perform_binary_err(Value::calc_pow, Mass(Ounce), Length(Mile)), Some(BadCastOp(Length(Mile), Mass(Ounce))));
2595        assert_eq!(perform_binary_err(Value::calc_pow, Mass(Ounce), Area(Acre)), Some(BadCastOp(Area(Acre), Mass(Ounce))));
2596        assert_eq!(perform_binary_err(Value::calc_pow, Mass(Ounce), Volume(Pint)), Some(BadCastOp(Volume(Pint), Mass(Ounce))));
2597        assert_eq!(perform_binary_err(Value::calc_pow, Mass(Ounce), Speed(Light)), Some(BadCastOp(Speed(Light), Mass(Ounce))));
2598        assert_eq!(perform_binary_err(Value::calc_pow, Mass(Ounce), Mass(Ounce)), Some(BadCastOp(Mass(Ounce), Mass(Ounce))));
2599        assert_eq!(perform_binary_err(Value::calc_pow, Mass(Ounce), Temp(Rankine)), Some(BadCastOp(Temp(Rankine), Mass(Ounce))));
2600        assert_eq!(perform_binary_err(Value::calc_pow, Mass(Ounce), Data(Bit)), Some(BadCastOp(Data(Bit), Mass(Ounce))));
2601
2602        assert_eq!(perform_binary_err(Value::calc_pow, Temp(Rankine), Plain), Some(BadCastOp(Plain, Temp(Rankine))));
2603        assert_eq!(perform_binary_err(Value::calc_pow, Temp(Rankine), Delta(Hour)), Some(BadCastOp(Delta(Hour), Temp(Rankine))));
2604        assert_eq!(perform_binary_err(Value::calc_pow, Temp(Rankine), Time), Some(BadCastOp(Time, Temp(Rankine))));
2605        assert_eq!(perform_binary_err(Value::calc_pow, Temp(Rankine), Length(Mile)), Some(BadCastOp(Length(Mile), Temp(Rankine))));
2606        assert_eq!(perform_binary_err(Value::calc_pow, Temp(Rankine), Area(Acre)), Some(BadCastOp(Area(Acre), Temp(Rankine))));
2607        assert_eq!(perform_binary_err(Value::calc_pow, Temp(Rankine), Volume(Pint)), Some(BadCastOp(Volume(Pint), Temp(Rankine))));
2608        assert_eq!(perform_binary_err(Value::calc_pow, Temp(Rankine), Speed(Light)), Some(BadCastOp(Speed(Light), Temp(Rankine))));
2609        assert_eq!(perform_binary_err(Value::calc_pow, Temp(Rankine), Mass(Ounce)), Some(BadCastOp(Mass(Ounce), Temp(Rankine))));
2610        assert_eq!(perform_binary_err(Value::calc_pow, Temp(Rankine), Temp(Rankine)), Some(BadCastOp(Temp(Rankine), Temp(Rankine))));
2611        assert_eq!(perform_binary_err(Value::calc_pow, Temp(Rankine), Data(Bit)), Some(BadCastOp(Data(Bit), Temp(Rankine))));
2612
2613        assert_eq!(perform_binary_err(Value::calc_pow, Data(Bit), Plain), Some(BadCastOp(Plain, Data(Bit))));
2614        assert_eq!(perform_binary_err(Value::calc_pow, Data(Bit), Delta(Hour)), Some(BadCastOp(Delta(Hour), Data(Bit))));
2615        assert_eq!(perform_binary_err(Value::calc_pow, Data(Bit), Time), Some(BadCastOp(Time, Data(Bit))));
2616        assert_eq!(perform_binary_err(Value::calc_pow, Data(Bit), Length(Mile)), Some(BadCastOp(Length(Mile), Data(Bit))));
2617        assert_eq!(perform_binary_err(Value::calc_pow, Data(Bit), Area(Acre)), Some(BadCastOp(Area(Acre), Data(Bit))));
2618        assert_eq!(perform_binary_err(Value::calc_pow, Data(Bit), Volume(Pint)), Some(BadCastOp(Volume(Pint), Data(Bit))));
2619        assert_eq!(perform_binary_err(Value::calc_pow, Data(Bit), Speed(Light)), Some(BadCastOp(Speed(Light), Data(Bit))));
2620        assert_eq!(perform_binary_err(Value::calc_pow, Data(Bit), Mass(Ounce)), Some(BadCastOp(Mass(Ounce), Data(Bit))));
2621        assert_eq!(perform_binary_err(Value::calc_pow, Data(Bit), Temp(Rankine)), Some(BadCastOp(Temp(Rankine), Data(Bit))));
2622        assert_eq!(perform_binary_err(Value::calc_pow, Data(Bit), Data(Bit)), Some(BadCastOp(Data(Bit), Data(Bit))));
2623    }
2624
2625    // Sqrt  |
2626    // ------+-------
2627    // Plain | Plain
2628    // Delta | -
2629    // Time  | -
2630    // Other | -
2631
2632    #[test]
2633    fn test_plain_values_have_square_root_by_meaning() {
2634        assert_eq!(perform_unary_ok(Value::calc_sqrt, Plain), Some(Plain));
2635        assert_eq!(perform_unary_err(Value::calc_sqrt, Delta(Hour)), Some(BadCastOp(Delta(Hour), Plain)));
2636        assert_eq!(perform_unary_err(Value::calc_sqrt, Time), Some(BadCastOp(Time, Plain)));
2637        assert_eq!(perform_unary_err(Value::calc_sqrt, Length(Mile)), Some(BadCastOp(Length(Mile), Plain)));
2638        assert_eq!(perform_unary_err(Value::calc_sqrt, Area(Acre)), Some(BadCastOp(Area(Acre), Plain)));
2639        assert_eq!(perform_unary_err(Value::calc_sqrt, Volume(Pint)), Some(BadCastOp(Volume(Pint), Plain)));
2640        assert_eq!(perform_unary_err(Value::calc_sqrt, Speed(Light)), Some(BadCastOp(Speed(Light), Plain)));
2641        assert_eq!(perform_unary_err(Value::calc_sqrt, Mass(Ounce)), Some(BadCastOp(Mass(Ounce), Plain)));
2642        assert_eq!(perform_unary_err(Value::calc_sqrt, Temp(Rankine)), Some(BadCastOp(Temp(Rankine), Plain)));
2643        assert_eq!(perform_unary_err(Value::calc_sqrt, Data(Bit)), Some(BadCastOp(Data(Bit), Plain)));
2644    }
2645
2646    // And   | Plain Delta Time  | Other
2647    // ------+-------------------+-------
2648    // Plain | Plain -     -     | -
2649    // Delta | -     -     -     | -
2650    // Time  | -     -     -     | -
2651    // ------+-------------------+-------
2652    // Other | -     -     -     | -
2653
2654    #[test]
2655    fn test_plain_values_have_bitwise_and_by_meaning() {
2656        assert_eq!(perform_binary_ok(Value::calc_and, Plain, Plain), Some(Plain));
2657        assert_eq!(perform_binary_err(Value::calc_and, Plain, Delta(Hour)), Some(BadCastOp(Delta(Hour), Plain)));
2658        assert_eq!(perform_binary_err(Value::calc_and, Plain, Time), Some(BadCastOp(Time, Plain)));
2659        assert_eq!(perform_binary_err(Value::calc_and, Delta(Hour), Plain), Some(BadCastOp(Plain, Delta(Hour))));
2660        assert_eq!(perform_binary_err(Value::calc_and, Delta(Hour), Delta(Hour)), Some(BadCastOp(Delta(Hour), Delta(Hour))));
2661        assert_eq!(perform_binary_err(Value::calc_and, Delta(Hour), Time), Some(BadCastOp(Time, Delta(Hour))));
2662        assert_eq!(perform_binary_err(Value::calc_and, Time, Plain), Some(BadCastOp(Plain, Time)));
2663        assert_eq!(perform_binary_err(Value::calc_and, Time, Delta(Hour)), Some(BadCastOp(Delta(Hour), Time)));
2664        assert_eq!(perform_binary_err(Value::calc_and, Time, Time), Some(BadCastOp(Time, Time)));
2665    }
2666
2667    #[test]
2668    fn test_plain_values_have_bitwise_or_by_meaning() {
2669        assert_eq!(perform_binary_ok(Value::calc_or, Plain, Plain), Some(Plain));
2670        assert_eq!(perform_binary_err(Value::calc_or, Plain, Delta(Hour)), Some(BadCastOp(Delta(Hour), Plain)));
2671        assert_eq!(perform_binary_err(Value::calc_or, Plain, Time), Some(BadCastOp(Time, Plain)));
2672        assert_eq!(perform_binary_err(Value::calc_or, Delta(Hour), Plain), Some(BadCastOp(Plain, Delta(Hour))));
2673        assert_eq!(perform_binary_err(Value::calc_or, Delta(Hour), Delta(Hour)), Some(BadCastOp(Delta(Hour), Delta(Hour))));
2674        assert_eq!(perform_binary_err(Value::calc_or, Delta(Hour), Time), Some(BadCastOp(Time, Delta(Hour))));
2675        assert_eq!(perform_binary_err(Value::calc_or, Time, Plain), Some(BadCastOp(Plain, Time)));
2676        assert_eq!(perform_binary_err(Value::calc_or, Time, Delta(Hour)), Some(BadCastOp(Delta(Hour), Time)));
2677        assert_eq!(perform_binary_err(Value::calc_or, Time, Time), Some(BadCastOp(Time, Time)));
2678    }
2679
2680    #[test]
2681    fn test_plain_values_have_bitwise_xor_by_meaning() {
2682        assert_eq!(perform_binary_ok(Value::calc_xor, Plain, Plain), Some(Plain));
2683        assert_eq!(perform_binary_err(Value::calc_xor, Plain, Delta(Hour)), Some(BadCastOp(Delta(Hour), Plain)));
2684        assert_eq!(perform_binary_err(Value::calc_xor, Plain, Time), Some(BadCastOp(Time, Plain)));
2685        assert_eq!(perform_binary_err(Value::calc_xor, Delta(Hour), Plain), Some(BadCastOp(Plain, Delta(Hour))));
2686        assert_eq!(perform_binary_err(Value::calc_xor, Delta(Hour), Delta(Hour)), Some(BadCastOp(Delta(Hour), Delta(Hour))));
2687        assert_eq!(perform_binary_err(Value::calc_xor, Delta(Hour), Time), Some(BadCastOp(Time, Delta(Hour))));
2688        assert_eq!(perform_binary_err(Value::calc_xor, Time, Plain), Some(BadCastOp(Plain, Time)));
2689        assert_eq!(perform_binary_err(Value::calc_xor, Time, Delta(Hour)), Some(BadCastOp(Delta(Hour), Time)));
2690        assert_eq!(perform_binary_err(Value::calc_xor, Time, Time), Some(BadCastOp(Time, Time)));
2691    }
2692
2693    #[test]
2694    fn test_unit_values_are_shifted_left_by_meaning() {
2695        assert_eq!(perform_binary_ok(Value::calc_shl, Plain, Plain), Some(Plain));
2696        assert_eq!(perform_binary_err(Value::calc_shl, Plain, Delta(Hour)), Some(BadCastOp(Delta(Hour), Plain)));
2697        assert_eq!(perform_binary_err(Value::calc_shl, Plain, Time), Some(BadCastOp(Time, Plain)));
2698        assert_eq!(perform_binary_err(Value::calc_shl, Plain, Length(Mile)), Some(BadCastOp(Length(Mile), Plain)));
2699        assert_eq!(perform_binary_err(Value::calc_shl, Plain, Area(Acre)), Some(BadCastOp(Area(Acre), Plain)));
2700        assert_eq!(perform_binary_err(Value::calc_shl, Plain, Volume(Pint)), Some(BadCastOp(Volume(Pint), Plain)));
2701        assert_eq!(perform_binary_err(Value::calc_shl, Plain, Speed(Light)), Some(BadCastOp(Speed(Light), Plain)));
2702        assert_eq!(perform_binary_err(Value::calc_shl, Plain, Mass(Ounce)), Some(BadCastOp(Mass(Ounce), Plain)));
2703        assert_eq!(perform_binary_err(Value::calc_shl, Plain, Temp(Rankine)), Some(BadCastOp(Temp(Rankine), Plain)));
2704        assert_eq!(perform_binary_err(Value::calc_shl, Plain, Data(Bit)), Some(BadCastOp(Data(Bit), Plain)));
2705
2706        assert_eq!(perform_binary_err(Value::calc_shl, Delta(Hour), Plain), Some(BadCastOp(Plain, Delta(Hour))));
2707        assert_eq!(perform_binary_err(Value::calc_shl, Delta(Hour), Delta(Hour)), Some(BadCastOp(Delta(Hour), Delta(Hour))));
2708        assert_eq!(perform_binary_err(Value::calc_shl, Delta(Hour), Time), Some(BadCastOp(Time, Delta(Hour))));
2709        assert_eq!(perform_binary_err(Value::calc_shl, Delta(Hour), Length(Mile)), Some(BadCastOp(Length(Mile), Delta(Hour))));
2710        assert_eq!(perform_binary_err(Value::calc_shl, Delta(Hour), Area(Acre)), Some(BadCastOp(Area(Acre), Delta(Hour))));
2711        assert_eq!(perform_binary_err(Value::calc_shl, Delta(Hour), Volume(Pint)), Some(BadCastOp(Volume(Pint), Delta(Hour))));
2712        assert_eq!(perform_binary_err(Value::calc_shl, Delta(Hour), Speed(Light)), Some(BadCastOp(Speed(Light), Delta(Hour))));
2713        assert_eq!(perform_binary_err(Value::calc_shl, Delta(Hour), Mass(Ounce)), Some(BadCastOp(Mass(Ounce), Delta(Hour))));
2714        assert_eq!(perform_binary_err(Value::calc_shl, Delta(Hour), Temp(Rankine)), Some(BadCastOp(Temp(Rankine), Delta(Hour))));
2715        assert_eq!(perform_binary_err(Value::calc_shl, Delta(Hour), Data(Bit)), Some(BadCastOp(Data(Bit), Delta(Hour))));
2716
2717        assert_eq!(perform_binary_err(Value::calc_shl, Time, Plain), Some(BadCastOp(Plain, Time)));
2718        assert_eq!(perform_binary_err(Value::calc_shl, Time, Delta(Hour)), Some(BadCastOp(Delta(Hour), Time)));
2719        assert_eq!(perform_binary_err(Value::calc_shl, Time, Time), Some(BadCastOp(Time, Time)));
2720        assert_eq!(perform_binary_err(Value::calc_shl, Time, Length(Mile)), Some(BadCastOp(Length(Mile), Time)));
2721        assert_eq!(perform_binary_err(Value::calc_shl, Time, Area(Acre)), Some(BadCastOp(Area(Acre), Time)));
2722        assert_eq!(perform_binary_err(Value::calc_shl, Time, Volume(Pint)), Some(BadCastOp(Volume(Pint), Time)));
2723        assert_eq!(perform_binary_err(Value::calc_shl, Time, Speed(Light)), Some(BadCastOp(Speed(Light), Time)));
2724        assert_eq!(perform_binary_err(Value::calc_shl, Time, Mass(Ounce)), Some(BadCastOp(Mass(Ounce), Time)));
2725        assert_eq!(perform_binary_err(Value::calc_shl, Time, Temp(Rankine)), Some(BadCastOp(Temp(Rankine), Time)));
2726        assert_eq!(perform_binary_err(Value::calc_shl, Time, Data(Bit)), Some(BadCastOp(Data(Bit), Time)));
2727
2728        assert_eq!(perform_binary_err(Value::calc_shl, Length(Mile), Plain), Some(BadCastOp(Plain, Length(Mile))));
2729        assert_eq!(perform_binary_err(Value::calc_shl, Length(Mile), Delta(Hour)), Some(BadCastOp(Delta(Hour), Length(Mile))));
2730        assert_eq!(perform_binary_err(Value::calc_shl, Length(Mile), Time), Some(BadCastOp(Time, Length(Mile))));
2731        assert_eq!(perform_binary_err(Value::calc_shl, Length(Mile), Length(Mile)), Some(BadCastOp(Length(Mile), Length(Mile))));
2732        assert_eq!(perform_binary_err(Value::calc_shl, Length(Mile), Area(Acre)), Some(BadCastOp(Area(Acre), Length(Mile))));
2733        assert_eq!(perform_binary_err(Value::calc_shl, Length(Mile), Volume(Pint)), Some(BadCastOp(Volume(Pint), Length(Mile))));
2734        assert_eq!(perform_binary_err(Value::calc_shl, Length(Mile), Speed(Light)), Some(BadCastOp(Speed(Light), Length(Mile))));
2735        assert_eq!(perform_binary_err(Value::calc_shl, Length(Mile), Mass(Ounce)), Some(BadCastOp(Mass(Ounce), Length(Mile))));
2736        assert_eq!(perform_binary_err(Value::calc_shl, Length(Mile), Temp(Rankine)), Some(BadCastOp(Temp(Rankine), Length(Mile))));
2737        assert_eq!(perform_binary_err(Value::calc_shl, Length(Mile), Data(Bit)), Some(BadCastOp(Data(Bit), Length(Mile))));
2738
2739        assert_eq!(perform_binary_err(Value::calc_shl, Area(Acre), Plain), Some(BadCastOp(Plain, Area(Acre))));
2740        assert_eq!(perform_binary_err(Value::calc_shl, Area(Acre), Delta(Hour)), Some(BadCastOp(Delta(Hour), Area(Acre))));
2741        assert_eq!(perform_binary_err(Value::calc_shl, Area(Acre), Time), Some(BadCastOp(Time, Area(Acre))));
2742        assert_eq!(perform_binary_err(Value::calc_shl, Area(Acre), Length(Mile)), Some(BadCastOp(Length(Mile), Area(Acre))));
2743        assert_eq!(perform_binary_err(Value::calc_shl, Area(Acre), Area(Acre)), Some(BadCastOp(Area(Acre), Area(Acre))));
2744        assert_eq!(perform_binary_err(Value::calc_shl, Area(Acre), Volume(Pint)), Some(BadCastOp(Volume(Pint), Area(Acre))));
2745        assert_eq!(perform_binary_err(Value::calc_shl, Area(Acre), Speed(Light)), Some(BadCastOp(Speed(Light), Area(Acre))));
2746        assert_eq!(perform_binary_err(Value::calc_shl, Area(Acre), Mass(Ounce)), Some(BadCastOp(Mass(Ounce), Area(Acre))));
2747        assert_eq!(perform_binary_err(Value::calc_shl, Area(Acre), Temp(Rankine)), Some(BadCastOp(Temp(Rankine), Area(Acre))));
2748        assert_eq!(perform_binary_err(Value::calc_shl, Area(Acre), Data(Bit)), Some(BadCastOp(Data(Bit), Area(Acre))));
2749
2750        assert_eq!(perform_binary_err(Value::calc_shl, Volume(Pint), Plain), Some(BadCastOp(Plain, Volume(Pint))));
2751        assert_eq!(perform_binary_err(Value::calc_shl, Volume(Pint), Delta(Hour)), Some(BadCastOp(Delta(Hour), Volume(Pint))));
2752        assert_eq!(perform_binary_err(Value::calc_shl, Volume(Pint), Time), Some(BadCastOp(Time, Volume(Pint))));
2753        assert_eq!(perform_binary_err(Value::calc_shl, Volume(Pint), Length(Mile)), Some(BadCastOp(Length(Mile), Volume(Pint))));
2754        assert_eq!(perform_binary_err(Value::calc_shl, Volume(Pint), Area(Acre)), Some(BadCastOp(Area(Acre), Volume(Pint))));
2755        assert_eq!(perform_binary_err(Value::calc_shl, Volume(Pint), Volume(Pint)), Some(BadCastOp(Volume(Pint), Volume(Pint))));
2756        assert_eq!(perform_binary_err(Value::calc_shl, Volume(Pint), Speed(Light)), Some(BadCastOp(Speed(Light), Volume(Pint))));
2757        assert_eq!(perform_binary_err(Value::calc_shl, Volume(Pint), Mass(Ounce)), Some(BadCastOp(Mass(Ounce), Volume(Pint))));
2758        assert_eq!(perform_binary_err(Value::calc_shl, Volume(Pint), Temp(Rankine)), Some(BadCastOp(Temp(Rankine), Volume(Pint))));
2759        assert_eq!(perform_binary_err(Value::calc_shl, Volume(Pint), Data(Bit)), Some(BadCastOp(Data(Bit), Volume(Pint))));
2760
2761        assert_eq!(perform_binary_err(Value::calc_shl, Speed(Light), Plain), Some(BadCastOp(Plain, Speed(Light))));
2762        assert_eq!(perform_binary_err(Value::calc_shl, Speed(Light), Delta(Hour)), Some(BadCastOp(Delta(Hour), Speed(Light))));
2763        assert_eq!(perform_binary_err(Value::calc_shl, Speed(Light), Time), Some(BadCastOp(Time, Speed(Light))));
2764        assert_eq!(perform_binary_err(Value::calc_shl, Speed(Light), Length(Mile)), Some(BadCastOp(Length(Mile), Speed(Light))));
2765        assert_eq!(perform_binary_err(Value::calc_shl, Speed(Light), Area(Acre)), Some(BadCastOp(Area(Acre), Speed(Light))));
2766        assert_eq!(perform_binary_err(Value::calc_shl, Speed(Light), Volume(Pint)), Some(BadCastOp(Volume(Pint), Speed(Light))));
2767        assert_eq!(perform_binary_err(Value::calc_shl, Speed(Light), Speed(Light)), Some(BadCastOp(Speed(Light), Speed(Light))));
2768        assert_eq!(perform_binary_err(Value::calc_shl, Speed(Light), Mass(Ounce)), Some(BadCastOp(Mass(Ounce), Speed(Light))));
2769        assert_eq!(perform_binary_err(Value::calc_shl, Speed(Light), Temp(Rankine)), Some(BadCastOp(Temp(Rankine), Speed(Light))));
2770        assert_eq!(perform_binary_err(Value::calc_shl, Speed(Light), Data(Bit)), Some(BadCastOp(Data(Bit), Speed(Light))));
2771
2772        assert_eq!(perform_binary_err(Value::calc_shl, Mass(Ounce), Plain), Some(BadCastOp(Plain, Mass(Ounce))));
2773        assert_eq!(perform_binary_err(Value::calc_shl, Mass(Ounce), Delta(Hour)), Some(BadCastOp(Delta(Hour), Mass(Ounce))));
2774        assert_eq!(perform_binary_err(Value::calc_shl, Mass(Ounce), Time), Some(BadCastOp(Time, Mass(Ounce))));
2775        assert_eq!(perform_binary_err(Value::calc_shl, Mass(Ounce), Length(Mile)), Some(BadCastOp(Length(Mile), Mass(Ounce))));
2776        assert_eq!(perform_binary_err(Value::calc_shl, Mass(Ounce), Area(Acre)), Some(BadCastOp(Area(Acre), Mass(Ounce))));
2777        assert_eq!(perform_binary_err(Value::calc_shl, Mass(Ounce), Volume(Pint)), Some(BadCastOp(Volume(Pint), Mass(Ounce))));
2778        assert_eq!(perform_binary_err(Value::calc_shl, Mass(Ounce), Speed(Light)), Some(BadCastOp(Speed(Light), Mass(Ounce))));
2779        assert_eq!(perform_binary_err(Value::calc_shl, Mass(Ounce), Mass(Ounce)), Some(BadCastOp(Mass(Ounce), Mass(Ounce))));
2780        assert_eq!(perform_binary_err(Value::calc_shl, Mass(Ounce), Temp(Rankine)), Some(BadCastOp(Temp(Rankine), Mass(Ounce))));
2781        assert_eq!(perform_binary_err(Value::calc_shl, Mass(Ounce), Data(Bit)), Some(BadCastOp(Data(Bit), Mass(Ounce))));
2782
2783        assert_eq!(perform_binary_err(Value::calc_shl, Temp(Rankine), Plain), Some(BadCastOp(Plain, Temp(Rankine))));
2784        assert_eq!(perform_binary_err(Value::calc_shl, Temp(Rankine), Delta(Hour)), Some(BadCastOp(Delta(Hour), Temp(Rankine))));
2785        assert_eq!(perform_binary_err(Value::calc_shl, Temp(Rankine), Time), Some(BadCastOp(Time, Temp(Rankine))));
2786        assert_eq!(perform_binary_err(Value::calc_shl, Temp(Rankine), Length(Mile)), Some(BadCastOp(Length(Mile), Temp(Rankine))));
2787        assert_eq!(perform_binary_err(Value::calc_shl, Temp(Rankine), Area(Acre)), Some(BadCastOp(Area(Acre), Temp(Rankine))));
2788        assert_eq!(perform_binary_err(Value::calc_shl, Temp(Rankine), Volume(Pint)), Some(BadCastOp(Volume(Pint), Temp(Rankine))));
2789        assert_eq!(perform_binary_err(Value::calc_shl, Temp(Rankine), Speed(Light)), Some(BadCastOp(Speed(Light), Temp(Rankine))));
2790        assert_eq!(perform_binary_err(Value::calc_shl, Temp(Rankine), Mass(Ounce)), Some(BadCastOp(Mass(Ounce), Temp(Rankine))));
2791        assert_eq!(perform_binary_err(Value::calc_shl, Temp(Rankine), Temp(Rankine)), Some(BadCastOp(Temp(Rankine), Temp(Rankine))));
2792        assert_eq!(perform_binary_err(Value::calc_shl, Temp(Rankine), Data(Bit)), Some(BadCastOp(Data(Bit), Temp(Rankine))));
2793
2794        assert_eq!(perform_binary_err(Value::calc_shl, Data(Bit), Plain), Some(BadCastOp(Plain, Data(Bit))));
2795        assert_eq!(perform_binary_err(Value::calc_shl, Data(Bit), Delta(Hour)), Some(BadCastOp(Delta(Hour), Data(Bit))));
2796        assert_eq!(perform_binary_err(Value::calc_shl, Data(Bit), Time), Some(BadCastOp(Time, Data(Bit))));
2797        assert_eq!(perform_binary_err(Value::calc_shl, Data(Bit), Length(Mile)), Some(BadCastOp(Length(Mile), Data(Bit))));
2798        assert_eq!(perform_binary_err(Value::calc_shl, Data(Bit), Area(Acre)), Some(BadCastOp(Area(Acre), Data(Bit))));
2799        assert_eq!(perform_binary_err(Value::calc_shl, Data(Bit), Volume(Pint)), Some(BadCastOp(Volume(Pint), Data(Bit))));
2800        assert_eq!(perform_binary_err(Value::calc_shl, Data(Bit), Speed(Light)), Some(BadCastOp(Speed(Light), Data(Bit))));
2801        assert_eq!(perform_binary_err(Value::calc_shl, Data(Bit), Mass(Ounce)), Some(BadCastOp(Mass(Ounce), Data(Bit))));
2802        assert_eq!(perform_binary_err(Value::calc_shl, Data(Bit), Temp(Rankine)), Some(BadCastOp(Temp(Rankine), Data(Bit))));
2803        assert_eq!(perform_binary_err(Value::calc_shl, Data(Bit), Data(Bit)), Some(BadCastOp(Data(Bit), Data(Bit))));
2804    }
2805
2806    #[test]
2807    fn test_unit_values_are_shifted_right_by_meaning() {
2808        assert_eq!(perform_binary_ok(Value::calc_shr, Plain, Plain), Some(Plain));
2809        assert_eq!(perform_binary_err(Value::calc_shr, Plain, Delta(Hour)), Some(BadCastOp(Delta(Hour), Plain)));
2810        assert_eq!(perform_binary_err(Value::calc_shr, Plain, Time), Some(BadCastOp(Time, Plain)));
2811        assert_eq!(perform_binary_err(Value::calc_shr, Plain, Length(Mile)), Some(BadCastOp(Length(Mile), Plain)));
2812        assert_eq!(perform_binary_err(Value::calc_shr, Plain, Area(Acre)), Some(BadCastOp(Area(Acre), Plain)));
2813        assert_eq!(perform_binary_err(Value::calc_shr, Plain, Volume(Pint)), Some(BadCastOp(Volume(Pint), Plain)));
2814        assert_eq!(perform_binary_err(Value::calc_shr, Plain, Speed(Light)), Some(BadCastOp(Speed(Light), Plain)));
2815        assert_eq!(perform_binary_err(Value::calc_shr, Plain, Mass(Ounce)), Some(BadCastOp(Mass(Ounce), Plain)));
2816        assert_eq!(perform_binary_err(Value::calc_shr, Plain, Temp(Rankine)), Some(BadCastOp(Temp(Rankine), Plain)));
2817        assert_eq!(perform_binary_err(Value::calc_shr, Plain, Data(Bit)), Some(BadCastOp(Data(Bit), Plain)));
2818
2819        assert_eq!(perform_binary_err(Value::calc_shr, Delta(Hour), Plain), Some(BadCastOp(Plain, Delta(Hour))));
2820        assert_eq!(perform_binary_err(Value::calc_shr, Delta(Hour), Delta(Hour)), Some(BadCastOp(Delta(Hour), Delta(Hour))));
2821        assert_eq!(perform_binary_err(Value::calc_shr, Delta(Hour), Time), Some(BadCastOp(Time, Delta(Hour))));
2822        assert_eq!(perform_binary_err(Value::calc_shr, Delta(Hour), Length(Mile)), Some(BadCastOp(Length(Mile), Delta(Hour))));
2823        assert_eq!(perform_binary_err(Value::calc_shr, Delta(Hour), Area(Acre)), Some(BadCastOp(Area(Acre), Delta(Hour))));
2824        assert_eq!(perform_binary_err(Value::calc_shr, Delta(Hour), Volume(Pint)), Some(BadCastOp(Volume(Pint), Delta(Hour))));
2825        assert_eq!(perform_binary_err(Value::calc_shr, Delta(Hour), Speed(Light)), Some(BadCastOp(Speed(Light), Delta(Hour))));
2826        assert_eq!(perform_binary_err(Value::calc_shr, Delta(Hour), Mass(Ounce)), Some(BadCastOp(Mass(Ounce), Delta(Hour))));
2827        assert_eq!(perform_binary_err(Value::calc_shr, Delta(Hour), Temp(Rankine)), Some(BadCastOp(Temp(Rankine), Delta(Hour))));
2828        assert_eq!(perform_binary_err(Value::calc_shr, Delta(Hour), Data(Bit)), Some(BadCastOp(Data(Bit), Delta(Hour))));
2829
2830        assert_eq!(perform_binary_err(Value::calc_shr, Time, Plain), Some(BadCastOp(Plain, Time)));
2831        assert_eq!(perform_binary_err(Value::calc_shr, Time, Delta(Hour)), Some(BadCastOp(Delta(Hour), Time)));
2832        assert_eq!(perform_binary_err(Value::calc_shr, Time, Time), Some(BadCastOp(Time, Time)));
2833        assert_eq!(perform_binary_err(Value::calc_shr, Time, Length(Mile)), Some(BadCastOp(Length(Mile), Time)));
2834        assert_eq!(perform_binary_err(Value::calc_shr, Time, Area(Acre)), Some(BadCastOp(Area(Acre), Time)));
2835        assert_eq!(perform_binary_err(Value::calc_shr, Time, Volume(Pint)), Some(BadCastOp(Volume(Pint), Time)));
2836        assert_eq!(perform_binary_err(Value::calc_shr, Time, Speed(Light)), Some(BadCastOp(Speed(Light), Time)));
2837        assert_eq!(perform_binary_err(Value::calc_shr, Time, Mass(Ounce)), Some(BadCastOp(Mass(Ounce), Time)));
2838        assert_eq!(perform_binary_err(Value::calc_shr, Time, Temp(Rankine)), Some(BadCastOp(Temp(Rankine), Time)));
2839        assert_eq!(perform_binary_err(Value::calc_shr, Time, Data(Bit)), Some(BadCastOp(Data(Bit), Time)));
2840
2841        assert_eq!(perform_binary_err(Value::calc_shr, Length(Mile), Plain), Some(BadCastOp(Plain, Length(Mile))));
2842        assert_eq!(perform_binary_err(Value::calc_shr, Length(Mile), Delta(Hour)), Some(BadCastOp(Delta(Hour), Length(Mile))));
2843        assert_eq!(perform_binary_err(Value::calc_shr, Length(Mile), Time), Some(BadCastOp(Time, Length(Mile))));
2844        assert_eq!(perform_binary_err(Value::calc_shr, Length(Mile), Length(Mile)), Some(BadCastOp(Length(Mile), Length(Mile))));
2845        assert_eq!(perform_binary_err(Value::calc_shr, Length(Mile), Area(Acre)), Some(BadCastOp(Area(Acre), Length(Mile))));
2846        assert_eq!(perform_binary_err(Value::calc_shr, Length(Mile), Volume(Pint)), Some(BadCastOp(Volume(Pint), Length(Mile))));
2847        assert_eq!(perform_binary_err(Value::calc_shr, Length(Mile), Speed(Light)), Some(BadCastOp(Speed(Light), Length(Mile))));
2848        assert_eq!(perform_binary_err(Value::calc_shr, Length(Mile), Mass(Ounce)), Some(BadCastOp(Mass(Ounce), Length(Mile))));
2849        assert_eq!(perform_binary_err(Value::calc_shr, Length(Mile), Temp(Rankine)), Some(BadCastOp(Temp(Rankine), Length(Mile))));
2850        assert_eq!(perform_binary_err(Value::calc_shr, Length(Mile), Data(Bit)), Some(BadCastOp(Data(Bit), Length(Mile))));
2851
2852        assert_eq!(perform_binary_err(Value::calc_shr, Area(Acre), Plain), Some(BadCastOp(Plain, Area(Acre))));
2853        assert_eq!(perform_binary_err(Value::calc_shr, Area(Acre), Delta(Hour)), Some(BadCastOp(Delta(Hour), Area(Acre))));
2854        assert_eq!(perform_binary_err(Value::calc_shr, Area(Acre), Time), Some(BadCastOp(Time, Area(Acre))));
2855        assert_eq!(perform_binary_err(Value::calc_shr, Area(Acre), Length(Mile)), Some(BadCastOp(Length(Mile), Area(Acre))));
2856        assert_eq!(perform_binary_err(Value::calc_shr, Area(Acre), Area(Acre)), Some(BadCastOp(Area(Acre), Area(Acre))));
2857        assert_eq!(perform_binary_err(Value::calc_shr, Area(Acre), Volume(Pint)), Some(BadCastOp(Volume(Pint), Area(Acre))));
2858        assert_eq!(perform_binary_err(Value::calc_shr, Area(Acre), Speed(Light)), Some(BadCastOp(Speed(Light), Area(Acre))));
2859        assert_eq!(perform_binary_err(Value::calc_shr, Area(Acre), Mass(Ounce)), Some(BadCastOp(Mass(Ounce), Area(Acre))));
2860        assert_eq!(perform_binary_err(Value::calc_shr, Area(Acre), Temp(Rankine)), Some(BadCastOp(Temp(Rankine), Area(Acre))));
2861        assert_eq!(perform_binary_err(Value::calc_shr, Area(Acre), Data(Bit)), Some(BadCastOp(Data(Bit), Area(Acre))));
2862
2863        assert_eq!(perform_binary_err(Value::calc_shr, Volume(Pint), Plain), Some(BadCastOp(Plain, Volume(Pint))));
2864        assert_eq!(perform_binary_err(Value::calc_shr, Volume(Pint), Delta(Hour)), Some(BadCastOp(Delta(Hour), Volume(Pint))));
2865        assert_eq!(perform_binary_err(Value::calc_shr, Volume(Pint), Time), Some(BadCastOp(Time, Volume(Pint))));
2866        assert_eq!(perform_binary_err(Value::calc_shr, Volume(Pint), Length(Mile)), Some(BadCastOp(Length(Mile), Volume(Pint))));
2867        assert_eq!(perform_binary_err(Value::calc_shr, Volume(Pint), Area(Acre)), Some(BadCastOp(Area(Acre), Volume(Pint))));
2868        assert_eq!(perform_binary_err(Value::calc_shr, Volume(Pint), Volume(Pint)), Some(BadCastOp(Volume(Pint), Volume(Pint))));
2869        assert_eq!(perform_binary_err(Value::calc_shr, Volume(Pint), Speed(Light)), Some(BadCastOp(Speed(Light), Volume(Pint))));
2870        assert_eq!(perform_binary_err(Value::calc_shr, Volume(Pint), Mass(Ounce)), Some(BadCastOp(Mass(Ounce), Volume(Pint))));
2871        assert_eq!(perform_binary_err(Value::calc_shr, Volume(Pint), Temp(Rankine)), Some(BadCastOp(Temp(Rankine), Volume(Pint))));
2872        assert_eq!(perform_binary_err(Value::calc_shr, Volume(Pint), Data(Bit)), Some(BadCastOp(Data(Bit), Volume(Pint))));
2873
2874        assert_eq!(perform_binary_err(Value::calc_shr, Speed(Light), Plain), Some(BadCastOp(Plain, Speed(Light))));
2875        assert_eq!(perform_binary_err(Value::calc_shr, Speed(Light), Delta(Hour)), Some(BadCastOp(Delta(Hour), Speed(Light))));
2876        assert_eq!(perform_binary_err(Value::calc_shr, Speed(Light), Time), Some(BadCastOp(Time, Speed(Light))));
2877        assert_eq!(perform_binary_err(Value::calc_shr, Speed(Light), Length(Mile)), Some(BadCastOp(Length(Mile), Speed(Light))));
2878        assert_eq!(perform_binary_err(Value::calc_shr, Speed(Light), Area(Acre)), Some(BadCastOp(Area(Acre), Speed(Light))));
2879        assert_eq!(perform_binary_err(Value::calc_shr, Speed(Light), Volume(Pint)), Some(BadCastOp(Volume(Pint), Speed(Light))));
2880        assert_eq!(perform_binary_err(Value::calc_shr, Speed(Light), Speed(Light)), Some(BadCastOp(Speed(Light), Speed(Light))));
2881        assert_eq!(perform_binary_err(Value::calc_shr, Speed(Light), Mass(Ounce)), Some(BadCastOp(Mass(Ounce), Speed(Light))));
2882        assert_eq!(perform_binary_err(Value::calc_shr, Speed(Light), Temp(Rankine)), Some(BadCastOp(Temp(Rankine), Speed(Light))));
2883        assert_eq!(perform_binary_err(Value::calc_shr, Speed(Light), Data(Bit)), Some(BadCastOp(Data(Bit), Speed(Light))));
2884
2885        assert_eq!(perform_binary_err(Value::calc_shr, Mass(Ounce), Plain), Some(BadCastOp(Plain, Mass(Ounce))));
2886        assert_eq!(perform_binary_err(Value::calc_shr, Mass(Ounce), Delta(Hour)), Some(BadCastOp(Delta(Hour), Mass(Ounce))));
2887        assert_eq!(perform_binary_err(Value::calc_shr, Mass(Ounce), Time), Some(BadCastOp(Time, Mass(Ounce))));
2888        assert_eq!(perform_binary_err(Value::calc_shr, Mass(Ounce), Length(Mile)), Some(BadCastOp(Length(Mile), Mass(Ounce))));
2889        assert_eq!(perform_binary_err(Value::calc_shr, Mass(Ounce), Area(Acre)), Some(BadCastOp(Area(Acre), Mass(Ounce))));
2890        assert_eq!(perform_binary_err(Value::calc_shr, Mass(Ounce), Volume(Pint)), Some(BadCastOp(Volume(Pint), Mass(Ounce))));
2891        assert_eq!(perform_binary_err(Value::calc_shr, Mass(Ounce), Speed(Light)), Some(BadCastOp(Speed(Light), Mass(Ounce))));
2892        assert_eq!(perform_binary_err(Value::calc_shr, Mass(Ounce), Mass(Ounce)), Some(BadCastOp(Mass(Ounce), Mass(Ounce))));
2893        assert_eq!(perform_binary_err(Value::calc_shr, Mass(Ounce), Temp(Rankine)), Some(BadCastOp(Temp(Rankine), Mass(Ounce))));
2894        assert_eq!(perform_binary_err(Value::calc_shr, Mass(Ounce), Data(Bit)), Some(BadCastOp(Data(Bit), Mass(Ounce))));
2895
2896        assert_eq!(perform_binary_err(Value::calc_shr, Temp(Rankine), Plain), Some(BadCastOp(Plain, Temp(Rankine))));
2897        assert_eq!(perform_binary_err(Value::calc_shr, Temp(Rankine), Delta(Hour)), Some(BadCastOp(Delta(Hour), Temp(Rankine))));
2898        assert_eq!(perform_binary_err(Value::calc_shr, Temp(Rankine), Time), Some(BadCastOp(Time, Temp(Rankine))));
2899        assert_eq!(perform_binary_err(Value::calc_shr, Temp(Rankine), Length(Mile)), Some(BadCastOp(Length(Mile), Temp(Rankine))));
2900        assert_eq!(perform_binary_err(Value::calc_shr, Temp(Rankine), Area(Acre)), Some(BadCastOp(Area(Acre), Temp(Rankine))));
2901        assert_eq!(perform_binary_err(Value::calc_shr, Temp(Rankine), Volume(Pint)), Some(BadCastOp(Volume(Pint), Temp(Rankine))));
2902        assert_eq!(perform_binary_err(Value::calc_shr, Temp(Rankine), Speed(Light)), Some(BadCastOp(Speed(Light), Temp(Rankine))));
2903        assert_eq!(perform_binary_err(Value::calc_shr, Temp(Rankine), Mass(Ounce)), Some(BadCastOp(Mass(Ounce), Temp(Rankine))));
2904        assert_eq!(perform_binary_err(Value::calc_shr, Temp(Rankine), Temp(Rankine)), Some(BadCastOp(Temp(Rankine), Temp(Rankine))));
2905        assert_eq!(perform_binary_err(Value::calc_shr, Temp(Rankine), Data(Bit)), Some(BadCastOp(Data(Bit), Temp(Rankine))));
2906
2907        assert_eq!(perform_binary_err(Value::calc_shr, Data(Bit), Plain), Some(BadCastOp(Plain, Data(Bit))));
2908        assert_eq!(perform_binary_err(Value::calc_shr, Data(Bit), Delta(Hour)), Some(BadCastOp(Delta(Hour), Data(Bit))));
2909        assert_eq!(perform_binary_err(Value::calc_shr, Data(Bit), Time), Some(BadCastOp(Time, Data(Bit))));
2910        assert_eq!(perform_binary_err(Value::calc_shr, Data(Bit), Length(Mile)), Some(BadCastOp(Length(Mile), Data(Bit))));
2911        assert_eq!(perform_binary_err(Value::calc_shr, Data(Bit), Area(Acre)), Some(BadCastOp(Area(Acre), Data(Bit))));
2912        assert_eq!(perform_binary_err(Value::calc_shr, Data(Bit), Volume(Pint)), Some(BadCastOp(Volume(Pint), Data(Bit))));
2913        assert_eq!(perform_binary_err(Value::calc_shr, Data(Bit), Speed(Light)), Some(BadCastOp(Speed(Light), Data(Bit))));
2914        assert_eq!(perform_binary_err(Value::calc_shr, Data(Bit), Mass(Ounce)), Some(BadCastOp(Mass(Ounce), Data(Bit))));
2915        assert_eq!(perform_binary_err(Value::calc_shr, Data(Bit), Temp(Rankine)), Some(BadCastOp(Temp(Rankine), Data(Bit))));
2916        assert_eq!(perform_binary_err(Value::calc_shr, Data(Bit), Data(Bit)), Some(BadCastOp(Data(Bit), Data(Bit))));
2917    }
2918
2919    fn perform_cast_ok(
2920        lhs: Meaning,
2921        rhs: Meaning,
2922    ) -> Option<Meaning> {
2923        let value = create_value(1, 1).with_meaning(lhs);
2924        let result = value.apply_meaning(rhs);
2925        result.ok().map(get_meaning_only)
2926    }
2927
2928    fn perform_cast_value(
2929        lhs: Meaning,
2930        rhs: Meaning,
2931    ) -> Option<(Meaning, String)> {
2932        let value = create_value(1, 1).with_meaning(lhs);
2933        let result = value.apply_meaning(rhs);
2934        result.ok().map(get_meaning_value)
2935    }
2936
2937    fn perform_cast_temp(
2938        lhs: Meaning,
2939        rhs: Meaning,
2940        number: &str,
2941    ) -> Option<(Meaning, String)> {
2942        let value = Value::from_string(number).unwrap().with_meaning(lhs);
2943        let result = value.apply_meaning(rhs);
2944        result.ok().map(get_meaning_value)
2945    }
2946
2947    fn perform_cast_err(
2948        lhs: Meaning,
2949        rhs: Meaning,
2950    ) -> Option<EngineError> {
2951        let value = create_value(1, 1).with_meaning(lhs);
2952        let result = value.apply_meaning(rhs);
2953        result.err().and_then(get_engine_error)
2954    }
2955
2956    fn perform_unary_ok(
2957        function: fn(ValueRef) -> MyResult<ValueRef>,
2958        meaning: Meaning,
2959    ) -> Option<Meaning> {
2960        let value = create_value(1, 1).with_meaning(meaning);
2961        let value = Rc::new(RefCell::new(value));
2962        let result = function(value);
2963        result.ok().map(get_meaning_only)
2964    }
2965
2966    fn perform_unary_err(
2967        function: fn(ValueRef) -> MyResult<ValueRef>,
2968        meaning: Meaning,
2969    ) -> Option<EngineError> {
2970        let value = create_value(1, 1).with_meaning(meaning);
2971        let value = Rc::new(RefCell::new(value));
2972        let result = function(value);
2973        result.err().and_then(get_engine_error)
2974    }
2975
2976    fn perform_binary_ok(
2977        function: fn(ValueRef, ValueRef) -> MyResult<ValueRef>,
2978        lhs: Meaning,
2979        rhs: Meaning,
2980    ) -> Option<Meaning> {
2981        let lhs = create_value(1, 1).with_meaning(lhs);
2982        let rhs = create_value(1, 1).with_meaning(rhs);
2983        let lhs = Rc::new(RefCell::new(lhs));
2984        let rhs = Rc::new(RefCell::new(rhs));
2985        let result = function(lhs, rhs);
2986        result.ok().map(get_meaning_only)
2987    }
2988
2989    fn perform_binary_value(
2990        function: fn(ValueRef, ValueRef) -> MyResult<ValueRef>,
2991        lhs: Meaning,
2992        rhs: Meaning,
2993    ) -> Option<(Meaning, String)> {
2994        let lhs = create_value(1, 1).with_meaning(lhs);
2995        let rhs = create_value(1, 1).with_meaning(rhs);
2996        let lhs = Rc::new(RefCell::new(lhs));
2997        let rhs = Rc::new(RefCell::new(rhs));
2998        let result = function(lhs, rhs);
2999        result.ok().map(get_meaning_value)
3000    }
3001
3002    fn perform_binary_err(
3003        function: fn(ValueRef, ValueRef) -> MyResult<ValueRef>,
3004        lhs: Meaning,
3005        rhs: Meaning,
3006    ) -> Option<EngineError> {
3007        let lhs = create_value(1, 1).with_meaning(lhs);
3008        let rhs = create_value(1, 1).with_meaning(rhs);
3009        let lhs = Rc::new(RefCell::new(lhs));
3010        let rhs = Rc::new(RefCell::new(rhs));
3011        let result = function(lhs, rhs);
3012        result.err().and_then(get_engine_error)
3013    }
3014
3015    fn get_meaning_only(value: ValueRef) -> Meaning {
3016        value.borrow().meaning
3017    }
3018
3019    fn get_meaning_value(value: ValueRef) -> (Meaning, String) {
3020        let context = Context::new().with_dp(Some(9));
3021        let (integer, fraction, _, _, _) = value.borrow().to_strings(&context);
3022        let fraction = truncate_fraction(fraction);
3023        (value.borrow().meaning, format!("{}{}", integer, fraction))
3024    }
3025
3026    fn get_engine_error(error: MyError) -> Option<EngineError> {
3027        match error {
3028            MyError::Engine(error) => Some(error),
3029            _ => None,
3030        }
3031    }
3032
3033    #[test]
3034    fn test_fraction_is_truncated() {
3035        assert_eq!(truncate_fraction(String::from(".000")), String::from(".000"));
3036        assert_eq!(truncate_fraction(String::from(".010")), String::from(".010"));
3037        assert_eq!(truncate_fraction(String::from(".012")), String::from(".012"));
3038        assert_eq!(truncate_fraction(String::from(".000000000")), String::from(".0"));
3039        assert_eq!(truncate_fraction(String::from(".010000000")), String::from(".01"));
3040        assert_eq!(truncate_fraction(String::from(".012000000")), String::from(".012"));
3041        assert_eq!(truncate_fraction(String::from(".012300000")), String::from(".0123"));
3042        assert_eq!(truncate_fraction(String::from(".012340000")), String::from(".01234"));
3043        assert_eq!(truncate_fraction(String::from(".012345000")), String::from(".012345"));
3044        assert_eq!(truncate_fraction(String::from(".012345600")), String::from(".0123456"));
3045        assert_eq!(truncate_fraction(String::from(".012345670")), String::from(".01234567"));
3046        assert_eq!(truncate_fraction(String::from(".012345678")), String::from(".012345678"));
3047    }
3048
3049    fn truncate_fraction(fraction: String) -> String {
3050        let regex = regex!(r"^\.([0-9]*[1-9]|0+?)0+$");
3051        if fraction.len() > 4 {
3052            regex.replace(&fraction, ".$1").to_string()
3053        } else {
3054            fraction
3055        }
3056    }
3057}