diff --git a/Cargo.lock b/Cargo.lock index 9716d17..e5487b7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1420,7 +1420,7 @@ dependencies = [ "security-framework", "security-framework-sys", "webpki-root-certs", - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] diff --git a/src/dice.rs b/src/dice.rs index 169ea03..fc33011 100644 --- a/src/dice.rs +++ b/src/dice.rs @@ -1,4 +1,6 @@ -use crate::limits::{MAX_DICE_COUNT_PER_ROLL, MAX_DISPLAYED_DICE_PER_MESSAGE, RESULT_CULL_CHARACTER_THRESHOLD}; +use crate::limits::{ + MAX_DICE_COUNT_PER_ROLL, MAX_DISPLAYED_DICE_PER_MESSAGE, RESULT_CULL_CHARACTER_THRESHOLD, +}; use anyhow::bail; use rand::{Rng, RngExt}; use std::convert::Infallible; @@ -116,10 +118,10 @@ impl Expression { // Exploding dice are early, they add rolls if let Some(fragments) = x { write!(w, "x")?; - let mut comparers = Vec::with_capacity(fragments.len()); - for fragment in fragments { - comparers.push(fragment.comparer(rng, w)?); - } + let comparers = fragments + .iter() + .map(|fragment| fragment.comparer(rng, w)) + .collect::, _>>()?; let mut i = 0; while i < rolls.len() { if i > MAX_DICE_COUNT_PER_ROLL { @@ -131,12 +133,8 @@ impl Expression { rolls.push(rng.random_range(1..=size)); } } else { - // Explode based on comparers provided - for comparer in comparers.iter() { - if comparer(rolls[i] as f64) { - rolls.push(rng.random_range(1..=size)); - break; - } + if comparers.iter().any(|comparer| comparer(rolls[i] as f64)) { + rolls.push(rng.random_range(1..=size)); } } i += 1; @@ -454,12 +452,15 @@ pub(crate) enum DiscordMdWitnessError { } impl DiscordMd { - pub(crate) fn create_witness(md: &Arc>) -> DiscordMdWitness { - let mut parent = md.write().unwrap(); - parent.buffers.push(String::new()); + pub(crate) fn create_witness(md: Arc>) -> DiscordMdWitness { + let buffer_idx = { + let mut md = md.write().unwrap(); + md.buffers.push(String::new()); + md.buffers.len() - 1 + }; DiscordMdWitness { - parent: md.clone(), - buffer_idx: parent.buffers.len() - 1, + parent: md, + buffer_idx, result: None, } } @@ -469,7 +470,6 @@ impl DiscordMd { } } - impl DiscordMdWitness { pub(crate) fn end(self) { let mut parent = self.parent.write().unwrap(); @@ -479,8 +479,7 @@ impl DiscordMdWitness { .map(|result| format!("**{result} = …**")) .unwrap_or_else(|| String::new()); } else if let Some(result) = self.result { - parent.buffers[self.buffer_idx] - .insert_str(0, &format!("**{result}** = ")); + parent.buffers[self.buffer_idx].insert_str(0, &format!("**{result}** = ")); } } } @@ -510,7 +509,6 @@ impl Witness for DiscordMdWitness { } } - impl<'a> WitnessSet for DiscordMdWitnessSet<'a> { type Ok = (); type Error = DiscordMdWitnessError; @@ -519,10 +517,7 @@ impl<'a> WitnessSet for DiscordMdWitnessSet<'a> { let mut parent = self.witness.parent.write().unwrap(); if parent.dice_written >= MAX_DISPLAYED_DICE_PER_MESSAGE { if !self.dice_elided { - write!( - parent.buffers[self.witness.buffer_idx], - "…" - )?; + write!(parent.buffers[self.witness.buffer_idx], "…")?; self.dice_elided = true; } return Ok(()); diff --git a/src/main.rs b/src/main.rs index 742b301..78308c0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -137,8 +137,7 @@ pub async fn roll(ctx: &Context, command: &CommandInteraction) -> anyhow::Result } }) .unwrap_or(1) - .min(MAX_ROLL_REPEATS as i64) - .max(1) as usize; + .clamp(1, MAX_ROLL_REPEATS as i64) as usize; let private = options .iter() .find(|option| option.name == "private") @@ -170,7 +169,8 @@ pub async fn roll(ctx: &Context, command: &CommandInteraction) -> anyhow::Result None } }) - .and_then(|s| s.parse::().ok()); + .map(|s| s.parse::().context("Seed could not be parsed. Make sure it is a 64 bit integer between 0 and 2^64-1.")) + .transpose()?; let expression = parsing::parse(&formula).context("Dice formula could not be parsed.")?; @@ -193,13 +193,13 @@ pub async fn roll(ctx: &Context, command: &CommandInteraction) -> anyhow::Result let surrounding_par_count = pre_paragraphs.len() + post_paragraphs.len(); - let paragraphs = if repeat <= 40 - surrounding_par_count { + let roll_paragraphs = if repeat <= 40 - surrounding_par_count { let discord_md = Arc::new(std::sync::RwLock::new(DiscordMd { buffers: Vec::with_capacity(repeat), dice_written: 0, })); for _ in 0..repeat { - let mut witness = DiscordMd::create_witness(&discord_md); + let mut witness = DiscordMd::create_witness(discord_md.clone()); let result = expression.evaluate(&mut rng, &mut witness, i64::MAX)?; witness.witness_total_result(result)?; witness.end(); @@ -208,7 +208,7 @@ pub async fn roll(ctx: &Context, command: &CommandInteraction) -> anyhow::Result discord_md.buffers } else { - let mut par = String::new(); + let mut par = String::with_capacity(8 * repeat); for i in 0..repeat { if i > 0 { write!(par, ", ")?; @@ -222,9 +222,11 @@ pub async fn roll(ctx: &Context, command: &CommandInteraction) -> anyhow::Result vec![par] }; - pre_paragraphs.extend(paragraphs); - pre_paragraphs.extend(post_paragraphs); - let paragraphs = pre_paragraphs; + let paragraphs = { + pre_paragraphs.extend(roll_paragraphs); + pre_paragraphs.extend(post_paragraphs); + pre_paragraphs + }; if paragraphs.iter().map(|s| s.chars().count()).sum::() > 4000 || paragraphs.len() > 40