Compare commits

...

4 Commits

19 changed files with 61 additions and 71 deletions

View File

@ -10,10 +10,6 @@ repository = 'https://git.agnos.is/projectmoon/matrix-dicebot'
keywords = ["games", "dice", "matrix", "bot"] keywords = ["games", "dice", "matrix", "bot"]
categories = ["games"] categories = ["games"]
[[bin]]
name = "dicebot-migrate"
path = "src/migrate_cli.rs"
[dependencies] [dependencies]
log = "0.4" log = "0.4"
tracing-subscriber = "0.2" tracing-subscriber = "0.2"

View File

@ -1,6 +1,6 @@
use crate::context::Context; use crate::context::Context;
use crate::error::{BotError, DiceRollingError}; use crate::error::{BotError, DiceRollingError};
use crate::parser::{Amount, Element, Operator}; use crate::parser::dice::{Amount, Element, Operator};
use itertools::Itertools; use itertools::Itertools;
use std::convert::TryFrom; use std::convert::TryFrom;
use std::fmt; use std::fmt;
@ -308,7 +308,7 @@ pub async fn roll_pool(pool: &DicePoolWithContext<'_>) -> Result<RolledDicePool,
return Err(DiceRollingError::ExpressionTooLarge.into()); return Err(DiceRollingError::ExpressionTooLarge.into());
} }
let num_dice = crate::dice::calculate_dice_amount(&pool.0.amounts, &pool.1).await?; let num_dice = crate::logic::calculate_dice_amount(&pool.0.amounts, &pool.1).await?;
let mut roller = RngDieRoller(rand::thread_rng()); let mut roller = RngDieRoller(rand::thread_rng());
if num_dice > 0 { if num_dice > 0 {
@ -578,7 +578,7 @@ mod tests {
let pool = DicePool::new(amounts, DicePoolModifiers::default()); let pool = DicePool::new(amounts, DicePoolModifiers::default());
assert_eq!( assert_eq!(
crate::dice::calculate_dice_amount(&pool.amounts, &ctx) crate::logic::calculate_dice_amount(&pool.amounts, &ctx)
.await .await
.unwrap(), .unwrap(),
10 10

View File

@ -1,6 +1,6 @@
use crate::cofd::dice::{DicePool, DicePoolModifiers, DicePoolQuality}; use crate::cofd::dice::{DicePool, DicePoolModifiers, DicePoolQuality};
use crate::error::BotError; use crate::error::BotError;
use crate::parser::{parse_amounts, DiceParsingError}; use crate::parser::dice::{parse_amounts, DiceParsingError};
use combine::parser::char::{digit, spaces, string}; use combine::parser::char::{digit, spaces, string};
use combine::{choice, count, many1, one_of, Parser}; use combine::{choice, count, many1, one_of, Parser};
@ -201,7 +201,7 @@ mod tests {
#[test] #[test]
fn dice_pool_complex_expression_test() { fn dice_pool_complex_expression_test() {
use crate::parser::*; use crate::parser::dice::*;
let modifiers = DicePoolModifiers::custom(DicePoolQuality::Rote, 3); let modifiers = DicePoolModifiers::custom(DicePoolQuality::Rote, 3);
let amounts = vec![ let amounts = vec![
Amount { Amount {

View File

@ -19,7 +19,7 @@ use crate::commands::{
use crate::cthulhu::parser::{parse_advancement_roll, parse_regular_roll}; use crate::cthulhu::parser::{parse_advancement_roll, parse_regular_roll};
use crate::error::BotError; use crate::error::BotError;
use crate::help::parse_help_topic; use crate::help::parse_help_topic;
use crate::variables::parse_set_variable; use crate::parser::variables::parse_set_variable;
use combine::parser::char::{char, letter, space}; use combine::parser::char::{char, letter, space};
use combine::{any, many1, optional, Parser}; use combine::{any, many1, optional, Parser};
use nom::Err as NomErr; use nom::Err as NomErr;

View File

@ -1,8 +1,8 @@
use crate::context::Context; use crate::context::Context;
use crate::db::Variables; use crate::db::Variables;
use crate::error::{BotError, DiceRollingError}; use crate::error::{BotError, DiceRollingError};
use crate::parser::{Amount, Element}; use crate::logic::calculate_single_die_amount;
use crate::{dice::calculate_single_die_amount, parser::DiceParsingError}; use crate::parser::dice::{Amount, DiceParsingError, Element};
use rand::rngs::StdRng; use rand::rngs::StdRng;
use rand::Rng; use rand::Rng;
use rand::SeedableRng; use rand::SeedableRng;
@ -420,7 +420,7 @@ pub async fn advancement_roll(
mod tests { mod tests {
use super::*; use super::*;
use crate::db::sqlite::Database; use crate::db::sqlite::Database;
use crate::parser::{Amount, Element, Operator}; use crate::parser::dice::{Amount, Element, Operator};
use url::Url; use url::Url;
macro_rules! dummy_room { macro_rules! dummy_room {

View File

@ -1,5 +1,5 @@
use super::dice::{AdvancementRoll, DiceRoll, DiceRollModifier}; use super::dice::{AdvancementRoll, DiceRoll, DiceRollModifier};
use crate::parser::DiceParsingError; use crate::parser::dice::DiceParsingError;
//TOOD convert these to use parse_amounts from the common dice code. //TOOD convert these to use parse_amounts from the common dice code.
@ -30,13 +30,13 @@ pub fn parse_regular_roll(input: &str) -> Result<DiceRoll, DiceParsingError> {
}?; }?;
let modifier = parse_modifier(modifiers_str)?; let modifier = parse_modifier(modifiers_str)?;
let amount = crate::parser::parse_single_amount(amounts_str)?; let amount = crate::parser::dice::parse_single_amount(amounts_str)?;
Ok(DiceRoll { modifier, amount }) Ok(DiceRoll { modifier, amount })
} }
pub fn parse_advancement_roll(input: &str) -> Result<AdvancementRoll, DiceParsingError> { pub fn parse_advancement_roll(input: &str) -> Result<AdvancementRoll, DiceParsingError> {
let input = input.trim(); let input = input.trim();
let amounts = crate::parser::parse_single_amount(input)?; let amounts = crate::parser::dice::parse_single_amount(input)?;
Ok(AdvancementRoll { Ok(AdvancementRoll {
existing_skill: amounts, existing_skill: amounts,
@ -45,9 +45,8 @@ pub fn parse_advancement_roll(input: &str) -> Result<AdvancementRoll, DiceParsin
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use crate::parser::{Amount, Element, Operator}; use crate::parser::dice::{Amount, Element, Operator};
#[test] #[test]
fn regular_roll_accepts_single_number() { fn regular_roll_accepts_single_number() {

View File

@ -1,45 +0,0 @@
use crate::context::Context;
use crate::db::Variables;
use crate::error::BotError;
use crate::error::DiceRollingError;
use crate::parser::Amount;
use crate::parser::Element as NewElement;
use futures::stream::{self, StreamExt, TryStreamExt};
use std::slice;
/// Calculate the amount of dice to roll by consulting the database
/// and replacing variables with corresponding the amount. Errors out
/// if it cannot find a variable defined, or if the database errors.
pub async fn calculate_single_die_amount(
amount: &Amount,
ctx: &Context<'_>,
) -> Result<i32, BotError> {
calculate_dice_amount(slice::from_ref(amount), ctx).await
}
/// Calculate the amount of dice to roll by consulting the database
/// and replacing variables with corresponding amounts. Errors out if
/// it cannot find a variable defined, or if the database errors.
pub async fn calculate_dice_amount(amounts: &[Amount], ctx: &Context<'_>) -> Result<i32, BotError> {
let stream = stream::iter(amounts);
let variables = &ctx
.db
.get_user_variables(&ctx.username, ctx.room_id().as_str())
.await?;
use DiceRollingError::VariableNotFound;
let dice_amount: i32 = stream
.then(|amount| async move {
match &amount.element {
NewElement::Number(num_dice) => Ok(num_dice * amount.operator.mult()),
NewElement::Variable(variable) => variables
.get(variable)
.ok_or_else(|| VariableNotFound(variable.clone()))
.map(|i| *i),
}
})
.try_fold(0, |total, num_dice| async move { Ok(total + num_dice) })
.await?;
Ok(dice_amount)
}

View File

@ -50,7 +50,7 @@ pub enum BotError {
IoError(#[from] std::io::Error), IoError(#[from] std::io::Error),
#[error("dice parsing error: {0}")] #[error("dice parsing error: {0}")]
DiceParsingError(#[from] crate::parser::DiceParsingError), DiceParsingError(#[from] crate::parser::dice::DiceParsingError),
#[error("command parsing error: {0}")] #[error("command parsing error: {0}")]
CommandParsingError(#[from] crate::commands::parser::CommandParsingError), CommandParsingError(#[from] crate::commands::parser::CommandParsingError),
@ -59,7 +59,7 @@ pub enum BotError {
DiceRollingError(#[from] DiceRollingError), DiceRollingError(#[from] DiceRollingError),
#[error("variable parsing error: {0}")] #[error("variable parsing error: {0}")]
VariableParsingError(#[from] crate::variables::VariableParsingError), VariableParsingError(#[from] crate::parser::variables::VariableParsingError),
#[error("legacy parsing error")] #[error("legacy parsing error")]
NomParserError(nom::error::ErrorKind), NomParserError(nom::error::ErrorKind),

View File

@ -6,7 +6,6 @@ pub mod config;
pub mod context; pub mod context;
pub mod cthulhu; pub mod cthulhu;
pub mod db; pub mod db;
pub mod dice;
pub mod error; pub mod error;
mod help; mod help;
pub mod logic; pub mod logic;
@ -14,4 +13,3 @@ pub mod matrix;
pub mod models; pub mod models;
mod parser; mod parser;
pub mod state; pub mod state;
pub mod variables;

View File

@ -1,9 +1,12 @@
use crate::db::Rooms; use crate::context::Context;
use crate::error::BotError; use crate::db::{Rooms, Variables};
use crate::error::{BotError, DiceRollingError};
use crate::matrix; use crate::matrix;
use crate::models::RoomInfo; use crate::models::RoomInfo;
use futures::stream::{self, StreamExt}; use crate::parser::dice::{Amount, Element};
use futures::stream::{self, StreamExt, TryStreamExt};
use matrix_sdk::{self, identifiers::RoomId, Client}; use matrix_sdk::{self, identifiers::RoomId, Client};
use std::slice;
/// Record the information about a room, including users in it. /// Record the information about a room, including users in it.
pub async fn record_room_information( pub async fn record_room_information(
@ -46,3 +49,40 @@ pub async fn record_room_information(
.into_iter() .into_iter()
.collect() .collect()
} }
/// Calculate the amount of dice to roll by consulting the database
/// and replacing variables with corresponding the amount. Errors out
/// if it cannot find a variable defined, or if the database errors.
pub async fn calculate_single_die_amount(
amount: &Amount,
ctx: &Context<'_>,
) -> Result<i32, BotError> {
calculate_dice_amount(slice::from_ref(amount), ctx).await
}
/// Calculate the amount of dice to roll by consulting the database
/// and replacing variables with corresponding amounts. Errors out if
/// it cannot find a variable defined, or if the database errors.
pub async fn calculate_dice_amount(amounts: &[Amount], ctx: &Context<'_>) -> Result<i32, BotError> {
let stream = stream::iter(amounts);
let variables = &ctx
.db
.get_user_variables(&ctx.username, ctx.room_id().as_str())
.await?;
use DiceRollingError::VariableNotFound;
let dice_amount: i32 = stream
.then(|amount| async move {
match &amount.element {
Element::Number(num_dice) => Ok(num_dice * amount.operator.mult()),
Element::Variable(variable) => variables
.get(variable)
.ok_or_else(|| VariableNotFound(variable.clone()))
.map(|i| *i),
}
})
.try_fold(0, |total, num_dice| async move { Ok(total + num_dice) })
.await?;
Ok(dice_amount)
}

View File

@ -27,7 +27,7 @@ pub enum DiceParsingError {
} }
impl From<std::num::ParseIntError> for DiceParsingError { impl From<std::num::ParseIntError> for DiceParsingError {
fn from(_error: std::num::ParseIntError) -> Self { fn from(_: std::num::ParseIntError) -> Self {
DiceParsingError::ConversionError DiceParsingError::ConversionError
} }
} }

2
src/parser/mod.rs Normal file
View File

@ -0,0 +1,2 @@
pub mod dice;
pub mod variables;