macro_rules! impl_from_str {
($t:ty) => {
impl ::std::str::FromStr for $t {
type Err = ::serde_json::Error;
fn from_str(s: &str) -> ::std::result::Result<Self, Self::Err> {
::serde_json::from_str(s)
}
}
};
}
macro_rules! impl_display {
($t:ty) => {
impl ::std::fmt::Display for $t {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
write!(
f,
"{}",
::serde_json::to_string(self)
.expect(concat!("failed to serialize ", stringify!($t)))
)
}
}
};
}
macro_rules! payload_impl {
($t:ty) => {
$crate::macros::impl_from_str! {$t}
$crate::macros::impl_display! {$t}
};
}
macro_rules! payloads_impl_for_kinds {
($($t:ty),*) => {
::paste::paste! {
$( $crate::macros::payload_impl! { [< $t Payload >] } )*
}
};
}
macro_rules! all_events {
($n:ident) => {
$n! {
Ping,
Joined,
Left,
MessageCreated,
MessageDeleted,
MessageUpdated,
DirectMessageCreated,
DirectMessageDeleted,
DirectMessageUpdated,
BotMessageStampsUpdated,
ChannelCreated,
ChannelTopicChanged,
UserCreated,
StampCreated,
TagAdded,
TagRemoved,
UserGroupCreated,
UserGroupUpdated,
UserGroupDeleted,
UserGroupMemberAdded,
UserGroupMemberUpdated,
UserGroupMemberRemoved,
UserGroupAdminAdded,
UserGroupAdminRemoved
}
};
}
macro_rules! event_convert {
($i:ident) => {
::paste::paste! {
impl ::std::convert::From< [<$i Payload>] > for Event {
fn from(event: [<$i Payload>]) -> Self {
Event::$i(event)
}
}
}
};
}
macro_rules! event_converts {
($($i:ident),*) => {
$($crate::macros::event_convert! {$i})*
};
}
macro_rules! match_event_to_kind {
($v:ident, $($i:ident),*) => {
::paste::paste! {
match $v {
$( Event::$i(_) => EventKind::$i, )*
}
}
};
}
macro_rules! match_event_kinds_to_str {
($v:ident, $($i:ident),*) => {
::paste::paste! {
match $v {
$( EventKind::$i => stringify!([< $i:snake:upper >]), )*
}
}
};
}
macro_rules! match_str_to_event_kinds {
($v:ident, $($i:ident),*) => {
::paste::paste! {
match $v {
$( stringify!([< $i:snake:upper >]) => ::core::result::Result::Ok(EventKind::$i), )*
_ => ::core::result::Result::Err($crate::ErrorKind::BotEventMismatch.into()),
}
}
};
}
macro_rules! error_with_source {
(
$( #[$m:meta] )*
$v:vis $k:ident
) => {
::paste::paste! {
$(#[$m])*
$v fn [< $k:snake >] <E>(source: E) -> Self
where
E: ::std::convert::Into<::std::boxed::Box<
dyn ::std::error::Error + Send + Sync + 'static
>>,
{
Self::new($crate::error::ErrorKind::[< $k:camel >], source)
}
}
};
}
#[cfg(feature = "tower")]
macro_rules! event_service_types {
() => {
type Response = ();
type Error = $crate::Error;
type Future = ::futures_util::future::Either<
$crate::handler::WrapErrorFuture<Service::Future, Service::Error>,
Fallback::Future,
>;
};
}
#[cfg(feature = "tower")]
macro_rules! event_service_poll_ready {
() => {
fn poll_ready(
&mut self,
cx: &mut ::std::task::Context<'_>,
) -> ::std::task::Poll<::std::result::Result<(), Self::Error>> {
if let ::std::result::Result::Err(e) = ::futures_core::ready!(self.inner.poll_ready(cx))
{
return ::std::task::Poll::Ready(::std::result::Result::Err(
$crate::Error::handler(e),
));
}
if let ::std::result::Result::Err(e) =
::futures_core::ready!(self.fallback.poll_ready(cx))
{
return ::std::task::Poll::Ready(::std::result::Result::Err(e));
}
::std::task::Poll::Ready(::std::result::Result::Ok(()))
}
};
}
#[cfg(feature = "tower")]
macro_rules! event_service_call {
(
$( #[$m:meta] )*
$v:ident ( $i:ident )
) => {
$( #[$m] )*
fn call(&mut self, req: $crate::Event) -> Self::Future {
match req {
$crate::Event::$v($i) => ::futures_util::future::Either::Left(
$crate::handler::WrapErrorFuture::new(self.inner.call($i)),
),
event => ::futures_util::future::Either::Right(self.fallback.call(event)),
}
}
};
(
$( #[$m:meta] )*
$s:ident;
$v:ident ( $i:ident ) => $e:expr
) => {
$( #[$m] )*
fn call(&mut self, req: (State, $crate::handler::Event)) -> Self::Future {
let ($s, event) = req;
match event {
$crate::Event::$v($i) => ::futures_util::future::Either::Left(
$crate::handler::WrapErrorFuture::new(self.inner.call($e)),
),
event => ::futures_util::future::Either::Right(self.fallback.call(($s, event))),
}
}
};
}
#[cfg(feature = "tower")]
macro_rules! event_service {
(
$( #[$m:meta] )*
$v:vis $e:ident
) => { ::paste::paste! {
$( #[$m] )*
$v struct
[< On $e:camel >] <Service, Fallback, Req>
{
_req: ::std::marker::PhantomData<Req>,
inner: Service,
fallback: Fallback,
}
impl<Service, Fallback> ::tower_service::Service<$crate::Event>
for [< On $e:camel >] <Service, Fallback, $crate::payloads::[< $e:camel Payload >] >
where
Service: ::tower_service::Service<$crate::payloads::[< $e:camel Payload >], Response = ()>,
Service::Error: ::std::convert::Into<::std::boxed::Box<
dyn ::std::error::Error + ::std::marker::Send + ::std::marker::Sync + 'static,
>>,
Fallback: ::tower_service::Service<$crate::Event, Response = (), Error = $crate::Error>,
{
$crate::macros::event_service_types! {}
$crate::macros::event_service_poll_ready! {}
$crate::macros::event_service_call! {
#[inline]
[< $e:camel >] (e)
}
}
impl<State, Service, Fallback> ::tower_service::Service<(State, $crate::handler::Event)>
for [< On $e:camel >] <Service, Fallback, $crate::payloads::[< $e:camel Payload >] >
where
Service: ::tower_service::Service<$crate::payloads::[< $e:camel Payload >], Response = ()>,
Service::Error: ::std::convert::Into<::std::boxed::Box<
dyn ::std::error::Error + ::std::marker::Send + ::std::marker::Sync + 'static,
>>,
Fallback: ::tower_service::Service<
(State, $crate::handler::Event),
Response = (),
Error = $crate::Error,
>,
{
$crate::macros::event_service_types! {}
$crate::macros::event_service_poll_ready! {}
$crate::macros::event_service_call! {
#[inline]
state;
[< $e:camel >] (e) => e
}
}
impl<State, Service, Fallback> ::tower_service::Service<(State, $crate::handler::Event)>
for [< On $e:camel >] <Service, Fallback, (State, $crate::payloads::[< $e:camel Payload >] )>
where
Service: ::tower_service::Service<
(State, $crate::payloads::[< $e:camel Payload >]),
Response = (),
>,
Service::Error: ::std::convert::Into<::std::boxed::Box<
dyn ::std::error::Error + ::std::marker::Send + ::std::marker::Sync + 'static,
>>,
Fallback: ::tower_service::Service<
(State, $crate::handler::Event),
Response = (),
Error = $crate::Error
>,
{
$crate::macros::event_service_types! {}
$crate::macros::event_service_poll_ready! {}
$crate::macros::event_service_call! {
#[inline]
state;
[< $e:camel >] (e) => (state, e)
}
}
}};
}
#[cfg(feature = "tower")]
macro_rules! handler_on_events {
($(
$( #[$m:meta] )*
$v:vis $e:ident;
)+) => { ::paste::paste! {
impl<Service1> $crate::Handler<Service1> {
$(
$( #[$m] )*
$v fn [< on_ $e:snake:lower >] <Service2, Req> (self, service: Service2)
-> $crate::Handler<$crate::handler::[< On $e:camel >] <Service2, Service1, Req>>
where
Service2: ::tower_service::Service<Req>,
{
let Self {
service: fallback,
parser,
} = self;
$crate::Handler {
service: $crate::handler::[< On $e:camel >] {
_req: ::std::marker::PhantomData,
inner: service,
fallback,
},
parser,
}
}
)+
}
}};
}
pub(crate) use {
all_events, error_with_source, event_convert, event_converts, impl_display, impl_from_str,
match_event_kinds_to_str, match_event_to_kind, match_str_to_event_kinds, payload_impl,
payloads_impl_for_kinds,
};
#[cfg(feature = "tower")]
pub(crate) use {
event_service, event_service_call, event_service_poll_ready, event_service_types,
handler_on_events,
};
#[cfg(test)]
macro_rules! test_event_convert {
($group:expr, $i:ident) => {
::paste::paste! {
#[test]
fn [< $i:snake:lower _convert >]() {
let data = ::std::fs::read_to_string(concat!(
"testdata/",
$group,
"/",
stringify!([< $i:snake:lower >]),
".json"
))
.unwrap();
let payload: [<$i Payload>] = data.parse().unwrap();
let event: Event = payload.into();
assert_eq!(event, Event::$i(data.parse().unwrap()));
}
}
};
}
#[cfg(test)]
macro_rules! test_event_to_kind {
($group:expr, $i:ident) => {
::paste::paste! {
#[test]
fn [< $i:snake:lower _kind >]() {
let data = ::std::fs::read_to_string(concat!(
"testdata/",
$group,
"/",
stringify!([< $i:snake:lower >]),
".json"
))
.unwrap();
let payload: [<$i Payload>] = data.parse().unwrap();
let event: Event = payload.into();
assert_eq!(event.kind(), EventKind::$i);
}
}
};
}
#[cfg(test)]
macro_rules! test_event_kind_from_str {
($i:ident) => {
::paste::paste! {
#[test]
fn [< $i:snake:lower _kind_from_str >]() {
let s = stringify!( [< $i:snake:upper >] );
let kind: EventKind = s.parse().unwrap();
assert_eq!(kind, EventKind::$i);
}
}
};
}
#[cfg(test)]
macro_rules! test_event_kind_to_string {
($i:ident) => {
::paste::paste! {
#[test]
fn [< $i:snake:lower _kind_to_string >]() {
let kind = EventKind::$i;
let s = kind.to_string();
assert_eq!(&s, stringify!([< $i:snake:upper >]))
}
}
};
}
#[cfg(test)]
macro_rules! test_parse_payload {
($group:expr, $i:ident) => {
::paste::paste! {
#[test]
fn [< parse_ $i:snake:lower >]() {
let parser = $crate::test_utils::make_parser();
let kind = stringify!([< $i:snake:upper >]);
let headers = $crate::test_utils::make_headers(kind);
let body = ::std::fs::read_to_string(concat!(
"testdata/",
$group,
"/",
stringify!([< $i:snake:lower >]),
".json"
))
.unwrap();
let event = parser.parse(&headers, body.as_bytes()).unwrap();
let payload = ::serde_json::from_str::< $crate::payloads:: [< $i Payload >] >(&body).unwrap();
assert_eq!(event, Event::$i(payload));
}
}
};
}
#[cfg(test)]
macro_rules! test_error_kind_convert {
($kind:ident) => {
::paste::paste! {
#[test]
fn [< error_kind_ $kind:snake:lower >]() {
let kind = ErrorKind::$kind;
let error = Error::from(kind);
assert_eq!(error.kind(), kind);
}
}
};
}
#[cfg(test)]
macro_rules! all_error_kinds {
($n:ident) => {
$n! {
ContentTypeNotFound,
ReadContentTypeFailed,
ContentTypeMismatch,
BotTokenNotFound,
ReadBotTokenFailed,
BotTokenMismatch,
BotEventNotFound,
ReadBotEventFailed,
BotEventMismatch,
ReadBodyFailed,
ParseBodyFailed,
Handler
}
};
}
#[cfg(test)]
pub(crate) use {
all_error_kinds, test_error_kind_convert, test_event_convert, test_event_kind_from_str,
test_event_kind_to_string, test_event_to_kind, test_parse_payload,
};