1#![doc = include_str!("../README.md")]
9
10pub mod error;
11mod myths;
12mod tols;
13mod unit;
14
15pub use self::unit::*;
16pub use myths::myth16::*;
17pub use myths::myth32::*;
18pub use myths::myth64::*;
19pub use tols::tol128::*;
20pub use tols::tol64::*;
21
22use error::ToleranceError;
23
24#[cfg(feature = "serde")]
25include!("tols/serde.rs");
26
27#[inline]
28fn str2int(bytes: &[u8], t_type: &str) -> Result<i64, ToleranceError> {
29 let mut v = 0i64;
30 for c in bytes {
31 match c {
32 0x30..=0x39 => v = v * 10 + i64::from(c - 0x30),
33 _ => {
34 return Err(ToleranceError::ParseError(format!(
35 "Found ascii #{c} (a non-numerical literal) in input, can't parse input into a {t_type}!",
36 )))
37 }
38 }
39 }
40 Ok(v)
41}
42
43#[inline]
45pub(crate) fn try_from_str(value: &str, t_type: &'static str) -> Result<i64, ToleranceError> {
46 let value = value.trim();
47 if value.is_empty() {
48 return Err(ToleranceError::ParseEmptyStr(t_type));
49 }
50 let (base, fraction) = value.split_once('.').unwrap_or((value, "0"));
51 let mut base = base.as_bytes();
52 let &c = base.first().unwrap_or(&b'0');
53 let sign = 1 - i64::from(c == b'-') * 2;
54 if c == b'-' || c == b'+' {
55 base = &base[1..];
56 }
57 if base.is_empty() && fraction == "0" {
58 return Err(ToleranceError::ParseError(format!(
59 "Not a valid Number: '{value}'"
60 )));
61 }
62 let fraction = fraction.to_string() + "00000";
63 let fraction = fraction.split_at(4).0.as_bytes();
64 Ok((str2int(base, t_type)? * Unit::MM + str2int(fraction, t_type)?) * sign)
65}