From 3e0b394e209d94feb212115ab24259b7fe28c37a Mon Sep 17 00:00:00 2001 From: Charles Date: Sun, 24 Nov 2024 22:41:39 -0800 Subject: [PATCH] add: use fixed-size array and no allocs --- src/lib.rs | 86 +++++++++++++++++++++++++++++++++--------------------- 1 file changed, 53 insertions(+), 33 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 556b0f8..dc885ab 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,52 +1,72 @@ use nom::{branch::alt, character::complete, IResult}; use rand::Rng; -pub struct Roller { - expr: Expr, +pub struct Roller { + exprs: [Option; S], } -impl Roller { +impl Roller { /// parse converts the str, of form: - /// 2d8 + 1d8 + 4 - /// into a parsed expression, returning an Expr enum - /// and the remaining unparsed string. - pub fn parse(expr: &str) -> Result>> { - let (mut expr, left) = term(expr)?; - let mut res = Expr::Term(left); + /// 2d8+1d8+4 + /// into a parsed expression. + pub fn parse(mut expr: &str) -> Result, nom::Err>> { + let mut op = Oper::Add; + let mut exprs = [const { None }; S]; + let mut i = 0; while expr.len() > 0 { - let (e, oper) = oper(expr)?; - let (e, term) = term(e)?; - res = Expr::Op(Box::new(res), oper, Box::new(Expr::Term(term))); + let (e, term) = term(expr)?; expr = e; + exprs[i] = Some(Cmd{term, oper: op}); + i += 1; + if i == exprs.len() { + return Err(nom::Err::Incomplete(nom::Needed::new(S + 1))); + } + + // Get the next oper + if e.len() > 0 { + let (e, _op) = oper(expr)?; + op = _op; + expr = e; + } } - Ok(Roller{expr: res}) + Ok(Roller{exprs}) } pub fn roll(&self, rng: &mut R) -> u64 { - self.expr.val(rng) - } -} - -enum Expr { - Term(Term), - Op(Box, Oper, Box), -} - -impl Expr { - fn val(&self, rng: &mut R) -> u64 { - match self { - Expr::Term(Term::Const(x)) => *x, - Expr::Term(Term::Roll(r)) => r.val(rng), - Expr::Op(a, Oper::Add, b) => a.val(rng) + b.val(rng), - Expr::Op(a, Oper::Sub, b) => a.val(rng) - b.val(rng), + let mut sum = 0; + for expr in &self.exprs { + if expr.is_none() { + break; + } + let cmd = expr.as_ref().unwrap(); + match cmd.oper { + Oper::Add => sum += cmd.term.val(rng), + Oper::Sub => sum -= cmd.term.val(rng), + }; } + sum } } +struct Cmd { + oper: Oper, + term: Term, +} + enum Term { Roll(Roll), Const(u64), } +impl Term { + fn val(&self, rng: &mut R) -> u64 { + match self { + Term::Const(c) => *c, + Term::Roll(r) => r.val(rng), + } + } +} + +#[derive(Clone, Copy)] enum Oper { Add, Sub, @@ -106,7 +126,7 @@ mod tests { #[test] fn roll_many_d6s() { let mut rng = StdRng::seed_from_u64(1337); - let roller = Roller::parse("1d6").unwrap(); + let roller = Roller::<1024>::parse("1d6").unwrap(); let mut results = [0u64; 6]; for _ in 0..1000 { results[(roller.roll(&mut rng)-1) as usize] += 1; @@ -120,7 +140,7 @@ mod tests { #[test] fn roll_many_d6s_plus_2() { let mut rng = StdRng::seed_from_u64(1337); - let roller = Roller::parse("1d6+2").unwrap(); + let roller = Roller::<1024>::parse("1d6+2").unwrap(); let mut results = [0u64; 6+2]; for _ in 0..1000 { results[(roller.roll(&mut rng)-1) as usize] += 1; @@ -136,7 +156,7 @@ mod tests { #[test] fn roll_many_d6s_plus_1d6() { let mut rng = StdRng::seed_from_u64(1337); - let roller = Roller::parse("1d6+1d6").unwrap(); + let roller = Roller::<1024>::parse("1d6+1d6").unwrap(); let mut results = [0u64; 6+6]; for _ in 0..1000 { results[(roller.roll(&mut rng)-1) as usize] += 1; @@ -151,7 +171,7 @@ mod tests { #[test] fn roll_many_d6s_plus_1d6_minus_one() { let mut rng = StdRng::seed_from_u64(1337); - let roller = Roller::parse("1d6+1d6-1").unwrap(); + let roller = Roller::<1024>::parse("1d6+1d6-1").unwrap(); let mut results = [0u64; 6+6]; for _ in 0..1000 { results[(roller.roll(&mut rng)-1) as usize] += 1;