Merge pull request #20 from teloxide/update-dispatching

Remove support for the old dispatching
This commit is contained in:
Hirrolot 2022-04-02 08:20:10 -07:00 committed by GitHub
commit dfba097c71
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 8 additions and 172 deletions

View file

@ -6,6 +6,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## unreleased
### Removed
- Support for the old dispatching: `#[teloxide(subtransition)]`.
## 0.5.1 - 2022-03-23
### Fixed

View file

@ -99,9 +99,9 @@ pub fn expand(item: ItemEnum) -> Result<TokenStream, syn::Error> {
fn assert_clone<T: Clone>() {}
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;
fn handler() -> dptree::Handler<'static, dptree::di::DependencyMap, Self::Out> {

View file

@ -18,185 +18,17 @@ use crate::{
};
use proc_macro::TokenStream;
use quote::{quote, ToTokens};
use syn::{
parse_macro_input, DeriveInput, Fields, FnArg, ItemEnum, ItemFn,
ReturnType, Type,
};
use std::fmt::Write;
use syn::{parse_macro_input, DeriveInput, Fields, ItemEnum};
#[proc_macro_derive(DialogueState, attributes(handler, handler_out, store))]
pub fn derive_dialogue_state(item: TokenStream) -> TokenStream {
let input = parse_macro_input!(item as ItemEnum);
match dialogue_state::expand(input) {
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 {
($($some:tt)*) => {
match $($some)* {