mirror of
https://github.com/teloxide/teloxide.git
synced 2024-12-23 06:51:01 +01:00
Merge pull request #20 from teloxide/update-dispatching
Remove support for the old dispatching
This commit is contained in:
commit
dfba097c71
3 changed files with 8 additions and 172 deletions
|
@ -6,6 +6,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||||
|
|
||||||
## unreleased
|
## unreleased
|
||||||
|
|
||||||
|
### Removed
|
||||||
|
|
||||||
|
- Support for the old dispatching: `#[teloxide(subtransition)]`.
|
||||||
|
|
||||||
## 0.5.1 - 2022-03-23
|
## 0.5.1 - 2022-03-23
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
|
@ -99,9 +99,9 @@ pub fn expand(item: ItemEnum) -> Result<TokenStream, syn::Error> {
|
||||||
fn assert_clone<T: Clone>() {}
|
fn assert_clone<T: Clone>() {}
|
||||||
|
|
||||||
use teloxide::dptree;
|
use teloxide::dptree;
|
||||||
use teloxide::dispatching2::dialogue::Dialogue;
|
use teloxide::dispatching::dialogue::Dialogue;
|
||||||
|
|
||||||
impl #self_params_with_bounds teloxide::dispatching2::HandlerFactory for #enum_ident #self_params #where_clause {
|
impl #self_params_with_bounds teloxide::dispatching::HandlerFactory for #enum_ident #self_params #where_clause {
|
||||||
type Out = #out;
|
type Out = #out;
|
||||||
|
|
||||||
fn handler() -> dptree::Handler<'static, dptree::di::DependencyMap, Self::Out> {
|
fn handler() -> dptree::Handler<'static, dptree::di::DependencyMap, Self::Out> {
|
||||||
|
|
172
src/lib.rs
172
src/lib.rs
|
@ -18,185 +18,17 @@ use crate::{
|
||||||
};
|
};
|
||||||
use proc_macro::TokenStream;
|
use proc_macro::TokenStream;
|
||||||
use quote::{quote, ToTokens};
|
use quote::{quote, ToTokens};
|
||||||
use syn::{
|
use syn::{parse_macro_input, DeriveInput, Fields, ItemEnum};
|
||||||
parse_macro_input, DeriveInput, Fields, FnArg, ItemEnum, ItemFn,
|
|
||||||
ReturnType, Type,
|
|
||||||
};
|
|
||||||
|
|
||||||
use std::fmt::Write;
|
|
||||||
|
|
||||||
#[proc_macro_derive(DialogueState, attributes(handler, handler_out, store))]
|
#[proc_macro_derive(DialogueState, attributes(handler, handler_out, store))]
|
||||||
pub fn derive_dialogue_state(item: TokenStream) -> TokenStream {
|
pub fn derive_dialogue_state(item: TokenStream) -> TokenStream {
|
||||||
let input = parse_macro_input!(item as ItemEnum);
|
let input = parse_macro_input!(item as ItemEnum);
|
||||||
match dialogue_state::expand(input) {
|
match dialogue_state::expand(input) {
|
||||||
Ok(s) => s.into(),
|
Ok(s) => s.into(),
|
||||||
Err(e) => e.into_compile_error().into(),
|
Err(e) => e.to_compile_error().into(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The docs is below.
|
|
||||||
///
|
|
||||||
/// The only accepted form at the current moment is `#[teloxide(subtransition)]`
|
|
||||||
/// on an asynchronous function. Either this:
|
|
||||||
///
|
|
||||||
/// ```no_compile
|
|
||||||
/// #[teloxide(subtransition)]
|
|
||||||
/// async fn my_transition(state: MyState, cx: TransitionIn, ans: T) -> TransitionOut<MyDialogue> {
|
|
||||||
/// todo!()
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// Or this:
|
|
||||||
///
|
|
||||||
/// ```no_compile
|
|
||||||
/// #[teloxide(subtransition)]
|
|
||||||
/// async fn my_transition(state: MyState, cx: TransitionIn) -> TransitionOut<MyDialogue> {
|
|
||||||
/// todo!()
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// Notice the presence/absence of `ans: T`. In the first case, it generates
|
|
||||||
/// `impl SubTransition for MyState { type Aux = T; type Dialogue = MyDialogue;
|
|
||||||
/// ... }`. In the second case, the `Aux` type defaults to `()`.
|
|
||||||
#[proc_macro_attribute]
|
|
||||||
pub fn teloxide(attr: TokenStream, item: TokenStream) -> TokenStream {
|
|
||||||
match attr.to_string().as_ref() {
|
|
||||||
"subtransition" => {
|
|
||||||
let item_cloned = item.clone();
|
|
||||||
let input = parse_macro_input!(item as ItemFn);
|
|
||||||
let params = input.sig.inputs.iter().collect::<Vec<&FnArg>>();
|
|
||||||
|
|
||||||
if params.len() != 2 && params.len() != 3 {
|
|
||||||
panic!(
|
|
||||||
"An transition function must accept two/three parameters: \
|
|
||||||
a state type, TransitionIn, and an optional data."
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// This is actually used inside the quite! { ... } below.
|
|
||||||
#[allow(unused_variables)]
|
|
||||||
let state_type = match params[0] {
|
|
||||||
FnArg::Typed(pat_type) => &pat_type.ty,
|
|
||||||
_ => unreachable!(),
|
|
||||||
};
|
|
||||||
let fn_name = input.sig.ident;
|
|
||||||
let fn_return_type = match input.sig.output {
|
|
||||||
ReturnType::Type(_arrow, _type) => _type,
|
|
||||||
_ => panic!(
|
|
||||||
"A subtransition must return TransitionOut<your dialogue \
|
|
||||||
type>"
|
|
||||||
),
|
|
||||||
};
|
|
||||||
let requester_param_type = match params
|
|
||||||
.get(1)
|
|
||||||
.expect("A requester parameter must be specified")
|
|
||||||
{
|
|
||||||
FnArg::Typed(typed) => typed.ty.clone(),
|
|
||||||
_ => unreachable!(),
|
|
||||||
};
|
|
||||||
let aux_param_type = match params.get(2) {
|
|
||||||
Some(data_param_type) => match *data_param_type {
|
|
||||||
FnArg::Typed(typed) => typed.ty.clone(),
|
|
||||||
_ => unreachable!(),
|
|
||||||
},
|
|
||||||
None => {
|
|
||||||
let unit_type = proc_macro::TokenStream::from(quote! {()});
|
|
||||||
Box::new(parse_macro_input!(unit_type as Type))
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let call_fn = match params.get(2) {
|
|
||||||
Some(_) => {
|
|
||||||
quote! { #fn_name(self, cx, aux) }
|
|
||||||
}
|
|
||||||
None => quote! { #fn_name(self, cx) },
|
|
||||||
};
|
|
||||||
|
|
||||||
let item = proc_macro2::TokenStream::from(item_cloned);
|
|
||||||
|
|
||||||
let impl_transition = quote! {
|
|
||||||
impl teloxide::dispatching::dialogue::Subtransition for #state_type {
|
|
||||||
type Aux = #aux_param_type;
|
|
||||||
type Dialogue = <#fn_return_type as teloxide::dispatching::dialogue::SubtransitionOutputType>::Output;
|
|
||||||
type Error = <#fn_return_type as teloxide::dispatching::dialogue::SubtransitionOutputType>::Error;
|
|
||||||
type Requester = <#requester_param_type as teloxide::dispatching::UpdateWithCxRequesterType>::Requester;
|
|
||||||
|
|
||||||
fn react(self, cx: teloxide::dispatching::dialogue::TransitionIn<Self::Requester>, aux: #aux_param_type)
|
|
||||||
-> futures::future::BoxFuture<'static, #fn_return_type> {
|
|
||||||
#item
|
|
||||||
futures::future::FutureExt::boxed(#call_fn)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
impl_transition.into()
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
panic!("Unrecognised attribute '{}'", attr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The docs is below.
|
|
||||||
///
|
|
||||||
/// All the variants must be of the form `VariantName(MyStateType)`, and
|
|
||||||
/// `MyStateType` must implement `Subtransition`. All `MyStateType`s must have
|
|
||||||
/// the same `Subtransition::Aux` and `Subtransition::Error`, which will be also
|
|
||||||
/// used in the generated implementation.
|
|
||||||
#[proc_macro_derive(Transition)]
|
|
||||||
pub fn derive_transition(item: TokenStream) -> TokenStream {
|
|
||||||
let input = parse_macro_input!(item as ItemEnum);
|
|
||||||
let mut dispatch_fn = "".to_owned();
|
|
||||||
|
|
||||||
let enum_name = input.ident;
|
|
||||||
let field_type_of_first_variant =
|
|
||||||
match &input.variants.iter().next().unwrap().fields {
|
|
||||||
Fields::Unnamed(fields) => {
|
|
||||||
fields
|
|
||||||
.unnamed
|
|
||||||
.iter()
|
|
||||||
.next()
|
|
||||||
// .unwrap() because empty enumerations are not yet allowed
|
|
||||||
// in stable Rust.
|
|
||||||
.unwrap()
|
|
||||||
.ty
|
|
||||||
.to_token_stream()
|
|
||||||
.to_string()
|
|
||||||
}
|
|
||||||
_ => panic!("Only one unnamed field per variant is allowed"),
|
|
||||||
};
|
|
||||||
|
|
||||||
write!(
|
|
||||||
dispatch_fn,
|
|
||||||
"impl teloxide::dispatching::dialogue::Transition for {1} {{type Aux \
|
|
||||||
= <{0} as teloxide::dispatching::dialogue::Subtransition>::Aux;type \
|
|
||||||
Error = <{0} as \
|
|
||||||
teloxide::dispatching::dialogue::Subtransition>::Error;type \
|
|
||||||
Requester = <{0} as \
|
|
||||||
teloxide::dispatching::dialogue::Subtransition>::Requester;fn \
|
|
||||||
react(self, cx: \
|
|
||||||
teloxide::dispatching::dialogue::TransitionIn<Self::Requester>, aux: \
|
|
||||||
Self::Aux) -> futures::future::BoxFuture<'static, \
|
|
||||||
teloxide::dispatching::dialogue::TransitionOut<Self, Self::Error>> \
|
|
||||||
{{ futures::future::FutureExt::boxed(async move {{ match self {{",
|
|
||||||
field_type_of_first_variant, enum_name
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
for variant in input.variants.iter() {
|
|
||||||
write!(
|
|
||||||
dispatch_fn,
|
|
||||||
"{}::{}(state) => \
|
|
||||||
teloxide::dispatching::dialogue::Subtransition::react(state, cx, \
|
|
||||||
aux).await,",
|
|
||||||
enum_name, variant.ident
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
write!(dispatch_fn, "}} }}) }} }}").unwrap();
|
|
||||||
dispatch_fn.parse().unwrap()
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! get_or_return {
|
macro_rules! get_or_return {
|
||||||
($($some:tt)*) => {
|
($($some:tt)*) => {
|
||||||
match $($some)* {
|
match $($some)* {
|
||||||
|
|
Loading…
Reference in a new issue