xref: /aosp_15_r20/external/cronet/third_party/rust/chromium_crates_io/vendor/fend-core-1.4.6/src/num/unit.rs (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 use crate::ast::{BitwiseBop, Bop};
2 use crate::error::{FendError, Interrupt};
3 use crate::num::complex::{Complex, UseParentheses};
4 use crate::num::dist::Dist;
5 use crate::num::{Base, FormattingStyle};
6 use crate::result::FResult;
7 use crate::scope::Scope;
8 use crate::serialize::{Deserialize, Serialize};
9 use crate::units::{lookup_default_unit, query_unit_static};
10 use crate::{ast, ident::Ident};
11 use crate::{Attrs, Span, SpanKind};
12 use std::borrow::Cow;
13 use std::cmp::Ordering;
14 use std::collections::HashMap;
15 use std::ops::Neg;
16 use std::sync::Arc;
17 use std::{cmp, fmt, io};
18 
19 pub(crate) mod base_unit;
20 pub(crate) mod named_unit;
21 pub(crate) mod unit_exponent;
22 
23 use base_unit::BaseUnit;
24 use named_unit::NamedUnit;
25 use unit_exponent::UnitExponent;
26 
27 use self::named_unit::compare_hashmaps;
28 
29 use super::Exact;
30 
31 #[derive(Clone)]
32 #[allow(clippy::pedantic)]
33 pub(crate) struct Value {
34 	#[allow(clippy::struct_field_names)]
35 	value: Dist,
36 	unit: Unit,
37 	exact: bool,
38 	base: Base,
39 	format: FormattingStyle,
40 	simplifiable: bool,
41 }
42 
43 impl Value {
compare<I: Interrupt>( &self, other: &Self, int: &I, ) -> FResult<Option<cmp::Ordering>>44 	pub(crate) fn compare<I: Interrupt>(
45 		&self,
46 		other: &Self,
47 		int: &I,
48 	) -> FResult<Option<cmp::Ordering>> {
49 		match self.clone().sub(other.clone(), int) {
50 			Err(FendError::Interrupted) => Err(FendError::Interrupted),
51 			Err(_) => Ok(None),
52 			Ok(result) => {
53 				if result.is_zero(int)? {
54 					return Ok(Some(cmp::Ordering::Equal));
55 				}
56 				let Ok(c) = result.value.one_point() else {
57 					return Ok(None);
58 				};
59 				c.compare(&0.into(), int)
60 			}
61 		}
62 	}
63 
serialize(&self, write: &mut impl io::Write) -> FResult<()>64 	pub(crate) fn serialize(&self, write: &mut impl io::Write) -> FResult<()> {
65 		self.value.serialize(write)?;
66 		self.unit.serialize(write)?;
67 		self.exact.serialize(write)?;
68 		self.base.serialize(write)?;
69 		self.format.serialize(write)?;
70 		self.simplifiable.serialize(write)?;
71 		Ok(())
72 	}
73 
deserialize(read: &mut impl io::Read) -> FResult<Self>74 	pub(crate) fn deserialize(read: &mut impl io::Read) -> FResult<Self> {
75 		Ok(Self {
76 			value: Dist::deserialize(read)?,
77 			unit: Unit::deserialize(read)?,
78 			exact: bool::deserialize(read)?,
79 			base: Base::deserialize(read)?,
80 			format: FormattingStyle::deserialize(read)?,
81 			simplifiable: bool::deserialize(read)?,
82 		})
83 	}
84 
try_as_usize<I: Interrupt>(self, int: &I) -> FResult<usize>85 	pub(crate) fn try_as_usize<I: Interrupt>(self, int: &I) -> FResult<usize> {
86 		if !self.is_unitless(int)? {
87 			return Err(FendError::NumberWithUnitToInt);
88 		}
89 		self.try_as_usize_unit(int)
90 	}
91 
try_as_usize_unit<I: Interrupt>(self, int: &I) -> FResult<usize>92 	pub(crate) fn try_as_usize_unit<I: Interrupt>(self, int: &I) -> FResult<usize> {
93 		if !self.exact {
94 			return Err(FendError::InexactNumberToInt);
95 		}
96 		self.value.one_point()?.try_as_usize(int)
97 	}
98 
create_unit_value_from_value<I: Interrupt>( value: &Self, prefix: Cow<'static, str>, alias: bool, singular_name: Cow<'static, str>, plural_name: Cow<'static, str>, int: &I, ) -> FResult<Self>99 	pub(crate) fn create_unit_value_from_value<I: Interrupt>(
100 		value: &Self,
101 		prefix: Cow<'static, str>,
102 		alias: bool,
103 		singular_name: Cow<'static, str>,
104 		plural_name: Cow<'static, str>,
105 		int: &I,
106 	) -> FResult<Self> {
107 		let (hashmap, scale) = value.unit.to_hashmap_and_scale(int)?;
108 		let scale = scale.mul(&Exact::new(value.value.one_point_ref()?.clone(), true), int)?;
109 		let resulting_unit = NamedUnit::new(
110 			prefix,
111 			singular_name,
112 			plural_name,
113 			alias,
114 			hashmap,
115 			scale.value,
116 		);
117 		let mut result = Self::new(1, vec![UnitExponent::new(resulting_unit, 1)]);
118 		result.exact = result.exact && value.exact && scale.exact;
119 		Ok(result)
120 	}
121 
new_base_unit( singular_name: Cow<'static, str>, plural_name: Cow<'static, str>, ) -> Self122 	pub(crate) fn new_base_unit(
123 		singular_name: Cow<'static, str>,
124 		plural_name: Cow<'static, str>,
125 	) -> Self {
126 		let base_unit = BaseUnit::new(singular_name.clone());
127 		let mut hashmap = HashMap::new();
128 		hashmap.insert(base_unit, 1.into());
129 		let unit = NamedUnit::new(
130 			Cow::Borrowed(""),
131 			singular_name,
132 			plural_name,
133 			false,
134 			hashmap,
135 			1,
136 		);
137 		Self::new(1, vec![UnitExponent::new(unit, 1)])
138 	}
139 
with_format(self, format: FormattingStyle) -> Self140 	pub(crate) fn with_format(self, format: FormattingStyle) -> Self {
141 		Self {
142 			value: self.value,
143 			unit: self.unit,
144 			exact: self.exact,
145 			base: self.base,
146 			simplifiable: self.simplifiable,
147 			format,
148 		}
149 	}
150 
with_base(self, base: Base) -> Self151 	pub(crate) fn with_base(self, base: Base) -> Self {
152 		Self {
153 			value: self.value,
154 			unit: self.unit,
155 			exact: self.exact,
156 			format: self.format,
157 			simplifiable: self.simplifiable,
158 			base,
159 		}
160 	}
161 
factorial<I: Interrupt>(self, int: &I) -> FResult<Self>162 	pub(crate) fn factorial<I: Interrupt>(self, int: &I) -> FResult<Self> {
163 		if !self.is_unitless(int)? {
164 			return Err(FendError::FactorialUnitless);
165 		}
166 		Ok(Self {
167 			value: Dist::from(self.value.one_point()?.factorial(int)?),
168 			unit: self.unit,
169 			exact: self.exact,
170 			base: self.base,
171 			format: self.format,
172 			simplifiable: self.simplifiable,
173 		})
174 	}
175 
new(value: impl Into<Dist>, unit_components: Vec<UnitExponent>) -> Self176 	fn new(value: impl Into<Dist>, unit_components: Vec<UnitExponent>) -> Self {
177 		Self {
178 			value: value.into(),
179 			unit: Unit {
180 				components: unit_components,
181 			},
182 			exact: true,
183 			base: Base::default(),
184 			format: FormattingStyle::default(),
185 			simplifiable: true,
186 		}
187 	}
188 
add<I: Interrupt>(self, rhs: Self, int: &I) -> FResult<Self>189 	pub(crate) fn add<I: Interrupt>(self, rhs: Self, int: &I) -> FResult<Self> {
190 		let scale_factor = Unit::compute_scale_factor(&rhs.unit, &self.unit, int)?;
191 		let scaled = Exact::new(rhs.value, rhs.exact)
192 			.mul(&scale_factor.scale_1.apply(Dist::from), int)?
193 			.div(&scale_factor.scale_2.apply(Dist::from), int)?;
194 		let value =
195 			Exact::new(self.value, self.exact).add(&Exact::new(scaled.value, scaled.exact), int)?;
196 		Ok(Self {
197 			value: value.value,
198 			unit: self.unit,
199 			exact: self.exact && rhs.exact && value.exact,
200 			base: self.base,
201 			format: self.format,
202 			simplifiable: self.simplifiable,
203 		})
204 	}
205 
206 	/// Called for implicit addition to modify the second operand.
207 	/// For example, when evaluating `5'0`, this function can change the second
208 	/// operand's unit from `unitless` to `"`.
fudge_implicit_rhs_unit<I: Interrupt>( &self, rhs: Self, attrs: Attrs, context: &mut crate::Context, int: &I, ) -> FResult<Self>209 	fn fudge_implicit_rhs_unit<I: Interrupt>(
210 		&self,
211 		rhs: Self,
212 		attrs: Attrs,
213 		context: &mut crate::Context,
214 		int: &I,
215 	) -> FResult<Self> {
216 		for (lhs_unit, rhs_unit) in crate::units::IMPLICIT_UNIT_MAP {
217 			if self.unit.equal_to(lhs_unit, int)? && rhs.is_unitless(int)? {
218 				let inches =
219 					ast::resolve_identifier(&Ident::new_str(rhs_unit), None, attrs, context, int)?
220 						.expect_num()?;
221 				return rhs.mul(inches, int);
222 			}
223 		}
224 		Ok(rhs)
225 	}
226 
convert_to<I: Interrupt>(self, rhs: Self, int: &I) -> FResult<Self>227 	pub(crate) fn convert_to<I: Interrupt>(self, rhs: Self, int: &I) -> FResult<Self> {
228 		if rhs.value.one_point()?.compare(&1.into(), int)? != Some(Ordering::Equal) {
229 			return Err(FendError::ConversionRhsNumerical);
230 		}
231 		let scale_factor = Unit::compute_scale_factor(&self.unit, &rhs.unit, int)?;
232 		let new_value = Exact::new(self.value, self.exact)
233 			.mul(&scale_factor.scale_1.apply(Dist::from), int)?
234 			.add(&scale_factor.offset.apply(Dist::from), int)?
235 			.div(&scale_factor.scale_2.apply(Dist::from), int)?;
236 		Ok(Self {
237 			value: new_value.value,
238 			unit: rhs.unit,
239 			exact: self.exact && rhs.exact && new_value.exact,
240 			base: self.base,
241 			format: self.format,
242 			simplifiable: false,
243 		})
244 	}
245 
sub<I: Interrupt>(self, rhs: Self, int: &I) -> FResult<Self>246 	pub(crate) fn sub<I: Interrupt>(self, rhs: Self, int: &I) -> FResult<Self> {
247 		let scale_factor = Unit::compute_scale_factor(&rhs.unit, &self.unit, int)?;
248 		let scaled = Exact::new(rhs.value, rhs.exact)
249 			.mul(&scale_factor.scale_1.apply(Dist::from), int)?
250 			.div(&scale_factor.scale_2.apply(Dist::from), int)?;
251 		let value = Exact::new(self.value, self.exact).add(&-scaled, int)?;
252 		Ok(Self {
253 			value: value.value,
254 			unit: self.unit,
255 			exact: self.exact && rhs.exact && value.exact,
256 			base: self.base,
257 			format: self.format,
258 			simplifiable: self.simplifiable,
259 		})
260 	}
261 
div<I: Interrupt>(self, rhs: Self, int: &I) -> FResult<Self>262 	pub(crate) fn div<I: Interrupt>(self, rhs: Self, int: &I) -> FResult<Self> {
263 		let mut components = self.unit.components.clone();
264 		for rhs_component in rhs.unit.components {
265 			components.push(UnitExponent::new(
266 				rhs_component.unit,
267 				-rhs_component.exponent,
268 			));
269 		}
270 		let value =
271 			Exact::new(self.value, self.exact).div(&Exact::new(rhs.value, rhs.exact), int)?;
272 		Ok(Self {
273 			value: value.value,
274 			unit: Unit { components },
275 			exact: value.exact && self.exact && rhs.exact,
276 			base: self.base,
277 			format: self.format,
278 			simplifiable: self.simplifiable,
279 		})
280 	}
281 
modulo<I: Interrupt>(self, rhs: Self, int: &I) -> FResult<Self>282 	fn modulo<I: Interrupt>(self, rhs: Self, int: &I) -> FResult<Self> {
283 		if !self.is_unitless(int)? || !rhs.is_unitless(int)? {
284 			return Err(FendError::ModuloUnitless);
285 		}
286 		Ok(Self {
287 			value: Dist::from(
288 				self.value
289 					.one_point()?
290 					.modulo(rhs.value.one_point()?, int)?,
291 			),
292 			unit: self.unit,
293 			exact: self.exact && rhs.exact,
294 			base: self.base,
295 			format: self.format,
296 			simplifiable: self.simplifiable,
297 		})
298 	}
299 
bitwise<I: Interrupt>(self, rhs: Self, op: BitwiseBop, int: &I) -> FResult<Self>300 	fn bitwise<I: Interrupt>(self, rhs: Self, op: BitwiseBop, int: &I) -> FResult<Self> {
301 		if !self.is_unitless(int)? || !rhs.is_unitless(int)? {
302 			return Err(FendError::ExpectedAUnitlessNumber);
303 		}
304 		Ok(Self {
305 			value: Dist::from(
306 				self.value
307 					.one_point()?
308 					.bitwise(rhs.value.one_point()?, op, int)?,
309 			),
310 			unit: self.unit,
311 			exact: self.exact && rhs.exact,
312 			base: self.base,
313 			format: self.format,
314 			simplifiable: self.simplifiable,
315 		})
316 	}
317 
combination<I: Interrupt>(self, rhs: Self, int: &I) -> FResult<Self>318 	pub(crate) fn combination<I: Interrupt>(self, rhs: Self, int: &I) -> FResult<Self> {
319 		if !self.is_unitless(int)? || !rhs.is_unitless(int)? {
320 			return Err(FendError::ExpectedAUnitlessNumber);
321 		}
322 		Ok(Self {
323 			value: Dist::from(
324 				self.value
325 					.one_point()?
326 					.combination(rhs.value.one_point()?, int)?,
327 			),
328 			unit: self.unit,
329 			exact: self.exact && rhs.exact,
330 			base: self.base,
331 			format: self.format,
332 			simplifiable: self.simplifiable,
333 		})
334 	}
335 
permutation<I: Interrupt>(self, rhs: Self, int: &I) -> FResult<Self>336 	pub(crate) fn permutation<I: Interrupt>(self, rhs: Self, int: &I) -> FResult<Self> {
337 		if !self.is_unitless(int)? || !rhs.is_unitless(int)? {
338 			return Err(FendError::ExpectedAUnitlessNumber);
339 		}
340 		Ok(Self {
341 			value: Dist::from(
342 				self.value
343 					.one_point()?
344 					.permutation(rhs.value.one_point()?, int)?,
345 			),
346 			unit: self.unit,
347 			exact: self.exact && rhs.exact,
348 			base: self.base,
349 			format: self.format,
350 			simplifiable: self.simplifiable,
351 		})
352 	}
353 
bop<I: Interrupt>( self, op: Bop, rhs: Self, attrs: Attrs, context: &mut crate::Context, int: &I, ) -> FResult<Self>354 	pub(crate) fn bop<I: Interrupt>(
355 		self,
356 		op: Bop,
357 		rhs: Self,
358 		attrs: Attrs,
359 		context: &mut crate::Context,
360 		int: &I,
361 	) -> FResult<Self> {
362 		match op {
363 			Bop::Plus => self.add(rhs, int),
364 			Bop::ImplicitPlus => {
365 				let rhs = self.fudge_implicit_rhs_unit(rhs, attrs, context, int)?;
366 				self.add(rhs, int)
367 			}
368 			Bop::Minus => self.sub(rhs, int),
369 			Bop::Mul => self.mul(rhs, int),
370 			Bop::Div => self.div(rhs, int),
371 			Bop::Mod => self.modulo(rhs, int),
372 			Bop::Pow => self.pow(rhs, int),
373 			Bop::Bitwise(bitwise_bop) => self.bitwise(rhs, bitwise_bop, int),
374 			Bop::Combination => self.combination(rhs, int),
375 			Bop::Permutation => self.permutation(rhs, int),
376 		}
377 	}
378 
is_unitless<I: Interrupt>(&self, int: &I) -> FResult<bool>379 	pub(crate) fn is_unitless<I: Interrupt>(&self, int: &I) -> FResult<bool> {
380 		// todo this is broken for unitless components
381 		if self.unit.components.is_empty() {
382 			return Ok(true);
383 		}
384 		let (hashmap, _scale) = self.unit.to_hashmap_and_scale(int)?;
385 		if hashmap.is_empty() {
386 			return Ok(true);
387 		}
388 		Ok(false)
389 	}
390 
is_unitless_one<I: Interrupt>(&self, int: &I) -> FResult<bool>391 	pub(crate) fn is_unitless_one<I: Interrupt>(&self, int: &I) -> FResult<bool> {
392 		Ok(self.exact && self.value.equals_int(1, int)? && self.is_unitless(int)?)
393 	}
394 
pow<I: Interrupt>(self, rhs: Self, int: &I) -> FResult<Self>395 	pub(crate) fn pow<I: Interrupt>(self, rhs: Self, int: &I) -> FResult<Self> {
396 		if !rhs.is_unitless(int)? {
397 			return Err(FendError::ExpUnitless);
398 		}
399 		let mut new_components = vec![];
400 		let mut exact_res = true;
401 		for unit_exp in self.unit.components {
402 			let exponent = Exact::new(unit_exp.exponent, self.exact)
403 				.mul(&Exact::new(rhs.value.clone().one_point()?, rhs.exact), int)?;
404 			exact_res = exact_res && exponent.exact;
405 			new_components.push(UnitExponent {
406 				unit: unit_exp.unit,
407 				exponent: exponent.value,
408 			});
409 		}
410 		let new_unit = Unit {
411 			components: new_components,
412 		};
413 		let value = self.value.one_point()?.pow(rhs.value.one_point()?, int)?;
414 		Ok(Self {
415 			value: value.value.into(),
416 			unit: new_unit,
417 			exact: self.exact && rhs.exact && exact_res && value.exact,
418 			base: self.base,
419 			format: self.format,
420 			simplifiable: self.simplifiable,
421 		})
422 	}
423 
i() -> Self424 	pub(crate) fn i() -> Self {
425 		Self {
426 			value: Complex::i().into(),
427 			unit: Unit { components: vec![] },
428 			exact: true,
429 			base: Base::default(),
430 			format: FormattingStyle::default(),
431 			simplifiable: true,
432 		}
433 	}
434 
pi() -> Self435 	pub(crate) fn pi() -> Self {
436 		Self {
437 			value: Complex::pi().into(),
438 			unit: Unit { components: vec![] },
439 			exact: true,
440 			base: Base::default(),
441 			format: FormattingStyle::default(),
442 			simplifiable: true,
443 		}
444 	}
445 
abs<I: Interrupt>(self, int: &I) -> FResult<Self>446 	pub(crate) fn abs<I: Interrupt>(self, int: &I) -> FResult<Self> {
447 		let value = self.value.one_point()?.abs(int)?;
448 		Ok(Self {
449 			value: Complex::from(value.value).into(),
450 			unit: self.unit,
451 			exact: self.exact && value.exact,
452 			base: self.base,
453 			format: self.format,
454 			simplifiable: self.simplifiable,
455 		})
456 	}
457 
make_approximate(self) -> Self458 	pub(crate) fn make_approximate(self) -> Self {
459 		Self {
460 			value: self.value,
461 			unit: self.unit,
462 			exact: false,
463 			base: self.base,
464 			format: self.format,
465 			simplifiable: self.simplifiable,
466 		}
467 	}
468 
zero_with_base(base: Base) -> Self469 	pub(crate) fn zero_with_base(base: Base) -> Self {
470 		Self {
471 			value: Dist::from(0),
472 			unit: Unit::unitless(),
473 			exact: true,
474 			base,
475 			format: FormattingStyle::default(),
476 			simplifiable: true,
477 		}
478 	}
479 
is_zero<I: Interrupt>(&self, int: &I) -> FResult<bool>480 	pub(crate) fn is_zero<I: Interrupt>(&self, int: &I) -> FResult<bool> {
481 		self.value.equals_int(0, int)
482 	}
483 
new_die<I: Interrupt>(count: u32, faces: u32, int: &I) -> FResult<Self>484 	pub(crate) fn new_die<I: Interrupt>(count: u32, faces: u32, int: &I) -> FResult<Self> {
485 		Ok(Self::new(Dist::new_die(count, faces, int)?, vec![]))
486 	}
487 
remove_unit_scaling<I: Interrupt>(self, int: &I) -> FResult<Self>488 	fn remove_unit_scaling<I: Interrupt>(self, int: &I) -> FResult<Self> {
489 		self.convert_to(Self::unitless(), int)
490 	}
491 
apply_fn_exact<I: Interrupt>( mut self, f: impl FnOnce(Complex, &I) -> FResult<Exact<Complex>>, require_unitless: bool, int: &I, ) -> FResult<Self>492 	fn apply_fn_exact<I: Interrupt>(
493 		mut self,
494 		f: impl FnOnce(Complex, &I) -> FResult<Exact<Complex>>,
495 		require_unitless: bool,
496 		int: &I,
497 	) -> FResult<Self> {
498 		self = self.remove_unit_scaling(int)?;
499 		if require_unitless && !self.is_unitless(int)? {
500 			return Err(FendError::ExpectedAUnitlessNumber);
501 		}
502 		let exact = f(self.value.one_point()?, int)?;
503 		Ok(Self {
504 			value: exact.value.into(),
505 			unit: self.unit,
506 			exact: self.exact && exact.exact,
507 			base: self.base,
508 			format: self.format,
509 			simplifiable: self.simplifiable,
510 		})
511 	}
512 
apply_fn<I: Interrupt>( mut self, f: impl FnOnce(Complex, &I) -> FResult<Complex>, require_unitless: bool, int: &I, ) -> FResult<Self>513 	fn apply_fn<I: Interrupt>(
514 		mut self,
515 		f: impl FnOnce(Complex, &I) -> FResult<Complex>,
516 		require_unitless: bool,
517 		int: &I,
518 	) -> FResult<Self> {
519 		self = self.remove_unit_scaling(int)?;
520 		if require_unitless && !self.is_unitless(int)? {
521 			return Err(FendError::ExpectedAUnitlessNumber);
522 		}
523 		Ok(Self {
524 			value: f(self.value.one_point()?, int)?.into(),
525 			unit: self.unit,
526 			exact: false,
527 			base: self.base,
528 			format: self.format,
529 			simplifiable: self.simplifiable,
530 		})
531 	}
532 
sample<I: Interrupt>(self, ctx: &crate::Context, int: &I) -> FResult<Self>533 	pub(crate) fn sample<I: Interrupt>(self, ctx: &crate::Context, int: &I) -> FResult<Self> {
534 		Ok(Self {
535 			value: self.value.sample(ctx, int)?,
536 			..self
537 		})
538 	}
539 
mean<I: Interrupt>(self, int: &I) -> FResult<Self>540 	pub(crate) fn mean<I: Interrupt>(self, int: &I) -> FResult<Self> {
541 		Ok(Self {
542 			value: self.value.mean(int)?,
543 			..self
544 		})
545 	}
546 
convert_angle_to_rad<I: Interrupt>( self, scope: Option<Arc<Scope>>, attrs: Attrs, context: &mut crate::Context, int: &I, ) -> FResult<Self>547 	fn convert_angle_to_rad<I: Interrupt>(
548 		self,
549 		scope: Option<Arc<Scope>>,
550 		attrs: Attrs,
551 		context: &mut crate::Context,
552 		int: &I,
553 	) -> FResult<Self> {
554 		let radians =
555 			ast::resolve_identifier(&Ident::new_str("radians"), scope, attrs, context, int)?
556 				.expect_num()?;
557 		self.convert_to(radians, int)
558 	}
559 
unitless() -> Self560 	fn unitless() -> Self {
561 		Self {
562 			value: 1.into(),
563 			unit: Unit::unitless(),
564 			exact: true,
565 			base: Base::default(),
566 			format: FormattingStyle::default(),
567 			simplifiable: true,
568 		}
569 	}
570 
floor<I: Interrupt>(self, int: &I) -> FResult<Self>571 	pub(crate) fn floor<I: Interrupt>(self, int: &I) -> FResult<Self> {
572 		let value = self.value.one_point()?.floor(int)?;
573 		Ok(Self {
574 			value: Complex::from(value.value).into(),
575 			unit: self.unit,
576 			exact: self.exact && value.exact,
577 			base: self.base,
578 			format: self.format,
579 			simplifiable: self.simplifiable,
580 		})
581 	}
582 
ceil<I: Interrupt>(self, int: &I) -> FResult<Self>583 	pub(crate) fn ceil<I: Interrupt>(self, int: &I) -> FResult<Self> {
584 		let value = self.value.one_point()?.ceil(int)?;
585 		Ok(Self {
586 			value: Complex::from(value.value).into(),
587 			unit: self.unit,
588 			exact: self.exact && value.exact,
589 			base: self.base,
590 			format: self.format,
591 			simplifiable: self.simplifiable,
592 		})
593 	}
594 
round<I: Interrupt>(self, int: &I) -> FResult<Self>595 	pub(crate) fn round<I: Interrupt>(self, int: &I) -> FResult<Self> {
596 		let value = self.value.one_point()?.round(int)?;
597 		Ok(Self {
598 			value: Complex::from(value.value).into(),
599 			unit: self.unit,
600 			exact: self.exact && value.exact,
601 			base: self.base,
602 			format: self.format,
603 			simplifiable: self.simplifiable,
604 		})
605 	}
606 
real(self) -> FResult<Self>607 	pub(crate) fn real(self) -> FResult<Self> {
608 		Ok(Self {
609 			value: Complex::from(self.value.one_point()?.real()).into(),
610 			..self
611 		})
612 	}
613 
imag(self) -> FResult<Self>614 	pub(crate) fn imag(self) -> FResult<Self> {
615 		Ok(Self {
616 			value: Complex::from(self.value.one_point()?.imag()).into(),
617 			..self
618 		})
619 	}
620 
arg<I: Interrupt>(self, int: &I) -> FResult<Self>621 	pub(crate) fn arg<I: Interrupt>(self, int: &I) -> FResult<Self> {
622 		self.apply_fn_exact(
623 			|c, int| c.arg(int).map(|c| c.apply(Complex::from)),
624 			false,
625 			int,
626 		)
627 	}
628 
conjugate(self) -> FResult<Self>629 	pub(crate) fn conjugate(self) -> FResult<Self> {
630 		Ok(Self {
631 			value: self.value.one_point()?.conjugate().into(),
632 			..self
633 		})
634 	}
635 
sin<I: Interrupt>( self, scope: Option<Arc<Scope>>, attrs: Attrs, context: &mut crate::Context, int: &I, ) -> FResult<Self>636 	pub(crate) fn sin<I: Interrupt>(
637 		self,
638 		scope: Option<Arc<Scope>>,
639 		attrs: Attrs,
640 		context: &mut crate::Context,
641 		int: &I,
642 	) -> FResult<Self> {
643 		if let Ok(rad) = self
644 			.clone()
645 			.convert_angle_to_rad(scope, attrs, context, int)
646 		{
647 			Ok(rad
648 				.apply_fn_exact(Complex::sin, false, int)?
649 				.convert_to(Self::unitless(), int)?)
650 		} else {
651 			self.apply_fn_exact(Complex::sin, false, int)
652 		}
653 	}
654 
cos<I: Interrupt>( self, scope: Option<Arc<Scope>>, attrs: Attrs, context: &mut crate::Context, int: &I, ) -> FResult<Self>655 	pub(crate) fn cos<I: Interrupt>(
656 		self,
657 		scope: Option<Arc<Scope>>,
658 		attrs: Attrs,
659 		context: &mut crate::Context,
660 		int: &I,
661 	) -> FResult<Self> {
662 		if let Ok(rad) = self
663 			.clone()
664 			.convert_angle_to_rad(scope, attrs, context, int)
665 		{
666 			rad.apply_fn_exact(Complex::cos, false, int)?
667 				.convert_to(Self::unitless(), int)
668 		} else {
669 			self.apply_fn_exact(Complex::cos, false, int)
670 		}
671 	}
672 
tan<I: Interrupt>( self, scope: Option<Arc<Scope>>, attrs: Attrs, context: &mut crate::Context, int: &I, ) -> FResult<Self>673 	pub(crate) fn tan<I: Interrupt>(
674 		self,
675 		scope: Option<Arc<Scope>>,
676 		attrs: Attrs,
677 		context: &mut crate::Context,
678 		int: &I,
679 	) -> FResult<Self> {
680 		if let Ok(rad) = self
681 			.clone()
682 			.convert_angle_to_rad(scope, attrs, context, int)
683 		{
684 			rad.apply_fn_exact(Complex::tan, false, int)?
685 				.convert_to(Self::unitless(), int)
686 		} else {
687 			self.apply_fn_exact(Complex::tan, false, int)
688 		}
689 	}
690 
asin<I: Interrupt>(self, int: &I) -> FResult<Self>691 	pub(crate) fn asin<I: Interrupt>(self, int: &I) -> FResult<Self> {
692 		self.apply_fn(Complex::asin, false, int)
693 	}
694 
acos<I: Interrupt>(self, int: &I) -> FResult<Self>695 	pub(crate) fn acos<I: Interrupt>(self, int: &I) -> FResult<Self> {
696 		self.apply_fn(Complex::acos, false, int)
697 	}
698 
atan<I: Interrupt>(self, int: &I) -> FResult<Self>699 	pub(crate) fn atan<I: Interrupt>(self, int: &I) -> FResult<Self> {
700 		self.apply_fn(Complex::atan, false, int)
701 	}
702 
sinh<I: Interrupt>(self, int: &I) -> FResult<Self>703 	pub(crate) fn sinh<I: Interrupt>(self, int: &I) -> FResult<Self> {
704 		self.apply_fn(Complex::sinh, false, int)
705 	}
706 
cosh<I: Interrupt>(self, int: &I) -> FResult<Self>707 	pub(crate) fn cosh<I: Interrupt>(self, int: &I) -> FResult<Self> {
708 		self.apply_fn(Complex::cosh, false, int)
709 	}
710 
tanh<I: Interrupt>(self, int: &I) -> FResult<Self>711 	pub(crate) fn tanh<I: Interrupt>(self, int: &I) -> FResult<Self> {
712 		self.apply_fn(Complex::tanh, false, int)
713 	}
714 
asinh<I: Interrupt>(self, int: &I) -> FResult<Self>715 	pub(crate) fn asinh<I: Interrupt>(self, int: &I) -> FResult<Self> {
716 		self.apply_fn(Complex::asinh, false, int)
717 	}
718 
acosh<I: Interrupt>(self, int: &I) -> FResult<Self>719 	pub(crate) fn acosh<I: Interrupt>(self, int: &I) -> FResult<Self> {
720 		self.apply_fn(Complex::acosh, false, int)
721 	}
722 
atanh<I: Interrupt>(self, int: &I) -> FResult<Self>723 	pub(crate) fn atanh<I: Interrupt>(self, int: &I) -> FResult<Self> {
724 		self.apply_fn(Complex::atanh, false, int)
725 	}
726 
ln<I: Interrupt>(self, int: &I) -> FResult<Self>727 	pub(crate) fn ln<I: Interrupt>(self, int: &I) -> FResult<Self> {
728 		self.apply_fn_exact(Complex::ln, true, int)
729 	}
730 
log2<I: Interrupt>(self, int: &I) -> FResult<Self>731 	pub(crate) fn log2<I: Interrupt>(self, int: &I) -> FResult<Self> {
732 		self.apply_fn(Complex::log2, true, int)
733 	}
734 
log10<I: Interrupt>(self, int: &I) -> FResult<Self>735 	pub(crate) fn log10<I: Interrupt>(self, int: &I) -> FResult<Self> {
736 		self.apply_fn(Complex::log10, true, int)
737 	}
738 
format<I: Interrupt>( &self, ctx: &crate::Context, int: &I, ) -> FResult<FormattedValue>739 	pub(crate) fn format<I: Interrupt>(
740 		&self,
741 		ctx: &crate::Context,
742 		int: &I,
743 	) -> FResult<FormattedValue> {
744 		let use_parentheses = if self.unit.components.is_empty() {
745 			UseParentheses::No
746 		} else {
747 			UseParentheses::IfComplex
748 		};
749 		let mut formatted_value = String::new();
750 		let mut exact = self
751 			.value
752 			.format(
753 				self.exact,
754 				self.format,
755 				self.base,
756 				use_parentheses,
757 				&mut formatted_value,
758 				ctx,
759 				int,
760 			)?
761 			.exact;
762 		let unit_string = self.unit.format(
763 			"",
764 			self.value.equals_int(1, int)?,
765 			self.base,
766 			self.format,
767 			true,
768 			int,
769 		)?;
770 		exact = exact && unit_string.exact;
771 		Ok(FormattedValue {
772 			number: formatted_value,
773 			exact,
774 			unit_str: unit_string.value,
775 		})
776 	}
777 
mul<I: Interrupt>(self, rhs: Self, int: &I) -> FResult<Self>778 	pub(crate) fn mul<I: Interrupt>(self, rhs: Self, int: &I) -> FResult<Self> {
779 		let components = [self.unit.components, rhs.unit.components].concat();
780 		let value =
781 			Exact::new(self.value, self.exact).mul(&Exact::new(rhs.value, rhs.exact), int)?;
782 		Ok(Self {
783 			value: value.value,
784 			unit: Unit { components },
785 			exact: self.exact && rhs.exact && value.exact,
786 			base: self.base,
787 			format: self.format,
788 			simplifiable: self.simplifiable,
789 		})
790 	}
791 
792 	#[allow(clippy::too_many_lines)]
simplify<I: Interrupt>( self, attrs: Attrs, ctx: &mut crate::Context, int: &I, ) -> FResult<Self>793 	pub(crate) fn simplify<I: Interrupt>(
794 		self,
795 		attrs: Attrs,
796 		ctx: &mut crate::Context,
797 		int: &I,
798 	) -> FResult<Self> {
799 		if !self.simplifiable {
800 			return Ok(self);
801 		}
802 
803 		let mut res_components: Vec<UnitExponent> = vec![];
804 		let mut res_exact = self.exact;
805 		let mut res_value = self.value;
806 
807 		// remove alias units and combine identical or compatible units
808 		// by summing their exponents and potentially adjusting the value
809 		'outer: for comp in self.unit.components {
810 			if comp.is_alias() {
811 				// remove alias units
812 				let adjusted_res = Exact {
813 					value: res_value,
814 					exact: res_exact,
815 				}
816 				.mul(
817 					&comp.unit.scale.pow(comp.exponent, int)?.apply(Dist::from),
818 					int,
819 				)?;
820 				res_value = adjusted_res.value;
821 				res_exact = adjusted_res.exact;
822 				continue;
823 			}
824 			for res_comp in &mut res_components {
825 				if comp.unit.has_no_base_units() && !comp.unit.compare(&res_comp.unit, int)? {
826 					continue;
827 				}
828 				let conversion = Unit::compute_scale_factor(
829 					&Unit {
830 						components: vec![UnitExponent {
831 							unit: comp.unit.clone(),
832 							exponent: 1.into(),
833 						}],
834 					},
835 					&Unit {
836 						components: vec![UnitExponent {
837 							unit: res_comp.unit.clone(),
838 							exponent: 1.into(),
839 						}],
840 					},
841 					int,
842 				);
843 				match conversion {
844 					Ok(scale_factor) => {
845 						if scale_factor.offset.value.compare(&0.into(), int)?
846 							!= Some(Ordering::Equal)
847 						{
848 							// don't merge units that have offsets
849 							break;
850 						}
851 						let scale = scale_factor.scale_1.div(scale_factor.scale_2, int)?;
852 
853 						let lhs = Exact {
854 							value: res_comp.exponent.clone(),
855 							exact: res_exact,
856 						};
857 						let rhs = Exact {
858 							value: comp.exponent.clone(),
859 							exact: res_exact,
860 						};
861 						let sum = lhs.add(rhs, int)?;
862 						res_comp.exponent = sum.value;
863 						res_exact = res_exact && sum.exact && scale.exact;
864 
865 						let scale = scale.value.pow(comp.exponent, int)?;
866 						let adjusted_value = Exact {
867 							value: res_value.one_point()?,
868 							exact: res_exact,
869 						}
870 						.mul(&scale, int)?;
871 						res_value = Dist::from(adjusted_value.value);
872 						res_exact = res_exact && adjusted_value.exact;
873 
874 						continue 'outer;
875 					}
876 					Err(FendError::Interrupted) => return Err(FendError::Interrupted),
877 					Err(_) => (),
878 				};
879 			}
880 			res_components.push(comp.clone());
881 		}
882 
883 		// remove units with exponent == 0
884 		{
885 			let mut res_components2 = Vec::with_capacity(res_components.len());
886 			for c in res_components {
887 				if c.exponent.compare(&0.into(), int)? != Some(Ordering::Equal) {
888 					res_components2.push(c);
889 				}
890 			}
891 			res_components = res_components2;
892 		}
893 		let result = Self {
894 			value: res_value,
895 			unit: Unit {
896 				components: res_components,
897 			},
898 			exact: res_exact,
899 			base: self.base,
900 			format: self.format,
901 			simplifiable: self.simplifiable,
902 		};
903 
904 		if result.unit.components.len() > 1
905 			&& !result
906 				.unit
907 				.components
908 				.iter()
909 				.any(|c| c.unit.singular_name == "rad" || c.unit.singular_name == "radian")
910 		{
911 			// try and replace unit with a default one, e.g. `kilogram` or `ampere`
912 			let (hashmap, _) = result.unit.to_hashmap_and_scale(int)?;
913 			if let Ok(mut base_units) = hashmap
914 				.into_iter()
915 				.map(|(k, v)| v.try_as_i64(int).map(|v| format!("{}^{v}", k.name())))
916 				.collect::<Result<Vec<String>, _>>()
917 			{
918 				base_units.sort();
919 				if let Some(new_unit) = lookup_default_unit(&base_units.join(" ")) {
920 					let rhs = query_unit_static(new_unit, attrs, ctx, int)?.expect_num()?;
921 					return result.convert_to(rhs, int);
922 				}
923 			}
924 		}
925 
926 		Ok(result)
927 	}
928 
unit_equal_to<I: Interrupt>(&self, rhs: &str, int: &I) -> FResult<bool>929 	pub(crate) fn unit_equal_to<I: Interrupt>(&self, rhs: &str, int: &I) -> FResult<bool> {
930 		self.unit.equal_to(rhs, int)
931 	}
932 }
933 
934 impl Neg for Value {
935 	type Output = Self;
neg(self) -> Self936 	fn neg(self) -> Self {
937 		Self {
938 			value: -self.value,
939 			unit: self.unit,
940 			exact: self.exact,
941 			base: self.base,
942 			format: self.format,
943 			simplifiable: self.simplifiable,
944 		}
945 	}
946 }
947 
948 impl From<u64> for Value {
from(i: u64) -> Self949 	fn from(i: u64) -> Self {
950 		Self {
951 			value: i.into(),
952 			unit: Unit::unitless(),
953 			exact: true,
954 			base: Base::default(),
955 			format: FormattingStyle::default(),
956 			simplifiable: true,
957 		}
958 	}
959 }
960 
961 impl fmt::Debug for Value {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result962 	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
963 		if !self.exact {
964 			write!(f, "approx. ")?;
965 		}
966 		let simplifiable = if self.simplifiable { "" } else { "not " };
967 		write!(
968 			f,
969 			"{:?} {:?} ({:?}, {:?}, {simplifiable}simplifiable)",
970 			self.value, self.unit, self.base, self.format
971 		)?;
972 		Ok(())
973 	}
974 }
975 
976 #[derive(Debug)]
977 pub(crate) struct FormattedValue {
978 	exact: bool,
979 	number: String,
980 	unit_str: String,
981 }
982 
983 impl FormattedValue {
spans(self, spans: &mut Vec<Span>, attrs: Attrs)984 	pub(crate) fn spans(self, spans: &mut Vec<Span>, attrs: Attrs) {
985 		if !self.exact && attrs.show_approx && !attrs.plain_number {
986 			spans.push(Span {
987 				string: "approx. ".to_string(),
988 				kind: SpanKind::Ident,
989 			});
990 		}
991 		if ["$", "\u{a3}", "\u{a5}"].contains(&self.unit_str.as_str()) && !attrs.plain_number {
992 			spans.push(Span {
993 				string: self.unit_str,
994 				kind: SpanKind::Ident,
995 			});
996 			spans.push(Span {
997 				string: self.number,
998 				kind: SpanKind::Number,
999 			});
1000 			return;
1001 		}
1002 		spans.push(Span {
1003 			string: self.number.to_string(),
1004 			kind: SpanKind::Number,
1005 		});
1006 		if !attrs.plain_number {
1007 			spans.push(Span {
1008 				string: self.unit_str,
1009 				kind: SpanKind::Ident,
1010 			});
1011 		}
1012 	}
1013 }
1014 
1015 impl fmt::Display for FormattedValue {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result1016 	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1017 		if !self.exact {
1018 			write!(f, "approx. ")?;
1019 		}
1020 		write!(f, "{}{}", self.number, self.unit_str)?;
1021 		Ok(())
1022 	}
1023 }
1024 
1025 // TODO: equality comparisons should not depend on order
1026 #[derive(Clone)]
1027 struct Unit {
1028 	components: Vec<UnitExponent>,
1029 }
1030 
1031 type HashmapScale = (HashMap<BaseUnit, Complex>, Exact<Complex>);
1032 type HashmapScaleOffset = (HashMap<BaseUnit, Complex>, Exact<Complex>, Exact<Complex>);
1033 
1034 struct ScaleFactor {
1035 	scale_1: Exact<Complex>,
1036 	offset: Exact<Complex>,
1037 	scale_2: Exact<Complex>,
1038 }
1039 
1040 impl Unit {
serialize(&self, write: &mut impl io::Write) -> FResult<()>1041 	pub(crate) fn serialize(&self, write: &mut impl io::Write) -> FResult<()> {
1042 		self.components.len().serialize(write)?;
1043 		for c in &self.components {
1044 			c.serialize(write)?;
1045 		}
1046 		Ok(())
1047 	}
1048 
deserialize(read: &mut impl io::Read) -> FResult<Self>1049 	pub(crate) fn deserialize(read: &mut impl io::Read) -> FResult<Self> {
1050 		let len = usize::deserialize(read)?;
1051 		let mut cs = Vec::with_capacity(len);
1052 		for _ in 0..len {
1053 			cs.push(UnitExponent::deserialize(read)?);
1054 		}
1055 		Ok(Self { components: cs })
1056 	}
1057 
equal_to<I: Interrupt>(&self, rhs: &str, int: &I) -> FResult<bool>1058 	pub(crate) fn equal_to<I: Interrupt>(&self, rhs: &str, int: &I) -> FResult<bool> {
1059 		if self.components.len() != 1 {
1060 			return Ok(false);
1061 		}
1062 		let unit = &self.components[0];
1063 		if unit.exponent.compare(&1.into(), int)? != Some(Ordering::Equal) {
1064 			return Ok(false);
1065 		}
1066 		let (prefix, name) = unit.unit.prefix_and_name(false);
1067 		Ok(prefix.is_empty() && name == rhs)
1068 	}
1069 
1070 	/// base units with cancelled exponents do not appear in the hashmap
to_hashmap_and_scale<I: Interrupt>(&self, int: &I) -> FResult<HashmapScale>1071 	fn to_hashmap_and_scale<I: Interrupt>(&self, int: &I) -> FResult<HashmapScale> {
1072 		let mut hashmap = HashMap::<BaseUnit, Complex>::new();
1073 		let mut scale = Complex::from(1);
1074 		let mut exact = true;
1075 		for named_unit_exp in &self.components {
1076 			named_unit_exp.add_to_hashmap(&mut hashmap, &mut scale, &mut exact, int)?;
1077 		}
1078 		Ok((hashmap, Exact::new(scale, exact)))
1079 	}
1080 
reduce_hashmap<I: Interrupt>( hashmap: HashMap<BaseUnit, Complex>, int: &I, ) -> FResult<HashmapScaleOffset>1081 	fn reduce_hashmap<I: Interrupt>(
1082 		hashmap: HashMap<BaseUnit, Complex>,
1083 		int: &I,
1084 	) -> FResult<HashmapScaleOffset> {
1085 		let check = |s: &'static str| -> FResult<bool> {
1086 			Ok(hashmap.len() == 1
1087 				&& match hashmap.get(&BaseUnit::new(Cow::Borrowed(s))) {
1088 					None => false,
1089 					Some(c) => c.compare(&1.into(), int)? == Some(Ordering::Equal),
1090 				})
1091 		};
1092 		if check("celsius")? {
1093 			let mut result_hashmap = HashMap::new();
1094 			result_hashmap.insert(BaseUnit::new(Cow::Borrowed("kelvin")), 1.into());
1095 			return Ok((
1096 				result_hashmap,
1097 				Exact::new(1.into(), true),
1098 				Exact::new(Complex::from(27315), true)
1099 					.div(Exact::new(Complex::from(100), true), int)?,
1100 			));
1101 		}
1102 		if check("fahrenheit")? {
1103 			let mut result_hashmap = HashMap::new();
1104 			result_hashmap.insert(BaseUnit::new(Cow::Borrowed("kelvin")), 1.into());
1105 			return Ok((
1106 				result_hashmap,
1107 				Exact::new(Complex::from(5), true).div(Exact::new(Complex::from(9), true), int)?,
1108 				Exact::new(Complex::from(45967), true)
1109 					.div(Exact::new(Complex::from(180), true), int)?,
1110 			));
1111 		}
1112 		let mut scale_adjustment = Exact::new(Complex::from(1), true);
1113 		let mut result_hashmap = HashMap::new();
1114 		for (mut base_unit, exponent) in hashmap {
1115 			if base_unit.name() == "celsius" {
1116 				base_unit = BaseUnit::new_static("kelvin");
1117 			} else if base_unit.name() == "fahrenheit" {
1118 				base_unit = BaseUnit::new_static("kelvin");
1119 				scale_adjustment = scale_adjustment.mul(
1120 					&Exact::new(Complex::from(5), true)
1121 						.div(Exact::new(Complex::from(9), true), int)?
1122 						.value
1123 						.pow(exponent.clone(), int)?,
1124 					int,
1125 				)?;
1126 			}
1127 			result_hashmap.insert(base_unit.clone(), exponent.clone());
1128 		}
1129 		Ok((result_hashmap, scale_adjustment, Exact::new(0.into(), true)))
1130 	}
1131 
print_base_units<I: Interrupt>( hash: HashMap<BaseUnit, Complex>, int: &I, ) -> FResult<String>1132 	fn print_base_units<I: Interrupt>(
1133 		hash: HashMap<BaseUnit, Complex>,
1134 		int: &I,
1135 	) -> FResult<String> {
1136 		let from_base_units: Vec<_> = hash
1137 			.into_iter()
1138 			.map(|(base_unit, exponent)| {
1139 				UnitExponent::new(NamedUnit::new_from_base(base_unit), exponent)
1140 			})
1141 			.collect();
1142 		Ok(Self {
1143 			components: from_base_units,
1144 		}
1145 		.format(
1146 			"unitless",
1147 			false,
1148 			Base::default(),
1149 			FormattingStyle::Auto,
1150 			false,
1151 			int,
1152 		)?
1153 		.value)
1154 	}
1155 
1156 	/// Returns the combined scale factor if successful
compute_scale_factor<I: Interrupt>( from: &Self, into: &Self, int: &I, ) -> FResult<ScaleFactor>1157 	fn compute_scale_factor<I: Interrupt>(
1158 		from: &Self,
1159 		into: &Self,
1160 		int: &I,
1161 	) -> FResult<ScaleFactor> {
1162 		let (hash_a, scale_a) = from.to_hashmap_and_scale(int)?;
1163 		let (hash_b, scale_b) = into.to_hashmap_and_scale(int)?;
1164 		let (hash_a, adj_a, offset_a) = Self::reduce_hashmap(hash_a, int)?;
1165 		let (hash_b, adj_b, offset_b) = Self::reduce_hashmap(hash_b, int)?;
1166 		if compare_hashmaps(&hash_a, &hash_b, int)? {
1167 			Ok(ScaleFactor {
1168 				scale_1: scale_a.mul(&adj_a, int)?,
1169 				offset: offset_a.add(-offset_b, int)?,
1170 				scale_2: scale_b.mul(&adj_b, int)?,
1171 			})
1172 		} else {
1173 			let from_formatted = from
1174 				.format(
1175 					"unitless",
1176 					false,
1177 					Base::default(),
1178 					FormattingStyle::Auto,
1179 					false,
1180 					int,
1181 				)?
1182 				.value;
1183 			let into_formatted = into
1184 				.format(
1185 					"unitless",
1186 					false,
1187 					Base::default(),
1188 					FormattingStyle::Auto,
1189 					false,
1190 					int,
1191 				)?
1192 				.value;
1193 			Err(FendError::IncompatibleConversion {
1194 				from: from_formatted,
1195 				to: into_formatted,
1196 				from_base: Self::print_base_units(hash_a, int)?,
1197 				to_base: Self::print_base_units(hash_b, int)?,
1198 			})
1199 		}
1200 	}
1201 
unitless() -> Self1202 	const fn unitless() -> Self {
1203 		Self { components: vec![] }
1204 	}
1205 
format<I: Interrupt>( &self, unitless: &str, value_is_one: bool, base: Base, format: FormattingStyle, consider_printing_space: bool, int: &I, ) -> FResult<Exact<String>>1206 	fn format<I: Interrupt>(
1207 		&self,
1208 		unitless: &str,
1209 		value_is_one: bool,
1210 		base: Base,
1211 		format: FormattingStyle,
1212 		consider_printing_space: bool,
1213 		int: &I,
1214 	) -> FResult<Exact<String>> {
1215 		let mut unit_string = String::new();
1216 		if self.components.is_empty() {
1217 			unit_string.push_str(unitless);
1218 			return Ok(Exact::new(unit_string, true));
1219 		}
1220 		// Pluralisation:
1221 		// All units should be singular, except for the last unit
1222 		// that has a positive exponent, iff the number is not equal to 1
1223 		let mut exact = true;
1224 		let mut positive_components = vec![];
1225 		let mut negative_components = vec![];
1226 		let mut first = true;
1227 		for unit_exponent in &self.components {
1228 			if unit_exponent.exponent.compare(&0.into(), int)? == Some(Ordering::Less) {
1229 				negative_components.push(unit_exponent);
1230 			} else {
1231 				positive_components.push(unit_exponent);
1232 			}
1233 		}
1234 		let invert_negative_component =
1235 			!positive_components.is_empty() && negative_components.len() == 1;
1236 		let mut merged_components = vec![];
1237 		let pluralised_idx = if positive_components.is_empty() {
1238 			usize::MAX
1239 		} else {
1240 			positive_components.len() - 1
1241 		};
1242 		for pos_comp in positive_components {
1243 			merged_components.push((pos_comp, false));
1244 		}
1245 		for neg_comp in negative_components {
1246 			merged_components.push((neg_comp, invert_negative_component));
1247 		}
1248 		let last_component_plural = !value_is_one;
1249 		for (i, (unit_exponent, invert)) in merged_components.into_iter().enumerate() {
1250 			if !first || (consider_printing_space && unit_exponent.unit.print_with_space()) {
1251 				unit_string.push(' ');
1252 			}
1253 			first = false;
1254 			if invert {
1255 				unit_string.push('/');
1256 				unit_string.push(' ');
1257 			}
1258 			let plural = last_component_plural && i == pluralised_idx;
1259 			let exp_format = if format == FormattingStyle::Auto {
1260 				FormattingStyle::Exact
1261 			} else {
1262 				format
1263 			};
1264 			let formatted_exp = unit_exponent.format(base, exp_format, plural, invert, int)?;
1265 			unit_string.push_str(formatted_exp.value.to_string().as_str());
1266 			exact = exact && formatted_exp.exact;
1267 		}
1268 		Ok(Exact::new(unit_string, true))
1269 	}
1270 }
1271 
1272 impl fmt::Debug for Unit {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result1273 	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1274 		if self.components.is_empty() {
1275 			write!(f, "(unitless)")?;
1276 		}
1277 		let mut first = true;
1278 		for component in &self.components {
1279 			if !first {
1280 				write!(f, " * ")?;
1281 			}
1282 			write!(f, "{component:?}")?;
1283 			first = false;
1284 		}
1285 		Ok(())
1286 	}
1287 }
1288 
1289 #[cfg(test)]
1290 mod tests {
1291 	use super::*;
1292 	use crate::interrupt::Never;
1293 
to_string(n: &Value) -> String1294 	fn to_string(n: &Value) -> String {
1295 		let int = &crate::interrupt::Never;
1296 		n.format(&crate::Context::new(), int).unwrap().to_string()
1297 	}
1298 
1299 	#[test]
test_basic_kg()1300 	fn test_basic_kg() {
1301 		let base_kg = BaseUnit::new("kilogram".into());
1302 		let mut hashmap = HashMap::new();
1303 		hashmap.insert(base_kg, 1.into());
1304 		let kg = NamedUnit::new("k".into(), "g".into(), "g".into(), false, hashmap, 1);
1305 		let one_kg = Value::new(1, vec![UnitExponent::new(kg.clone(), 1)]);
1306 		let two_kg = Value::new(2, vec![UnitExponent::new(kg, 1)]);
1307 		let sum = one_kg.add(two_kg, &Never).unwrap();
1308 		assert_eq!(to_string(&sum), "3 kg");
1309 	}
1310 
1311 	#[test]
test_basic_kg_and_g()1312 	fn test_basic_kg_and_g() {
1313 		let int = &Never;
1314 		let base_kg = BaseUnit::new("kilogram".into());
1315 		let mut hashmap = HashMap::new();
1316 		hashmap.insert(base_kg, 1.into());
1317 		let kg = NamedUnit::new(
1318 			"k".into(),
1319 			"g".into(),
1320 			"g".into(),
1321 			false,
1322 			hashmap.clone(),
1323 			1,
1324 		);
1325 		let g = NamedUnit::new(
1326 			Cow::Borrowed(""),
1327 			Cow::Borrowed("g"),
1328 			Cow::Borrowed("g"),
1329 			false,
1330 			hashmap,
1331 			Exact::new(Complex::from(1), true)
1332 				.div(Exact::new(1000.into(), true), int)
1333 				.unwrap()
1334 				.value,
1335 		);
1336 		let one_kg = Value::new(1, vec![UnitExponent::new(kg, 1)]);
1337 		let twelve_g = Value::new(12, vec![UnitExponent::new(g, 1)]);
1338 		assert_eq!(
1339 			to_string(&one_kg.clone().add(twelve_g.clone(), int).unwrap()),
1340 			"1.012 kg"
1341 		);
1342 		assert_eq!(to_string(&twelve_g.add(one_kg, int).unwrap()), "1012 g");
1343 	}
1344 }
1345