diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 589bb662..f05f9948 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -17,17 +17,12 @@ env: CARGO_NET_RETRY: 10 RUSTUP_MAX_RETRIES: 10 - rust_nightly: nightly-2022-01-17 + rust_nightly: nightly-2022-09-23 # When updating this, also update: # - README.md # - src/lib.rs # - down below in a matrix - rust_msrv: 1.58.0 - # When updating this, also update: - # - down below in a matrix - # - # This is needed because some of our tests can't run on MSRV. - rust_msrv_dev: 1.59.0 + rust_msrv: 1.64.0 CI: 1 @@ -43,7 +38,6 @@ jobs: - check-examples - clippy - doc - - msrv steps: - run: exit 0 @@ -82,7 +76,7 @@ jobs: - stable - beta - nightly - - msrv_dev + - msrv include: - rust: stable @@ -92,10 +86,10 @@ jobs: toolchain: beta features: "--features full" - rust: nightly - toolchain: nightly-2022-01-17 + toolchain: nightly-2022-09-23 features: "--all-features" - - rust: msrv_dev - toolchain: 1.59.0 + - rust: msrv + toolchain: 1.64.0 features: "--features full" steps: @@ -108,6 +102,7 @@ jobs: profile: minimal toolchain: ${{ matrix.toolchain }} override: true + components: rustfmt # required by codegen - name: Cache Dependencies uses: Swatinem/rust-cache@v1 @@ -194,27 +189,3 @@ jobs: uses: actions-rs/cargo@v1 with: command: docs # from .cargo/config.toml - - msrv: - name: minimal supported rust version - runs-on: ubuntu-latest - - steps: - - name: Checkout - uses: actions/checkout@v3 - - - name: Install Rust ${{ env.rust_msrv }} - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: ${{ env.rust_msrv }} - override: true - - - name: Cache Dependencies - uses: Swatinem/rust-cache@v1 - - - name: Check - uses: actions-rs/cargo@v1 - with: - command: check - args: --verbose --features full diff --git a/CHANGELOG.md b/CHANGELOG.md index 58f99914..9f9aa9eb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,12 +7,25 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## unreleased +### Changed + +- **You can now `.await` any `Request`!** ([#249][pr249]) + - `Request` now requires `Self: IntoFuture` + - There is no need for `AutoSend` anymore +- MSRV (Minimal Supported Rust Version) was bumped from `1.58.0` to `1.64.0` + ### Removed - Methods for creating `InlineQuery` ([#246][pr244]) [pr244]: https://github.com/teloxide/teloxide-core/pull/246 +### Deprecated + +- `AutoSend` adaptor ([#249][pr249]) + +[pr249]: https://github.com/teloxide/teloxide-core/pull/249 + ## 0.7.1 - 2022-08-19 ### Fixed diff --git a/Cargo.toml b/Cargo.toml index 86dba265..a3e25291 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,7 +24,7 @@ exclude = [ futures = "0.3.5" tokio = { version = "1.12.0", features = ["fs"] } tokio-util = { version = "0.7.0", features = ["codec"] } -pin-project = "1.0.3" +pin-project = "1.0.12" bytes = "1.0.0" reqwest = { version = "0.11.10", features = ["json", "stream", "multipart"], default-features = false } url = { version = "2", features = ["serde"] } @@ -99,8 +99,8 @@ cargo-args = ["-Zunstable-options", "-Zrustdoc-scrape-examples=examples"] [[example]] name = "self_info" -required-features = ["tokio/macros", "tokio/rt-multi-thread", "auto_send"] +required-features = ["tokio/macros", "tokio/rt-multi-thread"] [[example]] name = "erased" -required-features = ["tokio/macros", "tokio/rt-multi-thread", "auto_send", "erased"] +required-features = ["tokio/macros", "tokio/rt-multi-thread", "erased", "trace_adaptor"] diff --git a/README.md b/README.md index e3aedce7..25e08273 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ ```toml teloxide-core = "0.7" ``` -_Compiler support: requires rustc 1.58+_. +_Compiler support: requires rustc 1.64+_. [`teloxide`]: https://docs.rs/teloxide [Telegram Bot API]: https://core.telegram.org/bots/api diff --git a/examples/erased.rs b/examples/erased.rs index d980ddc3..2c54123c 100644 --- a/examples/erased.rs +++ b/examples/erased.rs @@ -32,9 +32,9 @@ async fn main() -> Result<(), Box> { log::info!("Trace settings: {:?}", trace_settings); let bot = if trace_settings.is_empty() { - Bot::from_env().erase().auto_send() + Bot::from_env().erase() } else { - Bot::from_env().trace(trace_settings).erase().auto_send() + Bot::from_env().trace(trace_settings).erase() }; bot.send_chat_action(chat_id, ChatAction::Typing).await?; diff --git a/examples/self_info.rs b/examples/self_info.rs index b56271c8..e3747671 100644 --- a/examples/self_info.rs +++ b/examples/self_info.rs @@ -13,9 +13,7 @@ async fn main() -> Result<(), Box> { .parse::()?, ); - let bot = Bot::from_env() - .parse_mode(ParseMode::MarkdownV2) - .auto_send(); + let bot = Bot::from_env().parse_mode(ParseMode::MarkdownV2); let Me { user: me, .. } = bot.get_me().await?; diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 66a1979e..b4990f3d 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,4 +1,4 @@ [toolchain] -channel = "nightly-2022-01-17" +channel = "nightly-2022-09-23" components = ["rustfmt", "clippy"] profile = "minimal" diff --git a/src/adaptors.rs b/src/adaptors.rs index 4f1b7406..c54a65ec 100644 --- a/src/adaptors.rs +++ b/src/adaptors.rs @@ -3,17 +3,18 @@ //! Bot adaptors are very similar to the [`Iterator`] adaptors: they are bots //! wrapping other bots to alter existing or add new functionality. //! -//! E.g. [`AutoSend`] allows `await`ing requests directly, no need to use -//! `.send()`. -//! //! [`Requester`]: crate::requests::Requester -/// [`AutoSend`] bot adaptor which allows sending a request without calling -/// [`send`]. +/// [`AutoSend`] bot adaptor which used to allow sending a request without +/// calling [`send`]. /// /// [`AutoSend`]: auto_send::AutoSend /// [`send`]: crate::requests::Request::send #[cfg(feature = "auto_send")] +#[deprecated( + since = "0.8.0", + note = "`AutoSend` is no longer required to `.await` requests and is now noop" +)] pub mod auto_send; /// [`CacheMe`] bot adaptor which caches [`GetMe`] requests. @@ -47,6 +48,7 @@ pub mod throttle; mod parse_mode; #[cfg(feature = "auto_send")] +#[allow(deprecated)] pub use auto_send::AutoSend; #[cfg(feature = "cache_me")] pub use cache_me::CacheMe; diff --git a/src/adaptors/auto_send.rs b/src/adaptors/auto_send.rs index e10f763f..dfd4a4c8 100644 --- a/src/adaptors/auto_send.rs +++ b/src/adaptors/auto_send.rs @@ -1,10 +1,5 @@ -use std::{ - future::Future, - pin::Pin, - task::{Context, Poll}, -}; +use std::future::IntoFuture; -use futures::future::FusedFuture; use url::Url; use crate::{ @@ -12,32 +7,16 @@ use crate::{ types::*, }; -/// Send requests automatically. +/// Previously was used to send requests automatically. /// -/// Requests returned by ` as `[`Requester`]`>` are [`Future`]s -/// which means that you can simply `.await` them instead of using -/// `.send().await`. +/// Before addition of [`IntoFuture`] you could only `.await` [`Future`]s. +/// This adaptor turned requests into futures, allowing to `.await` them, +/// without calling `.send()`. /// -/// Notes: -/// 1. This wrapper should be the most outer i.e.: `AutoSend>` -/// will automatically send requests, while `CacheMe>` - won't. -/// 2. After first call to `poll` on a request you will be unable to access -/// payload nor could you use [`send_ref`](Request::send_ref). +/// Now, however, all requests are required to implement `IntoFuture`, allowing +/// you to `.await` them directly. This adaptor is noop, and shouldn't be used. /// -/// ## Examples -/// -/// ```rust -/// use teloxide_core::{ -/// requests::{Requester, RequesterExt}, -/// types::Me, -/// Bot, -/// }; -/// -/// # async { -/// let bot = Bot::new("TOKEN").auto_send(); -/// let myself: Me = bot.get_me().await?; // No .send()! -/// # Ok::<_, teloxide_core::RequestError>(()) }; -/// ``` +/// [`Future`]: std::future::Future #[derive(Clone, Debug)] pub struct AutoSend { bot: B, @@ -192,33 +171,17 @@ download_forward! { } #[must_use = "Futures are lazy and do nothing unless polled or awaited"] -#[pin_project::pin_project] -pub struct AutoRequest(#[pin] Inner); +pub struct AutoRequest(R); impl AutoRequest where R: Request, { pub fn new(inner: R) -> Self { - Self(Inner::Request(inner)) + Self(inner) } } -/// Data of the `AutoRequest` used to not expose variants (I wish there were -/// private enum variants). -#[pin_project::pin_project(project = InnerProj, project_replace = InnerRepl)] -enum Inner { - /// An unsent modifiable request. - Request(R), - /// A sent request. - Future(#[pin] R::Send), - /// Done state. Set after `R::Send::poll` returned `Ready(_)`. - /// - /// Also used as a temporary replacement to turn pinned `Request(req)` - /// into `Future(req.send())` in `AutoRequest::poll`. - Done, -} - impl Request for AutoRequest where R: Request, @@ -228,19 +191,20 @@ where type SendRef = R::SendRef; fn send(self) -> Self::Send { - match self.0 { - Inner::Request(req) => req.send(), - Inner::Future(fut) => fut, - Inner::Done => done_unreachable(), - } + self.0.send() } fn send_ref(&self) -> Self::SendRef { - match &self.0 { - Inner::Request(req) => req.send_ref(), - Inner::Future(_) => already_polled(), - Inner::Done => done_unreachable(), - } + self.0.send_ref() + } +} + +impl IntoFuture for AutoRequest { + type Output = Result, ::Err>; + type IntoFuture = ::Send; + + fn into_future(self) -> Self::IntoFuture { + self.send() } } @@ -248,75 +212,10 @@ impl HasPayload for AutoRequest { type Payload = R::Payload; fn payload_mut(&mut self) -> &mut Self::Payload { - match &mut self.0 { - Inner::Request(req) => req.payload_mut(), - Inner::Future(_) => already_polled(), - Inner::Done => done_unreachable(), - } + self.0.payload_mut() } fn payload_ref(&self) -> &Self::Payload { - match &self.0 { - Inner::Request(req) => req.payload_ref(), - Inner::Future(_) => already_polled(), - Inner::Done => done_unreachable(), - } + self.0.payload_ref() } } - -impl Future for AutoRequest { - type Output = Result, R::Err>; - - fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - let mut this: Pin<&mut Inner<_>> = self.as_mut().project().0; - - match this.as_mut().project() { - // Poll the underling future. - InnerProj::Future(fut) => { - let res = futures::ready!(fut.poll(cx)); - // We've got the result, so we set the state to done. - this.set(Inner::Done); - Poll::Ready(res) - } - - // This future is fused. - InnerProj::Done => Poll::Pending, - // The `AutoRequest` future was polled for the first time after - // creation. We need to transform it into sent form by calling - // `R::send` and doing some magic around Pin. - InnerProj::Request(_) => { - // Replace `Request(_)` by `Done(_)` to obtain ownership over - // the former. - let inner = this.as_mut().project_replace(Inner::Done); - // Map Request(req) to `Future(req.send())`. - let inner = match inner { - InnerRepl::Request(req) => Inner::Future(req.send()), - // Practically this is unreachable, because we've just checked for - // both `Future(_)` and `Done` variants. - InnerRepl::Future(_) | InnerRepl::Done => done_unreachable(), - }; - // Set the resulting `Future(_)` back to pin. - this.set(inner); - - // Poll `self`. This time another brunch will be executed, returning `Poll`. - self.poll(cx) - } - } - } -} - -impl FusedFuture for AutoRequest { - fn is_terminated(&self) -> bool { - matches!(&self.0, Inner::Done) - } -} - -#[inline(never)] -fn done_unreachable() -> ! { - unreachable!("future is completed and as such doesn't provide any functionality") -} - -#[inline(never)] -fn already_polled() -> ! { - panic!("AutoRequest was already polled once") -} diff --git a/src/adaptors/cache_me.rs b/src/adaptors/cache_me.rs index b1918ab8..5ae8669a 100644 --- a/src/adaptors/cache_me.rs +++ b/src/adaptors/cache_me.rs @@ -1,4 +1,4 @@ -use std::{pin::Pin, sync::Arc}; +use std::{future::IntoFuture, pin::Pin, sync::Arc}; use futures::{ future, @@ -244,6 +244,15 @@ impl> HasPayload for CachedMeRequest { } } +impl> IntoFuture for CachedMeRequest { + type Output = Result; + type IntoFuture = Send; + + fn into_future(self) -> Self::IntoFuture { + self.send() + } +} + type ReadyMe = Ready>; #[pin_project::pin_project] diff --git a/src/adaptors/erased.rs b/src/adaptors/erased.rs index 98dd2c95..fc12d8ac 100644 --- a/src/adaptors/erased.rs +++ b/src/adaptors/erased.rs @@ -1,4 +1,4 @@ -use std::sync::Arc; +use std::{future::IntoFuture, sync::Arc}; use futures::{future::BoxFuture, FutureExt}; use reqwest::Url; @@ -51,7 +51,8 @@ pub struct ErasedRequest<'a, T, E> { inner: Box + 'a>, } -impl<'a, T, E> ErasedRequest<'a, T, E> { +// `T: Payload` required b/c of +impl<'a, T: Payload, E> ErasedRequest<'a, T, E> { pub(crate) fn erase(request: impl Request + 'a) -> Self { Self { inner: Box::new(request), @@ -94,6 +95,19 @@ where } } +impl<'a, T, E> IntoFuture for ErasedRequest<'a, T, E> +where + T: Payload, + E: std::error::Error + Send, +{ + type Output = Result, ::Err>; + type IntoFuture = ::Send; + + fn into_future(self) -> Self::IntoFuture { + self.send() + } +} + /// Object safe version of [`Request`]. /// /// TODO(waffle): make [`Request`] object safe and remove this trait (this is a diff --git a/src/adaptors/throttle/request.rs b/src/adaptors/throttle/request.rs index bf431ebb..46235fce 100644 --- a/src/adaptors/throttle/request.rs +++ b/src/adaptors/throttle/request.rs @@ -1,4 +1,9 @@ -use std::{future::Future, pin::Pin, sync::Arc, time::Instant}; +use std::{ + future::{Future, IntoFuture}, + pin::Pin, + sync::Arc, + time::Instant, +}; use futures::{ future::BoxFuture, @@ -74,6 +79,20 @@ where } } +impl IntoFuture for ThrottlingRequest +where + R: Request + Clone + Send + Sync + 'static, + R::Err: AsResponseParameters + Send, + Output: Send, +{ + type Output = Result, ::Err>; + type IntoFuture = ::Send; + + fn into_future(self) -> Self::IntoFuture { + self.send() + } +} + impl Future for ThrottlingSend where R::Err: AsResponseParameters, @@ -159,7 +178,7 @@ where let res = match &mut request { ShareableRequest::Shared(shared) => shared.send_ref().await, - ShareableRequest::Owned(owned) => owned.take().unwrap().send().await, + ShareableRequest::Owned(owned) => owned.take().unwrap().await, }; return res; @@ -178,7 +197,7 @@ where request.send_ref().await } (false, ShareableRequest::Shared(shared)) => shared.send_ref().await, - (false, ShareableRequest::Owned(owned)) => owned.take().unwrap().send().await, + (false, ShareableRequest::Owned(owned)) => owned.take().unwrap().await, }; let retry_after = res.as_ref().err().and_then(<_>::retry_after); diff --git a/src/adaptors/throttle/worker.rs b/src/adaptors/throttle/worker.rs index a3202f4c..62438013 100644 --- a/src/adaptors/throttle/worker.rs +++ b/src/adaptors/throttle/worker.rs @@ -9,7 +9,7 @@ use vecrem::VecExt; use crate::{ adaptors::throttle::{request_lock::RequestLock, ChatIdHash, Limits, Settings}, errors::AsResponseParameters, - requests::{Request, Requester}, + requests::Requester, }; const MINUTE: Duration = Duration::from_secs(60); @@ -321,7 +321,7 @@ async fn freeze( // TODO: maybe not call `get_chat` every time? // At this point there isn't much we can do with the error besides ignoring - if let Ok(chat) = bot.get_chat(id).send().await { + if let Ok(chat) = bot.get_chat(id).await { match chat.slow_mode_delay() { Some(delay) => { let now = Instant::now(); diff --git a/src/adaptors/trace.rs b/src/adaptors/trace.rs index a3b3fcfa..7e0e9a78 100644 --- a/src/adaptors/trace.rs +++ b/src/adaptors/trace.rs @@ -1,6 +1,6 @@ use std::{ fmt::Debug, - future::Future, + future::{Future, IntoFuture}, pin::Pin, task::{self, Poll}, }; @@ -309,6 +309,21 @@ where } } +impl IntoFuture for TraceRequest +where + R: Request, + Output: Debug, + R::Err: Debug, + R::Payload: Debug, +{ + type Output = Result, ::Err>; + type IntoFuture = ::Send; + + fn into_future(self) -> Self::IntoFuture { + self.send() + } +} + #[pin_project::pin_project] pub struct Send where diff --git a/src/bot.rs b/src/bot.rs index 2b3f6893..19bb00d5 100644 --- a/src/bot.rs +++ b/src/bot.rs @@ -29,7 +29,7 @@ const TELOXIDE_TOKEN: &str = "TELOXIDE_TOKEN"; /// use teloxide_core::prelude::*; /// /// let bot = Bot::new("TOKEN"); -/// dbg!(bot.get_me().send().await?); +/// dbg!(bot.get_me().await?); /// # Ok::<_, teloxide_core::RequestError>(()) }; /// ``` /// @@ -158,7 +158,7 @@ impl Bot { /// let url = reqwest::Url::parse("https://localhost/tbas").unwrap(); /// let bot = Bot::new("TOKEN").set_api_url(url); /// // From now all methods will use "https://localhost/tbas" as an API URL. - /// bot.get_me().send().await + /// bot.get_me().await /// # }; /// ``` /// diff --git a/src/codegen.rs b/src/codegen.rs index 5f80912b..c26575f1 100644 --- a/src/codegen.rs +++ b/src/codegen.rs @@ -23,7 +23,7 @@ use xshell::{cmd, Shell}; fn ensure_rustfmt(sh: &Shell) { // FIXME(waffle): find a better way to set toolchain - let toolchain = "nightly-2022-01-17"; + let toolchain = "nightly-2022-09-23"; let version = cmd!(sh, "rustup run {toolchain} rustfmt --version") .read() @@ -38,7 +38,7 @@ fn ensure_rustfmt(sh: &Shell) { } pub fn reformat(text: String) -> String { - let toolchain = "nightly-2022-01-17"; + let toolchain = "nightly-2022-09-23"; let sh = Shell::new().unwrap(); ensure_rustfmt(&sh); diff --git a/src/lib.rs b/src/lib.rs index 4b65f9c9..5e92048c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,10 +7,9 @@ //!```toml //! teloxide_core = "0.7" //! ``` -//! _Compiler support: requires rustc 1.58+_. +//! _Compiler support: requires rustc 1.64+_. //! //! ``` -//! # #[cfg(feature = "auto_send")] //! # async { //! # let chat_id = teloxide_core::types::ChatId(-1); //! use teloxide_core::{ @@ -18,9 +17,7 @@ //! types::{DiceEmoji, ParseMode}, //! }; //! -//! let bot = Bot::from_env() -//! .parse_mode(ParseMode::MarkdownV2) -//! .auto_send(); +//! let bot = Bot::from_env().parse_mode(ParseMode::MarkdownV2); //! //! let me = bot.get_me().await?; //! @@ -46,7 +43,6 @@ //! - `native-tls` = use [`native-tls`] tls implementation (**enabled by //! default**) //! - `rustls` — use [`rustls`] tls implementation -//! - `auto_send` — enables [`AutoSend`] bot adaptor //! - `trace_adaptor` — enables [`Trace`] bot adaptor //! - `erased` — enables [`ErasedRequester`] bot adaptor //! - `throttle` — enables [`Throttle`] bot adaptor @@ -55,6 +51,7 @@ //! - `nightly` — enables nightly-only features, currently: //! - Removes some future boxing using `#![feature(type_alias_impl_trait)]` //! - Used to built docs (`#![feature(doc_cfg, doc_notable_trait)]`) +//! - `auto_send` — enables [`AutoSend`] bot adaptor (deprecated) //! //! [`AutoSend`]: adaptors::AutoSend //! [`Trace`]: adaptors::Trace @@ -93,6 +90,13 @@ #![allow(clippy::return_self_not_must_use)] // Workaround for CI #![allow(rustdoc::bare_urls)] +// FIXME: deal with these lints +#![allow( + clippy::collapsible_str_replace, + clippy::borrow_deref_ref, + clippy::unnecessary_lazy_evaluations, + clippy::derive_partial_eq_without_eq +)] // The internal helper macros. #[macro_use] diff --git a/src/net/download.rs b/src/net/download.rs index da05352d..dcef724f 100644 --- a/src/net/download.rs +++ b/src/net/download.rs @@ -42,7 +42,7 @@ pub trait Download<'w> /// # async fn run() -> Result<(), Box> { /// let bot = Bot::new("TOKEN"); /// - /// let TgFile { file_path, .. } = bot.get_file("*file_id*").send().await?; + /// let TgFile { file_path, .. } = bot.get_file("*file_id*").await?; /// let mut file = File::create("/tmp/test.png").await?; /// bot.download_file(&file_path, &mut file).await?; /// # Ok(()) } diff --git a/src/requests/json.rs b/src/requests/json.rs index fc9e068b..5898cfa2 100644 --- a/src/requests/json.rs +++ b/src/requests/json.rs @@ -1,3 +1,5 @@ +use std::future::IntoFuture; + use serde::{de::DeserializeOwned, Serialize}; use crate::{ @@ -49,6 +51,20 @@ where } } +impl

IntoFuture for JsonRequest

+where + P: 'static, + P: Payload + Serialize, + P::Output: DeserializeOwned, +{ + type Output = Result; + type IntoFuture = ::Send; + + fn into_future(self) -> Self::IntoFuture { + self.send() + } +} + impl

HasPayload for JsonRequest

where P: Payload, diff --git a/src/requests/multipart.rs b/src/requests/multipart.rs index 6aa36dda..6578acd9 100644 --- a/src/requests/multipart.rs +++ b/src/requests/multipart.rs @@ -1,3 +1,5 @@ +use std::future::IntoFuture; + use serde::{de::DeserializeOwned, Serialize}; use crate::{ @@ -50,6 +52,20 @@ where } } +impl

IntoFuture for MultipartRequest

+where + P: 'static, + P: Payload + MultipartPayload + Serialize, + P::Output: DeserializeOwned, +{ + type Output = Result; + type IntoFuture = ::Send; + + fn into_future(self) -> Self::IntoFuture { + self.send() + } +} + impl

HasPayload for MultipartRequest

where P: Payload, diff --git a/src/requests/request.rs b/src/requests/request.rs index ee91232b..bd5113af 100644 --- a/src/requests/request.rs +++ b/src/requests/request.rs @@ -1,7 +1,7 @@ -use std::future::Future; +use std::future::{Future, IntoFuture}; -use either::Either; -use futures::future; +// use either::Either; +// use futures::future; use crate::requests::{HasPayload, Output}; @@ -20,12 +20,11 @@ use crate::requests::{HasPayload, Output}; /// /// [`Throttle`]: crate::adaptors::Throttle #[cfg_attr(all(any(docsrs, dep_docsrs), feature = "nightly"), doc(notable_trait))] -pub trait Request: HasPayload { - /* - * Could be mostly `core::future::IntoFuture` though there is no reason to - * use it before it's integrated in async/await - */ - +pub trait Request +where + Self: HasPayload, + Self: IntoFuture, Self::Err>, IntoFuture = Self::Send>, +{ /// The type of an error that may happen while sending a request to /// Telegram. type Err: std::error::Error + Send; @@ -42,6 +41,7 @@ pub trait Request: HasPayload { /// Send this request. /// /// ## Examples + /// /// ``` /// # async { /// use teloxide_core::{ @@ -56,7 +56,11 @@ pub trait Request: HasPayload { /// // Note: it's recommended to `Requester` instead of creating requests directly /// let method = GetMe::new(); /// let request = JsonRequest::new(bot, method); + /// let request_clone = request.clone(); /// let _: Me = request.send().await.unwrap(); + /// + /// // You can also just await requests, without calling `send`: + /// let _: Me = request_clone.await.unwrap(); /// # }; /// ``` #[must_use = "Futures are lazy and do nothing unless polled or awaited"] @@ -73,6 +77,7 @@ pub trait Request: HasPayload { /// and then serializing it, this method should just serialize the data.) /// /// ## Examples + /// /// ``` /// # async { /// use teloxide_core::{prelude::*, requests::Request, types::ChatId, Bot}; @@ -99,27 +104,30 @@ pub trait Request: HasPayload { } } -impl Request for Either -where - L: Request, - R: Request, -{ - type Err = L::Err; +// FIXME: re-introduce `Either` impls once `Either: IntoFuture` (or make out own +// `Either`) (same for `Requester`) - type Send = future::Either; +// impl Request for Either +// where +// L: Request, +// R: Request, +// { +// type Err = L::Err; - type SendRef = future::Either; +// type Send = future::Either; - fn send(self) -> Self::Send { - self.map_left(<_>::send) - .map_right(<_>::send) - .either(future::Either::Left, future::Either::Right) - } +// type SendRef = future::Either; - fn send_ref(&self) -> Self::SendRef { - self.as_ref() - .map_left(<_>::send_ref) - .map_right(<_>::send_ref) - .either(future::Either::Left, future::Either::Right) - } -} +// fn send(self) -> Self::Send { +// self.map_left(<_>::send) +// .map_right(<_>::send) +// .either(future::Either::Left, future::Either::Right) +// } + +// fn send_ref(&self) -> Self::SendRef { +// self.as_ref() +// .map_left(<_>::send_ref) +// .map_right(<_>::send_ref) +// .either(future::Either::Left, future::Either::Right) +// } +// } diff --git a/src/requests/requester.rs b/src/requests/requester.rs index bafb7b01..874517bf 100644 --- a/src/requests/requester.rs +++ b/src/requests/requester.rs @@ -32,8 +32,7 @@ use crate::{ /// bot.send_message(chat_id, "Text") /// // Optional parameters can be supplied by calling setters /// .parse_mode(ParseMode::Html) -/// // To send request to telegram you need to call `.send()` and await the resulting future -/// .send() +/// // To send request to telegram you need to `.await` the request /// .await?; /// # Ok::<_, teloxide_core::RequestError>(()) /// # }; @@ -51,7 +50,7 @@ use crate::{ /// where /// R: Requester, /// { -/// bot.send_message(chat, "hi").send().await.expect("error") +/// bot.send_message(chat, "hi").await.expect("error") /// } /// ``` #[cfg_attr(all(any(docsrs, dep_docsrs), feature = "nightly"), doc(notable_trait))] @@ -1090,30 +1089,30 @@ where forward_all! {} } -macro_rules! fty_either { - ($T:ident) => { - either::Either - }; -} +// macro_rules! fty_either { +// ($T:ident) => { +// either::Either +// }; +// } -macro_rules! fwd_either { - ($m:ident $this:ident ($($arg:ident : $T:ty),*)) => { - match ($this) { - either::Either::Left(l) => either::Either::Left(l.$m($($arg),*)), - either::Either::Right(r) => either::Either::Right(r.$m($($arg),*)), - } - }; -} +// macro_rules! fwd_either { +// ($m:ident $this:ident ($($arg:ident : $T:ty),*)) => { +// match ($this) { +// either::Either::Left(l) => either::Either::Left(l.$m($($arg),*)), +// either::Either::Right(r) => +// either::Either::Right(r.$m($($arg),*)), } +// }; +// } -impl Requester for either::Either -where - LR: Requester, - RR: Requester, -{ - type Err = LR::Err; +// impl Requester for either::Either +// where +// LR: Requester, +// RR: Requester, +// { +// type Err = LR::Err; - forward_all! { fwd_either, fty_either } -} +// forward_all! { fwd_either, fty_either } +// } #[test] fn codegen_requester_methods() { diff --git a/src/requests/requester_ext.rs b/src/requests/requester_ext.rs index 0bcf438e..35509409 100644 --- a/src/requests/requester_ext.rs +++ b/src/requests/requester_ext.rs @@ -4,6 +4,7 @@ use crate::{adaptors::DefaultParseMode, requests::Requester, types::ParseMode}; use crate::adaptors::CacheMe; #[cfg(feature = "auto_send")] +#[allow(deprecated)] use crate::adaptors::AutoSend; #[cfg(feature = "erased")] @@ -28,6 +29,11 @@ pub trait RequesterExt: Requester { /// Send requests automatically, see [`AutoSend`] for more. #[cfg(feature = "auto_send")] + #[deprecated( + since = "0.8.0", + note = "`AutoSend` is no longer required to `.await` requests and is now noop" + )] + #[allow(deprecated)] fn auto_send(self) -> AutoSend where Self: Sized,