initial version
This commit is contained in:
54
bqst-core/src/api.rs
Normal file
54
bqst-core/src/api.rs
Normal file
@@ -0,0 +1,54 @@
|
||||
use std::fmt::Debug;
|
||||
|
||||
use dashu::rational::RBig;
|
||||
|
||||
use crate::{PrecDec, prefixes, qty::Qty, unit};
|
||||
|
||||
macro_rules! _t {
|
||||
($e:expr) => {
|
||||
$e.map_err(|e| Box::new(e) as Box<dyn Debug>)
|
||||
};
|
||||
}
|
||||
|
||||
fn parse_decimal<const B: u32>(s: &str) -> Result<RBig, dashu::base::ParseError> {
|
||||
if let Some((int_part, frac_part)) = s.split_once('.') {
|
||||
let denominator = B.pow(frac_part.len() as u32);
|
||||
let numerator = RBig::from_str_radix(&format!("{}{}", int_part, frac_part), B)?;
|
||||
Ok(numerator / RBig::from(denominator))
|
||||
} else {
|
||||
Ok(RBig::from_str_radix(s, B)?)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn qty(q: &str) -> Result<Qty, Box<dyn Debug>> {
|
||||
let split_idx = q
|
||||
.char_indices()
|
||||
.rev()
|
||||
.find(|&(_, c)| c.is_ascii_digit())
|
||||
.map(|(i, _)| i + 1) // found digit and digits are 1 byte so no worries byt ugly
|
||||
.unwrap_or(0);
|
||||
|
||||
let (amt, unt) = q.split_at(split_idx);
|
||||
let mut amt: PrecDec = if amt.is_empty() {
|
||||
PrecDec::from(1)
|
||||
} else {
|
||||
_t!(parse_decimal::<10>(amt))?
|
||||
};
|
||||
|
||||
let unt = if let Some((_, rem, exp)) = prefixes::extract_prefix_and_rem(unt.trim()) {
|
||||
let e = PrecDec::from(10isize.pow(exp.unsigned_abs().into()));
|
||||
if exp < 0 {
|
||||
amt /= e;
|
||||
} else {
|
||||
amt *= e;
|
||||
}
|
||||
|
||||
rem
|
||||
} else {
|
||||
unt
|
||||
};
|
||||
|
||||
let unt = _t!(unit::Unit::try_from(unt.trim()))?;
|
||||
|
||||
Ok(Qty { n: amt, u: unt })
|
||||
}
|
||||
Reference in New Issue
Block a user