mirror of
https://github.com/teloxide/teloxide.git
synced 2024-12-23 06:51:01 +01:00
Merge branch 'master' into redis
This commit is contained in:
commit
37a0ac8ef8
8 changed files with 61 additions and 114 deletions
36
README.md
36
README.md
|
@ -30,9 +30,6 @@
|
||||||
- [Dialogues](https://github.com/teloxide/teloxide#dialogues)
|
- [Dialogues](https://github.com/teloxide/teloxide#dialogues)
|
||||||
- [Recommendations](https://github.com/teloxide/teloxide#recommendations)
|
- [Recommendations](https://github.com/teloxide/teloxide#recommendations)
|
||||||
- [FAQ](https://github.com/teloxide/teloxide#faq)
|
- [FAQ](https://github.com/teloxide/teloxide#faq)
|
||||||
- [Where I can ask questions?](https://github.com/teloxide/teloxide#where-i-can-ask-questions)
|
|
||||||
- [Why Rust?](https://github.com/teloxide/teloxide#why-rust)
|
|
||||||
- [Can I use different loggers?](https://github.com/teloxide/teloxide#can-i-use-different-loggers)
|
|
||||||
- [Community bots](https://github.com/teloxide/teloxide#community-bots)
|
- [Community bots](https://github.com/teloxide/teloxide#community-bots)
|
||||||
- [Contributing](https://github.com/teloxide/teloxide#contributing)
|
- [Contributing](https://github.com/teloxide/teloxide#contributing)
|
||||||
|
|
||||||
|
@ -225,11 +222,6 @@ pub type Dialogue = Coprod!(
|
||||||
ReceiveAgeState,
|
ReceiveAgeState,
|
||||||
ReceiveFavouriteMusicState,
|
ReceiveFavouriteMusicState,
|
||||||
);
|
);
|
||||||
|
|
||||||
wrap_dialogue!(
|
|
||||||
Wrapper(Dialogue),
|
|
||||||
default Self(Dialogue::inject(StartState)),
|
|
||||||
);
|
|
||||||
```
|
```
|
||||||
|
|
||||||
The [`wrap_dialogue!`](https://docs.rs/teloxide/latest/teloxide/macro.wrap_dialogue.html) macro generates a new-type of `Dialogue` with a default implementation.
|
The [`wrap_dialogue!`](https://docs.rs/teloxide/latest/teloxide/macro.wrap_dialogue.html) macro generates a new-type of `Dialogue` with a default implementation.
|
||||||
|
@ -348,7 +340,7 @@ async fn main() {
|
||||||
[start, receive_full_name, receive_age, receive_favourite_music]
|
[start, receive_full_name, receive_age, receive_favourite_music]
|
||||||
)
|
)
|
||||||
.expect("Something wrong with the bot!")
|
.expect("Something wrong with the bot!")
|
||||||
}))
|
}, || Dialogue::inject(StartState)))
|
||||||
.dispatch()
|
.dispatch()
|
||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
|
@ -382,24 +374,32 @@ async fn main() {
|
||||||
The second one produces very strange compiler messages because of the `#[tokio::main]` macro. However, the examples in this README use the second variant for brevity.
|
The second one produces very strange compiler messages because of the `#[tokio::main]` macro. However, the examples in this README use the second variant for brevity.
|
||||||
|
|
||||||
## FAQ
|
## FAQ
|
||||||
### Where I can ask questions?
|
Q: Where I can ask questions?
|
||||||
[Issues](https://github.com/teloxide/teloxide/issues) is a good place for well-formed questions, for example, about the library design, enhancements, bug reports. But if you can't compile your bot due to compilation errors and need quick help, feel free to ask in [our official group](https://t.me/teloxide).
|
|
||||||
|
|
||||||
### Why Rust?
|
A: [Issues](https://github.com/teloxide/teloxide/issues) is a good place for well-formed questions, for example, about the library design, enhancements, bug reports. But if you can't compile your bot due to compilation errors and need quick help, feel free to ask in [our official group](https://t.me/teloxide).
|
||||||
Most programming languages have their own implementations of Telegram bots frameworks, so why not Rust? We think Rust provides enough good ecosystem and the language itself to be suitable for writing bots.
|
|
||||||
|
|
||||||
### Can I use webhooks?
|
Q: Why Rust?
|
||||||
teloxide doesn't provide special API for working with webhooks due to their nature with lots of subtle settings. Instead, you setup your webhook by yourself, as shown in [webhook_ping_pong_bot](examples/ngrok_ping_pong_bot/src/main.rs).
|
|
||||||
|
A: Most programming languages have their own implementations of Telegram bots frameworks, so why not Rust? We think Rust provides enough good ecosystem and the language itself to be suitable for writing bots.
|
||||||
|
|
||||||
|
Q: Can I use webhooks?
|
||||||
|
|
||||||
|
A: teloxide doesn't provide special API for working with webhooks due to their nature with lots of subtle settings. Instead, you setup your webhook by yourself, as shown in [webhook_ping_pong_bot](examples/ngrok_ping_pong_bot/src/main.rs).
|
||||||
|
|
||||||
Associated links:
|
Associated links:
|
||||||
- [Marvin's Marvellous Guide to All Things Webhook](https://core.telegram.org/bots/webhooks)
|
- [Marvin's Marvellous Guide to All Things Webhook](https://core.telegram.org/bots/webhooks)
|
||||||
- [Using self-signed certificates](https://core.telegram.org/bots/self-signed)
|
- [Using self-signed certificates](https://core.telegram.org/bots/self-signed)
|
||||||
|
|
||||||
### Can I use different loggers?
|
Q: Can I use different loggers?
|
||||||
Of course, you can. The [`enable_logging!`](https://docs.rs/teloxide/latest/teloxide/macro.enable_logging.html) and [`enable_logging_with_filter!`](https://docs.rs/teloxide/latest/teloxide/macro.enable_logging_with_filter.html) macros are just convenient utilities, not necessary to use them. You can setup a different logger, for example, [fern](https://crates.io/crates/fern), as usual, e.g. teloxide has no specific requirements as it depends only on [log](https://crates.io/crates/log).
|
|
||||||
|
A: Of course, you can. The [`enable_logging!`](https://docs.rs/teloxide/latest/teloxide/macro.enable_logging.html) and [`enable_logging_with_filter!`](https://docs.rs/teloxide/latest/teloxide/macro.enable_logging_with_filter.html) macros are just convenient utilities, not necessary to use them. You can setup a different logger, for example, [fern](https://crates.io/crates/fern), as usual, e.g. teloxide has no specific requirements as it depends only on [log](https://crates.io/crates/log).
|
||||||
|
|
||||||
## Community bots
|
## Community bots
|
||||||
Feel free to push your own bot into our collection: https://github.com/teloxide/community-bots. Later you will be able to play with them right in our official chat: https://t.me/teloxide.
|
Feel free to push your own bot into our collection!
|
||||||
|
|
||||||
|
- [Rust subreddit reader](https://github.com/steadylearner/Rust-Full-Stack/tree/master/commits/teloxide/subreddit_reader)
|
||||||
|
- [with_webserver - An example of the teloxide + warp combination](https://github.com/steadylearner/Rust-Full-Stack/tree/master/commits/teloxide/with_webserver)
|
||||||
|
- [vzmuinebot - Telegram bot for food menu navigate](https://github.com/ArtHome12/vzmuinebot)
|
||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
See [CONRIBUTING.md](https://github.com/teloxide/teloxide/blob/master/CONTRIBUTING.md).
|
See [CONRIBUTING.md](https://github.com/teloxide/teloxide/blob/master/CONTRIBUTING.md).
|
||||||
|
|
|
@ -38,18 +38,21 @@ async fn run() {
|
||||||
let bot = Bot::from_env();
|
let bot = Bot::from_env();
|
||||||
|
|
||||||
Dispatcher::new(bot)
|
Dispatcher::new(bot)
|
||||||
.messages_handler(DialogueDispatcher::new(|cx| async move {
|
.messages_handler(DialogueDispatcher::new(
|
||||||
let DialogueWithCx { cx, dialogue } = cx;
|
|cx| async move {
|
||||||
|
let DialogueWithCx { cx, dialogue } = cx;
|
||||||
|
|
||||||
// Unwrap without panic because of std::convert::Infallible.
|
// Unwrap without panic because of std::convert::Infallible.
|
||||||
let Wrapper(dialogue) = dialogue.unwrap();
|
let dialogue = dialogue.unwrap();
|
||||||
|
|
||||||
dispatch!(
|
dispatch!(
|
||||||
[cx, dialogue] ->
|
[cx, dialogue] ->
|
||||||
[start, receive_full_name, receive_age, receive_favourite_music]
|
[start, receive_full_name, receive_age, receive_favourite_music]
|
||||||
)
|
)
|
||||||
.expect("Something wrong with the bot!")
|
.expect("Something wrong with the bot!")
|
||||||
}))
|
},
|
||||||
|
|| Dialogue::inject(StartState),
|
||||||
|
))
|
||||||
.dispatch()
|
.dispatch()
|
||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,8 +42,3 @@ pub type Dialogue = Coprod!(
|
||||||
ReceiveAgeState,
|
ReceiveAgeState,
|
||||||
ReceiveFavouriteMusicState,
|
ReceiveFavouriteMusicState,
|
||||||
);
|
);
|
||||||
|
|
||||||
wrap_dialogue!(
|
|
||||||
Wrapper(Dialogue),
|
|
||||||
default Self(Dialogue::inject(StartState)),
|
|
||||||
);
|
|
||||||
|
|
|
@ -3,7 +3,7 @@ use teloxide::prelude::*;
|
||||||
use super::{favourite_music::FavouriteMusic, states::*};
|
use super::{favourite_music::FavouriteMusic, states::*};
|
||||||
|
|
||||||
pub type In<State> = TransitionIn<State, std::convert::Infallible>;
|
pub type In<State> = TransitionIn<State, std::convert::Infallible>;
|
||||||
pub type Out = TransitionOut<Wrapper>;
|
pub type Out = TransitionOut<Dialogue>;
|
||||||
|
|
||||||
pub async fn start(cx: In<StartState>) -> Out {
|
pub async fn start(cx: In<StartState>) -> Out {
|
||||||
let (cx, dialogue) = cx.unpack();
|
let (cx, dialogue) = cx.unpack();
|
||||||
|
|
|
@ -26,6 +26,7 @@ use std::sync::{Arc, Mutex};
|
||||||
pub struct DialogueDispatcher<D, S, H, Upd> {
|
pub struct DialogueDispatcher<D, S, H, Upd> {
|
||||||
storage: Arc<S>,
|
storage: Arc<S>,
|
||||||
handler: Arc<H>,
|
handler: Arc<H>,
|
||||||
|
default: Arc<dyn Fn() -> D + Send + Sync + 'static>,
|
||||||
_phantom: PhantomData<Mutex<D>>,
|
_phantom: PhantomData<Mutex<D>>,
|
||||||
|
|
||||||
/// A lock-free map to handle updates from the same chat sequentially, but
|
/// A lock-free map to handle updates from the same chat sequentially, but
|
||||||
|
@ -41,17 +42,22 @@ impl<D, H, Upd> DialogueDispatcher<D, InMemStorage<D>, H, Upd>
|
||||||
where
|
where
|
||||||
H: DialogueDispatcherHandler<Upd, D, Infallible> + Send + Sync + 'static,
|
H: DialogueDispatcherHandler<Upd, D, Infallible> + Send + Sync + 'static,
|
||||||
Upd: GetChatId + Send + 'static,
|
Upd: GetChatId + Send + 'static,
|
||||||
D: Default + Send + 'static,
|
D: Send + 'static,
|
||||||
{
|
{
|
||||||
/// Creates a dispatcher with the specified `handler` and [`InMemStorage`]
|
/// Creates a dispatcher with the specified `handler, [`InMemStorage`]
|
||||||
/// (a default storage).
|
/// (a default storage), and a function that returns a default dialogue,
|
||||||
|
/// used when a user initiates a new dialogue.
|
||||||
///
|
///
|
||||||
/// [`InMemStorage`]: crate::dispatching::dialogue::InMemStorage
|
/// [`InMemStorage`]: crate::dispatching::dialogue::InMemStorage
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn new(handler: H) -> Self {
|
pub fn new<F>(handler: H, default: F) -> Self
|
||||||
|
where
|
||||||
|
F: Fn() -> D + Send + Sync + 'static,
|
||||||
|
{
|
||||||
Self {
|
Self {
|
||||||
storage: InMemStorage::new(),
|
storage: InMemStorage::new(),
|
||||||
handler: Arc::new(handler),
|
handler: Arc::new(handler),
|
||||||
|
default: Arc::new(default),
|
||||||
senders: Arc::new(Map::new()),
|
senders: Arc::new(Map::new()),
|
||||||
_phantom: PhantomData,
|
_phantom: PhantomData,
|
||||||
}
|
}
|
||||||
|
@ -62,16 +68,22 @@ impl<D, S, H, Upd> DialogueDispatcher<D, S, H, Upd>
|
||||||
where
|
where
|
||||||
H: DialogueDispatcherHandler<Upd, D, S::Error> + Send + Sync + 'static,
|
H: DialogueDispatcherHandler<Upd, D, S::Error> + Send + Sync + 'static,
|
||||||
Upd: GetChatId + Send + 'static,
|
Upd: GetChatId + Send + 'static,
|
||||||
D: Default + Send + 'static,
|
D: Send + 'static,
|
||||||
S: Storage<D> + Send + Sync + 'static,
|
S: Storage<D> + Send + Sync + 'static,
|
||||||
S::Error: Send + 'static,
|
S::Error: Send + 'static,
|
||||||
{
|
{
|
||||||
/// Creates a dispatcher with the specified `handler` and `storage`.
|
/// Creates a dispatcher with the specified `handler`, `storage`, and a
|
||||||
|
/// function that returns a default dialogue, used when a user initiates a
|
||||||
|
/// new dialogue.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn with_storage(handler: H, storage: Arc<S>) -> Self {
|
pub fn with_storage<F>(handler: H, storage: Arc<S>, default: F) -> Self
|
||||||
|
where
|
||||||
|
F: Fn() -> D + Send + Sync + 'static,
|
||||||
|
{
|
||||||
Self {
|
Self {
|
||||||
storage,
|
storage,
|
||||||
handler: Arc::new(handler),
|
handler: Arc::new(handler),
|
||||||
|
default: Arc::new(default),
|
||||||
senders: Arc::new(Map::new()),
|
senders: Arc::new(Map::new()),
|
||||||
_phantom: PhantomData,
|
_phantom: PhantomData,
|
||||||
}
|
}
|
||||||
|
@ -83,11 +95,13 @@ where
|
||||||
|
|
||||||
let storage = Arc::clone(&self.storage);
|
let storage = Arc::clone(&self.storage);
|
||||||
let handler = Arc::clone(&self.handler);
|
let handler = Arc::clone(&self.handler);
|
||||||
|
let default = Arc::clone(&self.default);
|
||||||
let senders = Arc::clone(&self.senders);
|
let senders = Arc::clone(&self.senders);
|
||||||
|
|
||||||
tokio::spawn(rx.for_each(move |cx: UpdateWithCx<Upd>| {
|
tokio::spawn(rx.for_each(move |cx: UpdateWithCx<Upd>| {
|
||||||
let storage = Arc::clone(&storage);
|
let storage = Arc::clone(&storage);
|
||||||
let handler = Arc::clone(&handler);
|
let handler = Arc::clone(&handler);
|
||||||
|
let default = Arc::clone(&default);
|
||||||
let senders = Arc::clone(&senders);
|
let senders = Arc::clone(&senders);
|
||||||
|
|
||||||
async move {
|
async move {
|
||||||
|
@ -96,7 +110,7 @@ where
|
||||||
let dialogue = Arc::clone(&storage)
|
let dialogue = Arc::clone(&storage)
|
||||||
.remove_dialogue(chat_id)
|
.remove_dialogue(chat_id)
|
||||||
.await
|
.await
|
||||||
.map(Option::unwrap_or_default);
|
.map(|opt| opt.unwrap_or_else(move || default()));
|
||||||
|
|
||||||
match handler.handle(DialogueWithCx { cx, dialogue }).await {
|
match handler.handle(DialogueWithCx { cx, dialogue }).await {
|
||||||
DialogueStage::Next(new_dialogue) => {
|
DialogueStage::Next(new_dialogue) => {
|
||||||
|
@ -131,7 +145,7 @@ impl<D, S, H, Upd> DispatcherHandler<Upd> for DialogueDispatcher<D, S, H, Upd>
|
||||||
where
|
where
|
||||||
H: DialogueDispatcherHandler<Upd, D, S::Error> + Send + Sync + 'static,
|
H: DialogueDispatcherHandler<Upd, D, S::Error> + Send + Sync + 'static,
|
||||||
Upd: GetChatId + Send + 'static,
|
Upd: GetChatId + Send + 'static,
|
||||||
D: Default + Send + 'static,
|
D: Send + 'static,
|
||||||
S: Storage<D> + Send + Sync + 'static,
|
S: Storage<D> + Send + Sync + 'static,
|
||||||
S::Error: Send + 'static,
|
S::Error: Send + 'static,
|
||||||
{
|
{
|
||||||
|
@ -189,7 +203,7 @@ mod tests {
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn updates_from_same_chat_executed_sequentially() {
|
async fn updates_from_same_chat_executed_sequentially() {
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Default)]
|
||||||
struct MyUpdate {
|
struct MyUpdate {
|
||||||
chat_id: i64,
|
chat_id: i64,
|
||||||
unique_number: u32,
|
unique_number: u32,
|
||||||
|
@ -232,6 +246,7 @@ mod tests {
|
||||||
|
|
||||||
DialogueStage::Next(())
|
DialogueStage::Next(())
|
||||||
},
|
},
|
||||||
|
|| (),
|
||||||
);
|
);
|
||||||
|
|
||||||
let updates = stream::iter(
|
let updates = stream::iter(
|
||||||
|
|
|
@ -11,29 +11,21 @@ pub enum DialogueStage<D> {
|
||||||
Exit,
|
Exit,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A dialogue wrapper to bypass orphan rules.
|
|
||||||
pub trait DialogueWrapper<D> {
|
|
||||||
fn new(dialogue: D) -> Self;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns a new dialogue state.
|
/// Returns a new dialogue state.
|
||||||
///
|
///
|
||||||
/// See [the module-level documentation for the design
|
/// See [the module-level documentation for the design
|
||||||
/// overview](crate::dispatching::dialogue).
|
/// overview](crate::dispatching::dialogue).
|
||||||
pub fn next<Dialogue, State, Index, DWrapper>(
|
pub fn next<Dialogue, State, Index>(new_state: State) -> TransitionOut<Dialogue>
|
||||||
new_state: State,
|
|
||||||
) -> TransitionOut<DWrapper>
|
|
||||||
where
|
where
|
||||||
Dialogue: CoprodInjector<State, Index>,
|
Dialogue: CoprodInjector<State, Index>,
|
||||||
DWrapper: DialogueWrapper<Dialogue>,
|
|
||||||
{
|
{
|
||||||
Ok(DialogueStage::Next(DWrapper::new(Dialogue::inject(new_state))))
|
Ok(DialogueStage::Next(Dialogue::inject(new_state)))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Exits a dialogue.
|
/// Exits a dialogue.
|
||||||
///
|
///
|
||||||
/// See [the module-level documentation for the design
|
/// See [the module-level documentation for the design
|
||||||
/// overview](crate::dispatching::dialogue).
|
/// overview](crate::dispatching::dialogue).
|
||||||
pub fn exit<DWrapper>() -> TransitionOut<DWrapper> {
|
pub fn exit<D>() -> TransitionOut<D> {
|
||||||
Ok(DialogueStage::Exit)
|
Ok(DialogueStage::Exit)
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,7 +52,7 @@ mod storage;
|
||||||
use crate::{requests::ResponseResult, types::Message};
|
use crate::{requests::ResponseResult, types::Message};
|
||||||
pub use dialogue_dispatcher::DialogueDispatcher;
|
pub use dialogue_dispatcher::DialogueDispatcher;
|
||||||
pub use dialogue_dispatcher_handler::DialogueDispatcherHandler;
|
pub use dialogue_dispatcher_handler::DialogueDispatcherHandler;
|
||||||
pub use dialogue_stage::{exit, next, DialogueStage, DialogueWrapper};
|
pub use dialogue_stage::{exit, next, DialogueStage};
|
||||||
pub use dialogue_with_cx::DialogueWithCx;
|
pub use dialogue_with_cx::DialogueWithCx;
|
||||||
pub use get_chat_id::GetChatId;
|
pub use get_chat_id::GetChatId;
|
||||||
|
|
||||||
|
@ -79,13 +79,8 @@ pub use storage::{InMemStorage, Storage};
|
||||||
/// ReceiveNumberState,
|
/// ReceiveNumberState,
|
||||||
/// );
|
/// );
|
||||||
///
|
///
|
||||||
/// wrap_dialogue!(
|
|
||||||
/// Wrapper(Dialogue),
|
|
||||||
/// default Self(Dialogue::inject(StartState)),
|
|
||||||
/// );
|
|
||||||
///
|
|
||||||
/// pub type In<State> = TransitionIn<State, std::convert::Infallible>;
|
/// pub type In<State> = TransitionIn<State, std::convert::Infallible>;
|
||||||
/// pub type Out = TransitionOut<Wrapper>;
|
/// pub type Out = TransitionOut<Dialogue>;
|
||||||
///
|
///
|
||||||
/// pub async fn start(cx: In<StartState>) -> Out { todo!() }
|
/// pub async fn start(cx: In<StartState>) -> Out { todo!() }
|
||||||
/// pub async fn receive_word(cx: In<ReceiveWordState>) -> Out { todo!() }
|
/// pub async fn receive_word(cx: In<ReceiveWordState>) -> Out { todo!() }
|
||||||
|
@ -126,59 +121,6 @@ macro_rules! dispatch {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generates a dialogue wrapper and implements `Default` for it.
|
|
||||||
///
|
|
||||||
/// The reason is to bypass orphan rules to be able to pass a user-defined
|
|
||||||
/// dialogue into [`DialogueDispatcher`]. Since a dialogue is
|
|
||||||
/// [`frunk::Coproduct`], we cannot directly satisfy the `D: Default`
|
|
||||||
/// constraint.
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
/// ```
|
|
||||||
/// use teloxide::prelude::*;
|
|
||||||
///
|
|
||||||
/// struct StartState;
|
|
||||||
/// struct ReceiveWordState;
|
|
||||||
/// struct ReceiveNumberState;
|
|
||||||
/// struct ExitState;
|
|
||||||
///
|
|
||||||
/// type Dialogue = Coprod!(
|
|
||||||
/// StartState,
|
|
||||||
/// ReceiveWordState,
|
|
||||||
/// ReceiveNumberState,
|
|
||||||
/// );
|
|
||||||
///
|
|
||||||
/// wrap_dialogue!(
|
|
||||||
/// Wrapper(Dialogue),
|
|
||||||
/// default Self(Dialogue::inject(StartState)),
|
|
||||||
/// );
|
|
||||||
///
|
|
||||||
/// let start_state = Wrapper::default();
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// [`DialogueDispatcher`]: crate::dispatching::dialogue::DialogueDispatcher
|
|
||||||
/// [`frunk::Coproduct`]: https://docs.rs/frunk/0.3.1/frunk/coproduct/enum.Coproduct.html
|
|
||||||
#[macro_export]
|
|
||||||
macro_rules! wrap_dialogue {
|
|
||||||
($name:ident($dialogue:ident), default $default_block:expr, ) => {
|
|
||||||
pub struct $name(pub $dialogue);
|
|
||||||
|
|
||||||
impl teloxide::dispatching::dialogue::DialogueWrapper<$dialogue>
|
|
||||||
for $name
|
|
||||||
{
|
|
||||||
fn new(d: $dialogue) -> Wrapper {
|
|
||||||
$name(d)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for $name {
|
|
||||||
fn default() -> $name {
|
|
||||||
$default_block
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Generates `.up(field)` methods for dialogue states.
|
/// Generates `.up(field)` methods for dialogue states.
|
||||||
///
|
///
|
||||||
/// Given inductively defined states, this macro generates `.up(field)` methods
|
/// Given inductively defined states, this macro generates `.up(field)` methods
|
||||||
|
@ -232,4 +174,4 @@ macro_rules! up {
|
||||||
pub type TransitionIn<State, E> = DialogueWithCx<Message, State, E>;
|
pub type TransitionIn<State, E> = DialogueWithCx<Message, State, E>;
|
||||||
|
|
||||||
// A type returned from a FSM transition function.
|
// A type returned from a FSM transition function.
|
||||||
pub type TransitionOut<DWrapper> = ResponseResult<DialogueStage<DWrapper>>;
|
pub type TransitionOut<D> = ResponseResult<DialogueStage<D>>;
|
||||||
|
|
|
@ -5,14 +5,14 @@ pub use crate::{
|
||||||
dispatching::{
|
dispatching::{
|
||||||
dialogue::{
|
dialogue::{
|
||||||
exit, next, DialogueDispatcher, DialogueStage, DialogueWithCx,
|
exit, next, DialogueDispatcher, DialogueStage, DialogueWithCx,
|
||||||
DialogueWrapper, GetChatId, TransitionIn, TransitionOut,
|
GetChatId, TransitionIn, TransitionOut,
|
||||||
},
|
},
|
||||||
Dispatcher, DispatcherHandlerRx, DispatcherHandlerRxExt, UpdateWithCx,
|
Dispatcher, DispatcherHandlerRx, DispatcherHandlerRxExt, UpdateWithCx,
|
||||||
},
|
},
|
||||||
error_handlers::{LoggingErrorHandler, OnError},
|
error_handlers::{LoggingErrorHandler, OnError},
|
||||||
requests::{Request, ResponseResult},
|
requests::{Request, ResponseResult},
|
||||||
types::{Message, Update},
|
types::{Message, Update},
|
||||||
up, wrap_dialogue, Bot, RequestError,
|
up, Bot, RequestError,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub use frunk::{Coprod, Coproduct};
|
pub use frunk::{Coprod, Coproduct};
|
||||||
|
|
Loading…
Reference in a new issue