Add auxiliary dialogues macros

This commit is contained in:
Temirkhan Myrzamadi 2020-05-24 17:08:40 +06:00
parent 963218bba0
commit 6ff1800f12
3 changed files with 55 additions and 52 deletions

View file

@ -15,6 +15,7 @@
// ```
#![allow(clippy::trivial_regex)]
#![allow(dead_code)]
#[macro_use]
extern crate frunk;
@ -59,54 +60,37 @@ impl FavouriteMusic {
struct StartState;
impl StartState {
fn up(self) -> ReceiveFullNameState {
ReceiveFullNameState
}
struct ReceiveFullNameState {
rest: StartState,
}
struct ReceiveFullNameState;
impl ReceiveFullNameState {
fn up(self, full_name: String) -> ReceiveAgeState {
ReceiveAgeState { full_name }
}
}
#[derive(Clone)]
struct ReceiveAgeState {
rest: ReceiveFullNameState,
full_name: String,
}
impl ReceiveAgeState {
fn up(self, age: u8) -> ReceiveFavouriteMusicState {
ReceiveFavouriteMusicState { full_name: self.full_name, age }
}
}
#[derive(Clone)]
struct ReceiveFavouriteMusicState {
full_name: String,
rest: ReceiveAgeState,
age: u8,
}
impl ReceiveFavouriteMusicState {
fn up(self, favourite_music: FavouriteMusic) -> ExitState {
ExitState { full_name: self.full_name, age: self.age, favourite_music }
}
}
#[derive(Display)]
#[display(
"Your full name: {full_name}, your age: {age}, your favourite music: \
{favourite_music}"
"Your full name: {rest.rest.full_name}, your age: {rest.age}, your \
favourite music: {favourite_music}"
)]
struct ExitState {
full_name: String,
age: u8,
rest: ReceiveFavouriteMusicState,
favourite_music: FavouriteMusic,
}
up!(
StartState -> ReceiveFullNameState,
ReceiveFullNameState + [full_name: String] -> ReceiveAgeState,
ReceiveAgeState + [age: u8] -> ReceiveFavouriteMusicState,
ReceiveFavouriteMusicState + [favourite_music: FavouriteMusic] -> ExitState
);
type Dialogue = Coprod!(
StartState,
ReceiveFullNameState,
@ -114,7 +98,7 @@ type Dialogue = Coprod!(
ReceiveFavouriteMusicState
);
struct Wrapper(Dialogue);
wrap_dialogue!(Wrapper, Dialogue);
impl Default for Wrapper {
fn default() -> Self {
@ -122,12 +106,6 @@ impl Default for Wrapper {
}
}
impl DialogueWrapper<Dialogue> for Wrapper {
fn new(dialogue: Dialogue) -> Wrapper {
Wrapper(dialogue)
}
}
// ============================================================================
// [Control a dialogue]
// ============================================================================
@ -196,16 +174,6 @@ async fn favourite_music(cx: Cx<ReceiveFavouriteMusicState>) -> Res {
}
}
async fn handle_message(cx: Cx<Wrapper>) -> Res {
let DialogueDispatcherHandlerCx { cx, dialogue } = cx;
// You need handle the error instead of panicking in real-world code, maybe
// send diagnostics to a development chat.
let Wrapper(dialogue) = dialogue.expect("Failed to get dialogue info from storage");
dispatch!([cx, dialogue] -> [start, full_name, age, favourite_music]);
}
// ============================================================================
// [Run!]
// ============================================================================
@ -223,7 +191,14 @@ async fn run() {
Dispatcher::new(bot)
.messages_handler(DialogueDispatcher::new(|cx| async move {
handle_message(cx).await.expect("Something wrong with the bot!")
let DialogueDispatcherHandlerCx { cx, dialogue } = cx;
// You need handle the error instead of panicking in real-world code, maybe
// send diagnostics to a development chat.
let Wrapper(dialogue) = dialogue.expect("Failed to get dialogue info from storage");
dispatch!([cx, dialogue] -> [start, full_name, age, favourite_music])
.expect("Something wrong with the bot!")
}))
.dispatch()
.await;

View file

@ -61,7 +61,7 @@ macro_rules! dispatch {
([$cx:ident, $dialogue:ident] -> [$transition:ident, $($transitions:ident),+]) => {
match $dialogue {
Coproduct::Inl(state) => {
return $transition(teloxide::dispatching::dialogue::DialogueDispatcherHandlerCx::new($cx, state)).await;
$transition(teloxide::dispatching::dialogue::DialogueDispatcherHandlerCx::new($cx, state)).await
}
Coproduct::Inr(another) => { dispatch!([$cx, another] -> [$($transitions),+]) }
}
@ -70,9 +70,37 @@ macro_rules! dispatch {
([$cx:ident, $dialogue:ident] -> [$transition:ident]) => {
match $dialogue {
Coproduct::Inl(state) => {
return $transition(teloxide::dispatching::dialogue::DialogueDispatcherHandlerCx::new($cx, state)).await;
$transition(teloxide::dispatching::dialogue::DialogueDispatcherHandlerCx::new($cx, state)).await
}
Coproduct::Inr(_absurd) => unreachable!(),
}
};
}
#[macro_export]
macro_rules! wrap_dialogue {
($name:ident, $dialogue:ident) => {
struct $name($dialogue);
impl teloxide::dispatching::dialogue::DialogueWrapper<$dialogue>
for $name
{
fn new(d: $dialogue) -> Wrapper {
$name(d)
}
}
};
}
#[macro_export]
macro_rules! up {
( $( $from:ident $(+ [$field_name:ident : $field_type:ty])? -> $to:ident ),+ ) => {
$(
impl $from {
fn up(self, $( $field_name: $field_type )?) -> $to {
$to { rest: self, $($field_name)? }
}
}
)+
};
}

View file

@ -13,7 +13,7 @@ pub use crate::{
error_handlers::{LoggingErrorHandler, OnError},
requests::{Request, ResponseResult},
types::{Message, Update},
Bot, RequestError,
up, wrap_dialogue, Bot, RequestError,
};
pub use tokio::sync::mpsc::UnboundedReceiver;