cas_compute/
primitive.rs

1//! Functions to construct [`Integer`]s, [`Float`]s, and [`Complex`] numbers from various types.
2
3use cas_parser::parser::ast::literal::DIGITS;
4use rug::{ops::Pow, Assign, Complex, Float, Integer};
5
6/// The number of digits of precision to use when computing values.
7pub const PRECISION: u32 = 1 << 9;
8
9/// Creates an [`Integer`] with the given value.
10pub fn int<T>(n: T) -> Integer
11where
12    Integer: From<T>,
13{
14    Integer::from(n)
15}
16
17/// Creates an [`Integer`] from a [`Float`] by truncating the fractional part.
18pub fn int_from_float(f: Float) -> Integer {
19    // TODO: can panic if NaN
20    f.trunc().to_integer().unwrap()
21}
22
23/// Creates an [`Integer`] from a string slice.
24pub fn int_from_str(s: &str) -> Integer {
25    Integer::from_str_radix(s, 10).unwrap()
26}
27
28/// Creates a [`Float`] with the given value.
29pub fn float<T>(n: T) -> Float
30where
31    Float: Assign<T>,
32{
33    Float::with_val(PRECISION, n)
34}
35
36/// Creates a [`Float`] from a string slice.
37pub fn float_from_str(s: &str) -> Float {
38    Float::with_val(PRECISION, Float::parse(s).unwrap())
39}
40
41/// Parses a number from a string, with the given radix. The radix must be between 2 and 64,
42/// inclusive.
43///
44/// TODO: Replace panics with errors
45pub fn from_str_radix(s: &str, radix: u8) -> Integer {
46    let mut result = int(0);
47    let allowed_digits = &DIGITS[..radix as usize];
48
49    let radix = int(radix);
50    for (i, c) in s.chars().rev().enumerate() {
51        let digit = int(allowed_digits.iter().position(|&d| d == c).unwrap());
52        result += digit * int((&radix).pow(i as u32));
53    }
54
55    result
56}
57
58/// Creates a [`Complex`] with the given value.
59pub fn complex<T>(n: T) -> Complex
60where
61    Complex: Assign<T>,
62{
63    Complex::with_val(PRECISION, n)
64}
65
66#[cfg(test)]
67mod tests {
68    use super::*;
69
70    #[test]
71    fn radix_eval() {
72        let expected = 1072.0;
73        let numbers = [
74            (2, "10000110000"),
75            (8, "2060"),
76            (25, "1hm"),
77            (32, "11g"),
78            (47, "mC"),
79        ];
80
81        for (radix, number) in numbers.iter() {
82            assert_eq!(from_str_radix(number, *radix), expected);
83        }
84    }
85}