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