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