tolerance/
lib.rs

1// Thanks to: https://linebender.org/blog/doc-include
2//
3//! [`Myth64`]: Myth64
4//! [`Myth32`]: Myth32
5//! [`Myth16`]: Myth16
6//! [`T128`]: T128
7//! [`T64`]: T64
8#![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/// helper-method used from all types.
44#[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}