1#![warn(clippy::all, clippy::pedantic, clippy::nursery, clippy::cargo)]
6#![allow(clippy::module_name_repetitions)]
8#![deny(missing_docs)]
10
11#[macro_use]
12extern crate lazy_static;
13
14pub mod dice;
15pub mod error;
16
17use anyhow::Result;
18use dice::DiceRoll;
19use evalexpr::eval;
20use rand::{rngs::SmallRng, SeedableRng};
21use regex::{Captures, Regex};
22use std::borrow::Cow;
23
24pub fn solve_dice_expression(expression: &str, random_seed: Option<u64>) -> Result<i64> {
37 lazy_static! {
38 static ref PATTERN: Regex = Regex::new(r"(\d+)d(\d+)").expect("Problem compiling regex");
39 }
40
41 let mut rng = match random_seed {
43 Some(inner) => SmallRng::seed_from_u64(inner),
44 None => SmallRng::from_entropy(),
45 };
46
47 let mut error = None;
50
51 let rolled_expression = PATTERN.replace_all(expression, |caps: &Captures| {
53 let diceroll_str = &caps.get(0).unwrap().as_str().to_string();
55 match DiceRoll::from_string(diceroll_str) {
56 Ok(dice) => match dice.roll(&mut rng) {
57 Ok(roll_result) => Cow::Owned(format!("{}", roll_result)),
58 Err(e) => {
59 error = Some(e.context(diceroll_str.clone()));
60 Cow::Borrowed("")
61 }
62 },
63 Err(e) => {
64 error = Some(e.context(diceroll_str.clone()));
65 Cow::Borrowed("")
66 }
67 }
68 });
69
70 if let Some(e) = error {
71 Err(e)
72 } else {
73 let result = eval(&rolled_expression)?.as_int()?;
75 Ok(result)
76 }
77}