calc_rational

CLI calculator for rational numbers.
git clone https://git.philomathiclife.com/repos/calc_rational
Log | Files | Refs | README

lib.rs (53584B)


      1 //! [![git]](https://git.philomathiclife.com/calc_rational/log.html) [![crates-io]](https://crates.io/crates/calc_rational) [![docs-rs]](crate)
      2 //!
      3 //! [git]: https://git.philomathiclife.com/git_badge.svg
      4 //! [crates-io]: https://img.shields.io/badge/crates.io-fc8d62?style=for-the-badge&labelColor=555555&logo=rust
      5 //! [docs-rs]: https://img.shields.io/badge/docs.rs-66c2a5?style=for-the-badge&labelColor=555555&logo=docs.rs
      6 //!
      7 //! `calc_lib` is a library for performing basic rational number arithmetic using standard operator precedence
      8 //! and associativity. Internally, it is based on
      9 //! [`Ratio<T>`] and [`BigInt`].
     10 //!   
     11 //! ## Expressions  
     12 //!   
     13 //! The following are the list of expressions in descending order of precedence:  
     14 //!   1. number literals, `@`, `()`, `||`, `round()`, `rand()`  
     15 //!   2. `!`  
     16 //!   3. `^`  
     17 //!   4. `-` (unary negation operator)  
     18 //!   5. `*`, `/`, `mod`  
     19 //!   6. `+`, `-`  
     20 //!   
     21 //! All binary operators are left-associative sans `^` which is right-associative.  
     22 //!   
     23 //! Any expression is allowed to be enclosed in `()`. Note that parentheses are purely for grouping expressions;
     24 //! in particular, you cannot use them to represent multiplication (e.g., `4(2)` is grammatically incorrect and
     25 //! will result in an error message).  
     26 //!   
     27 //! Any expression is allowed to be enclosed in `||`. This unary operator represents absolute value.  
     28 //!   
     29 //! `!` is the factorial operator. Due to its high precedence, something like *-i!^j!* for *i, j ∈ ℕ* is
     30 //! the same thing as *-((i!)^(j!))*. If the expression preceding it does not evaluate to a non-negative integer,
     31 //! then an error will be displayed. Spaces  and tabs are *not* ignored; so `1 !` is grammatically incorrect and
     32 //! will result in an error message.  
     33 //!   
     34 //! `^` is the exponentiation operator. The expression left of the operator can evaluate to any rational number;
     35 //! however the expression right of the operator must evaluate to an integer or ±1/2 unless the expression on
     36 //! the left evaluates to `0` or `1`. In the event of the former, the expression right of the operator must evaluate
     37 //! to a non-negative rational number. In the event of the latter, the expression right of the operator can evaluate to
     38 //! any rational number. Note that `0^0` is defined to be 1. When the operand right of `^` evaluates to ±1/2, then
     39 //! the left operand must be the square of a rational number.  
     40 //!   
     41 //! The unary operator `-` represents negation.  
     42 //!   
     43 //! The operators `*` and `/` represent multiplication and division respectively. Expressions right of `/`
     44 //! must evaluate to any non-zero rational number; otherwise an error will be displayed.  
     45 //!   
     46 //! The binary operator `mod` represents modulo such that *n mod m = r = n - m\*q* for *n,q ∈ ℤ, m ∈ ℤ\\{0}, and r ∈ ℕ*
     47 //! where *r* is the minimum non-negative solution.  
     48 //!   
     49 //! The binary operators `+` and `-` represent addition and subtraction respectively.  
     50 //!   
     51 //! With the aforementioned exception of `!`, all spaces and tabs before and after operators are ignored.  
     52 //!   
     53 //! ## Round expression  
     54 //!   
     55 //! `round(expression, digit)` rounds `expression` to `digit`-number of fractional digits. An error will
     56 //! be displayed if called incorrectly.  
     57 //!   
     58 //! ## Rand expression  
     59 //!   
     60 //! `rand(expression, expression)` generates a random 64-bit integer inclusively between the passed expressions.
     61 //! An error will be displayed if called incorrectly. `rand()` generates a random 64-bit integer.  
     62 //!   
     63 //! ## Numbers  
     64 //!   
     65 //! A number literal is a non-empty sequence of digits or a non-empty sequence of digits immediately followed by `.`
     66 //! which is immediately followed by a non-empty sequence of digits (e.g., `134.901`). This means that number
     67 //! literals represent precisely all rational numbers that are equivalent to a ratio of a non-negative integer
     68 //! to a positive integer whose sole prime factors are 2 or 5. To represent all other rational numbers, the unary
     69 //! operator `-` and binary operator `/` must be used.  
     70 //!   
     71 //! ## Empty expression  
     72 //!   
     73 //! The empty expression (i.e., expression that at most only consists of spaces and tabs) will return
     74 //! the result from the previous non-(empty/store) expression in *decimal* form using the minimum number of digits.
     75 //! In the event an infinite number of digits is required, it will be rounded to 9 fractional digits using normal rounding
     76 //! rules first.  
     77 //!   
     78 //! ## Store expression  
     79 //!   
     80 //! To store the result of the previous non-(empty/store) expression, one simply passes `s`. In addition to storing the
     81 //! result which will subsequently be available via `@`, it displays the result. At most 8 results can be stored at once;
     82 //! at which point, results that are stored overwrite the oldest result.  
     83 //!   
     84 //! ## Recall expression  
     85 //!   
     86 //! `@` is used to recall previously stored results. It can be followed by any *digit* from `1` to `8`.
     87 //! If such a digit does not immediately follow it, then it will be interpreted as if there were a `1`.
     88 //! `@i` returns the *i*-th most-previous stored result where *i ∈ {1, 2, 3, 4, 5, 6, 7, 8}*.
     89 //! Note that spaces and tabs are *not* ignored so `@ 2` is grammatically incorrect and will result in an error message.
     90 //! As emphasized, it does not work on expressions; so both `@@` and `@(1)` are grammatically incorrect.  
     91 //!   
     92 //! ## Character encoding  
     93 //!   
     94 //! All inputs must only contain the ASCII encoding of the following Unicode scalar values: `0`-`9`, `.`, `+`, `-`,
     95 //! `*`, `/`, `^`, `!`, `mod`, `|`, `(`, `)`, `round`, `rand`, `,`, `@`, `s`, &lt;space&gt;, &lt;tab&gt;,
     96 //! &lt;line feed&gt;, &lt;carriage return&gt;, and `q`. Any other byte sequences are grammatically incorrect and will
     97 //! lead to an error message.  
     98 //!   
     99 //! ## Errors  
    100 //!   
    101 //! Errors due to a language violation (e.g., dividing by `0`) manifest into an error message. `panic!`s
    102 //! and [`io::Error`](https://doc.rust-lang.org/std/io/struct.Error.html)s caused by writing to the global
    103 //! standard output stream lead to program abortion.  
    104 //!   
    105 //! ## Exiting  
    106 //!   
    107 //! `q` with any number of spaces and tabs before and after will cause the program to terminate.  
    108 //!   
    109 //! ### Formal language specification  
    110 //!   
    111 //! For a more precise specification of the “calc language”, one can read the
    112 //! [calc language specification](https://git.philomathiclife.com/calc_rational/lang.pdf).
    113 #![expect(
    114     clippy::doc_paragraphs_missing_punctuation,
    115     reason = "false positive for crate documentation having image links"
    116 )]
    117 #![expect(
    118     clippy::arithmetic_side_effects,
    119     reason = "calculator can't realistically avoid this"
    120 )]
    121 #![no_std]
    122 #![cfg_attr(docsrs, feature(doc_cfg))]
    123 extern crate alloc;
    124 /// Unit tests.
    125 #[cfg(test)]
    126 mod tests;
    127 use LangErr::{
    128     DivByZero, ExpDivByZero, ExpIsNotIntOrOneHalf, InvalidAbs, InvalidDec, InvalidPar, InvalidQuit,
    129     InvalidRound, InvalidStore, MissingTerm, ModIsNotInt, ModZero, NotEnoughPrevResults,
    130     NotNonNegIntFact, SqrtDoesNotExist, TrailingSyms,
    131 };
    132 use O::{Empty, Eval, Exit, Store};
    133 use alloc::{
    134     string::{String, ToString as _},
    135     vec,
    136     vec::Vec,
    137 };
    138 use cache::Cache;
    139 #[cfg(not(feature = "rand"))]
    140 use core::marker::PhantomData;
    141 use core::{
    142     convert,
    143     fmt::{self, Display, Formatter},
    144     ops::Index as _,
    145 };
    146 pub use num_bigint;
    147 use num_bigint::{BigInt, BigUint, Sign};
    148 use num_integer::Integer as _;
    149 pub use num_rational;
    150 use num_rational::Ratio;
    151 #[cfg(feature = "rand")]
    152 use num_traits::ToPrimitive as _;
    153 use num_traits::{Inv as _, Pow as _};
    154 #[cfg(target_os = "openbsd")]
    155 use priv_sep as _;
    156 #[cfg(feature = "rand")]
    157 pub use rand;
    158 #[cfg(feature = "rand")]
    159 use rand::{Rng as _, rngs::ThreadRng};
    160 /// Fixed-sized cache that automatically overwrites the oldest data
    161 /// when a new item is added and the cache is full.
    162 ///
    163 /// One can think of
    164 /// [`Cache`] as a very limited but more performant [`VecDeque`][alloc::collections::VecDeque] that only
    165 /// adds new data or reads old data.
    166 pub mod cache;
    167 /// Generalizes [`Iterator`] by using
    168 /// generic associated types.
    169 pub mod lending_iterator;
    170 /// Error due to a language violation.
    171 #[non_exhaustive]
    172 #[cfg_attr(test, derive(Eq, PartialEq))]
    173 #[derive(Debug)]
    174 pub enum LangErr {
    175     /// The input began with a `q` but had non-whitespace
    176     /// that followed it.
    177     InvalidQuit,
    178     /// The input began with an `s` but had non-whitespace
    179     /// that followed it.
    180     InvalidStore,
    181     /// A sub-expression in the input would have led
    182     /// to a division by zero.
    183     DivByZero(usize),
    184     /// A sub-expression in the input would have led
    185     /// to a rational number that was not 0 or 1 to be
    186     /// raised to a non-integer power that is not (+/-) 1/2.
    187     ExpIsNotIntOrOneHalf(usize),
    188     /// A sub-expression in the input would have led
    189     /// to 0 being raised to a negative power which itself
    190     /// would have led to a division by zero.
    191     ExpDivByZero(usize),
    192     /// A sub-expression in the input would have led
    193     /// to a number modulo 0.
    194     ModZero(usize),
    195     /// A sub-expression in the input would have led
    196     /// to the mod of two expressions with at least one
    197     /// not being an integer.
    198     ModIsNotInt(usize),
    199     /// A sub-expression in the input would have led
    200     /// to a non-integer factorial or a negative integer factorial.
    201     NotNonNegIntFact(usize),
    202     /// The input contained a non-empty sequence of digits followed
    203     /// by `.` which was not followed by a non-empty sequence of digits.
    204     InvalidDec(usize),
    205     /// A recall expression was used to recall the *i*-th most-recent stored result,
    206     /// but there are fewer than *i* stored where
    207     /// *i ∈ {1, 2, 3, 4, 5, 6, 7, 8}*.
    208     NotEnoughPrevResults(usize),
    209     /// The input did not contain a closing `|`.
    210     InvalidAbs(usize),
    211     /// The input did not contain a closing `)`.
    212     InvalidPar(usize),
    213     /// The input contained an invalid round expression.
    214     InvalidRound(usize),
    215     /// A sub-expression in the input had a missing terminal expression
    216     /// where a terminal expression is a decimal literal expression,
    217     /// recall expression, absolute value expression, parenthetical
    218     /// expression, or round expression.
    219     MissingTerm(usize),
    220     /// The expression that was passed to the square root does not have a solution
    221     /// in the field of rational numbers.
    222     SqrtDoesNotExist(usize),
    223     /// The input started with a valid expression but was immediately followed
    224     /// by symbols that could not be chained with the preceding expression.
    225     TrailingSyms(usize),
    226     /// The input contained an invalid random expression.
    227     #[cfg(feature = "rand")]
    228     InvalidRand(usize),
    229     /// Error when the second argument is less than first in the rand function.
    230     #[cfg(feature = "rand")]
    231     RandInvalidArgs(usize),
    232     /// Error when there are no 64-bit integers in the interval passed to the random function.
    233     #[cfg(feature = "rand")]
    234     RandNoInts(usize),
    235 }
    236 impl Display for LangErr {
    237     #[inline]
    238     fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
    239         match *self {
    240             InvalidStore => f.write_str("Invalid store expression. A store expression must be of the extended regex form: ^[ \\t]*s[ \\t]*$."),
    241             InvalidQuit => f.write_str("Invalid quit expression. A quit expression must be of the extended regex form: ^[ \\t]*q[ \\t]*$."),
    242             DivByZero(u) => write!(f, "Division by zero ending at position {u}."),
    243             ExpIsNotIntOrOneHalf(u) => write!(f, "Non-integer exponent that is not (+/-) 1/2 with a base that was not 0 or 1 ending at position {u}."),
    244             ExpDivByZero(u) => write!(f, "Non-negative exponent with a base of 0 ending at position {u}."),
    245             ModZero(u) => write!(f, "A number modulo 0 ending at position {u}."),
    246             ModIsNotInt(u) => write!(f, "The modulo expression was applied to at least one non-integer ending at position {u}."),
    247             NotNonNegIntFact(u) => write!(f, "Factorial of a rational number that was not a non-negative integer ending at position {u}."),
    248             InvalidDec(u) => write!(f, "Invalid decimal literal expression ending at position {u}. A decimal literal expression must be of the extended regex form: [0-9]+(\\.[0-9]+)?."),
    249             NotEnoughPrevResults(len) => write!(f, "There are only {len} previous results."),
    250             InvalidAbs(u) => write!(f, "Invalid absolute value expression ending at position {u}. An absolute value expression is an addition expression enclosed in '||'."),
    251             InvalidPar(u) => write!(f, "Invalid parenthetical expression ending at position {u}. A parenthetical expression is an addition expression enclosed in '()'."),
    252             InvalidRound(u) => write!(f, "Invalid round expression ending at position {u}. A round expression is of the form 'round(<mod expression>, digit)'"),
    253             SqrtDoesNotExist(u) => write!(f, "The square root of the passed expression does not have a solution in the field of rational numbers ending at position {u}."),
    254             #[cfg(not(feature = "rand"))]
    255             MissingTerm(u) => write!(f, "Missing terminal expression at position {u}. A terminal expression is a decimal literal expression, recall expression, absolute value expression, parenthetical expression, or round expression."),
    256             #[cfg(feature = "rand")]
    257             MissingTerm(u) => write!(f, "Missing terminal expression at position {u}. A terminal expression is a decimal literal expression, recall expression, absolute value expression, parenthetical expression, round expression, or rand expression."),
    258             TrailingSyms(u) => write!(f, "Trailing symbols starting at position {u}."),
    259             #[cfg(feature = "rand")]
    260             Self::InvalidRand(u) => write!(f, "Invalid rand expression ending at position {u}. A rand expression is of the form 'rand()' or 'rand(<mod expression>, <mod expression>)'."),
    261             #[cfg(feature = "rand")]
    262             Self::RandInvalidArgs(u) => write!(f, "The second expression passed to the random function evaluated to rational number less than the first ending at position {u}."),
    263             #[cfg(feature = "rand")]
    264             Self::RandNoInts(u) => write!(f, "There are no 64-bit integers within the interval passed to the random function ending at position {u}."),
    265         }
    266     }
    267 }
    268 /// A successful evaluation of an input.
    269 #[cfg_attr(test, derive(Eq, PartialEq))]
    270 #[derive(Debug)]
    271 pub enum O<'a> {
    272     /// The input only contained whitespace.
    273     /// This returns the previous `Eval`.
    274     /// It is `None` iff there have been no
    275     /// previous `Eval` results.
    276     Empty(&'a Option<Ratio<BigInt>>),
    277     /// The quit expression was issued to terminate the program.
    278     Exit,
    279     /// Result of a "normal" expression.
    280     Eval(&'a Ratio<BigInt>),
    281     /// The store expression stores and returns the previous `Eval`.
    282     /// It is `None` iff there have been no previous `Eval` results.
    283     Store(&'a Option<Ratio<BigInt>>),
    284 }
    285 impl Display for O<'_> {
    286     #[expect(
    287         unsafe_code,
    288         reason = "manually construct guaranteed UTF-8; thus avoid the needless check"
    289     )]
    290     #[expect(clippy::indexing_slicing, reason = "comment justifies correctness")]
    291     #[inline]
    292     fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
    293         match *self {
    294             Empty(o) => {
    295                 o.as_ref().map_or(Ok(()), |val| {
    296                     if val.is_integer() {
    297                         write!(f, "> {val}")
    298                     } else {
    299                         // If the prime factors of the denominator are only 2 and 5,
    300                         // then the number requires a finite number of digits and thus
    301                         // will be represented perfectly using the fewest number of digits.
    302                         // Any other situation will be rounded to 9 fractional digits.
    303                         // max{twos, fives} represents the minimum number of fractional
    304                         // digits necessary to represent val.
    305                         let mut twos = 0;
    306                         let mut fives = 0;
    307                         let zero = BigInt::from_biguint(Sign::NoSign, BigUint::new(Vec::new()));
    308                         let one = BigInt::from_biguint(Sign::Plus, BigUint::new(vec![1]));
    309                         let two = BigInt::from_biguint(Sign::Plus, BigUint::new(vec![2]));
    310                         let five = BigInt::from_biguint(Sign::Plus, BigUint::new(vec![5]));
    311                         let mut denom = val.denom().clone();
    312                         let mut div_rem;
    313                         while denom > one {
    314                             div_rem = denom.div_rem(&two);
    315                             if div_rem.1 == zero {
    316                                 twos += 1;
    317                                 denom = div_rem.0;
    318                             } else {
    319                                 break;
    320                             }
    321                         }
    322                         while denom > one {
    323                             div_rem = denom.div_rem(&five);
    324                             if div_rem.1 == zero {
    325                                 fives += 1;
    326                                 denom = div_rem.0;
    327                             } else {
    328                                 break;
    329                             }
    330                         }
    331                         // int < 0 iff val <= -1. frac < 0 iff val is a negative non-integer.
    332                         let (int, frac, digits) = if denom == one {
    333                             let (int, mut frac) = val.numer().div_rem(val.denom());
    334                             while twos > fives {
    335                                 frac *= &five;
    336                                 fives += 1;
    337                             }
    338                             while fives > twos {
    339                                 frac *= &two;
    340                                 twos += 1;
    341                             }
    342                             (int, frac, twos)
    343                         } else {
    344                             // Requires an infinite number of decimal digits to represent, so we display
    345                             // 9 digits after rounding.
    346                             let mult =
    347                                 BigInt::from_biguint(Sign::Plus, BigUint::new(vec![10])).pow(9u8);
    348                             let (int, frac) = (val * &mult).round().numer().div_rem(&mult);
    349                             (int, frac, 9)
    350                         };
    351                         let int_str = int.to_string().into_bytes();
    352                         let (mut v, frac_str) = if val.numer().sign() == Sign::Minus {
    353                             // Guaranteed to be non-empty.
    354                             if int_str[0] == b'-' {
    355                                 (
    356                                     Vec::with_capacity(int_str.len() + 1 + digits),
    357                                     (-frac).to_string().into_bytes(),
    358                                 )
    359                             } else {
    360                                 let mut tmp = Vec::with_capacity(int_str.len() + 2 + digits);
    361                                 tmp.push(b'-');
    362                                 (tmp, (-frac).to_string().into_bytes())
    363                             }
    364                         } else {
    365                             (
    366                                 Vec::with_capacity(int_str.len() + 1 + digits),
    367                                 frac.to_string().into_bytes(),
    368                             )
    369                         };
    370                         v.extend_from_slice(int_str.as_slice());
    371                         v.push(b'.');
    372                         // digits >= frac_str.len().
    373                         v.resize(v.len() + (digits - frac_str.len()), b'0');
    374                         v.extend_from_slice(frac_str.as_slice());
    375                         // SAFETY:
    376                         // v contains precisely the UTF-8 code units returned from Strings
    377                         // returned from the to_string function on the integer and fraction part of
    378                         // val plus optionally the single byte encodings of ".", "-", and "0".
    379                         write!(f, "> {}", unsafe { String::from_utf8_unchecked(v) })
    380                     }
    381                 })
    382             }
    383             Eval(r) => write!(f, "> {r}"),
    384             Exit => Ok(()),
    385             Store(o) => o.as_ref().map_or(Ok(()), |val| write!(f, "> {val}")),
    386         }
    387     }
    388 }
    389 /// Size of [`Evaluator::cache`].
    390 const CACHE_SIZE: usize = 8;
    391 /// Evaluates the supplied input.
    392 #[derive(Debug)]
    393 pub struct Evaluator<'input, 'cache, 'prev, 'scratch, 'rand> {
    394     /// The input to be evaluated.
    395     utf8: &'input [u8],
    396     /// The index within `utf8` that evaluation needs to continue.
    397     /// We use this instead of slicing from `utf8` since we want
    398     /// to be able to report the position within the input
    399     /// that an error occurs.
    400     i: usize,
    401     /// The cache of previously stored results.
    402     cache: &'cache mut Cache<Ratio<BigInt>, CACHE_SIZE>,
    403     /// The last result.
    404     prev: &'prev mut Option<Ratio<BigInt>>,
    405     /// Buffer used to evaluate right-associative sub-expressions.
    406     scratch: &'scratch mut Vec<Ratio<BigInt>>,
    407     /// Random number generator.
    408     #[cfg(feature = "rand")]
    409     rng: &'rand mut ThreadRng,
    410     /// Need to use `'rand`.
    411     #[cfg(not(feature = "rand"))]
    412     _rng: PhantomData<fn() -> &'rand ()>,
    413 }
    414 #[allow(
    415     single_use_lifetimes,
    416     clippy::allow_attributes,
    417     clippy::elidable_lifetime_names,
    418     reason = "unify rand and not rand"
    419 )]
    420 impl<'input, 'cache, 'prev, 'scratch, 'rand> Evaluator<'input, 'cache, 'prev, 'scratch, 'rand> {
    421     /// Creates an `Evaluator<'input, 'cache, 'prev, 'scratch, 'rand>` based on the supplied arguments.
    422     #[cfg(not(feature = "rand"))]
    423     #[inline]
    424     pub fn new(
    425         utf8: &'input [u8],
    426         cache: &'cache mut Cache<Ratio<BigInt>, 8>,
    427         prev: &'prev mut Option<Ratio<BigInt>>,
    428         scratch: &'scratch mut Vec<Ratio<BigInt>>,
    429     ) -> Self {
    430         Self {
    431             utf8,
    432             i: 0,
    433             cache,
    434             prev,
    435             scratch,
    436             _rng: PhantomData,
    437         }
    438     }
    439     /// Creates an `Evaluator<'input, 'cache, 'prev, 'scratch, 'rand>` based on the supplied arguments.
    440     #[cfg(feature = "rand")]
    441     #[inline]
    442     pub const fn new(
    443         utf8: &'input [u8],
    444         cache: &'cache mut Cache<Ratio<BigInt>, 8>,
    445         prev: &'prev mut Option<Ratio<BigInt>>,
    446         scratch: &'scratch mut Vec<Ratio<BigInt>>,
    447         rng: &'rand mut ThreadRng,
    448     ) -> Self {
    449         Self {
    450             utf8,
    451             i: 0,
    452             cache,
    453             prev,
    454             scratch,
    455             rng,
    456         }
    457     }
    458     /// Evaluates the input consuming the `Evaluator<'input, 'cache, 'exp>`.
    459     ///
    460     /// Requires the input to contain one expression (i.e., if there are
    461     /// multiple newlines, it will error).
    462     ///
    463     /// # Errors
    464     ///
    465     /// Returns a [`LangErr`] iff the input violates the calc language.
    466     #[expect(clippy::indexing_slicing, reason = "correct")]
    467     #[inline]
    468     pub fn evaluate(mut self) -> Result<O<'prev>, LangErr> {
    469         self.utf8 = if self.utf8.last().is_none_or(|b| *b != b'\n') {
    470             self.utf8
    471         } else {
    472             &self.utf8[..self.utf8.len()
    473                 - self
    474                     .utf8
    475                     .get(self.utf8.len().wrapping_sub(2))
    476                     .map_or(1, |b| if *b == b'\r' { 2 } else { 1 })]
    477         };
    478         self.consume_ws();
    479         let Some(b) = self.utf8.get(self.i) else {
    480             return Ok(Empty(self.prev));
    481         };
    482         if *b == b'q' {
    483             self.i += 1;
    484             self.consume_ws();
    485             if self.i == self.utf8.len() {
    486                 Ok(Exit)
    487             } else {
    488                 Err(InvalidQuit)
    489             }
    490         } else if *b == b's' {
    491             self.i += 1;
    492             self.consume_ws();
    493             if self.i == self.utf8.len() {
    494                 if let Some(ref val) = *self.prev {
    495                     self.cache.push(val.clone());
    496                 }
    497                 Ok(Store(self.prev))
    498             } else {
    499                 Err(InvalidStore)
    500             }
    501         } else {
    502             self.get_adds().and_then(move |val| {
    503                 self.consume_ws();
    504                 if self.i == self.utf8.len() {
    505                     Ok(Eval(self.prev.insert(val)))
    506                 } else {
    507                     Err(TrailingSyms(self.i))
    508                 }
    509             })
    510         }
    511     }
    512     /// Reads from the input until the next non-{space/tab} byte value.
    513     #[expect(clippy::indexing_slicing, reason = "correct")]
    514     fn consume_ws(&mut self) {
    515         // ControlFlow makes more sense to use in try_fold; however due to a lack
    516         // of a map_or_else function, it is easier to simply return a Result with
    517         // Err taking the role of ControlFlow::Break.
    518         self.i += self.utf8[self.i..]
    519             .iter()
    520             .try_fold(0, |val, b| match *b {
    521                 b' ' | b'\t' => Ok(val + 1),
    522                 _ => Err(val),
    523             })
    524             .unwrap_or_else(convert::identity);
    525     }
    526     /// Evaluates addition expressions as defined in the calc language.
    527     /// This function is used for both addition and subtraction operations which
    528     /// themselves are based on multiplication expressions.
    529     fn get_adds(&mut self) -> Result<Ratio<BigInt>, LangErr> {
    530         let mut left = self.get_mults()?;
    531         let mut j;
    532         self.consume_ws();
    533         while let Some(i) = self.utf8.get(self.i) {
    534             j = *i;
    535             self.consume_ws();
    536             if j == b'+' {
    537                 self.i += 1;
    538                 self.consume_ws();
    539                 left += self.get_mults()?;
    540             } else if j == b'-' {
    541                 self.i += 1;
    542                 self.consume_ws();
    543                 left -= self.get_mults()?;
    544             } else {
    545                 break;
    546             }
    547         }
    548         Ok(left)
    549     }
    550     /// Evaluates multiplication expressions as defined in the calc language.
    551     /// This function is used for both multiplication and division operations which
    552     /// themselves are based on negation expressions.
    553     fn get_mults(&mut self) -> Result<Ratio<BigInt>, LangErr> {
    554         let mut left = self.get_neg()?;
    555         let mut right;
    556         let mut j;
    557         let mut mod_val;
    558         let mut numer;
    559         self.consume_ws();
    560         while let Some(i) = self.utf8.get(self.i) {
    561             j = *i;
    562             self.consume_ws();
    563             if j == b'*' {
    564                 self.i += 1;
    565                 self.consume_ws();
    566                 left *= self.get_neg()?;
    567             } else if j == b'/' {
    568                 self.i += 1;
    569                 self.consume_ws();
    570                 right = self.get_neg()?;
    571                 if right.numer().sign() == Sign::NoSign {
    572                     return Err(DivByZero(self.i));
    573                 }
    574                 left /= right;
    575             } else if let Some(k) = self.utf8.get(self.i..self.i.saturating_add(3)) {
    576                 if k == b"mod" {
    577                     if !left.is_integer() {
    578                         return Err(ModIsNotInt(self.i));
    579                     }
    580                     self.i += 3;
    581                     self.consume_ws();
    582                     right = self.get_neg()?;
    583                     if !right.is_integer() {
    584                         return Err(ModIsNotInt(self.i));
    585                     }
    586                     numer = right.numer();
    587                     if numer.sign() == Sign::NoSign {
    588                         return Err(ModZero(self.i));
    589                     }
    590                     mod_val = left.numer() % numer;
    591                     left = Ratio::from_integer(if mod_val.sign() == Sign::Minus {
    592                         if numer.sign() == Sign::Minus {
    593                             mod_val - numer
    594                         } else {
    595                             mod_val + numer
    596                         }
    597                     } else {
    598                         mod_val
    599                     });
    600                 } else {
    601                     break;
    602                 }
    603             } else {
    604                 break;
    605             }
    606         }
    607         Ok(left)
    608     }
    609     /// Evaluates negation expressions as defined in the calc language.
    610     /// This function is based on exponentiation expressions.
    611     fn get_neg(&mut self) -> Result<Ratio<BigInt>, LangErr> {
    612         let mut count = 0usize;
    613         while let Some(b) = self.utf8.get(self.i) {
    614             if *b == b'-' {
    615                 self.i += 1;
    616                 self.consume_ws();
    617                 count += 1;
    618             } else {
    619                 break;
    620             }
    621         }
    622         self.get_exps()
    623             .map(|val| if count & 1 == 0 { val } else { -val })
    624     }
    625     /// Gets the square root of value so long as a solution exists.
    626     #[expect(
    627         clippy::unreachable,
    628         reason = "code that shouldn't happen did, so we want to crash"
    629     )]
    630     fn sqrt(val: Ratio<BigInt>) -> Option<Ratio<BigInt>> {
    631         /// Returns the square root of `n` if one exists; otherwise
    632         /// returns `None`.
    633         /// MUST NOT pass 0.
    634         #[expect(clippy::suspicious_operation_groupings, reason = "false positive")]
    635         fn calc(n: &BigUint) -> Option<BigUint> {
    636             let mut shift = n.bits();
    637             shift += shift & 1;
    638             let mut result = BigUint::new(Vec::new());
    639             let one = BigUint::new(vec![1]);
    640             let zero = BigUint::new(Vec::new());
    641             loop {
    642                 shift -= 2;
    643                 result <<= 1u32;
    644                 result |= &one;
    645                 result ^= if &result * &result > (n >> shift) {
    646                     &one
    647                 } else {
    648                     &zero
    649                 };
    650                 if shift == 0 {
    651                     break (&result * &result == *n).then_some(result);
    652                 }
    653             }
    654         }
    655         let numer = val.numer();
    656         if numer.sign() == Sign::NoSign {
    657             Some(val)
    658         } else {
    659             numer.try_into().map_or_else(
    660                 |_| None,
    661                 |num| {
    662                     calc(&num).and_then(|n| {
    663                         calc(&val.denom().try_into().unwrap_or_else(|_| {
    664                             unreachable!("Ratio must never have a negative denominator")
    665                         }))
    666                         .map(|d| Ratio::new(n.into(), d.into()))
    667                     })
    668                 },
    669             )
    670         }
    671     }
    672     /// Evaluates exponentiation expressions as defined in the calc language.
    673     /// This function is based on negation expressions.
    674     fn get_exps(&mut self) -> Result<Ratio<BigInt>, LangErr> {
    675         let mut t = self.get_fact()?;
    676         let ix = self.scratch.len();
    677         let mut prev;
    678         let mut numer;
    679         self.scratch.push(t);
    680         self.consume_ws();
    681         let mut j;
    682         let one = BigInt::new(Sign::Plus, vec![1]);
    683         let min_one = BigInt::new(Sign::Minus, vec![1]);
    684         let two = BigInt::new(Sign::Plus, vec![2]);
    685         while let Some(i) = self.utf8.get(self.i) {
    686             j = *i;
    687             self.consume_ws();
    688             if j == b'^' {
    689                 self.i += 1;
    690                 self.consume_ws();
    691                 t = self.get_neg()?;
    692                 // Safe since we always push at least one value, and we always
    693                 // return immediately once we encounter an error.
    694                 prev = self.scratch.index(self.scratch.len() - 1);
    695                 numer = prev.numer();
    696                 // Equiv to checking if prev is 0.
    697                 if numer.sign() == Sign::NoSign {
    698                     if t.numer().sign() == Sign::Minus {
    699                         self.scratch.clear();
    700                         return Err(ExpDivByZero(self.i));
    701                     }
    702                     self.scratch.push(t);
    703                 } else if prev.is_integer() {
    704                     let t_numer = t.numer();
    705                     // 1 raised to anything is 1, so we don't bother
    706                     // storing the exponent.
    707                     if *numer == one {
    708                     } else if t.is_integer()
    709                         || ((*t_numer == one || *t_numer == min_one) && *t.denom() == two)
    710                     {
    711                         self.scratch.push(t);
    712                     } else {
    713                         self.scratch.clear();
    714                         return Err(ExpIsNotIntOrOneHalf(self.i));
    715                     }
    716                 } else if t.is_integer()
    717                     || ((*t.numer() == one || *t.numer() == min_one) && *t.denom() == two)
    718                 {
    719                     self.scratch.push(t);
    720                 } else {
    721                     self.scratch.clear();
    722                     return Err(ExpIsNotIntOrOneHalf(self.i));
    723                 }
    724             } else {
    725                 break;
    726             }
    727         }
    728         self.scratch
    729             .drain(ix..)
    730             .try_rfold(Ratio::from_integer(one.clone()), |exp, base| {
    731                 if exp.is_integer() {
    732                     Ok(base.pow(exp.numer()))
    733                 } else if base.numer().sign() == Sign::NoSign {
    734                     Ok(base)
    735                 } else if *exp.denom() == two {
    736                     if *exp.numer() == one {
    737                         Self::sqrt(base).map_or_else(|| Err(SqrtDoesNotExist(self.i)), Ok)
    738                     } else if *exp.numer() == min_one {
    739                         Self::sqrt(base)
    740                             .map_or_else(|| Err(SqrtDoesNotExist(self.i)), |v| Ok(v.inv()))
    741                     } else {
    742                         Err(ExpIsNotIntOrOneHalf(self.i))
    743                     }
    744                 } else {
    745                     Err(ExpIsNotIntOrOneHalf(self.i))
    746                 }
    747             })
    748     }
    749     /// Evaluates factorial expressions as defined in the calc language.
    750     /// This function is based on terminal expressions.
    751     fn get_fact(&mut self) -> Result<Ratio<BigInt>, LangErr> {
    752         /// Calculates the factorial of `val`.
    753         fn fact(mut val: BigUint) -> BigUint {
    754             let zero = BigUint::new(Vec::new());
    755             let one = BigUint::new(vec![1]);
    756             let mut calc = BigUint::new(vec![1]);
    757             while val > zero {
    758                 calc *= &val;
    759                 val -= &one;
    760             }
    761             calc
    762         }
    763         let t = self.get_term()?;
    764         let Some(b) = self.utf8.get(self.i) else {
    765             return Ok(t);
    766         };
    767         if *b == b'!' {
    768             self.i += 1;
    769             if t.is_integer() {
    770                 // We can make a copy of self.i here, or call map_or instead
    771                 // of map_or_else.
    772                 let i = self.i;
    773                 t.numer().try_into().map_or_else(
    774                     |_| Err(NotNonNegIntFact(i)),
    775                     |val| {
    776                         let mut factorial = fact(val);
    777                         while let Some(b2) = self.utf8.get(self.i) {
    778                             if *b2 == b'!' {
    779                                 self.i += 1;
    780                                 factorial = fact(factorial);
    781                             } else {
    782                                 break;
    783                             }
    784                         }
    785                         Ok(Ratio::from_integer(BigInt::from_biguint(
    786                             Sign::Plus,
    787                             factorial,
    788                         )))
    789                     },
    790                 )
    791             } else {
    792                 Err(NotNonNegIntFact(self.i))
    793             }
    794         } else {
    795             Ok(t)
    796         }
    797     }
    798     /// Evaluates terminal expressions as defined in the calc language.
    799     /// This function is based on number literal expressions, parenthetical expressions,
    800     /// recall expressions, absolute value expressions, round expressions, and possibly
    801     /// rand expressions if that feature is enabled.
    802     fn get_term(&mut self) -> Result<Ratio<BigInt>, LangErr> {
    803         self.get_rational().map_or_else(Err, |o| {
    804             o.map_or_else(
    805                 || {
    806                     self.get_par().map_or_else(Err, |o2| {
    807                         o2.map_or_else(
    808                             || {
    809                                 self.get_recall().map_or_else(Err, |o3| {
    810                                     o3.map_or_else(
    811                                         || {
    812                                             self.get_abs().map_or_else(Err, |o4| {
    813                                                 o4.map_or_else(
    814                                                     || {
    815                                                         self.get_round().and_then(|o5| {
    816                                                             o5.map_or_else(
    817                                                                 #[cfg(not(feature = "rand"))]
    818                                                                 || Err(MissingTerm(self.i)),
    819                                                                 #[cfg(feature = "rand")]
    820                                                                 || self.get_rand(),
    821                                                                 Ok,
    822                                                             )
    823                                                         })
    824                                                     },
    825                                                     Ok,
    826                                                 )
    827                                             })
    828                                         },
    829                                         Ok,
    830                                     )
    831                                 })
    832                             },
    833                             Ok,
    834                         )
    835                     })
    836                 },
    837                 Ok,
    838             )
    839         })
    840     }
    841     /// Generates a random 64-bit integer. This function is based on add expressions. This is the last terminal
    842     /// expression attempted when needing a terminal expression; as a result, it is the only terminal expression
    843     /// that does not return an `Option`.
    844     #[cfg(feature = "rand")]
    845     fn get_rand(&mut self) -> Result<Ratio<BigInt>, LangErr> {
    846         /// Generates a random 64-bit integer.
    847         #[expect(clippy::host_endian_bytes, reason = "must keep platform endianness")]
    848         fn rand(rng: &mut ThreadRng) -> i64 {
    849             let mut bytes = [0; 8];
    850             // `ThreadRng::try_fill_bytes` is infallible, so easier to call `fill_bytes`.
    851             rng.fill_bytes(&mut bytes);
    852             i64::from_ne_bytes(bytes)
    853         }
    854         /// Generates a random 64-bit integer inclusively between the passed arguments.
    855         #[expect(
    856             clippy::integer_division_remainder_used,
    857             reason = "need for uniform randomness"
    858         )]
    859         #[expect(
    860             clippy::as_conversions,
    861             clippy::cast_possible_truncation,
    862             clippy::cast_possible_wrap,
    863             clippy::cast_sign_loss,
    864             reason = "lossless conversions between signed integers"
    865         )]
    866         fn rand_range(
    867             rng: &mut ThreadRng,
    868             lower: &Ratio<BigInt>,
    869             upper: &Ratio<BigInt>,
    870             i: usize,
    871         ) -> Result<i64, LangErr> {
    872             if lower > upper {
    873                 return Err(LangErr::RandInvalidArgs(i));
    874             }
    875             let lo = lower.ceil();
    876             let up = upper.floor();
    877             let lo_int = lo.numer();
    878             let up_int = up.numer();
    879             if lo_int > &BigInt::from(i64::MAX) || up_int < &BigInt::from(i64::MIN) {
    880                 return Err(LangErr::RandNoInts(i));
    881             }
    882             let lo_min = lo_int.to_i64().unwrap_or(i64::MIN);
    883             let up_max = up_int.to_i64().unwrap_or(i64::MAX);
    884             if up_max > lo_min || upper.is_integer() || lower.is_integer() {
    885                 let low = i128::from(lo_min);
    886                 // `i64::MAX >= up_max >= low`; so underflow and overflow cannot happen.
    887                 // range is [1, 2^64] so casting to a u128 is fine.
    888                 let modulus = (i128::from(up_max) - low + 1) as u128;
    889                 // range is [0, i64::MAX] so converting to a `u64` is fine.
    890                 // rem represents how many values need to be removed
    891                 // when generating a random i64 in order for uniformity.
    892                 let rem = (0x0001_0000_0000_0000_0000 % modulus) as u64;
    893                 let mut low_adj;
    894                 loop {
    895                     low_adj = rand(rng) as u64;
    896                     // Since rem is in [0, i64::MAX], this is the same as low_adj < 0 || low_adj >= rem.
    897                     if low_adj >= rem {
    898                         return Ok(
    899                             // range is [i64::MIN, i64::MAX]; thus casts are safe.
    900                             // modulus is up_max - low + 1; so as low grows,
    901                             // % shrinks by the same factor. i64::MAX happens
    902                             // when low = up_max = i64::MAX or when low = 0,
    903                             // up_max = i64::MAX and low_adj is i64::MAX.
    904                             ((u128::from(low_adj) % modulus) as i128 + low) as i64,
    905                         );
    906                     }
    907                 }
    908             } else {
    909                 Err(LangErr::RandNoInts(i))
    910             }
    911         }
    912         // This is the last kind of terminal expression that is attempted.
    913         // If there is no more data, then we have a missing terminal expression.
    914         let Some(b) = self.utf8.get(self.i..self.i.saturating_add(5)) else {
    915             return Err(MissingTerm(self.i));
    916         };
    917         if b == b"rand(" {
    918             self.i += 5;
    919             self.consume_ws();
    920             let i = self.i;
    921             self.utf8.get(self.i).map_or_else(
    922                 || Err(LangErr::InvalidRand(i)),
    923                 |p| {
    924                     if *p == b')' {
    925                         self.i += 1;
    926                         Ok(Ratio::from_integer(BigInt::from(rand(self.rng))))
    927                     } else {
    928                         let add = self.get_adds()?;
    929                         let Some(b2) = self.utf8.get(self.i) else {
    930                             return Err(LangErr::InvalidRand(self.i));
    931                         };
    932                         if *b2 == b',' {
    933                             self.i += 1;
    934                             self.consume_ws();
    935                             let add2 = self.get_adds()?;
    936                             self.consume_ws();
    937                             let Some(b3) = self.utf8.get(self.i) else {
    938                                 return Err(LangErr::InvalidRand(self.i));
    939                             };
    940                             if *b3 == b')' {
    941                                 self.i += 1;
    942                                 rand_range(self.rng, &add, &add2, self.i)
    943                                     .map(|v| Ratio::from_integer(BigInt::from(v)))
    944                             } else {
    945                                 Err(LangErr::InvalidRand(self.i))
    946                             }
    947                         } else {
    948                             Err(LangErr::InvalidRand(self.i))
    949                         }
    950                     }
    951                 },
    952             )
    953         } else {
    954             Err(MissingTerm(self.i))
    955         }
    956     }
    957     /// Rounds a value to the specified number of fractional digits.
    958     /// This function is based on add expressions.
    959     fn get_round(&mut self) -> Result<Option<Ratio<BigInt>>, LangErr> {
    960         let Some(b) = self.utf8.get(self.i..self.i.saturating_add(6)) else {
    961             return Ok(None);
    962         };
    963         if b == b"round(" {
    964             self.i += 6;
    965             self.consume_ws();
    966             let val = self.get_adds()?;
    967             self.consume_ws();
    968             let Some(b2) = self.utf8.get(self.i) else {
    969                 return Err(InvalidRound(self.i));
    970             };
    971             let b3 = *b2;
    972             if b3 == b',' {
    973                 self.i += 1;
    974                 self.consume_ws();
    975                 let Some(b4) = self.utf8.get(self.i) else {
    976                     return Err(InvalidRound(self.i));
    977                 };
    978                 let r = if b4.is_ascii_digit() {
    979                     self.i += 1;
    980                     *b4 - b'0'
    981                 } else {
    982                     return Err(InvalidRound(self.i));
    983                 };
    984                 self.consume_ws();
    985                 let i = self.i;
    986                 self.utf8.get(self.i).map_or_else(
    987                     || Err(InvalidRound(i)),
    988                     |p| {
    989                         if *p == b')' {
    990                             self.i += 1;
    991                             let mult =
    992                                 BigInt::from_biguint(Sign::Plus, BigUint::new(vec![10])).pow(r);
    993                             Ok(Some((val * &mult).round() / &mult))
    994                         } else {
    995                             Err(InvalidRound(self.i))
    996                         }
    997                     },
    998                 )
    999             } else {
   1000                 Err(InvalidRound(self.i))
   1001             }
   1002         } else {
   1003             Ok(None)
   1004         }
   1005     }
   1006     /// Evaluates absolute value expressions as defined in the calc language.
   1007     /// This function is based on add expressions.
   1008     fn get_abs(&mut self) -> Result<Option<Ratio<BigInt>>, LangErr> {
   1009         let Some(b) = self.utf8.get(self.i) else {
   1010             return Ok(None);
   1011         };
   1012         if *b == b'|' {
   1013             self.i += 1;
   1014             self.consume_ws();
   1015             let r = self.get_adds()?;
   1016             self.consume_ws();
   1017             let Some(b2) = self.utf8.get(self.i) else {
   1018                 return Err(InvalidAbs(self.i));
   1019             };
   1020             let b3 = *b2;
   1021             if b3 == b'|' {
   1022                 self.i += 1;
   1023                 Ok(Some(if r.numer().sign() == Sign::Minus {
   1024                     -r
   1025                 } else {
   1026                     r
   1027                 }))
   1028             } else {
   1029                 Err(InvalidAbs(self.i))
   1030             }
   1031         } else {
   1032             Ok(None)
   1033         }
   1034     }
   1035     /// Evaluates recall expressions as defined in the calc language.
   1036     // This does not return a Result<Option<&Ratio<BigInt>>, LangErr>
   1037     // since the only place this function is called is in get_term which
   1038     // would end up needing to clone the Ratio anyway. By not forcing
   1039     // get_term to clone, it can rely on map_or_else over match expressions.
   1040     fn get_recall(&mut self) -> Result<Option<Ratio<BigInt>>, LangErr> {
   1041         let Some(b) = self.utf8.get(self.i) else {
   1042             return Ok(None);
   1043         };
   1044         if *b == b'@' {
   1045             self.i += 1;
   1046             self.cache
   1047                 .get(self.utf8.get(self.i).map_or(0, |b2| {
   1048                     if (b'1'..b'9').contains(b2) {
   1049                         self.i += 1;
   1050                         usize::from(*b2 - b'1')
   1051                     } else {
   1052                         0
   1053                     }
   1054                 }))
   1055                 .map_or_else(
   1056                     || Err(NotEnoughPrevResults(self.cache.len())),
   1057                     |p| Ok(Some(p.clone())),
   1058                 )
   1059         } else {
   1060             Ok(None)
   1061         }
   1062     }
   1063     /// Evaluates parenthetical expressions as defined in the calc language.
   1064     /// This function is based on add expressions.
   1065     fn get_par(&mut self) -> Result<Option<Ratio<BigInt>>, LangErr> {
   1066         let Some(b) = self.utf8.get(self.i) else {
   1067             return Ok(None);
   1068         };
   1069         if *b == b'(' {
   1070             self.i += 1;
   1071             self.consume_ws();
   1072             let r = self.get_adds()?;
   1073             self.consume_ws();
   1074             let Some(b2) = self.utf8.get(self.i) else {
   1075                 return Err(InvalidPar(self.i));
   1076             };
   1077             let b3 = *b2;
   1078             if b3 == b')' {
   1079                 self.i += 1;
   1080                 Ok(Some(r))
   1081             } else {
   1082                 Err(InvalidPar(self.i))
   1083             }
   1084         } else {
   1085             Ok(None)
   1086         }
   1087     }
   1088     /// Evaluates number literal expressions as defined in the calc language.
   1089     #[expect(clippy::indexing_slicing, reason = "correct")]
   1090     fn get_rational(&mut self) -> Result<Option<Ratio<BigInt>>, LangErr> {
   1091         // ControlFlow makes more sense to use in try_fold; however due to a lack
   1092         // of a map_or_else function, it is easier to simply return a Result with
   1093         // Err taking the role of ControlFlow::Break.
   1094         /// Used to parse a sequence of digits into an unsigned integer.
   1095         fn to_biguint(v: &[u8]) -> (BigUint, usize) {
   1096             v.iter()
   1097                 .try_fold((BigUint::new(Vec::new()), 0), |mut prev, d| {
   1098                     if d.is_ascii_digit() {
   1099                         prev.1 += 1;
   1100                         // `*d - b'0'` is guaranteed to return a integer between 0 and 9.
   1101                         prev.0 = prev.0 * 10u8 + (*d - b'0');
   1102                         Ok(prev)
   1103                     } else {
   1104                         Err(prev)
   1105                     }
   1106                 })
   1107                 .unwrap_or_else(convert::identity)
   1108         }
   1109         let (int, len) = to_biguint(&self.utf8[self.i..]);
   1110         if len == 0 {
   1111             return Ok(None);
   1112         }
   1113         self.i += len;
   1114         if let Some(b) = self.utf8.get(self.i) {
   1115             if *b == b'.' {
   1116                 self.i += 1;
   1117                 let (numer, len2) = to_biguint(&self.utf8[self.i..]);
   1118                 if len2 == 0 {
   1119                     Err(InvalidDec(self.i))
   1120                 } else {
   1121                     self.i += len2;
   1122                     Ok(Some(
   1123                         Ratio::from_integer(BigInt::from_biguint(Sign::Plus, int))
   1124                             + Ratio::new(
   1125                                 BigInt::from_biguint(Sign::Plus, numer),
   1126                                 BigInt::from_biguint(Sign::Plus, BigUint::new(vec![10]).pow(len2)),
   1127                             ),
   1128                     ))
   1129                 }
   1130             } else {
   1131                 Ok(Some(Ratio::from_integer(BigInt::from_biguint(
   1132                     Sign::Plus,
   1133                     int,
   1134                 ))))
   1135             }
   1136         } else {
   1137             Ok(Some(Ratio::from_integer(BigInt::from_biguint(
   1138                 Sign::Plus,
   1139                 int,
   1140             ))))
   1141         }
   1142     }
   1143 }
   1144 /// Reads data from `R` passing each line to an [`Evaluator`] to be evaluated.
   1145 #[cfg(feature = "std")]
   1146 #[derive(Debug)]
   1147 pub struct EvalIter<R> {
   1148     /// Reader that contains input data.
   1149     reader: R,
   1150     /// Buffer that is used by `reader` to read
   1151     /// data into.
   1152     input_buffer: Vec<u8>,
   1153     /// Cache of stored results.
   1154     cache: Cache<Ratio<BigInt>, 8>,
   1155     /// Result of the previous expression.
   1156     prev: Option<Ratio<BigInt>>,
   1157     /// Buffer used by [`Evaluator`] to process
   1158     /// sub-expressions.
   1159     exp_buffer: Vec<Ratio<BigInt>>,
   1160     /// Random number generator.
   1161     #[cfg(feature = "rand")]
   1162     rng: ThreadRng,
   1163 }
   1164 #[cfg(feature = "std")]
   1165 impl<R> EvalIter<R> {
   1166     /// Creates a new `EvalIter`.
   1167     #[cfg(feature = "rand")]
   1168     #[inline]
   1169     pub fn new(reader: R) -> Self {
   1170         Self {
   1171             reader,
   1172             input_buffer: Vec::new(),
   1173             cache: Cache::new(),
   1174             prev: None,
   1175             exp_buffer: Vec::new(),
   1176             rng: rand::rng(),
   1177         }
   1178     }
   1179     /// Creates a new `EvalIter`.
   1180     #[cfg(any(doc, not(feature = "rand")))]
   1181     #[inline]
   1182     pub fn new(reader: R) -> Self {
   1183         Self {
   1184             reader,
   1185             input_buffer: Vec::new(),
   1186             cache: Cache::new(),
   1187             prev: None,
   1188             exp_buffer: Vec::new(),
   1189         }
   1190     }
   1191 }
   1192 #[cfg(feature = "std")]
   1193 extern crate std;
   1194 #[cfg(feature = "std")]
   1195 use std::io::{BufRead, Error};
   1196 /// Error returned from [`EvalIter`] when an expression has an error.
   1197 #[cfg(feature = "std")]
   1198 #[derive(Debug)]
   1199 pub enum E {
   1200     /// Error containing [`Error`] which is returned
   1201     /// from [`EvalIter`] when reading from the supplied
   1202     /// [`BufRead`]er.
   1203     Error(Error),
   1204     /// Error containing [`LangErr`] which is returned
   1205     /// from [`EvalIter`] when evaluating a single expression.
   1206     LangErr(LangErr),
   1207 }
   1208 #[cfg(feature = "std")]
   1209 impl Display for E {
   1210     #[inline]
   1211     fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
   1212         match *self {
   1213             Self::Error(ref e) => e.fmt(f),
   1214             Self::LangErr(ref e) => e.fmt(f),
   1215         }
   1216     }
   1217 }
   1218 #[cfg(feature = "std")]
   1219 use crate::lending_iterator::LendingIterator;
   1220 #[cfg(feature = "std")]
   1221 impl<R> LendingIterator for EvalIter<R>
   1222 where
   1223     R: BufRead,
   1224 {
   1225     type Item<'a>
   1226         = Result<O<'a>, E>
   1227     where
   1228         Self: 'a;
   1229     #[inline]
   1230     fn lend_next(&mut self) -> Option<Result<O<'_>, E>> {
   1231         self.input_buffer.clear();
   1232         self.exp_buffer.clear();
   1233         self.reader
   1234             .read_until(b'\n', &mut self.input_buffer)
   1235             .map_or_else(
   1236                 |e| Some(Err(E::Error(e))),
   1237                 |c| {
   1238                     if c == 0 {
   1239                         None
   1240                     } else {
   1241                         Evaluator::new(
   1242                             self.input_buffer.as_slice(),
   1243                             &mut self.cache,
   1244                             &mut self.prev,
   1245                             &mut self.exp_buffer,
   1246                             #[cfg(feature = "rand")]
   1247                             &mut self.rng,
   1248                         )
   1249                         .evaluate()
   1250                         .map_or_else(
   1251                             |e| Some(Err(E::LangErr(e))),
   1252                             |o| match o {
   1253                                 Empty(_) | Eval(_) | Store(_) => Some(Ok(o)),
   1254                                 Exit => None,
   1255                             },
   1256                         )
   1257                     }
   1258                 },
   1259             )
   1260     }
   1261 }