1 use std::cmp::Ordering; 2 use std::{collections::HashMap, fmt, io}; 3 4 use crate::interrupt::test_int; 5 use crate::num::complex::{self, Complex, UseParentheses}; 6 use crate::num::{Base, Exact, FormattingStyle}; 7 use crate::result::FResult; 8 use crate::Interrupt; 9 10 use super::{base_unit::BaseUnit, named_unit::NamedUnit}; 11 12 #[derive(Clone)] 13 pub(crate) struct UnitExponent { 14 pub(crate) unit: NamedUnit, 15 pub(crate) exponent: Complex, 16 } 17 18 impl UnitExponent { new(unit: NamedUnit, exponent: impl Into<Complex>) -> Self19 pub(crate) fn new(unit: NamedUnit, exponent: impl Into<Complex>) -> Self { 20 Self { 21 unit, 22 exponent: exponent.into(), 23 } 24 } 25 serialize(&self, write: &mut impl io::Write) -> FResult<()>26 pub(crate) fn serialize(&self, write: &mut impl io::Write) -> FResult<()> { 27 self.unit.serialize(write)?; 28 self.exponent.serialize(write)?; 29 Ok(()) 30 } 31 deserialize(read: &mut impl io::Read) -> FResult<Self>32 pub(crate) fn deserialize(read: &mut impl io::Read) -> FResult<Self> { 33 Ok(Self { 34 unit: NamedUnit::deserialize(read)?, 35 exponent: Complex::deserialize(read)?, 36 }) 37 } 38 is_alias(&self) -> bool39 pub(crate) fn is_alias(&self) -> bool { 40 self.unit.is_alias() 41 } 42 add_to_hashmap<I: Interrupt>( &self, hashmap: &mut HashMap<BaseUnit, Complex>, scale: &mut Complex, exact: &mut bool, int: &I, ) -> FResult<()>43 pub(crate) fn add_to_hashmap<I: Interrupt>( 44 &self, 45 hashmap: &mut HashMap<BaseUnit, Complex>, 46 scale: &mut Complex, 47 exact: &mut bool, 48 int: &I, 49 ) -> FResult<()> { 50 test_int(int)?; 51 let overall_exp = &Exact::new(self.exponent.clone(), true); 52 for (base_unit, base_exp) in &self.unit.base_units { 53 test_int(int)?; 54 let base_exp = Exact::new(base_exp.clone(), true); 55 let product = overall_exp.clone().mul(&base_exp, int)?; 56 if let Some(exp) = hashmap.get_mut(base_unit) { 57 let new_exp = Exact::new(exp.clone(), true).add(product, int)?; 58 *exact = *exact && new_exp.exact; 59 if new_exp.value.compare(&0.into(), int)? == Some(Ordering::Equal) { 60 hashmap.remove(base_unit); 61 } else { 62 *exp = new_exp.value; 63 } 64 } else { 65 *exact = *exact && product.exact; 66 if product.value.compare(&0.into(), int)? != Some(Ordering::Equal) { 67 let adj_exp = overall_exp.clone().mul(&base_exp, int)?; 68 hashmap.insert(base_unit.clone(), adj_exp.value); 69 *exact = *exact && adj_exp.exact; 70 } 71 } 72 } 73 let pow_result = self 74 .unit 75 .scale 76 .clone() 77 .pow(overall_exp.value.clone(), int)?; 78 *scale = Exact::new(scale.clone(), true).mul(&pow_result, int)?.value; 79 *exact = *exact && pow_result.exact; 80 Ok(()) 81 } 82 format<I: Interrupt>( &self, base: Base, format: FormattingStyle, plural: bool, invert_exp: bool, int: &I, ) -> FResult<Exact<FormattedExponent<'_>>>83 pub(crate) fn format<I: Interrupt>( 84 &self, 85 base: Base, 86 format: FormattingStyle, 87 plural: bool, 88 invert_exp: bool, 89 int: &I, 90 ) -> FResult<Exact<FormattedExponent<'_>>> { 91 let (prefix, name) = self.unit.prefix_and_name(plural); 92 let exp = if invert_exp { 93 -self.exponent.clone() 94 } else { 95 self.exponent.clone() 96 }; 97 let (exact, exponent) = if exp.compare(&1.into(), int)? == Some(Ordering::Equal) { 98 (true, None) 99 } else { 100 let formatted = 101 exp.format(true, format, base, UseParentheses::IfComplexOrFraction, int)?; 102 (formatted.exact, Some(formatted.value)) 103 }; 104 Ok(Exact::new( 105 FormattedExponent { 106 prefix, 107 name, 108 number: exponent, 109 }, 110 exact, 111 )) 112 } 113 } 114 115 impl fmt::Debug for UnitExponent { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result116 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 117 write!(f, "{:?}", self.unit)?; 118 if !self.exponent.is_definitely_one() { 119 write!(f, "^{:?}", self.exponent)?; 120 } 121 Ok(()) 122 } 123 } 124 125 #[derive(Debug)] 126 pub(crate) struct FormattedExponent<'a> { 127 prefix: &'a str, 128 name: &'a str, 129 number: Option<complex::Formatted>, 130 } 131 132 impl<'a> fmt::Display for FormattedExponent<'a> { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result133 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 134 write!(f, "{}{}", self.prefix, self.name)?; 135 if let Some(number) = &self.number { 136 write!(f, "^{number}")?; 137 } 138 Ok(()) 139 } 140 } 141