use std::error::Error;
use std::marker::PhantomData;
use std::sync::Arc;
pub use twilight_gateway::Event;
pub use twilight_model::gateway::payload::incoming::{
AutoModerationActionExecution, AutoModerationRuleCreate, AutoModerationRuleDelete,
AutoModerationRuleUpdate, BanAdd, BanRemove, ChannelCreate, ChannelDelete, ChannelPinsUpdate,
ChannelUpdate, CommandPermissionsUpdate, EntitlementCreate, EntitlementDelete,
EntitlementUpdate, GuildAuditLogEntryCreate, GuildCreate, GuildDelete, GuildEmojisUpdate,
GuildIntegrationsUpdate, GuildScheduledEventCreate, GuildScheduledEventDelete,
GuildScheduledEventUpdate, GuildScheduledEventUserAdd, GuildScheduledEventUserRemove,
GuildStickersUpdate, GuildUpdate, Hello, IntegrationCreate, IntegrationDelete,
IntegrationUpdate, InteractionCreate, InviteCreate, InviteDelete, MemberAdd, MemberChunk,
MemberRemove, MemberUpdate, MessageCreate, MessageDelete, MessageDeleteBulk,
MessagePollVoteAdd, MessagePollVoteRemove, MessageUpdate, PresenceUpdate, RateLimited,
ReactionAdd, ReactionRemove, ReactionRemoveAll, ReactionRemoveEmoji, Ready, RoleCreate,
RoleDelete, RoleUpdate, StageInstanceCreate, StageInstanceDelete, StageInstanceUpdate,
ThreadCreate, ThreadDelete, ThreadListSync, ThreadMemberUpdate, ThreadMembersUpdate,
ThreadUpdate, TypingStart, UnavailableGuild, UserUpdate, VoiceServerUpdate, VoiceStateUpdate,
WebhooksUpdate,
};
use crate::errors::{ErrorHandler, ErrorHandlerWithoutType, ErrorHandlerWrapper};
use crate::handle::Handle;
use crate::state::StateBound;
use crate::utils::DynFuture;
#[derive(Clone)]
pub struct EventContext<State, E>
where
State: StateBound,
{
pub state: State,
pub handle: Handle<State>,
pub event: E,
}
pub type EventResult = Result<(), Arc<dyn Error + Send + Sync>>;
pub trait IntoEventResult {
fn into_event_result(self) -> EventResult;
}
impl IntoEventResult for () {
fn into_event_result(self) -> EventResult {
Ok(())
}
}
impl<T, E> IntoEventResult for Result<T, E>
where
E: Error + Send + Sync + 'static,
{
fn into_event_result(self) -> EventResult {
match self {
Ok(_) => Ok(()),
Err(error) => Err(Arc::new(error)),
}
}
}
#[derive(Clone)]
pub(crate) struct EventHandler<State>
where
State: StateBound,
{
pub handler: Arc<dyn EventHandlerHandlerWithoutArgs<State> + 'static>,
pub on_errors: Vec<Arc<dyn ErrorHandlerWithoutType<State>>>,
}
pub struct EventHandlerBuilder<State>
where
State: StateBound,
{
handler: Arc<dyn EventHandlerHandlerWithoutArgs<State> + 'static>,
on_errors: Vec<Arc<dyn ErrorHandlerWithoutType<State>>>,
}
impl<State> EventHandlerBuilder<State>
where
State: StateBound,
{
pub fn on_error<Error>(mut self, handler: impl ErrorHandler<State, Error> + 'static) -> Self
where
Error: Send + Sync + 'static,
{
self.on_errors
.push(Arc::new(ErrorHandlerWrapper::new(handler)));
self
}
pub(crate) fn build(self) -> EventHandler<State> {
EventHandler {
handler: self.handler,
on_errors: self.on_errors,
}
}
}
pub trait EventHandlerHandler<State, E>: Send + Sync
where
State: StateBound,
{
fn handle(&self, ctx: EventContext<State, E>) -> DynFuture<'_, EventResult>;
}
macro_rules! impl_event_handler_for {
($($event:ty),* $(,)?) => {
$(
impl<State, F, Fut, Res> EventHandlerHandler<State, $event> for F
where
State: StateBound,
F: Fn(EventContext<State, $event>) -> Fut + Send + Sync + 'static,
Fut: Future<Output = Res> + Send + 'static,
Res: IntoEventResult,
{
fn handle(&self, ctx: EventContext<State, $event>) -> DynFuture<'_, EventResult> {
Box::pin(async move { self(ctx).await.into_event_result() })
}
}
)*
};
}
impl_event_handler_for!(
Event,
AutoModerationActionExecution,
AutoModerationRuleCreate,
AutoModerationRuleDelete,
AutoModerationRuleUpdate,
BanAdd,
BanRemove,
ChannelCreate,
ChannelDelete,
ChannelUpdate,
ChannelPinsUpdate,
CommandPermissionsUpdate,
EntitlementCreate,
EntitlementDelete,
EntitlementUpdate,
GuildAuditLogEntryCreate,
GuildCreate,
GuildUpdate,
GuildDelete,
GuildEmojisUpdate,
GuildIntegrationsUpdate,
GuildScheduledEventCreate,
GuildScheduledEventDelete,
GuildScheduledEventUpdate,
GuildScheduledEventUserAdd,
GuildScheduledEventUserRemove,
GuildStickersUpdate,
IntegrationCreate,
IntegrationUpdate,
IntegrationDelete,
InteractionCreate,
InviteCreate,
InviteDelete,
MemberAdd,
MemberRemove,
MemberUpdate,
MemberChunk,
MessageCreate,
MessageUpdate,
MessageDelete,
MessageDeleteBulk,
MessagePollVoteAdd,
MessagePollVoteRemove,
PresenceUpdate,
RateLimited,
ReactionAdd,
ReactionRemove,
ReactionRemoveAll,
ReactionRemoveEmoji,
Ready,
RoleCreate,
RoleDelete,
RoleUpdate,
StageInstanceCreate,
StageInstanceUpdate,
StageInstanceDelete,
ThreadCreate,
ThreadUpdate,
ThreadDelete,
ThreadListSync,
ThreadMemberUpdate,
ThreadMembersUpdate,
TypingStart,
UnavailableGuild,
UserUpdate,
VoiceServerUpdate,
VoiceStateUpdate,
WebhooksUpdate,
);
pub struct GatewayClose;
pub struct GatewayHeartbeat;
pub struct GatewayHeartbeatAck;
pub struct GatewayInvalidateSession;
pub struct GatewayReconnect;
pub struct Resumed;
pub struct EventHandlerWrapper<F, Event> {
func: F,
_event: PhantomData<Event>,
}
impl<F, Event> EventHandlerWrapper<F, Event> {
fn new(func: F) -> Self {
EventHandlerWrapper {
func,
_event: PhantomData,
}
}
}
pub trait EventHandlerHandlerWithoutArgs<State>: Send + Sync
where
State: StateBound,
{
fn handle(&self, ctx: EventContext<State, Event>) -> Option<DynFuture<'_, EventResult>>;
fn is_handler_for_type(&self, event: &Event) -> bool;
}
macro_rules! impl_event_handler_handler_without_args {
($event:ident) => {
impl<State, Func> EventHandlerHandlerWithoutArgs<State>
for EventHandlerWrapper<Func, $event>
where
State: StateBound,
Func: EventHandlerHandler<State, $event>,
{
fn handle(
&self,
ctx: EventContext<State, Event>,
) -> Option<DynFuture<'_, EventResult>> {
if let Event::$event(event) = ctx.event {
let ctx = EventContext {
event: event.clone(),
handle: ctx.handle.clone(),
state: ctx.state.clone(),
};
return Some(self.func.handle(ctx));
}
None
}
fn is_handler_for_type(&self, event: &Event) -> bool {
matches!(event, Event::$event(_))
}
}
};
($event:ident boxed) => {
impl<State, Func> EventHandlerHandlerWithoutArgs<State>
for EventHandlerWrapper<Func, $event>
where
State: StateBound,
Func: EventHandlerHandler<State, $event>,
{
fn handle(
&self,
ctx: EventContext<State, Event>,
) -> Option<DynFuture<'_, EventResult>> {
if let Event::$event(event) = ctx.event {
let ctx = EventContext {
event: (*event).clone(),
handle: ctx.handle.clone(),
state: ctx.state.clone(),
};
return Some(self.func.handle(ctx));
}
None
}
fn is_handler_for_type(&self, event: &Event) -> bool {
matches!(event, Event::$event(_))
}
}
};
($event:ident discarded) => {
impl<State, Func> EventHandlerHandlerWithoutArgs<State>
for EventHandlerWrapper<Func, $event>
where
State: StateBound,
Func: EventHandlerHandler<State, $event>,
{
fn handle(
&self,
ctx: EventContext<State, Event>,
) -> Option<DynFuture<'_, EventResult>> {
if let Event::$event(_) = ctx.event {
let ctx = EventContext {
event: $event,
handle: ctx.handle.clone(),
state: ctx.state.clone(),
};
return Some(self.func.handle(ctx));
}
None
}
fn is_handler_for_type(&self, event: &Event) -> bool {
matches!(event, Event::$event(_))
}
}
};
($event:ident placeholder) => {
impl<State, Func> EventHandlerHandlerWithoutArgs<State>
for EventHandlerWrapper<Func, $event>
where
State: StateBound,
Func: EventHandlerHandler<State, $event>,
{
fn handle(
&self,
ctx: EventContext<State, Event>,
) -> Option<DynFuture<'_, EventResult>> {
if let Event::$event = ctx.event {
let ctx = EventContext {
event: $event,
handle: ctx.handle.clone(),
state: ctx.state.clone(),
};
return Some(self.func.handle(ctx));
}
None
}
fn is_handler_for_type(&self, event: &Event) -> bool {
matches!(event, Event::$event)
}
}
};
($event:ident where inner = $inner:ident) => {
impl<State, Func> EventHandlerHandlerWithoutArgs<State>
for EventHandlerWrapper<Func, $inner>
where
State: StateBound,
Func: EventHandlerHandler<State, $inner>,
{
fn handle(
&self,
ctx: EventContext<State, Event>,
) -> Option<DynFuture<'_, EventResult>> {
if let Event::$event(event) = ctx.event {
let ctx = EventContext {
event,
handle: ctx.handle.clone(),
state: ctx.state.clone(),
};
return Some(self.func.handle(ctx));
}
None
}
fn is_handler_for_type(&self, event: &Event) -> bool {
matches!(event, Event::$event(_))
}
}
};
}
impl<State, Func> EventHandlerHandlerWithoutArgs<State> for EventHandlerWrapper<Func, Event>
where
State: StateBound,
Func: EventHandlerHandler<State, Event>,
{
fn handle(&self, ctx: EventContext<State, Event>) -> Option<DynFuture<'_, EventResult>> {
Some(self.func.handle(ctx))
}
fn is_handler_for_type(&self, _: &Event) -> bool {
true
}
}
impl_event_handler_handler_without_args!(AutoModerationActionExecution);
impl_event_handler_handler_without_args!(AutoModerationRuleCreate);
impl_event_handler_handler_without_args!(AutoModerationRuleDelete);
impl_event_handler_handler_without_args!(AutoModerationRuleUpdate);
impl_event_handler_handler_without_args!(BanAdd);
impl_event_handler_handler_without_args!(BanRemove);
impl_event_handler_handler_without_args!(ChannelCreate boxed);
impl_event_handler_handler_without_args!(ChannelDelete boxed);
impl_event_handler_handler_without_args!(ChannelUpdate boxed);
impl_event_handler_handler_without_args!(ChannelPinsUpdate);
impl_event_handler_handler_without_args!(CommandPermissionsUpdate);
impl_event_handler_handler_without_args!(EntitlementCreate);
impl_event_handler_handler_without_args!(EntitlementDelete);
impl_event_handler_handler_without_args!(EntitlementUpdate);
impl_event_handler_handler_without_args!(GuildAuditLogEntryCreate boxed);
impl_event_handler_handler_without_args!(GuildCreate boxed);
impl_event_handler_handler_without_args!(GuildUpdate boxed);
impl_event_handler_handler_without_args!(GuildDelete);
impl_event_handler_handler_without_args!(GuildEmojisUpdate);
impl_event_handler_handler_without_args!(GuildIntegrationsUpdate);
impl_event_handler_handler_without_args!(GuildScheduledEventCreate boxed);
impl_event_handler_handler_without_args!(GuildScheduledEventDelete boxed);
impl_event_handler_handler_without_args!(GuildScheduledEventUpdate boxed);
impl_event_handler_handler_without_args!(GuildScheduledEventUserAdd);
impl_event_handler_handler_without_args!(GuildScheduledEventUserRemove);
impl_event_handler_handler_without_args!(GuildStickersUpdate);
impl_event_handler_handler_without_args!(IntegrationCreate boxed);
impl_event_handler_handler_without_args!(IntegrationUpdate boxed);
impl_event_handler_handler_without_args!(IntegrationDelete);
impl_event_handler_handler_without_args!(InteractionCreate boxed);
impl_event_handler_handler_without_args!(InviteCreate boxed);
impl_event_handler_handler_without_args!(InviteDelete);
impl_event_handler_handler_without_args!(MemberAdd boxed);
impl_event_handler_handler_without_args!(MemberRemove);
impl_event_handler_handler_without_args!(MemberUpdate boxed);
impl_event_handler_handler_without_args!(MemberChunk);
impl_event_handler_handler_without_args!(MessageCreate boxed);
impl_event_handler_handler_without_args!(MessageUpdate boxed);
impl_event_handler_handler_without_args!(MessageDelete);
impl_event_handler_handler_without_args!(MessageDeleteBulk);
impl_event_handler_handler_without_args!(MessagePollVoteAdd);
impl_event_handler_handler_without_args!(MessagePollVoteRemove);
impl_event_handler_handler_without_args!(PresenceUpdate boxed);
impl_event_handler_handler_without_args!(RateLimited);
impl_event_handler_handler_without_args!(ReactionAdd boxed);
impl_event_handler_handler_without_args!(ReactionRemove boxed);
impl_event_handler_handler_without_args!(ReactionRemoveAll);
impl_event_handler_handler_without_args!(ReactionRemoveEmoji);
impl_event_handler_handler_without_args!(Ready);
impl_event_handler_handler_without_args!(RoleCreate);
impl_event_handler_handler_without_args!(RoleDelete);
impl_event_handler_handler_without_args!(RoleUpdate);
impl_event_handler_handler_without_args!(StageInstanceCreate);
impl_event_handler_handler_without_args!(StageInstanceUpdate);
impl_event_handler_handler_without_args!(StageInstanceDelete);
impl_event_handler_handler_without_args!(ThreadCreate boxed);
impl_event_handler_handler_without_args!(ThreadUpdate boxed);
impl_event_handler_handler_without_args!(ThreadDelete);
impl_event_handler_handler_without_args!(ThreadListSync);
impl_event_handler_handler_without_args!(ThreadMemberUpdate boxed);
impl_event_handler_handler_without_args!(ThreadMembersUpdate);
impl_event_handler_handler_without_args!(TypingStart boxed);
impl_event_handler_handler_without_args!(UnavailableGuild);
impl_event_handler_handler_without_args!(UserUpdate);
impl_event_handler_handler_without_args!(VoiceServerUpdate);
impl_event_handler_handler_without_args!(VoiceStateUpdate boxed);
impl_event_handler_handler_without_args!(WebhooksUpdate);
impl_event_handler_handler_without_args!(GatewayClose discarded);
impl_event_handler_handler_without_args!(GatewayHeartbeat placeholder);
impl_event_handler_handler_without_args!(GatewayHeartbeatAck placeholder);
impl_event_handler_handler_without_args!(GatewayHello where inner = Hello);
impl_event_handler_handler_without_args!(GatewayInvalidateSession discarded);
impl_event_handler_handler_without_args!(GatewayReconnect placeholder);
impl_event_handler_handler_without_args!(Resumed placeholder);
pub struct On;
macro_rules! impl_on {
($event:ident $func:ident) => {
pub fn $func<F, State>(handler: F) -> EventHandlerBuilder<State>
where
F: EventHandlerHandler<State, $event> + 'static,
State: StateBound,
{
EventHandlerBuilder {
handler: Arc::new(EventHandlerWrapper::new(handler)),
on_errors: Vec::new(),
}
}
};
($event:ident $func:ident ($inner:ident)) => {
pub fn $func<F, State>(handler: F) -> EventHandlerBuilder<State>
where
F: EventHandlerHandler<State, $inner> + 'static,
State: StateBound,
{
EventHandlerBuilder {
handler: Arc::new(EventHandlerWrapper::new(handler)),
on_errors: Vec::new(),
}
}
};
}
impl On {
impl_on!(All event (Event));
impl_on!(AutoModerationActionExecution auto_moderation_action_execution);
impl_on!(AutoModerationRuleCreate auto_moderation_rule_create);
impl_on!(AutoModerationRuleDelete auto_moderation_rule_delete);
impl_on!(AutoModerationRuleUpdate auto_moderation_rule_update);
impl_on!(BanAdd ban_add);
impl_on!(BanRemove ban_remove);
impl_on!(ChannelCreate channel_create);
impl_on!(ChannelDelete channel_delete);
impl_on!(ChannelPinsUpdate channel_pins_update);
impl_on!(ChannelUpdate channel_update);
impl_on!(CommandPermissionsUpdate command_permissions_update);
impl_on!(EntitlementCreate entitlement_create);
impl_on!(EntitlementDelete entitlement_delete);
impl_on!(EntitlementUpdate entitlement_update);
impl_on!(GatewayClose gateway_close);
impl_on!(GatewayHeartbeat gateway_heartbeat);
impl_on!(GatewayHeartbeatAck gateway_heartbeat_ack);
impl_on!(GatewayHello gateway_hello (Hello));
impl_on!(GatewayInvalidateSession gateway_invalidate_session);
impl_on!(GatewayReconnect gateway_reconnect);
impl_on!(GuildAuditLogEntryCreate guild_audit_log_entry_create);
impl_on!(GuildCreate guild_create);
impl_on!(GuildDelete guild_delete);
impl_on!(GuildEmojisUpdate guild_emojis_update);
impl_on!(GuildIntegrationsUpdate guild_integrations_update);
impl_on!(GuildScheduledEventCreate guild_scheduled_event_create);
impl_on!(GuildScheduledEventDelete guild_scheduled_event_delete);
impl_on!(GuildScheduledEventUpdate guild_scheduled_event_update);
impl_on!(GuildScheduledEventUserAdd guild_scheduled_event_user_add);
impl_on!(GuildScheduledEventUserRemove guild_scheduled_event_user_remove);
impl_on!(GuildStickersUpdate guild_stickers_update);
impl_on!(GuildUpdate guild_update);
impl_on!(IntegrationCreate integration_create);
impl_on!(IntegrationDelete integration_delete);
impl_on!(IntegrationUpdate integration_update);
impl_on!(InteractionCreate interaction_create);
impl_on!(InviteCreate invite_create);
impl_on!(InviteDelete invite_delete);
impl_on!(MemberAdd member_add);
impl_on!(MemberChunk member_chunk);
impl_on!(MemberRemove member_remove);
impl_on!(MemberUpdate member_update);
impl_on!(MessageCreate message_create);
impl_on!(MessageDelete message_delete);
impl_on!(MessageDeleteBulk message_delete_bulk);
impl_on!(MessagePollVoteAdd message_poll_vote_add);
impl_on!(MessagePollVoteRemove message_poll_vote_remove);
impl_on!(MessageUpdate message_update);
impl_on!(PresenceUpdate presence_update);
impl_on!(RateLimited rate_limited);
impl_on!(ReactionAdd reaction_add);
impl_on!(ReactionRemove reaction_remove);
impl_on!(ReactionRemoveAll reaction_remove_all);
impl_on!(ReactionRemoveEmoji reaction_remove_emoji);
impl_on!(Ready ready);
impl_on!(Resumed resumed);
impl_on!(RoleCreate role_create);
impl_on!(RoleDelete role_delete);
impl_on!(RoleUpdate role_update);
impl_on!(StageInstanceCreate stage_instance_create);
impl_on!(StageInstanceDelete stage_instance_delete);
impl_on!(StageInstanceUpdate stage_instance_update);
impl_on!(ThreadCreate thread_create);
impl_on!(ThreadDelete thread_delete);
impl_on!(ThreadListSync thread_list_sync);
impl_on!(ThreadMemberUpdate thread_member_update);
impl_on!(ThreadMembersUpdate thread_members_update);
impl_on!(ThreadUpdate thread_update);
impl_on!(TypingStart typing_start);
impl_on!(UnavailableGuild unavailable_guild);
impl_on!(UserUpdate user_update);
impl_on!(VoiceServerUpdate voice_server_update);
impl_on!(VoiceStateUpdate voice_state_update);
impl_on!(WebhooksUpdate webhooks_update);
}