4 Commits
Author SHA1 Message Date
Elias Wendland 24205326bf Add experimental f128 and f256 modes for /calc
Run cargo test / Run tests (push) Successful in 4m1s
Build Docker Package / build (push) Successful in 6m7s
Build Docker Package / build (release) Successful in 7m20s
2026-07-05 01:06:49 +02:00
Elias Wendland b3ada54689 Release 0.1.1
Run cargo test / Run tests (push) Successful in 3m36s
Build Docker Package / build (push) Successful in 6m26s
Build Docker Package / build (release) Successful in 7m7s
Fix a bug, add better error handling
2026-07-05 00:45:45 +02:00
ewenlau 2a2d359348 Fix typo
Build Docker Package / build (push) Successful in 7m51s
Run cargo test / Run tests (push) Successful in 4m40s
2026-07-05 00:18:37 +02:00
ewenlau 6719ebfda6 Fix typo
Build Docker Package / build (push) Successful in 6m37s
Run cargo test / Run tests (push) Successful in 3m30s
2026-07-05 00:18:19 +02:00
6 changed files with 153 additions and 6 deletions

No files matched your search

+5 -1
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "tg-dev-srv-bot" name = "tg-dev-srv-bot"
version = "0.1.0" version = "0.1.2"
edition = "2024" edition = "2024"
license = "GPL-3.0-or-later" license = "GPL-3.0-or-later"
description = "Bot for the TeenGovernment Development Server" description = "Bot for the TeenGovernment Development Server"
@@ -12,7 +12,11 @@ homepage = "https://git.ewenlau.net/ewenlau/tg-dev-srv-bot"
[dependencies] [dependencies]
dotenv = "0.15.0" dotenv = "0.15.0"
exmex = "0.21.0" exmex = "0.21.0"
f128 = "0.2.9"
f256 = "0.11.2"
num-traits = "0.2.19"
poise = "0.6.2" poise = "0.6.2"
regex = "1.12.4"
rug = "1.30.0" rug = "1.30.0"
serenity = "0.12.5" serenity = "0.12.5"
sqlx = { version = "0.9.0", features = ["postgres", "runtime-tokio", "macros"] } sqlx = { version = "0.9.0", features = ["postgres", "runtime-tokio", "macros"] }
+1 -1
View File
@@ -6,4 +6,4 @@ Not really meant for any other server, but feel free to use it if you'd like.
The bot is really made to be used with Docker, but you can run it locally. The bot is really made to be used with Docker, but you can run it locally.
An image is available at git.ewenlau.net/ewenlau/tg-dev-srv-bot:release for the stable version and git.ewenlau.net/ewenlau/tg-dev-srv-bot:dev for the development (or testing) version. An image is available at git.ewenlau.net/ewenlau/tg-dev-srv-bot:latest for the stable version and git.ewenlau.net/ewenlau/tg-dev-srv-bot:dev for the development (or testing) version.
+1 -1
View File
@@ -21,7 +21,7 @@ services:
context: . context: .
dockerfile: Dockerfile dockerfile: Dockerfile
# OR pull from registry # OR pull from registry
# image: git.ewenlau.net/ewenlau/tg-dev-srv-bot:release # image: git.ewenlau.net/ewenlau/tg-dev-srv-bot:latest
# image: git.ewenlau.net/ewenlau/tg-dev-srv-bot:dev # image: git.ewenlau.net/ewenlau/tg-dev-srv-bot:dev
container_name: tg-dev-srv-bot container_name: tg-dev-srv-bot
restart: always restart: always
Executable
BIN
View File
Binary file not shown.
+134 -3
View File
@@ -1,6 +1,112 @@
use crate::{Context, Error}; use crate::{Context, Error};
use tracing::{debug, trace, info}; use tracing::{debug, trace, info};
use crate::shared_functions::trace_message; use crate::shared_functions::trace_message;
use regex::Regex;
use std::sync::LazyLock;
use std::str::FromStr;
use std::fmt::{Display, Formatter};
use f128::f128;
use exmex::{Express, FlatEx, MakeOperators, Operator, BinOp};
use num_traits::float::Float;
#[derive(Clone, Copy, Debug)]
pub struct F128(pub f128);
impl Default for F128 {
fn default() -> Self {
F128(f128::new(0.0))
}
}
impl FromStr for F128 {
type Err = String;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match f128::parse(s) {
Ok(v) => Ok(F128(v)),
Err(e) => Err(format!("{:?}", e))
}
}
}
impl Display for F128 {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.0)
}
}
#[derive(Clone, Debug)]
pub struct F128OpsFactory;
impl MakeOperators<F128> for F128OpsFactory {
fn make<'a>() -> Vec<Operator<'a, F128>> {
vec![
Operator::make_bin("^", BinOp { apply: |a, b| F128(a.0.powf(b.0)), prio: 4, is_commutative: false }),
Operator::make_bin("*", BinOp { apply: |a, b| F128(a.0 * b.0), prio: 2, is_commutative: true }),
Operator::make_bin("/", BinOp { apply: |a, b| F128(a.0 / b.0), prio: 3, is_commutative: false }),
Operator::make_bin_unary("+", BinOp { apply: |a, b| F128(a.0 + b.0), prio: 0, is_commutative: true }, |a| a),
Operator::make_bin_unary("-", BinOp { apply: |a, b| F128(a.0 - b.0), prio: 1, is_commutative: false }, |a| F128(-a.0)),
Operator::make_unary("sin", |a| F128(a.0.sin())),
Operator::make_unary("cos", |a| F128(a.0.cos())),
Operator::make_unary("tan", |a| F128(a.0.tan())),
Operator::make_unary("floor", |a| F128(a.0.floor())),
Operator::make_unary("round", |a| F128(a.0.round())),
Operator::make_unary("ceil", |a| F128(a.0.ceil())),
Operator::make_unary("trunc", |a| F128(a.0.trunc())),
Operator::make_unary("fract", |a| F128(a.0.fract())),
Operator::make_unary("exp", |a| F128(a.0.exp())),
Operator::make_unary("sqrt", |a| F128(a.0.sqrt())),
Operator::make_unary("cbrt", |a| F128(a.0.cbrt())),
Operator::make_unary("ln", |a| F128(a.0.ln())),
Operator::make_unary("log2", |a| F128(a.0.log2())),
Operator::make_unary("log10", |a| F128(a.0.log10())),
Operator::make_unary("abs", |a| F128(a.0.abs())),
Operator::make_unary("signum", |a| F128(a.0.signum())),
Operator::make_constant("PI", F128(f128::new(std::f64::consts::PI))),
Operator::make_constant("π", F128(f128::new(std::f64::consts::PI))),
Operator::make_constant("E", F128(f128::new(std::f64::consts::E))),
Operator::make_constant("e", F128(f128::new(std::f64::consts::E))),
Operator::make_constant("TAU", F128(f128::new(std::f64::consts::TAU))),
Operator::make_constant("τ", F128(f128::new(std::f64::consts::TAU))),
]
}
}
#[derive(Clone, Debug)]
pub struct F256OpsFactory;
impl MakeOperators<f256::f256> for F256OpsFactory {
fn make<'a>() -> Vec<Operator<'a, f256::f256>> {
vec![
Operator::make_bin("^", BinOp { apply: |a, b| a.powf(&b), prio: 4, is_commutative: false }),
Operator::make_bin("*", BinOp { apply: |a, b| a * b, prio: 2, is_commutative: true }),
Operator::make_bin("/", BinOp { apply: |a, b| a / b, prio: 3, is_commutative: false }),
Operator::make_bin_unary("+", BinOp { apply: |a, b| a + b, prio: 0, is_commutative: true }, |a| a),
Operator::make_bin_unary("-", BinOp { apply: |a, b| a - b, prio: 1, is_commutative: false }, |a| -a),
Operator::make_unary("sin", |a| a.sin()),
Operator::make_unary("cos", |a| a.cos()),
Operator::make_unary("tan", |a| a.tan()),
Operator::make_unary("floor", |a| a.floor()),
Operator::make_unary("round", |a| a.round()),
Operator::make_unary("ceil", |a| a.ceil()),
Operator::make_unary("trunc", |a| a.trunc()),
Operator::make_unary("fract", |a| a.fract()),
Operator::make_unary("exp", |a| a.exp()),
Operator::make_unary("sqrt", |a| a.sqrt()),
Operator::make_unary("cbrt", |a| a.cbrt()),
Operator::make_unary("ln", |a| a.ln()),
Operator::make_unary("log2", |a| a.log2()),
Operator::make_unary("log10", |a| a.log10()),
Operator::make_unary("abs", |a| a.abs()),
Operator::make_unary("signum", |a| a.signum()),
Operator::make_constant("PI", f256::f256::from(std::f64::consts::PI)),
Operator::make_constant("π", f256::f256::from(std::f64::consts::PI)),
Operator::make_constant("E", f256::f256::from(std::f64::consts::E)),
Operator::make_constant("e", f256::f256::from(std::f64::consts::E)),
Operator::make_constant("TAU", f256::f256::from(std::f64::consts::TAU)),
Operator::make_constant("τ", f256::f256::from(std::f64::consts::TAU)),
]
}
}
static FIND_SCI_NOTATION_RE: LazyLock<Regex> = LazyLock::new(|| Regex::new(r"([0-9]+(?:\.[0-9]+)?)e([+-]?[0-9]+)").unwrap());
#[derive(Debug, poise::ChoiceParameter)] #[derive(Debug, poise::ChoiceParameter)]
pub enum Precision { pub enum Precision {
@@ -8,6 +114,18 @@ pub enum Precision {
Bits32, Bits32,
#[name = "64-bit"] #[name = "64-bit"]
Bits64, Bits64,
#[name = "128-bit"]
Bits128,
#[name = "256-bit"]
Bits256,
}
#[derive(Debug, poise::ChoiceParameter)]
pub enum Mode {
#[name = "Floating Point"]
Float,
#[name = "Integer"]
Int,
} }
/// Calculator /// Calculator
@@ -24,10 +142,21 @@ pub async fn calc(ctx: Context<'_>,
let response_message = ctx.say(msg).await?; let response_message = ctx.say(msg).await?;
let start_time = std::time::Instant::now(); let start_time = std::time::Instant::now();
trace!("Saving start time: {:?}", start_time); trace!("Saving start time: {:?}", start_time);
let processed_expr = FIND_SCI_NOTATION_RE.replace_all(&expression, "($1 * 10^($2))");
trace!("Processed expression: {}", processed_expr);
let value = match precision { let value = match precision {
Some(Precision::Bits32) => exmex::eval_str::<f32>(&expression).map_err(|err| err.to_string())?.to_string(), Some(Precision::Bits32) => exmex::eval_str::<f32>(&processed_expr).map_err(|err| err.to_string())?.to_string(),
Some(Precision::Bits64) => exmex::eval_str::<f64>(&expression).map_err(|err| err.to_string())?.to_string(), Some(Precision::Bits64) => exmex::eval_str::<f64>(&processed_expr).map_err(|err| err.to_string())?.to_string(),
None => exmex::eval_str::<f64>(&expression).map_err(|err| err.to_string())?.to_string(), Some(Precision::Bits128) => {
let expr = exmex::FlatEx::<F128, F128OpsFactory>::parse(&processed_expr).map_err(|err| err.to_string())?;
expr.eval(&[]).map_err(|err| err.to_string())?.to_string()
},
Some(Precision::Bits256) => {
let expr = exmex::FlatEx::<f256::f256, F256OpsFactory>::parse(&processed_expr).map_err(|err| err.to_string())?;
expr.eval(&[]).map_err(|err| err.to_string())?.to_string()
},
None => exmex::eval_str::<f64>(&processed_expr).map_err(|err| err.to_string())?.to_string(),
}; };
let end_time = std::time::Instant::now(); let end_time = std::time::Instant::now();
trace!("Saving end time: {:?}", end_time); trace!("Saving end time: {:?}", end_time);
@@ -36,6 +165,8 @@ pub async fn calc(ctx: Context<'_>,
let precision_str = match precision { let precision_str = match precision {
Some(Precision::Bits32) => "32-bit".to_string(), Some(Precision::Bits32) => "32-bit".to_string(),
Some(Precision::Bits64) => "64-bit".to_string(), Some(Precision::Bits64) => "64-bit".to_string(),
Some(Precision::Bits128) => "128-bit".to_string(),
Some(Precision::Bits256) => "256-bit".to_string(),
None => "64-bit".to_string(), None => "64-bit".to_string(),
}; };
let msg = format!("{} = {} \n-# Precision: {} Compute time : {:?}", expression, value, precision_str, duration); let msg = format!("{} = {} \n-# Precision: {} Compute time : {:?}", expression, value, precision_str, duration);
+12
View File
@@ -75,6 +75,18 @@ async fn main() {
event_handler: |ctx, event, framework, user_data| { event_handler: |ctx, event, framework, user_data| {
Box::pin(event_handler::event_handler(ctx, event, framework, user_data)) Box::pin(event_handler::event_handler(ctx, event, framework, user_data))
}, },
on_error: |error| Box::pin(async move {
match error {
poise::FrameworkError::Command { error, ctx, .. } => {
error!("Error in command `{}`: {:?}", ctx.command().name, error);
}
error => {
if let Err(e) = poise::builtins::on_error(error).await {
error!("Error while handling error: {}", e);
}
}
}
}),
commands: vec![commands::ping(), commands::calc(), commands::manage_admins(), commands::manage_auto_role(), commands::version()], commands: vec![commands::ping(), commands::calc(), commands::manage_admins(), commands::manage_auto_role(), commands::version()],
..Default::default() ..Default::default()
}) })