From b58f731ef3d7b70bae4ba439fe7190866c5d3e8a Mon Sep 17 00:00:00 2001 From: Hirrolot Date: Fri, 7 Oct 2022 22:50:08 +0600 Subject: [PATCH 01/21] Simplify the brief description of `crate::stop` Usually, we have very brief descriptions of modules. I see no reason to make it elaborate -- it does even contain only a few items. Former-commit-id: a7981cc99b362f0769b3dd9f70aa45231f708537 --- src/stop.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/stop.rs b/src/stop.rs index f61caf3d..71fcebe9 100644 --- a/src/stop.rs +++ b/src/stop.rs @@ -1,8 +1,5 @@ -//! This module contains stop [token] and stop [flag] that are used to stop -//! async tasks, for example [listeners]. +//! Stopping asynchronous tasks, e.g., [listeners]. //! -//! [token]: StopToken -//! [flag]: StopFlag //! [listeners]: crate::dispatching::update_listeners use std::{convert::Infallible, future::Future, pin::Pin, task}; From fdaddb390266e7537bf0e8cfb635109cf7c4eff9 Mon Sep 17 00:00:00 2001 From: Lev Khoroshansky Date: Sun, 9 Oct 2022 19:41:52 +0300 Subject: [PATCH 02/21] fix: Sync docs & comments with code Former-commit-id: 6ebf51efeb068b0291922be16bc6bc7d0fadc9c4 --- examples/admin.rs | 4 ++-- src/utils/command.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/admin.rs b/examples/admin.rs index 4be9a543..fbbc1615 100644 --- a/examples/admin.rs +++ b/examples/admin.rs @@ -5,8 +5,8 @@ use teloxide::{prelude::*, types::ChatPermissions, utils::command::BotCommands}; // Derive BotCommands to parse text with a command into this enumeration. // -// 1. rename = "lowercase" turns all the commands into lowercase letters. -// 2. `description = "..."` specifies a text before all the commands. +// 1. `rename_rule = "lowercase"` turns all the commands into lowercase +// letters. 2. `description = "..."` specifies a text before all the commands. // // That is, you can just call Command::descriptions() to get a description of // your commands in this format: diff --git a/src/utils/command.rs b/src/utils/command.rs index 24e001cf..2d16f23b 100644 --- a/src/utils/command.rs +++ b/src/utils/command.rs @@ -233,7 +233,7 @@ pub trait BotCommands: Sized { /// Returns `PhantomData` that is used as a param of [`commands_repl`] /// - /// [`commands_repl`]: (crate::repls2::commands_repl) + /// [`commands_repl`]: (crate::repls::commands_repl) #[must_use] fn ty() -> PhantomData { PhantomData From a5419f3475d4c26f3e87585977cd96c03d7643da Mon Sep 17 00:00:00 2001 From: Lev Khoroshansky Date: Sun, 9 Oct 2022 19:42:20 +0300 Subject: [PATCH 03/21] fix: Grammar & typos Former-commit-id: b3fe220d9929c55840411d68e6db42a4e76e1618 --- CHANGELOG.md | 8 ++++---- MIGRATION_GUIDE.md | 6 +++--- README.md | 6 +++--- examples/db_remember.rs | 2 +- examples/dispatching_features.rs | 2 +- examples/heroku_ping_pong.rs | 2 +- src/dispatching/update_listeners/polling.rs | 2 +- src/utils/command.rs | 12 ++++++------ src/utils/html.rs | 4 ++-- src/utils/markdown.rs | 2 +- 10 files changed, 23 insertions(+), 23 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4ea743ff..795ed08c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -75,7 +75,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed -- Fix Api Unknown error (Can't parse entities) on message created with `utils::markdown::user_mention_or_link` if user full name contaiins some escapable symbols eg '.' +- Fix Api Unknown error (Can't parse entities) on message created with `utils::markdown::user_mention_or_link` if user full name contains some escapable symbols eg '.' ## 0.9.1 - 2022-05-27 @@ -188,7 +188,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - `BotCommand::bot_commands` to obtain Telegram API commands ([issue 262](https://github.com/teloxide/teloxide/issues/262)). -- The `dispatching2` and `prelude2` modules. They presents a new dispatching model based on `dptree`. +- The `dispatching2` and `prelude2` modules. They present a new dispatching model based on `dptree`. ### Changed @@ -265,7 +265,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed - Remove the `reqwest` dependency. It's not needed after the [teloxide-core] integration. -- A storage persistency bug ([issue 304](https://github.com/teloxide/teloxide/issues/304)). +- A storage persistence bug ([issue 304](https://github.com/teloxide/teloxide/issues/304)). - Log errors from `Storage::{remove_dialogue, update_dialogue}` in `DialogueDispatcher` ([issue 302](https://github.com/teloxide/teloxide/issues/302)). - Mark all the functions of `Storage` as `#[must_use]`. @@ -371,7 +371,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed -- Now methods which can send file to Telegram returns `tokio::io::Result`. Early its could panic ([issue 216](https://github.com/teloxide/teloxide/issues/216)). +- Now methods which can send file to Telegram returns `tokio::io::Result`. Early it could panic ([issue 216](https://github.com/teloxide/teloxide/issues/216)). - If a bot wasn't triggered for several days, it stops responding ([issue 223](https://github.com/teloxide/teloxide/issues/223)). ## 0.2.0 - 2020-02-25 diff --git a/MIGRATION_GUIDE.md b/MIGRATION_GUIDE.md index 83ea0829..1449cca1 100644 --- a/MIGRATION_GUIDE.md +++ b/MIGRATION_GUIDE.md @@ -193,7 +193,7 @@ In order to make `Dispatcher` implement `Send`, `DispatcherBuilder::{default_han v0.6 of teloxide introduces a new dispatching model based on the [chain of responsibility pattern]. To use it, you need to replace `prelude` with `prelude2` and `dispatching` with `dispatching2`. Instead of using old REPLs, you should now use `teloxide::repls2`. -The whole design is different than the previous one based on Tokio streams. In this section, we are only to address the most common usage scenarios. +The whole design is different from the previous one based on Tokio streams. In this section, we are only to address the most common usage scenarios. First of all, now there are no streams. Instead of using streams, you use [`dptree`], which is a more suitable alternative for our purposes. Thus, if you previously used `Dispatcher::messages_handler`, now you should use `Update::filter_message()`, and so on. @@ -237,7 +237,7 @@ List of changed types: In teloxide `v0.4` (core `v0.2`) some API methods had wrong return types. This made them practically unusable as they've always returned parsing error. -On the offchance you were using the methods, you may need to adjust types in your code. +On the off-chance you were using the methods, you may need to adjust types in your code. List of changed return types: - `get_chat_administrators`: `ChatMember` -> `Vec` @@ -324,7 +324,7 @@ List of renamed items: #### Added `impl Clone` for {`CacheMe`, `DefaultParseMode`, `Throttle`} Previously said bot adaptors were lacking `Clone` implementation. -To workaround this issue it was proposed to wrap bot in `Arc`. +To work around this issue it was proposed to wrap bot in `Arc`. Now it's not required, so you can remove the `Arc`: ```diff diff --git a/README.md b/README.md index 2fb0010a..795a4006 100644 --- a/README.md +++ b/README.md @@ -58,7 +58,7 @@ $ set TELOXIDE_TOKEN= $ $env:TELOXIDE_TOKEN= ``` - 4. Make sure that your Rust compiler is up to date (`teloxide` currently requires rustc at least version 1.64): + 4. Make sure that your Rust compiler is up-to-date (`teloxide` currently requires rustc at least version 1.64): ```bash # If you're using stable $ rustup update stable @@ -82,7 +82,7 @@ tokio = { version = "1.8", features = ["rt-multi-thread", "macros"] } ### The dices bot -This bot replies with a dice throw to each received message: +This bot replies with a die throw to each received message: [[`examples/throw_dice.rs`](examples/throw_dice.rs)] @@ -326,7 +326,7 @@ Feel free to propose your own bot to our collection! - [`modos189/tg_blackbox_bot`](https://gitlab.com/modos189/tg_blackbox_bot) — Anonymous feedback for your Telegram project. - [`0xNima/spacecraft`](https://github.com/0xNima/spacecraft) — Yet another telegram bot to downloading Twitter spaces. - [`0xNima/Twideo`](https://github.com/0xNima/Twideo) — Simple Telegram Bot for downloading videos from Twitter via their links. - - [`mattrighetti/libgen-bot-rs`](https://github.com/mattrighetti/libgen-bot-rs) — Telgram bot to interface with libgen. + - [`mattrighetti/libgen-bot-rs`](https://github.com/mattrighetti/libgen-bot-rs) — Telegram bot to interface with libgen. - [`zamazan4ik/npaperbot-telegram`](https://github.com/zamazan4ik/npaperbot-telegram) — Telegram bot for searching via C++ proposals.
diff --git a/examples/db_remember.rs b/examples/db_remember.rs index de09db0d..980d1357 100644 --- a/examples/db_remember.rs +++ b/examples/db_remember.rs @@ -91,7 +91,7 @@ async fn got_number( } Command::Reset => { dialogue.reset().await?; - bot.send_message(msg.chat.id, "Number resetted.").await?; + bot.send_message(msg.chat.id, "Number reset.").await?; } } Ok(()) diff --git a/examples/dispatching_features.rs b/examples/dispatching_features.rs index 983f0002..6ce059d9 100644 --- a/examples/dispatching_features.rs +++ b/examples/dispatching_features.rs @@ -32,7 +32,7 @@ async fn main() { .endpoint(simple_commands_handler), ) .branch( - // Filter a maintainer by a used ID. + // Filter a maintainer by a user ID. dptree::filter(|cfg: ConfigParameters, msg: Message| { msg.from().map(|user| user.id == cfg.bot_maintainer).unwrap_or_default() }) diff --git a/examples/heroku_ping_pong.rs b/examples/heroku_ping_pong.rs index 6fe50847..59767047 100644 --- a/examples/heroku_ping_pong.rs +++ b/examples/heroku_ping_pong.rs @@ -10,7 +10,7 @@ // heroku create --buildpack emk/rust // ``` // -// To set buildpack for existing applicaton: +// To set buildpack for existing application: // // ``` // heroku buildpacks:set emk/rust diff --git a/src/dispatching/update_listeners/polling.rs b/src/dispatching/update_listeners/polling.rs index 5fb863f0..ffe8aa5a 100644 --- a/src/dispatching/update_listeners/polling.rs +++ b/src/dispatching/update_listeners/polling.rs @@ -225,7 +225,7 @@ where /// /// C->>P: next /// -/// P->>T: *Acknolegment of update(5)* +/// P->>T: *Acknowledgement of update(5)* /// T->>P: ok /// /// P->>C: None diff --git a/src/utils/command.rs b/src/utils/command.rs index 2d16f23b..785479d7 100644 --- a/src/utils/command.rs +++ b/src/utils/command.rs @@ -91,7 +91,7 @@ pub use teloxide_macros::BotCommands; /// Change a prefix for all commands (the default is `/`). /// /// 3. `#[command(description = "description")]` -/// Add a sumary description of commands before all commands. +/// Add a summary description of commands before all commands. /// /// 4. `#[command(parse_with = "parser")]` /// Change the parser of arguments. Possible values: @@ -115,7 +115,7 @@ pub use teloxide_macros::BotCommands; /// # } /// ``` /// -/// - `split` - separates a messsage by a given separator (the default is the +/// - `split` - separates a message by a given separator (the default is the /// space character) and parses each part into the corresponding arguments, /// which must implement [`FromStr`]. /// @@ -412,9 +412,9 @@ where return None; } let mut words = text.split_whitespace(); - let mut splited = words.next()?[prefix.len()..].split('@'); - let command = splited.next()?; - let bot = splited.next(); + let mut split = words.next()?[prefix.len()..].split('@'); + let command = split.next()?; + let bot = split.next(); match bot { Some(name) if name.eq_ignore_ascii_case(bot_name.as_ref()) => {} None => {} @@ -485,7 +485,7 @@ impl Display for CommandDescriptions<'_> { } } -// The rest of tests are integrational due to problems with macro expansion in +// The rest of tests are integration due to problems with macro expansion in // unit tests. #[cfg(test)] mod tests { diff --git a/src/utils/html.rs b/src/utils/html.rs index 407f0792..d2243d5d 100644 --- a/src/utils/html.rs +++ b/src/utils/html.rs @@ -95,7 +95,7 @@ pub fn code_inline(s: &str) -> String { /// style. /// /// Does not escape ' and " characters (as should be for usual HTML), because -/// they shoudn't be escaped by the [spec]. +/// they shouldn't be escaped by the [spec]. /// /// [spec]: https://core.telegram.org/bots/api#html-style #[must_use = "This function returns a new string, rather than mutating the argument, so calling it \ @@ -176,7 +176,7 @@ mod tests { assert_eq!( code_block_with_lang( "

pre-'formatted'\n & fixed-width \\code `block`

", - "\"" + "\"", ), concat!( "
",
diff --git a/src/utils/markdown.rs b/src/utils/markdown.rs
index 9c355444..976e0ab4 100644
--- a/src/utils/markdown.rs
+++ b/src/utils/markdown.rs
@@ -38,7 +38,7 @@ pub fn italic(s: &str) -> String {
               without using its output does nothing useful"]
 pub fn underline(s: &str) -> String {
     // In case of ambiguity between italic and underline entities
-    // ‘__’ is always greadily treated from left to right as beginning or end of
+    // ‘__’ is always greedily treated from left to right as beginning or end of
     // underline entity, so instead of ___italic underline___ we should use
     // ___italic underline_\r__, where \r is a character with code 13, which
     // will be ignored.

From 98150c401a32fd6cf88ec870e553bd313ad3ce28 Mon Sep 17 00:00:00 2001
From: Lev Khoroshansky 
Date: Sun, 9 Oct 2022 19:47:45 +0300
Subject: [PATCH 04/21] fix: Spacing

Former-commit-id: a9739c7da4f5629a120409daa6d3f468686d7224
---
 examples/admin.rs | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/examples/admin.rs b/examples/admin.rs
index fbbc1615..17f7373f 100644
--- a/examples/admin.rs
+++ b/examples/admin.rs
@@ -5,8 +5,8 @@ use teloxide::{prelude::*, types::ChatPermissions, utils::command::BotCommands};
 
 // Derive BotCommands to parse text with a command into this enumeration.
 //
-//  1. `rename_rule = "lowercase"` turns all the commands into lowercase
-// letters.  2. `description = "..."` specifies a text before all the commands.
+// 1. `rename_rule = "lowercase"` turns all the commands into lowercase letters.
+// 2. `description = "..."` specifies a text before all the commands.
 //
 // That is, you can just call Command::descriptions() to get a description of
 // your commands in this format:

From a57ff6056d00c3479dc87d9e6f8b39d53dc19387 Mon Sep 17 00:00:00 2001
From: Lev Khoroshansky 
Date: Sun, 9 Oct 2022 19:49:42 +0300
Subject: [PATCH 05/21] fix: Plural verb and better wording

Former-commit-id: 643ef423e87aa4f22f7b81d22c0fc8f6e83e3e13
---
 CHANGELOG.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 795ed08c..7687aa9b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -371,7 +371,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 
 ### Fixed
 
-- Now methods which can send file to Telegram returns `tokio::io::Result`. Early it could panic ([issue 216](https://github.com/teloxide/teloxide/issues/216)).
+- Now methods which can send file to Telegram return `tokio::io::Result`. Before that it could panic ([issue 216](https://github.com/teloxide/teloxide/issues/216)).
 - If a bot wasn't triggered for several days, it stops responding ([issue 223](https://github.com/teloxide/teloxide/issues/223)).
 
 ## 0.2.0 - 2020-02-25

From 5fb01ee8d53b8791b25c1cbe9f4f112ff2160a10 Mon Sep 17 00:00:00 2001
From: Lev Khoroshansky 
Date: Sun, 9 Oct 2022 19:59:52 +0300
Subject: [PATCH 06/21] fix: No need for hyphens

Former-commit-id: aec777d89994acfe1f42b1568f5617bd90f135e7
---
 README.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/README.md b/README.md
index 795a4006..d25c150f 100644
--- a/README.md
+++ b/README.md
@@ -58,7 +58,7 @@ $ set TELOXIDE_TOKEN=
 $ $env:TELOXIDE_TOKEN=
 ```
 
- 4. Make sure that your Rust compiler is up-to-date (`teloxide` currently requires rustc at least version 1.64):
+ 4. Make sure that your Rust compiler is up to date (`teloxide` currently requires rustc at least version 1.64):
 ```bash
 # If you're using stable
 $ rustup update stable

From f54db300ed4b5136636ba1e00350f46bca9e5499 Mon Sep 17 00:00:00 2001
From: Hirrolot 
Date: Tue, 11 Oct 2022 14:54:51 +0600
Subject: [PATCH 07/21] Implement the `CommandRepl` trait

Former-commit-id: 739772929bd7e13f42f12e9afa02fef450ec0222
---
 CHANGELOG.md                           |   8 ++
 MIGRATION_GUIDE.md                     |  16 +++
 examples/admin.rs                      |   2 +-
 examples/command.rs                    |   2 +-
 src/dispatching/repls.rs               |   2 +
 src/dispatching/repls/commands_repl.rs | 140 +++++++++++++++++++++++++
 src/lib.rs                             |   7 +-
 src/prelude.rs                         |   3 +-
 8 files changed, 174 insertions(+), 6 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 7687aa9b..b9b891ec 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,6 +6,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 
 ## unreleased
 
+### Added
+
+ - `teloxide::dispatching::repls::CommandRepl`, `teloxide::prelude::CommandRepl` ([issue #740](https://github.com/teloxide/teloxide/issues/740))
+
+### Deprecated
+
+ - `teloxide::dispatching::repls::{commands_repl, commands_repl_with_listener}` (use `CommandRepl` instead)
+
 ## 0.11.0 - 2022-10-07
 
 ### Changed
diff --git a/MIGRATION_GUIDE.md b/MIGRATION_GUIDE.md
index 1449cca1..937320a7 100644
--- a/MIGRATION_GUIDE.md
+++ b/MIGRATION_GUIDE.md
@@ -1,6 +1,22 @@
 This document describes breaking changes of `teloxide` crate, as well as the ways to update code.
 Note that the list of required changes is not fully exhaustive and it may lack something in rare cases.
 
+## 0.10 -> 0.xxx.xxx
+
+### teloxide
+
+We have introduced the new trait `CommandRepl` that replaces the old `commands_repl_(with_listener)` functions:
+
+```diff,rust
+- teloxide::commands_repl(bot, answer, Command::ty())
++ Command::repl(bot, answer)
+```
+
+```diff,rust
+- teloxide::commands_repl_with_listener(bot, answer, listener, Command::ty())
++ Command::repl_with_listener(bot, answer, listener)
+```
+
 ## 0.10 -> 0.11
 
 ### core
diff --git a/examples/admin.rs b/examples/admin.rs
index 17f7373f..113d6f07 100644
--- a/examples/admin.rs
+++ b/examples/admin.rs
@@ -60,7 +60,7 @@ async fn main() {
 
     let bot = teloxide::Bot::from_env();
 
-    teloxide::commands_repl(bot, action, Command::ty()).await;
+    Command::repl(bot, action).await;
 }
 
 async fn action(bot: Bot, msg: Message, cmd: Command) -> ResponseResult<()> {
diff --git a/examples/command.rs b/examples/command.rs
index 00f44315..26848015 100644
--- a/examples/command.rs
+++ b/examples/command.rs
@@ -7,7 +7,7 @@ async fn main() {
 
     let bot = Bot::from_env();
 
-    teloxide::commands_repl(bot, answer, Command::ty()).await;
+    Command::repl(bot, answer).await;
 }
 
 #[derive(BotCommands, Clone)]
diff --git a/src/dispatching/repls.rs b/src/dispatching/repls.rs
index 71d70343..e8e6c4ac 100644
--- a/src/dispatching/repls.rs
+++ b/src/dispatching/repls.rs
@@ -11,5 +11,7 @@
 mod commands_repl;
 mod repl;
 
+pub use commands_repl::CommandRepl;
+#[allow(deprecated)]
 pub use commands_repl::{commands_repl, commands_repl_with_listener};
 pub use repl::{repl, repl_with_listener};
diff --git a/src/dispatching/repls/commands_repl.rs b/src/dispatching/repls/commands_repl.rs
index fe9d9fb7..0c237044 100644
--- a/src/dispatching/repls/commands_repl.rs
+++ b/src/dispatching/repls/commands_repl.rs
@@ -8,8 +8,145 @@ use crate::{
     utils::command::BotCommands,
 };
 use dptree::di::{DependencyMap, Injectable};
+use futures::future::BoxFuture;
 use std::{fmt::Debug, marker::PhantomData};
 
+/// A [REPL] for commands.
+///
+/// REPLs are meant only for simple bots and rapid prototyping. If you need to
+/// supply dependencies or describe more complex dispatch logic, please use
+/// [`Dispatcher`]. See also: ["Dispatching or
+/// REPLs?"](../index.html#dispatching-or-repls).
+///
+/// [`Dispatcher`]: crate::dispatching::Dispatcher
+///
+/// All errors from the handler and update listener will be logged.
+///
+/// [REPL]: https://en.wikipedia.org/wiki/Read-eval-print_loop
+///
+/// This trait extends your [`BotCommands`] type with REPL facilities.
+///
+/// ## Signatures
+///
+/// Don't be scared by many trait bounds in the signatures, in essence they
+/// require:
+///
+/// 1. `bot` is a bot, client for the Telegram bot API. It is represented via
+///    the [`Requester`] trait.
+/// 2. `handler` is an `async` function that takes arguments from
+///    [`DependencyMap`] (see below) and returns [`ResponseResult`].
+/// 3. `listener` is something that takes updates from a Telegram server and
+///    implements [`UpdateListener`].
+///
+/// All the other requirements are about thread safety and data validity and can
+/// be ignored for most of the time.
+///
+/// ## Handler arguments
+///
+/// `teloxide` provides the following types to the `handler`:
+/// - [`Message`]
+/// - `R` (type of the `bot`)
+/// - `Cmd` (type of the parsed command)
+/// - [`Me`]
+///
+/// Each of these types can be accepted as a handler parameter. Note that they
+/// aren't all required at the same time: e.g., you can take only the bot and
+/// the command without [`Me`] and [`Message`].
+///
+/// [`Me`]: crate::types::Me
+/// [`Message`]: crate::types::Message
+///
+/// ## Stopping
+//
+#[doc = include_str!("stopping.md")]
+///
+/// ## Caution
+//
+#[doc = include_str!("caution.md")]
+///
+#[cfg(feature = "ctrlc_handler")]
+pub trait CommandRepl {
+    /// A REPL for commands.
+    ///
+    /// See [`CommandRepl`] for more details.
+    fn repl<'a, R, H, Args>(bot: R, handler: H) -> BoxFuture<'a, ()>
+    where
+        R: Requester + Clone + Send + Sync + 'static,
+        ::GetUpdates: Send,
+        ::GetWebhookInfo: Send,
+        ::GetMe: Send,
+        ::DeleteWebhook: Send,
+        H: Injectable, Args> + Send + Sync + 'static;
+
+    /// A REPL for commands with a custom [`UpdateListener`].
+    ///
+    /// See [`CommandRepl`] for more details.
+    fn repl_with_listener<'a, R, H, L, Args>(bot: R, handler: H, listener: L) -> BoxFuture<'a, ()>
+    where
+        H: Injectable, Args> + Send + Sync + 'static,
+        L: UpdateListener + Send + 'a,
+        L::Err: Debug + Send + 'a,
+        R: Requester + Clone + Send + Sync + 'static,
+        ::GetMe: Send;
+}
+
+#[cfg(feature = "ctrlc_handler")]
+impl CommandRepl for Cmd
+where
+    Cmd: BotCommands + Send + Sync + 'static,
+{
+    fn repl<'a, R, H, Args>(bot: R, handler: H) -> BoxFuture<'a, ()>
+    where
+        R: Requester + Clone + Send + Sync + 'static,
+        ::GetUpdates: Send,
+        ::GetWebhookInfo: Send,
+        ::GetMe: Send,
+        ::DeleteWebhook: Send,
+        H: Injectable, Args> + Send + Sync + 'static,
+    {
+        let cloned_bot = bot.clone();
+
+        Box::pin(async move {
+            Self::repl_with_listener(
+                bot,
+                handler,
+                update_listeners::polling_default(cloned_bot).await,
+            )
+            .await
+        })
+    }
+
+    fn repl_with_listener<'a, R, H, L, Args>(bot: R, handler: H, listener: L) -> BoxFuture<'a, ()>
+    where
+        H: Injectable, Args> + Send + Sync + 'static,
+        L: UpdateListener + Send + 'a,
+        L::Err: Debug + Send + 'a,
+        R: Requester + Clone + Send + Sync + 'static,
+        ::GetMe: Send,
+    {
+        use crate::dispatching::Dispatcher;
+
+        // Other update types are of no interest to use since this REPL is only for
+        // commands. See .
+        let ignore_update = |_upd| Box::pin(async {});
+
+        Box::pin(async move {
+            Dispatcher::builder(
+                bot,
+                Update::filter_message().filter_command::().endpoint(handler),
+            )
+            .default_handler(ignore_update)
+            .enable_ctrlc_handler()
+            .build()
+            .dispatch_with_listener(
+                listener,
+                LoggingErrorHandler::with_custom_text("An error from the update listener"),
+            )
+            .await
+        })
+    }
+}
+
 /// A [REPL] for commands.
 //
 ///
@@ -59,6 +196,7 @@ use std::{fmt::Debug, marker::PhantomData};
 #[doc = include_str!("caution.md")]
 ///
 #[cfg(feature = "ctrlc_handler")]
+#[deprecated(note = "Use `CommandsRepl::repl` instead")]
 pub async fn commands_repl<'a, R, Cmd, H, Args>(bot: R, handler: H, cmd: PhantomData)
 where
     R: Requester + Clone + Send + Sync + 'static,
@@ -68,6 +206,7 @@ where
 {
     let cloned_bot = bot.clone();
 
+    #[allow(deprecated)]
     commands_repl_with_listener(
         bot,
         handler,
@@ -127,6 +266,7 @@ where
 #[doc = include_str!("caution.md")]
 ///
 #[cfg(feature = "ctrlc_handler")]
+#[deprecated(note = "Use `CommandsRepl::repl_with_listener` instead")]
 pub async fn commands_repl_with_listener<'a, R, Cmd, H, L, Args>(
     bot: R,
     handler: H,
diff --git a/src/lib.rs b/src/lib.rs
index 80237a9d..04012a60 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -58,9 +58,10 @@
 #![allow(clippy::nonstandard_macro_braces)]
 
 #[cfg(feature = "ctrlc_handler")]
-pub use dispatching::repls::{
-    commands_repl, commands_repl_with_listener, repl, repl_with_listener,
-};
+pub use dispatching::repls::{repl, repl_with_listener};
+
+#[allow(deprecated)]
+pub use dispatching::repls::{commands_repl, commands_repl_with_listener};
 
 pub mod dispatching;
 pub mod error_handlers;
diff --git a/src/prelude.rs b/src/prelude.rs
index 6dbe94df..499eaea7 100644
--- a/src/prelude.rs
+++ b/src/prelude.rs
@@ -6,7 +6,8 @@ pub use crate::error_handlers::{LoggingErrorHandler, OnError};
 pub use crate::respond;
 
 pub use crate::dispatching::{
-    dialogue::Dialogue, Dispatcher, HandlerExt as _, MessageFilterExt as _, UpdateFilterExt as _,
+    dialogue::Dialogue, repls::CommandRepl as _, Dispatcher, HandlerExt as _,
+    MessageFilterExt as _, UpdateFilterExt as _,
 };
 
 pub use teloxide_core::{

From 5ed01a91d4164133781e79debbcb4bc80e476020 Mon Sep 17 00:00:00 2001
From: Hirrolot 
Date: Tue, 11 Oct 2022 14:57:40 +0600
Subject: [PATCH 08/21] Use `Command::repl` in `README.md`

Former-commit-id: db30e9efbe6333ad836fc3cb78916fa69caf6d00
---
 README.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/README.md b/README.md
index d25c150f..2b6594e4 100644
--- a/README.md
+++ b/README.md
@@ -131,7 +131,7 @@ async fn main() {
 
     let bot = Bot::from_env();
 
-    teloxide::commands_repl(bot, answer, Command::ty()).await;
+    Command::repl(bot, answer).await;
 }
 
 #[derive(BotCommands, Clone)]

From e39a9d007afa1ad1f008bfccc3876e3a5836404f Mon Sep 17 00:00:00 2001
From: Hirrolot 
Date: Tue, 11 Oct 2022 15:00:02 +0600
Subject: [PATCH 09/21] Deprecate `BotCommands::ty` too

Former-commit-id: d90a9ff2e466db4fdcdaa8a6b62ab86e6f9e76af
---
 CHANGELOG.md         | 2 +-
 src/utils/command.rs | 1 +
 2 files changed, 2 insertions(+), 1 deletion(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index b9b891ec..513e536d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -12,7 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 
 ### Deprecated
 
- - `teloxide::dispatching::repls::{commands_repl, commands_repl_with_listener}` (use `CommandRepl` instead)
+ - `teloxide::dispatching::repls::{commands_repl, commands_repl_with_listener}`, `teloxide::utils::command::BotCommands::ty` (use `CommandRepl` instead)
 
 ## 0.11.0 - 2022-10-07
 
diff --git a/src/utils/command.rs b/src/utils/command.rs
index 785479d7..9c9814eb 100644
--- a/src/utils/command.rs
+++ b/src/utils/command.rs
@@ -235,6 +235,7 @@ pub trait BotCommands: Sized {
     ///
     /// [`commands_repl`]: (crate::repls::commands_repl)
     #[must_use]
+    #[deprecated(note = "Use `CommandRepl` instead")]
     fn ty() -> PhantomData {
         PhantomData
     }

From 9b8e21231c9aee74170d6bb3542222effea6b8e1 Mon Sep 17 00:00:00 2001
From: Hirrolot 
Date: Sat, 15 Oct 2022 23:54:16 +0600
Subject: [PATCH 10/21] Make `CommandRepl`'s methods `#[must_use]`

Former-commit-id: 0fb9399201cfa24d5890311ad9cc3cdf7cb1d0ad
---
 src/dispatching/repls/commands_repl.rs | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/src/dispatching/repls/commands_repl.rs b/src/dispatching/repls/commands_repl.rs
index 0c237044..5cbecd5b 100644
--- a/src/dispatching/repls/commands_repl.rs
+++ b/src/dispatching/repls/commands_repl.rs
@@ -69,6 +69,7 @@ pub trait CommandRepl {
     /// A REPL for commands.
     ///
     /// See [`CommandRepl`] for more details.
+    #[must_use]
     fn repl<'a, R, H, Args>(bot: R, handler: H) -> BoxFuture<'a, ()>
     where
         R: Requester + Clone + Send + Sync + 'static,
@@ -81,6 +82,7 @@ pub trait CommandRepl {
     /// A REPL for commands with a custom [`UpdateListener`].
     ///
     /// See [`CommandRepl`] for more details.
+    #[must_use]
     fn repl_with_listener<'a, R, H, L, Args>(bot: R, handler: H, listener: L) -> BoxFuture<'a, ()>
     where
         H: Injectable, Args> + Send + Sync + 'static,

From 7963a9184ab047e3602eff14d1fb130019d28b19 Mon Sep 17 00:00:00 2001
From: Sima Kinsart 
Date: Sat, 22 Oct 2022 10:11:18 +0600
Subject: [PATCH 11/21] Mention graceful shutdown in the highlights

Former-commit-id: d60a7d034156866dc37f478ee5bf2c110fb14a63
---
 README.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/README.md b/README.md
index 2fb0010a..878c4ad8 100644
--- a/README.md
+++ b/README.md
@@ -29,7 +29,7 @@
 [`dptree`]: https://github.com/teloxide/dptree
 [chain of responsibility]: https://en.wikipedia.org/wiki/Chain-of-responsibility_pattern
 
- - **Feature-rich.** You can use both long polling and webhooks, configure an underlying HTTPS client, set a custom URL of a Telegram API server, and much more.
+ - **Feature-rich.** You can use both long polling and webhooks, configure an underlying HTTPS client, set a custom URL of a Telegram API server, do graceful shutdown, and much more.
 
  - **Simple dialogues.** Our dialogues subsystem is simple and easy-to-use, and, furthermore, is agnostic of how/where dialogues are stored. For example, you can just replace a one line to achieve [persistence]. Out-of-the-box storages include [Redis] and [Sqlite].
 

From 6b8336a6697c31d6d4cf2628ccf2d872c977dea1 Mon Sep 17 00:00:00 2001
From: xamgore 
Date: Sat, 22 Oct 2022 17:13:32 +0400
Subject: [PATCH 12/21] Extend dialogue storages with RocksDB

Former-commit-id: d75b46520578b9389384b749fb39416c3fff19cb
---
 CHANGELOG.md                                  |   4 +
 Cargo.toml                                    |   5 +
 README.md                                     |   3 +-
 src/dispatching/dialogue/storage.rs           |   8 ++
 .../dialogue/storage/rocksdb_storage.rs       | 113 ++++++++++++++++++
 tests/rocksdb.rs                              |  95 +++++++++++++++
 6 files changed, 227 insertions(+), 1 deletion(-)
 create mode 100644 src/dispatching/dialogue/storage/rocksdb_storage.rs
 create mode 100644 tests/rocksdb.rs

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 7687aa9b..9abe238c 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,6 +6,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 
 ## unreleased
 
+### Added
+
+- The `rocksdb-storage` feature -- enables the RocksDB support.
+
 ## 0.11.0 - 2022-10-07
 
 ### Changed
diff --git a/Cargo.toml b/Cargo.toml
index 65e5135a..8eb1b351 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -19,6 +19,7 @@ webhooks-axum = ["webhooks", "axum", "tower", "tower-http"]
 
 sqlite-storage = ["sqlx"]
 redis-storage = ["redis"]
+rocksdb-storage = ["rocksdb"]
 cbor-serializer = ["serde_cbor"]
 bincode-serializer = ["bincode"]
 
@@ -42,6 +43,7 @@ full = [
     "webhooks-axum",
     "sqlite-storage",
     "redis-storage",
+    "rocksdb-storage",
     "cbor-serializer",
     "bincode-serializer",
     "macros",
@@ -92,6 +94,9 @@ sqlx = { version = "0.6", optional = true, default-features = false, features =
         "sqlite",
 ] }
 redis = { version = "0.21", features = ["tokio-comp"], optional = true }
+rocksdb = { version = "0.19", optional = true, default-features = false, features = [
+        "lz4",
+] }
 serde_cbor = { version = "0.11", optional = true }
 bincode = { version = "1.3", optional = true }
 axum = { version = "0.5.13", optional = true }
diff --git a/README.md b/README.md
index d25c150f..64dfc8c5 100644
--- a/README.md
+++ b/README.md
@@ -31,10 +31,11 @@
 
  - **Feature-rich.** You can use both long polling and webhooks, configure an underlying HTTPS client, set a custom URL of a Telegram API server, and much more.
 
- - **Simple dialogues.** Our dialogues subsystem is simple and easy-to-use, and, furthermore, is agnostic of how/where dialogues are stored. For example, you can just replace a one line to achieve [persistence]. Out-of-the-box storages include [Redis] and [Sqlite].
+ - **Simple dialogues.** Our dialogues subsystem is simple and easy-to-use, and, furthermore, is agnostic of how/where dialogues are stored. For example, you can just replace a one line to achieve [persistence]. Out-of-the-box storages include [Redis], [RocksDB] and [Sqlite].
 
 [persistence]: https://en.wikipedia.org/wiki/Persistence_(computer_science)
 [Redis]: https://redis.io/
+[RocksDB]: https://rocksdb.org/
 [Sqlite]: https://www.sqlite.org
 
  - **Strongly typed commands.** Define bot commands as an `enum` and teloxide will parse them automatically — just like JSON structures in [`serde-json`] and command-line arguments in [`structopt`].
diff --git a/src/dispatching/dialogue/storage.rs b/src/dispatching/dialogue/storage.rs
index b78cd72e..e8d2c158 100644
--- a/src/dispatching/dialogue/storage.rs
+++ b/src/dispatching/dialogue/storage.rs
@@ -9,6 +9,9 @@ mod redis_storage;
 #[cfg(feature = "sqlite-storage")]
 mod sqlite_storage;
 
+#[cfg(feature = "rocksdb-storage")]
+mod rocksdb_storage;
+
 use futures::future::BoxFuture;
 use teloxide_core::types::ChatId;
 
@@ -25,6 +28,9 @@ use std::sync::Arc;
 #[cfg(feature = "sqlite-storage")]
 pub use sqlite_storage::{SqliteStorage, SqliteStorageError};
 
+#[cfg(feature = "rocksdb-storage")]
+pub use rocksdb_storage::{RocksDbStorage, RocksDbStorageError};
+
 /// A storage with an erased error type.
 pub type ErasedStorage =
     dyn Storage> + Send + Sync;
@@ -41,10 +47,12 @@ pub type ErasedStorage =
 ///
 /// - [`InMemStorage`] -- a storage based on [`std::collections::HashMap`].
 /// - [`RedisStorage`] -- a Redis-based storage.
+/// - [`RocksDbStorage`] -- a RocksDB-based persistent storage.
 /// - [`SqliteStorage`] -- an SQLite-based persistent storage.
 ///
 /// [`InMemStorage`]: crate::dispatching::dialogue::InMemStorage
 /// [`RedisStorage`]: crate::dispatching::dialogue::RedisStorage
+/// [`RocksDbStorage`]: crate::dispatching::dialogue::RocksDbStorage
 /// [`SqliteStorage`]: crate::dispatching::dialogue::SqliteStorage
 pub trait Storage {
     type Error;
diff --git a/src/dispatching/dialogue/storage/rocksdb_storage.rs b/src/dispatching/dialogue/storage/rocksdb_storage.rs
new file mode 100644
index 00000000..d01d8fd9
--- /dev/null
+++ b/src/dispatching/dialogue/storage/rocksdb_storage.rs
@@ -0,0 +1,113 @@
+use super::{serializer::Serializer, Storage};
+use futures::future::BoxFuture;
+use rocksdb::{DBCompressionType, DBWithThreadMode, MultiThreaded};
+use serde::{de::DeserializeOwned, Serialize};
+use std::{
+    convert::Infallible,
+    fmt::{Debug, Display},
+    str,
+    sync::Arc,
+};
+use teloxide_core::types::ChatId;
+use thiserror::Error;
+
+/// A persistent dialogue storage based on [RocksDb](http://rocksdb.org/).
+pub struct RocksDbStorage {
+    db: DBWithThreadMode,
+    serializer: S,
+}
+
+/// An error returned from [`RocksDbStorage`].
+#[derive(Debug, Error)]
+pub enum RocksDbStorageError
+where
+    SE: Debug + Display,
+{
+    #[error("dialogue serialization error: {0}")]
+    SerdeError(SE),
+
+    #[error("RocksDb error: {0}")]
+    RocksDbError(#[from] rocksdb::Error),
+
+    /// Returned from [`RocksDbStorage::remove_dialogue`].
+    #[error("row not found")]
+    DialogueNotFound,
+}
+
+impl RocksDbStorage {
+    pub async fn open(
+        path: &str,
+        serializer: S,
+        options: Option,
+    ) -> Result, RocksDbStorageError> {
+        let options = match options {
+            Some(opts) => opts,
+            None => {
+                let mut opts = rocksdb::Options::default();
+                opts.set_compression_type(DBCompressionType::Lz4);
+                opts.create_if_missing(true);
+                opts
+            }
+        };
+
+        let db = DBWithThreadMode::::open(&options, path)?;
+        Ok(Arc::new(Self { db, serializer }))
+    }
+}
+
+impl Storage for RocksDbStorage
+where
+    S: Send + Sync + Serializer + 'static,
+    D: Send + Serialize + DeserializeOwned + 'static,
+    >::Error: Debug + Display,
+{
+    type Error = RocksDbStorageError<>::Error>;
+
+    /// Returns [`RocksDbStorageError::DialogueNotFound`] if a dialogue does not
+    /// exist.
+    fn remove_dialogue(
+        self: Arc,
+        ChatId(chat_id): ChatId,
+    ) -> BoxFuture<'static, Result<(), Self::Error>> {
+        Box::pin(async move {
+            let key = chat_id.to_le_bytes();
+
+            if self.db.get(&key)?.is_none() {
+                return Err(RocksDbStorageError::DialogueNotFound);
+            }
+
+            self.db.delete(&key).unwrap();
+
+            Ok(())
+        })
+    }
+
+    fn update_dialogue(
+        self: Arc,
+        ChatId(chat_id): ChatId,
+        dialogue: D,
+    ) -> BoxFuture<'static, Result<(), Self::Error>> {
+        Box::pin(async move {
+            let d =
+                self.serializer.serialize(&dialogue).map_err(RocksDbStorageError::SerdeError)?;
+
+            let key = chat_id.to_le_bytes();
+            self.db.put(&key, &d)?;
+
+            Ok(())
+        })
+    }
+
+    fn get_dialogue(
+        self: Arc,
+        ChatId(chat_id): ChatId,
+    ) -> BoxFuture<'static, Result, Self::Error>> {
+        Box::pin(async move {
+            let key = chat_id.to_le_bytes();
+            self.db
+                .get(&key)?
+                .map(|d| self.serializer.deserialize(&d).map_err(RocksDbStorageError::SerdeError))
+                .transpose()
+        })
+    }
+}
diff --git a/tests/rocksdb.rs b/tests/rocksdb.rs
new file mode 100644
index 00000000..7366a262
--- /dev/null
+++ b/tests/rocksdb.rs
@@ -0,0 +1,95 @@
+use std::{
+    fmt::{Debug, Display},
+    fs,
+    sync::Arc,
+};
+use teloxide::{
+    dispatching::dialogue::{RocksDbStorage, RocksDbStorageError, Serializer, Storage},
+    types::ChatId,
+};
+
+#[tokio::test(flavor = "multi_thread")]
+async fn test_rocksdb_json() {
+    fs::remove_dir_all("./test_db1").ok();
+    fs::create_dir("./test_db1").unwrap();
+    let storage = RocksDbStorage::open(
+        "./test_db1/test_db1.rocksdb",
+        teloxide::dispatching::dialogue::serializer::Json,
+        None,
+    )
+    .await
+    .unwrap();
+    test_rocksdb(storage).await;
+    fs::remove_dir_all("./test_db1").unwrap();
+}
+
+#[tokio::test(flavor = "multi_thread")]
+async fn test_rocksdb_bincode() {
+    fs::remove_dir_all("./test_db2").ok();
+    fs::create_dir("./test_db2").unwrap();
+    let storage = RocksDbStorage::open(
+        "./test_db2/test_db2.rocksdb",
+        teloxide::dispatching::dialogue::serializer::Bincode,
+        None,
+    )
+    .await
+    .unwrap();
+    test_rocksdb(storage).await;
+    fs::remove_dir_all("./test_db2").unwrap();
+}
+
+#[tokio::test(flavor = "multi_thread")]
+async fn test_rocksdb_cbor() {
+    fs::remove_dir_all("./test_db3").ok();
+    fs::create_dir("./test_db3").unwrap();
+    let storage = RocksDbStorage::open(
+        "./test_db3/test_db3.rocksdb",
+        teloxide::dispatching::dialogue::serializer::Cbor,
+        None,
+    )
+    .await
+    .unwrap();
+    test_rocksdb(storage).await;
+    fs::remove_dir_all("./test_db3").unwrap();
+}
+
+type Dialogue = String;
+
+macro_rules! test_dialogues {
+    ($storage:expr, $_0:expr, $_1:expr, $_2:expr) => {
+        assert_eq!(Arc::clone(&$storage).get_dialogue(ChatId(1)).await.unwrap(), $_0);
+        assert_eq!(Arc::clone(&$storage).get_dialogue(ChatId(11)).await.unwrap(), $_1);
+        assert_eq!(Arc::clone(&$storage).get_dialogue(ChatId(256)).await.unwrap(), $_2);
+    };
+}
+
+async fn test_rocksdb(storage: Arc>)
+where
+    S: Send + Sync + Serializer + 'static,
+    >::Error: Debug + Display,
+{
+    test_dialogues!(storage, None, None, None);
+
+    Arc::clone(&storage).update_dialogue(ChatId(1), "ABC".to_owned()).await.unwrap();
+    Arc::clone(&storage).update_dialogue(ChatId(11), "DEF".to_owned()).await.unwrap();
+    Arc::clone(&storage).update_dialogue(ChatId(256), "GHI".to_owned()).await.unwrap();
+
+    test_dialogues!(
+        storage,
+        Some("ABC".to_owned()),
+        Some("DEF".to_owned()),
+        Some("GHI".to_owned())
+    );
+
+    Arc::clone(&storage).remove_dialogue(ChatId(1)).await.unwrap();
+    Arc::clone(&storage).remove_dialogue(ChatId(11)).await.unwrap();
+    Arc::clone(&storage).remove_dialogue(ChatId(256)).await.unwrap();
+
+    test_dialogues!(storage, None, None, None);
+
+    // Check that a try to remove a non-existing dialogue results in an error.
+    assert!(matches!(
+        Arc::clone(&storage).remove_dialogue(ChatId(1)).await.unwrap_err(),
+        RocksDbStorageError::DialogueNotFound
+    ));
+}

From 5532a4cd87d56ba130d01183f2f2f65f5c92f590 Mon Sep 17 00:00:00 2001
From: Hirrolot 
Date: Sat, 29 Oct 2022 14:39:21 +0600
Subject: [PATCH 13/21] Rename `CommandRepl` => `CommandReplExt`

Former-commit-id: e7c5317954943f6ca3e65f036796078a8c4f0525
---
 CHANGELOG.md                           | 4 ++--
 src/dispatching/repls.rs               | 2 +-
 src/dispatching/repls/commands_repl.rs | 8 ++++----
 src/prelude.rs                         | 2 +-
 src/utils/command.rs                   | 2 +-
 5 files changed, 9 insertions(+), 9 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 513e536d..5f6c5e26 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -8,11 +8,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 
 ### Added
 
- - `teloxide::dispatching::repls::CommandRepl`, `teloxide::prelude::CommandRepl` ([issue #740](https://github.com/teloxide/teloxide/issues/740))
+ - `teloxide::dispatching::repls::CommandReplExt`, `teloxide::prelude::CommandReplExt` ([issue #740](https://github.com/teloxide/teloxide/issues/740))
 
 ### Deprecated
 
- - `teloxide::dispatching::repls::{commands_repl, commands_repl_with_listener}`, `teloxide::utils::command::BotCommands::ty` (use `CommandRepl` instead)
+ - `teloxide::dispatching::repls::{commands_repl, commands_repl_with_listener}`, `teloxide::utils::command::BotCommands::ty` (use `CommandReplExt` instead)
 
 ## 0.11.0 - 2022-10-07
 
diff --git a/src/dispatching/repls.rs b/src/dispatching/repls.rs
index e8e6c4ac..aea4806e 100644
--- a/src/dispatching/repls.rs
+++ b/src/dispatching/repls.rs
@@ -11,7 +11,7 @@
 mod commands_repl;
 mod repl;
 
-pub use commands_repl::CommandRepl;
+pub use commands_repl::CommandReplExt;
 #[allow(deprecated)]
 pub use commands_repl::{commands_repl, commands_repl_with_listener};
 pub use repl::{repl, repl_with_listener};
diff --git a/src/dispatching/repls/commands_repl.rs b/src/dispatching/repls/commands_repl.rs
index 5cbecd5b..15f2396d 100644
--- a/src/dispatching/repls/commands_repl.rs
+++ b/src/dispatching/repls/commands_repl.rs
@@ -65,10 +65,10 @@ use std::{fmt::Debug, marker::PhantomData};
 #[doc = include_str!("caution.md")]
 ///
 #[cfg(feature = "ctrlc_handler")]
-pub trait CommandRepl {
+pub trait CommandReplExt {
     /// A REPL for commands.
     ///
-    /// See [`CommandRepl`] for more details.
+    /// See [`CommandReplExt`] for more details.
     #[must_use]
     fn repl<'a, R, H, Args>(bot: R, handler: H) -> BoxFuture<'a, ()>
     where
@@ -81,7 +81,7 @@ pub trait CommandRepl {
 
     /// A REPL for commands with a custom [`UpdateListener`].
     ///
-    /// See [`CommandRepl`] for more details.
+    /// See [`CommandReplExt`] for more details.
     #[must_use]
     fn repl_with_listener<'a, R, H, L, Args>(bot: R, handler: H, listener: L) -> BoxFuture<'a, ()>
     where
@@ -93,7 +93,7 @@ pub trait CommandRepl {
 }
 
 #[cfg(feature = "ctrlc_handler")]
-impl CommandRepl for Cmd
+impl CommandReplExt for Cmd
 where
     Cmd: BotCommands + Send + Sync + 'static,
 {
diff --git a/src/prelude.rs b/src/prelude.rs
index 499eaea7..ca6afa90 100644
--- a/src/prelude.rs
+++ b/src/prelude.rs
@@ -6,7 +6,7 @@ pub use crate::error_handlers::{LoggingErrorHandler, OnError};
 pub use crate::respond;
 
 pub use crate::dispatching::{
-    dialogue::Dialogue, repls::CommandRepl as _, Dispatcher, HandlerExt as _,
+    dialogue::Dialogue, repls::CommandReplExt as _, Dispatcher, HandlerExt as _,
     MessageFilterExt as _, UpdateFilterExt as _,
 };
 
diff --git a/src/utils/command.rs b/src/utils/command.rs
index 9c9814eb..8f96998e 100644
--- a/src/utils/command.rs
+++ b/src/utils/command.rs
@@ -235,7 +235,7 @@ pub trait BotCommands: Sized {
     ///
     /// [`commands_repl`]: (crate::repls::commands_repl)
     #[must_use]
-    #[deprecated(note = "Use `CommandRepl` instead")]
+    #[deprecated(note = "Use `CommandReplExt` instead")]
     fn ty() -> PhantomData {
         PhantomData
     }

From 49cd9a8548717055a1b5155424490911ffde9042 Mon Sep 17 00:00:00 2001
From: Sima Kinsart 
Date: Sun, 30 Oct 2022 11:55:54 +0600
Subject: [PATCH 14/21] Link the PR to `CHANGELOG.md`

Former-commit-id: 2b749ed15c32ade8dfaf0f478ab41db7de3c80fc
---
 CHANGELOG.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 9abe238c..dca7896d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -8,7 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 
 ### Added
 
-- The `rocksdb-storage` feature -- enables the RocksDB support.
+- The `rocksdb-storage` feature -- enables the RocksDB support ([PR #753](https://github.com/teloxide/teloxide/pull/753)).
 
 ## 0.11.0 - 2022-10-07
 

From 01929c5476d81e19c8fcbe9b256f6592c68531bd Mon Sep 17 00:00:00 2001
From: Sima Kinsart 
Date: Sun, 30 Oct 2022 14:39:45 +0600
Subject: [PATCH 15/21] Update the feature set with `rocksdb-storage`

Former-commit-id: e2f6fde7432bc943d9cf78a03b247025b55668c3
---
 src/features.md | 41 +++++++++++++++++++++--------------------
 1 file changed, 21 insertions(+), 20 deletions(-)

diff --git a/src/features.md b/src/features.md
index 1545af78..a0456377 100644
--- a/src/features.md
+++ b/src/features.md
@@ -1,27 +1,28 @@
 ## Cargo features
 
-| Feature              | Description                                                                                |
-|----------------------|--------------------------------------------------------------------------------------------|
-| `webhooks`           | Enables general webhook utilities (almost useless on its own)                              |
-| `webhooks-axum`      | Enables webhook implementation based on axum framework                                     |
-| `macros`             | Re-exports macros from [`teloxide-macros`].                                                |
+| Feature              | Description |
+|----------------------|-------------|
+| `webhooks`           | Enables general webhook utilities (almost useless on its own). |
+| `webhooks-axum`      | Enables webhook implementation based on axum framework. |
+| `macros`             | Re-exports macros from [`teloxide-macros`]. |
 | `ctrlc_handler`      | Enables the [`DispatcherBuilder::enable_ctrlc_handler`] function (**enabled by default**). |
-| `auto-send`          | Enables the [`AutoSend`](adaptors::AutoSend) bot adaptor (**enabled by default; DEPRECATED**).         |
-| `throttle`           | Enables the [`Throttle`](adaptors::Throttle) bot adaptor.                                  |
-| `cache-me`           | Enables the [`CacheMe`](adaptors::CacheMe) bot adaptor.                                    |
-| `trace-adaptor`      | Enables the [`Trace`](adaptors::Trace) bot adaptor.                                        |
-| `erased`             | Enables the [`ErasedRequester`](adaptors::ErasedRequester) bot adaptor.                    |
-| `full`               | Enables all the features except `nightly`.                                                 |
-| `nightly`            | Enables nightly-only features (see the [`teloxide-core` features]).                          |
-| `native-tls`         | Enables the [`native-tls`] TLS implementation (**enabled by default**).                    |
-| `rustls`             | Enables the [`rustls`] TLS implementation.                                                 |
-| `redis-storage`      | Enables the [Redis] storage support for dialogues.                                         |
-| `sqlite-storage`     | Enables the [Sqlite] storage support for dialogues.                                        |
-| `cbor-serializer`    | Enables the [CBOR] serializer for dialogues.                                               |
-| `bincode-serializer` | Enables the [Bincode] serializer for dialogues.                                            |
-
+| `auto-send`          | Enables the [`AutoSend`](adaptors::AutoSend) bot adaptor (**enabled by default; DEPRECATED**). |
+| `throttle`           | Enables the [`Throttle`](adaptors::Throttle) bot adaptor. |
+| `cache-me`           | Enables the [`CacheMe`](adaptors::CacheMe) bot adaptor. |
+| `trace-adaptor`      | Enables the [`Trace`](adaptors::Trace) bot adaptor. |
+| `erased`             | Enables the [`ErasedRequester`](adaptors::ErasedRequester) bot adaptor. |
+| `full`               | Enables all the features except `nightly`. |
+| `nightly`            | Enables nightly-only features (see the [`teloxide-core` features]). |
+| `native-tls`         | Enables the [`native-tls`] TLS implementation (**enabled by default**). |
+| `rustls`             | Enables the [`rustls`] TLS implementation. |
+| `redis-storage`      | Enables the [Redis] storage support for dialogues. |
+| `rocksdb-storage`    | Enables the [RocksDB] storage support for dialogues. |
+| `sqlite-storage`     | Enables the [Sqlite] storage support for dialogues. |
+| `cbor-serializer`    | Enables the [CBOR] serializer for dialogues. |
+| `bincode-serializer` | Enables the [Bincode] serializer for dialogues. |
 
 [Redis]: https://redis.io/
+[RocksDB]: https://rocksdb.org/
 [Sqlite]: https://www.sqlite.org/
 [CBOR]: https://en.wikipedia.org/wiki/CBOR
 [Bincode]: https://github.com/servo/bincode
@@ -31,4 +32,4 @@
 [`teloxide::utils::UpState`]: utils::UpState
 [`teloxide-core` features]: https://docs.rs/teloxide-core/latest/teloxide_core/#cargo-features
 
-[`DispatcherBuilder::enable_ctrlc_handler`]: dispatching::DispatcherBuilder::enable_ctrlc_handler
\ No newline at end of file
+[`DispatcherBuilder::enable_ctrlc_handler`]: dispatching::DispatcherBuilder::enable_ctrlc_handler

From e094d6a20a4d09437655d948cd5f2012ffca46cf Mon Sep 17 00:00:00 2001
From: Maybe Waffle 
Date: Mon, 31 Oct 2022 13:36:26 +0400
Subject: [PATCH 16/21] Remove `,rust` from languages in `MIGRATION_GUIDE.md`

Anyway no one is rendering the syntax for diffs, while some even stop
understanding that it's a diff.


Former-commit-id: 2f18b5f0603a99b7a3e4472171b3e1df506719bf
---
 MIGRATION_GUIDE.md | 18 +++++++++---------
 1 file changed, 9 insertions(+), 9 deletions(-)

diff --git a/MIGRATION_GUIDE.md b/MIGRATION_GUIDE.md
index 937320a7..de6665c4 100644
--- a/MIGRATION_GUIDE.md
+++ b/MIGRATION_GUIDE.md
@@ -7,12 +7,12 @@ Note that the list of required changes is not fully exhaustive and it may lack s
 
 We have introduced the new trait `CommandRepl` that replaces the old `commands_repl_(with_listener)` functions:
 
-```diff,rust
+```diff
 - teloxide::commands_repl(bot, answer, Command::ty())
 + Command::repl(bot, answer)
 ```
 
-```diff,rust
+```diff
 - teloxide::commands_repl_with_listener(bot, answer, listener, Command::ty())
 + Command::repl_with_listener(bot, answer, listener)
 ```
@@ -24,12 +24,12 @@ We have introduced the new trait `CommandRepl` that replaces the old `commands_r
 Requests can now be `.await`ed directly, without need of `.send()` or `AutoSend`.
 If you previously used `AutoSend` adaptor, you can safely remove it:
 
-```diff,rust
+```diff
 -let bot = Bot::from_env().auto_send();
 +let bot = Bot::from_env();
 ```
 
-```diff,rust
+```diff
 -async fn start(bot: AutoSend, dialogue: MyDialogue, msg: Message) -> HandlerResult {
 +async fn start(bot: Bot, dialogue: MyDialogue, msg: Message) -> HandlerResult {
 ```
@@ -57,7 +57,7 @@ You may need to change code accordingly:
 -let id: i32 = message.id;
 +let id: MessageId = message.id;
 ```
-```diff,rust
+```diff
 let (cid, mid): (ChatId, i32) = get_message_to_delete_from_db();
 -bot.delete_message(cid, mid).await?;
 +bot.delete_message(cid, MessageId(mid)).await?;
@@ -66,7 +66,7 @@ let (cid, mid): (ChatId, i32) = get_message_to_delete_from_db();
 Note that at the same time `MessageId` is now a tuple struct.
 If you've accessed its only field you'll need to change it too:
 
-```diff,rust
+```diff
 -let MessageId { message_id } = bot.copy_message(dst_chat, src_chat, mid).await?;
 +let MessageId(message_id) = bot.copy_message(dst_chat, src_chat, mid).await?;
 save_to_db(message_id);
@@ -80,7 +80,7 @@ See `Sticker` documentation for more information about the new structure.
 
 You can now write `Ok(())` instead of `respond(())` at the end of closures provided to RELPs:
 
-```diff,rust
+```diff
 teloxide::repl(bot, |bot: Bot, msg: Message| async move {
     bot.send_dice(msg.chat.id).await?;
 -    respond(())
@@ -95,7 +95,7 @@ This is because REPLs now require the closure to return `RequestError` instead o
 
 `parse_with` now accepts a Rust _path_ to a custom parser function instead of a string:
 
-```diff,rust
+```diff
 fn custom_parser(input: String) -> Result<(u8,), ParseError> {
     todo!()
 }
@@ -110,7 +110,7 @@ enum Command {
 
 `rename` now only renames a command literally; use `rename_rule` to change the case of a command:
 
-```diff,rust
+```diff
 #[derive(BotCommands)]
 - #[command(rename = "lowercase", description = "These commands are supported:")]
 + #[command(rename_rule = "lowercase", description = "These commands are supported:")]

From 3ecb3fb06a51578617d55a0983ab90ca84af384b Mon Sep 17 00:00:00 2001
From: Maybe Waffle 
Date: Mon, 31 Oct 2022 13:44:32 +0400
Subject: [PATCH 17/21] Add stop token changes to the migration guide

Former-commit-id: 7287ffe2f0e212a20843c709cdfbdb31fb462544
---
 MIGRATION_GUIDE.md | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/MIGRATION_GUIDE.md b/MIGRATION_GUIDE.md
index de6665c4..0c8a33bf 100644
--- a/MIGRATION_GUIDE.md
+++ b/MIGRATION_GUIDE.md
@@ -91,6 +91,16 @@ teloxide::repl(bot, |bot: Bot, msg: Message| async move {
 
 This is because REPLs now require the closure to return `RequestError` instead of a generic error type, so type inference works perfectly for a return value. If you use something other than `RequestError`, you can transfer your code to `teloxide::dispatching`, which still permits a generic error type.
 
+"Stop tokens" were refactored, the trait is now removed and the types were renamed:
+
+```diff
+-use teloxide::dispatching::stop_token::{AsyncStopToken, AsyncStopFlag};
++use teloxide::stop::{StopToken, StopFlag, mk_stop_token};
+
+-let (token, flag): (AsyncStopToken, AsyncStopFlag) = AsyncStopToken::new_pair();
++let (token, flag): (StopToken, StopFlag) = mk_stop_token();
+```
+
 ### macros
 
 `parse_with` now accepts a Rust _path_ to a custom parser function instead of a string:

From ba064a243d931e21fb1a41701edecba3df563ecc Mon Sep 17 00:00:00 2001
From: Sima Kinsart 
Date: Mon, 31 Oct 2022 15:56:13 +0600
Subject: [PATCH 18/21] Don't list the `auto-send` feature in `README.md`

Former-commit-id: 69d86d91ddabfc854dc5978876e5821d59d47b4d
---
 README.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/README.md b/README.md
index b1e528a1..bf649dd5 100644
--- a/README.md
+++ b/README.md
@@ -73,7 +73,7 @@ $ rustup override set nightly
  5. Run `cargo new my_bot`, enter the directory and put these lines into your `Cargo.toml`:
 ```toml
 [dependencies]
-teloxide = { version = "0.11", features = ["macros", "auto-send"] }
+teloxide = { version = "0.11", features = ["macros"] }
 log = "0.4"
 pretty_env_logger = "0.4"
 tokio = { version =  "1.8", features = ["rt-multi-thread", "macros"] }

From 6d105d3b7832fd744cda75bc3a0ea3e7265e9313 Mon Sep 17 00:00:00 2001
From: Hirrolot 
Date: Mon, 31 Oct 2022 16:30:49 +0600
Subject: [PATCH 19/21] Release v0.11.1

Former-commit-id: b97c2c6063fece1c7ac501e3784d147046c61975
---
 CHANGELOG.md | 2 ++
 Cargo.toml   | 2 +-
 2 files changed, 3 insertions(+), 1 deletion(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index b1b8937a..5522bab0 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,6 +6,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 
 ## unreleased
 
+# 0.11.1 - 2022-10-31
+
 ### Added
 
 - The `rocksdb-storage` feature -- enables the RocksDB support ([PR #753](https://github.com/teloxide/teloxide/pull/753))
diff --git a/Cargo.toml b/Cargo.toml
index 8eb1b351..f4056c49 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "teloxide"
-version = "0.11.0"
+version = "0.11.1"
 edition = "2021"
 description = "An elegant Telegram bots framework for Rust"
 repository = "https://github.com/teloxide/teloxide"

From 727a60463890695d93a374fe364924658cd934b4 Mon Sep 17 00:00:00 2001
From: Hirrolot 
Date: Mon, 31 Oct 2022 21:26:28 +0600
Subject: [PATCH 20/21] Update the migration guide version

Former-commit-id: 08d2e4f10278a4040f615610f766a36fa5ac979f
---
 MIGRATION_GUIDE.md | 2 +-
 README.md          | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/MIGRATION_GUIDE.md b/MIGRATION_GUIDE.md
index 0c8a33bf..c5da2a04 100644
--- a/MIGRATION_GUIDE.md
+++ b/MIGRATION_GUIDE.md
@@ -1,7 +1,7 @@
 This document describes breaking changes of `teloxide` crate, as well as the ways to update code.
 Note that the list of required changes is not fully exhaustive and it may lack something in rare cases.
 
-## 0.10 -> 0.xxx.xxx
+## 0.11 -> 0.11.1
 
 ### teloxide
 
diff --git a/README.md b/README.md
index bf649dd5..f211a547 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-> [v0.10 -> v0.11 migration guide >>](MIGRATION_GUIDE.md#010---011)
+> [v0.11 -> v0.11.1 migration guide >>](MIGRATION_GUIDE.md#011---0111)
 
 
From 48946f3315647ad3b4b134d4789b4c5ddc2eb119 Mon Sep 17 00:00:00 2001 From: Sima Kinsart Date: Mon, 31 Oct 2022 21:29:38 +0600 Subject: [PATCH 21/21] Fix the version header (`CHANGELOG.md`) Former-commit-id: bce24fdf8df8f40c960923e7838c290258bf9549 --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5522bab0..3e84df63 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## unreleased -# 0.11.1 - 2022-10-31 +## 0.11.1 - 2022-10-31 ### Added