use crate::context::{BotContext, MessageContext};
use async_trait::async_trait;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum HandlerAction {
Done,
Continue,
}
impl HandlerAction {
pub const fn done() -> HandlerResult {
Ok(HandlerAction::Done)
}
pub const fn r#continue() -> HandlerResult {
Ok(HandlerAction::Continue)
}
}
impl From<()> for HandlerAction {
fn from(_: ()) -> Self {
HandlerAction::Done
}
}
pub type HandlerResult = Result<HandlerAction, Box<dyn std::error::Error + Send + Sync>>;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ArgType {
String,
Int,
Float,
Bool,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum ArgMode {
#[default]
Positional,
Named,
}
#[derive(Debug, Clone)]
pub struct Arg {
pub name: &'static str,
pub arg_type: ArgType,
pub mode: ArgMode,
pub required: bool,
pub default: Option<ArgValue>,
pub description: Option<&'static str>,
}
impl Default for Arg {
fn default() -> Self {
Self {
name: "",
arg_type: ArgType::String,
mode: ArgMode::Positional,
required: false,
default: None,
description: None,
}
}
}
impl Arg {
pub fn new(name: &'static str) -> Self {
Self { name, ..Default::default() }
}
pub fn string(name: &'static str) -> Self {
Self::new(name).with_type(ArgType::String)
}
pub fn int(name: &'static str) -> Self {
Self::new(name).with_type(ArgType::Int)
}
pub fn float(name: &'static str) -> Self {
Self::new(name).with_type(ArgType::Float)
}
pub fn bool(name: &'static str) -> Self {
Self::new(name).with_type(ArgType::Bool)
}
pub fn with_type(mut self, arg_type: ArgType) -> Self {
self.arg_type = arg_type;
self
}
pub fn required(mut self) -> Self {
self.required = true;
self
}
pub fn optional(mut self) -> Self {
self.required = false;
self
}
pub fn default_value(mut self, value: ArgValue) -> Self {
self.default = Some(value);
self
}
pub fn description(mut self, desc: &'static str) -> Self {
self.description = Some(desc);
self
}
pub fn positional(mut self) -> Self {
self.mode = ArgMode::Positional;
self
}
pub fn named(mut self) -> Self {
self.mode = ArgMode::Named;
self
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum ArgValue {
String(String),
Int(i64),
Float(f64),
Bool(bool),
}
impl ArgValue {
pub fn as_str(&self) -> Option<&str> {
match self {
ArgValue::String(s) => Some(s),
_ => None,
}
}
pub fn as_int(&self) -> Option<i64> {
match self {
ArgValue::Int(i) => Some(*i),
_ => None,
}
}
pub fn as_float(&self) -> Option<f64> {
match self {
ArgValue::Float(f) => Some(*f),
_ => None,
}
}
pub fn as_bool(&self) -> Option<bool> {
match self {
ArgValue::Bool(b) => Some(*b),
_ => None,
}
}
pub fn into_string(self) -> Option<String> {
match self {
ArgValue::String(s) => Some(s),
_ => None,
}
}
}
impl From<String> for ArgValue {
fn from(s: String) -> Self {
ArgValue::String(s)
}
}
impl From<&str> for ArgValue {
fn from(s: &str) -> Self {
ArgValue::String(s.to_string())
}
}
impl From<i64> for ArgValue {
fn from(i: i64) -> Self {
ArgValue::Int(i)
}
}
impl From<f64> for ArgValue {
fn from(f: f64) -> Self {
ArgValue::Float(f)
}
}
impl From<bool> for ArgValue {
fn from(b: bool) -> Self {
ArgValue::Bool(b)
}
}
#[derive(Debug, Clone)]
pub struct Command {
pub name: &'static str,
pub description: Option<&'static str>,
pub args: Vec<Arg>,
pub rank: u64,
pub prefix: Option<String>,
pub alias: Option<Vec<&'static str>>,
}
#[async_trait]
pub trait CommandBuilder: Send + Sync + 'static {
fn name(&self) -> &'static str;
fn description(&self) -> Option<&'static str>;
fn args(&self) -> Vec<Arg>;
fn rank(&self) -> u64;
fn alias(&self) -> Option<Vec<&'static str>> {
None
}
async fn run(&self, bot: &BotContext, ev: &MessageContext) -> HandlerResult;
}