serenity
serenity copied to clipboard
Framework Redesign
Once #803 lands, it will be interesting to consider a rework of the framework.
Right now, the framework is represented as a trait, allowing everyone to implement their own framework. However this raises a maintenance problem, there might be portions of the framework a new framework would like to keep. Hereby mentioned portions could be divided into front API, dispatch evaluation, and command dispatch. The first offers the user an API to use, the second will evaluate whether an attempt to run a command is valid, the last will interpret the final type of command data.
We personally want to develop a new simple framework as an experiment to discover a replacement for the current single framework-trait we have right now. Unlike the standard framework, this simple framework won't require procedural macros at all. Furthermore, a second framework shall be developed that expands on the implemented portions of the simple framework by allowing to dynamically serialise/deserialise/delete commands, but limits the data format of commands.
We must be aware that serialising fn-pointers is not fully feasible. Serialising and deserialising Rust-code is not planned either. The idea of dynamic commands may be more about the idea of interpretable code.
This issue will serve as a tracker for updates and discussions on this matter.
An example of a simple framework would be:
use serenity::framework::{SimpleFramework, CommandResult, Args};
// `CommandResult` being an alias to `Result<(), Box<std::error::Error>>`
async fn ping(ctx: Arc<Context>, msg: Arc<Message>, _args: Args) -> CommandResult {
msg.channel_id.say("pong!").await?;
Ok(())
}
let mut framework = SimpleFramework::new(|config| config.prefix("!").delimiter(" "));
// SimpleFramework::add(name: &str, f: impl Fn(Arc<Context>, Arc<Message>, Args) -> F)
// where F: Future<Output=CommandResult>
framework.add("ping", ping);
// There will also be an help command implicitly provided, as if people did
// framework.add(help);
// themselves
let mut client = Client::new_with_framework(
/* DISCORD_TOKEN */,
/* EventHandler */,
framework
);
The purpose of this framework would be, as told by this issue, simple and to the point, without the use of procedural macros. It would have a limited set of configurable options. This is great if people need a command framework up-and-running in a matter of seconds without fiddling with macros or other antics as a result of weird interaction with some options. And, if people require a greater, more powerful framework, they will have an easy choice to switch between simpler frameworks and sophisticated frameworks (cf. the dynamic framework), as the latter would be based off the former. Thus, they can expand the bot as it grows with the least effort.
Unless I'm missing something, at the very least we might have to/should keep the #[hook]
or #[command]
procedural macro even for a simple framework. Since you can't easily store references to an async fn in a data structure on stable rust, and it might make more sense to the user if they could write:
#[command]
async fn ping(ctx: Arc<Context>, msg: Arc<Message>, _args: Args) -> CommandResult
{
//...
}
instead of
fn ping(ctx: Arc<Context>, msg: Arc<Message>, _args: Args) -> Pin<Box<dyn Future<Output = CommandResult>>>
{
async move {
//...
}.boxed()
}
I stand corrected, could be done this way, where each passed Fn
is wrapped in a closure:
pub fn insert<F>(&mut self, name: String, fut: &'static impl Fn(&Context, &Message, Args) -> F)
where F: 'static + Future<Output=CommandResult> {
//self.map: HashMap<String, Box<dyn Fn() -> Pin<Box<dyn Future<Output=CommandResult>>>>>
self.map.insert(name, Box::new(move |ctx, msg, args| Box::pin(fut(ctx, msg, args))));
}
We probably could leverage this within part of the existing standard framework and remove the need for using the #[hook]
procedural macro on at least some methods for use with it.
The new framework can be followed here: https://github.com/serenity-rs/framework
We have decided for poise to be the replacement of the standard framework.