diff --git a/Cargo.lock b/Cargo.lock index a244f97..9716d17 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1420,7 +1420,7 @@ dependencies = [ "security-framework", "security-framework-sys", "webpki-root-certs", - "windows-sys 0.61.2", + "windows-sys 0.52.0", ] [[package]] @@ -1570,7 +1570,7 @@ dependencies = [ [[package]] name = "serenity" version = "0.12.5" -source = "git+https://github.com/serenity-rs/serenity.git?branch=next#37b9f433ada8b9ccc5f93f04826403b175855f86" +source = "git+https://github.com/serenity-rs/serenity.git?rev=refs%2Fheads%2Fnext#37b9f433ada8b9ccc5f93f04826403b175855f86" dependencies = [ "aformat", "arrayvec", diff --git a/Cargo.toml b/Cargo.toml index 4fe1f28..5d24596 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,7 +5,7 @@ edition = "2024" [dependencies] dotenv = "0.15.0" -serenity = { version = "0.12.5" } +serenity = { git = "https://github.com/serenity-rs/serenity.git", rev = "refs/heads/next" , features = ["collector"] } tokio = { version = "1.53.1", features = ["rt-multi-thread"] } tracing = "0.1.44" tracing-subscriber = "0.3.23" @@ -15,6 +15,3 @@ thiserror = "2.0.20" nom-language = "0.1.0" rand_xoshiro = "0.8.1" rand = "0.10.2" - -[patch.crates-io] -serenity = { git = "https://github.com/serenity-rs/serenity.git", branch = "next" } diff --git a/src/dice.rs b/src/dice.rs index 49cdac4..169ea03 100644 --- a/src/dice.rs +++ b/src/dice.rs @@ -1,6 +1,4 @@ -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; @@ -118,23 +116,27 @@ impl Expression { // Exploding dice are early, they add rolls if let Some(fragments) = x { write!(w, "x")?; - let comparers = fragments - .iter() - .map(|fragment| fragment.comparer(rng, w)) - .collect::, _>>()?; + let mut comparers = Vec::with_capacity(fragments.len()); + for fragment in fragments { + comparers.push(fragment.comparer(rng, w)?); + } let mut i = 0; while i < rolls.len() { if i > MAX_DICE_COUNT_PER_ROLL { bail!("Explosion added too many dice.") } - if comparers.is_empty() { + if comparers.len() == 0 { // Explode on max size dice if rolls[i] == size { rolls.push(rng.random_range(1..=size)); } } else { - if comparers.iter().any(|comparer| comparer(rolls[i] as f64)) { - rolls.push(rng.random_range(1..=size)); + // Explode based on comparers provided + for comparer in comparers.iter() { + if comparer(rolls[i] as f64) { + rolls.push(rng.random_range(1..=size)); + break; + } } } i += 1; @@ -185,25 +187,25 @@ impl Expression { let mut skip = false; let roll = rolls[idx]; let rank = ranks[idx]; - if let Some(kh) = kh - && rolls.len() - 1 - rank >= kh - { - skip = true; + if let Some(kh) = kh { + if rolls.len() - 1 - rank >= kh { + skip = true; + } } - if let Some(dh) = dh - && rolls.len() - 1 - rank < dh - { - skip = true; + if let Some(dh) = dh { + if rolls.len() - 1 - rank < dh { + skip = true; + } } - if let Some(kl) = kl - && rank >= kl - { - skip = true; + if let Some(kl) = kl { + if rank >= kl { + skip = true; + } } - if let Some(dl) = dl - && rank < dl - { - skip = true; + if let Some(dl) = dl { + if rank < dl { + skip = true; + } } if !skip { result_set.push(roll as f64); @@ -298,19 +300,19 @@ impl Expression { bail!("Invalid die size.") } - if x.is_some() { + if let Some(_) = x { bail!("Not implemented yet"); } - if kh.is_some() { + if let Some(_) = kh { bail!("Not implemented yet"); }; - if kl.is_some() { + if let Some(_) = kl { bail!("Not implemented yet"); }; - if dh.is_some() { + if let Some(_) = dh { bail!("Not implemented yet"); }; - if dl.is_some() { + if let Some(_) = dl { bail!("Not implemented yet"); }; @@ -452,15 +454,12 @@ pub(crate) enum DiscordMdWitnessError { } impl DiscordMd { - 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 - }; + pub(crate) fn create_witness(md: &Arc>) -> DiscordMdWitness { + let mut parent = md.write().unwrap(); + parent.buffers.push(String::new()); DiscordMdWitness { - parent: md, - buffer_idx, + parent: md.clone(), + buffer_idx: parent.buffers.len() - 1, result: None, } } @@ -470,6 +469,7 @@ impl DiscordMd { } } + impl DiscordMdWitness { pub(crate) fn end(self) { let mut parent = self.parent.write().unwrap(); @@ -477,9 +477,10 @@ impl DiscordMdWitness { parent.buffers[self.buffer_idx] = self .result .map(|result| format!("**{result} = …**")) - .unwrap_or_default(); + .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}** = ")); } } } @@ -509,6 +510,7 @@ impl Witness for DiscordMdWitness { } } + impl<'a> WitnessSet for DiscordMdWitnessSet<'a> { type Ok = (); type Error = DiscordMdWitnessError; @@ -517,7 +519,10 @@ 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 c82fcab..742b301 100644 --- a/src/main.rs +++ b/src/main.rs @@ -137,7 +137,8 @@ pub async fn roll(ctx: &Context, command: &CommandInteraction) -> anyhow::Result } }) .unwrap_or(1) - .clamp(1, MAX_ROLL_REPEATS as i64) as usize; + .min(MAX_ROLL_REPEATS as i64) + .max(1) as usize; let private = options .iter() .find(|option| option.name == "private") @@ -169,10 +170,9 @@ pub async fn roll(ctx: &Context, command: &CommandInteraction) -> anyhow::Result None } }) - .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()?; + .and_then(|s| s.parse::().ok()); - let expression = parsing::parse(formula).context("Dice formula could not be parsed.")?; + let expression = parsing::parse(&formula).context("Dice formula could not be parsed.")?; let seed = fixed_seed.unwrap_or_else(|| rand::rng().next_u64()); let mut rng = rand_xoshiro::Xoshiro256PlusPlus::seed_from_u64(seed); @@ -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 roll_paragraphs = if repeat <= 40 - surrounding_par_count { + let 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.clone()); + let mut witness = DiscordMd::create_witness(&discord_md); 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::with_capacity(8 * repeat); + let mut par = String::new(); for i in 0..repeat { if i > 0 { write!(par, ", ")?; @@ -222,11 +222,9 @@ pub async fn roll(ctx: &Context, command: &CommandInteraction) -> anyhow::Result vec![par] }; - let paragraphs = { - pre_paragraphs.extend(roll_paragraphs); - pre_paragraphs.extend(post_paragraphs); - pre_paragraphs - }; + pre_paragraphs.extend(paragraphs); + pre_paragraphs.extend(post_paragraphs); + let paragraphs = pre_paragraphs; if paragraphs.iter().map(|s| s.chars().count()).sum::() > 4000 || paragraphs.len() > 40 @@ -255,29 +253,27 @@ pub async fn roll(ctx: &Context, command: &CommandInteraction) -> anyhow::Result Ok(()) } - match inner(ctx, command).await { - Ok(_) => {} - Err(err) => { - warn!("Error encountered: {err:?}"); - command - .create_response( - &ctx.http, - CreateInteractionResponse::Message( - CreateInteractionResponseMessage::new() - .components(vec![CreateComponent::Container(CreateContainer::new( - vec![CreateContainerComponent::TextDisplay( - CreateTextDisplay::new(err.to_string()), - )], - ))]) - // flags needs to be called before ephemeral for correct ordering - .flags( - MessageFlags::IS_COMPONENTS_V2 | MessageFlags::SUPPRESS_NOTIFICATIONS, - ) - .ephemeral(true), - ), - ) - .await? - } + if let Ok(_) = inner(ctx, command).await { + } else if let Err(err) = inner(ctx, command).await { + warn!("Error encountered: {err:?}"); + command + .create_response( + &ctx.http, + CreateInteractionResponse::Message( + CreateInteractionResponseMessage::new() + .components(vec![CreateComponent::Container(CreateContainer::new( + vec![CreateContainerComponent::TextDisplay( + CreateTextDisplay::new(err.to_string()), + )], + ))]) + // flags needs to be called before ephemeral for correct ordering + .flags( + MessageFlags::IS_COMPONENTS_V2 | MessageFlags::SUPPRESS_NOTIFICATIONS, + ) + .ephemeral(true), + ), + ) + .await? }; Ok(()) } diff --git a/src/parsing.rs b/src/parsing.rs index 92c2f25..81dc420 100644 --- a/src/parsing.rs +++ b/src/parsing.rs @@ -80,7 +80,7 @@ fn expr<'c, 'i>( ) .map(|(count, size, (kh, kl, dh, dl, x))| { Dice(DiceFormula { - count: count.map(Box::new), + count: count.map(|n| Box::new(n)), size: Box::new(size), kh: kh.map(|n| Box::new(n.unwrap_or(Const(1f64)))), kl: kl.map(|n| Box::new(n.unwrap_or(Const(1f64)))),