Merge branch 'master' into fix_set_webhook_again

This commit is contained in:
Hirrolot 2022-09-25 07:19:01 +06:00 committed by GitHub
commit 3d1cb9c665
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
24 changed files with 267 additions and 271 deletions

View file

@ -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

View file

@ -7,6 +7,13 @@ 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])
@ -19,6 +26,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
[pr250]: https://github.com/teloxide/teloxide-core/pull/250
### Deprecated
- `AutoSend` adaptor ([#249][pr249])
[pr249]: https://github.com/teloxide/teloxide-core/pull/249
## 0.7.1 - 2022-08-19
### Fixed

View file

@ -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"]

View file

@ -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

View file

@ -32,9 +32,9 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
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?;

View file

@ -13,9 +13,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
.parse::<i64>()?,
);
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?;

View file

@ -1,4 +1,4 @@
[toolchain]
channel = "nightly-2022-01-17"
channel = "nightly-2022-09-23"
components = ["rustfmt", "clippy"]
profile = "minimal"

View file

@ -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;

View file

@ -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 `<AutoSend<_> 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<CacheMe<Bot>>`
/// will automatically send requests, while `CacheMe<AutoSend<Bot>>` - 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<B> {
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<R: Request>(#[pin] Inner<R>);
pub struct AutoRequest<R>(R);
impl<R> AutoRequest<R>
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<R: Request> {
/// 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<R> Request for AutoRequest<R>
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<R: Request> IntoFuture for AutoRequest<R> {
type Output = Result<Output<Self>, <Self as Request>::Err>;
type IntoFuture = <Self as Request>::Send;
fn into_future(self) -> Self::IntoFuture {
self.send()
}
}
@ -248,75 +212,10 @@ impl<R: Request> HasPayload for AutoRequest<R> {
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<R: Request> Future for AutoRequest<R> {
type Output = Result<Output<R>, R::Err>;
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
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<R: Request> FusedFuture for AutoRequest<R> {
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")
}

View file

@ -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<R: Request<Payload = GetMe>> HasPayload for CachedMeRequest<R> {
}
}
impl<R: Request<Payload = GetMe>> IntoFuture for CachedMeRequest<R> {
type Output = Result<Me, R::Err>;
type IntoFuture = Send<R>;
fn into_future(self) -> Self::IntoFuture {
self.send()
}
}
type ReadyMe<Err> = Ready<Result<Me, Err>>;
#[pin_project::pin_project]

View file

@ -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<dyn ErasableRequest<'a, Payload = T, Err = E> + 'a>,
}
impl<'a, T, E> ErasedRequest<'a, T, E> {
// `T: Payload` required b/c of <https://github.com/rust-lang/rust/issues/102185>
impl<'a, T: Payload, E> ErasedRequest<'a, T, E> {
pub(crate) fn erase(request: impl Request<Payload = T, Err = E> + '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<Output<Self>, <Self as Request>::Err>;
type IntoFuture = <Self as Request>::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

View file

@ -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<R> IntoFuture for ThrottlingRequest<R>
where
R: Request + Clone + Send + Sync + 'static,
R::Err: AsResponseParameters + Send,
Output<R>: Send,
{
type Output = Result<Output<Self>, <Self as Request>::Err>;
type IntoFuture = <Self as Request>::Send;
fn into_future(self) -> Self::IntoFuture {
self.send()
}
}
impl<R: Request> Future for ThrottlingSend<R>
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);

View file

@ -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();

View file

@ -1,6 +1,6 @@
use std::{
fmt::Debug,
future::Future,
future::{Future, IntoFuture},
pin::Pin,
task::{self, Poll},
};
@ -309,6 +309,21 @@ where
}
}
impl<R> IntoFuture for TraceRequest<R>
where
R: Request,
Output<R>: Debug,
R::Err: Debug,
R::Payload: Debug,
{
type Output = Result<Output<Self>, <Self as Request>::Err>;
type IntoFuture = <Self as Request>::Send;
fn into_future(self) -> Self::IntoFuture {
self.send()
}
}
#[pin_project::pin_project]
pub struct Send<F>
where

View file

@ -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
/// # };
/// ```
///

View file

@ -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);

View file

@ -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]

View file

@ -42,7 +42,7 @@ pub trait Download<'w>
/// # async fn run() -> Result<(), Box<dyn std::error::Error>> {
/// 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(()) }

View file

@ -1,3 +1,5 @@
use std::future::IntoFuture;
use serde::{de::DeserializeOwned, Serialize};
use crate::{
@ -49,6 +51,20 @@ where
}
}
impl<P> IntoFuture for JsonRequest<P>
where
P: 'static,
P: Payload + Serialize,
P::Output: DeserializeOwned,
{
type Output = Result<P::Output, RequestError>;
type IntoFuture = <Self as Request>::Send;
fn into_future(self) -> Self::IntoFuture {
self.send()
}
}
impl<P> HasPayload for JsonRequest<P>
where
P: Payload,

View file

@ -1,3 +1,5 @@
use std::future::IntoFuture;
use serde::{de::DeserializeOwned, Serialize};
use crate::{
@ -50,6 +52,20 @@ where
}
}
impl<P> IntoFuture for MultipartRequest<P>
where
P: 'static,
P: Payload + MultipartPayload + Serialize,
P::Output: DeserializeOwned,
{
type Output = Result<P::Output, RequestError>;
type IntoFuture = <Self as Request>::Send;
fn into_future(self) -> Self::IntoFuture {
self.send()
}
}
impl<P> HasPayload for MultipartRequest<P>
where
P: Payload,

View file

@ -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<B>`]: 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<Output = Result<Output<Self>, 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<L, R> Request for Either<L, R>
where
L: Request,
R: Request<Payload = L::Payload, Err = L::Err>,
{
type Err = L::Err;
// FIXME: re-introduce `Either` impls once `Either: IntoFuture` (or make out own
// `Either`) (same for `Requester`)
type Send = future::Either<L::Send, R::Send>;
// impl<L, R> Request for Either<L, R>
// where
// L: Request,
// R: Request<Payload = L::Payload, Err = L::Err>,
// {
// type Err = L::Err;
type SendRef = future::Either<L::SendRef, R::SendRef>;
// type Send = future::Either<L::Send, R::Send>;
fn send(self) -> Self::Send {
self.map_left(<_>::send)
.map_right(<_>::send)
.either(future::Either::Left, future::Either::Right)
}
// type SendRef = future::Either<L::SendRef, R::SendRef>;
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)
// }
// }

View file

@ -32,8 +32,7 @@ use crate::{
/// bot.send_message(chat_id, "<b>Text</b>")
/// // 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<LR::$T, RR::$T>
};
}
// macro_rules! fty_either {
// ($T:ident) => {
// either::Either<LR::$T, RR::$T>
// };
// }
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<LR, RR> Requester for either::Either<LR, RR>
where
LR: Requester,
RR: Requester<Err = LR::Err>,
{
type Err = LR::Err;
// impl<LR, RR> Requester for either::Either<LR, RR>
// where
// LR: Requester,
// RR: Requester<Err = LR::Err>,
// {
// type Err = LR::Err;
forward_all! { fwd_either, fty_either }
}
// forward_all! { fwd_either, fty_either }
// }
#[test]
fn codegen_requester_methods() {

View file

@ -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<Self>
where
Self: Sized,

View file

@ -17,26 +17,8 @@ pub struct KeyboardButton {
/// Request something from user. This is available in private chats only.
///
/// - If `Some(Contact)`, the user's phone number will be sent as a contact
/// when the button is pressed.
/// - If `Some(Location)`, the user's current location will be sent when the
/// button is pressed.
/// - If `Some(Poll(_))`, the user will be asked to create a poll and send
/// it to the bot when the button is pressed.
/// - If `Some(WebApp(_))`, the described Web App will be launched when the
/// button is pressed. The Web App will be able to send a “web_app_data”
/// service message.
///
/// **Note:** `Contact` and `Location` options will only work in Telegram
/// versions released after 9 April, 2016. Older clients will display
/// unsupported message.
///
/// **Note:** `Poll(_)` option will only work in Telegram versions released
/// after 23 January, 2020. Older clients will display unsupported message.
///
/// **Note:** `WebApp(_)` option will only work in Telegram versions
/// released after 16 April, 2022. Older clients will display unsupported
/// message.
/// See [`ButtonRequest`] documentation for options on what can be
/// requested.
#[serde(flatten)]
pub request: Option<ButtonRequest>,
}
@ -61,13 +43,38 @@ impl KeyboardButton {
}
}
// Serialize + Deserialize are implemented by hand
// FIXME: add documentation
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
/// Request something from user, when a button is pressed.
///
/// See individual variants documentation for more info.
#[derive(Clone, Debug, Eq, Hash, PartialEq /*, Serialize, Deserialize */)]
pub enum ButtonRequest {
/// If this variant is used, the user's current location will be sent when
/// the button is pressed.
///
/// **Note:** this option will only work in Telegram versions released after
/// 9 April, 2016. Older clients will display unsupported message.
Location,
/// If this variant is used, the user's phone number will be sent as a
/// contact when the button is pressed.
///
/// **Note:** this option will only work in Telegram versions released after
/// 9 April, 2016. Older clients will display unsupported message.
Contact,
/// If this variant is used, the user will be asked to create a poll and
/// send it to the bot when the button is pressed.
///
/// **Note:** this option will only work in Telegram versions released after
/// 23 January, 2020. Older clients will display unsupported message.
Poll(KeyboardButtonPollType),
/// If this variant is used, the described Web App will be launched when the
/// button is pressed. The Web App will be able to send a “web_app_data”
/// service message.
///
/// **Note:** this option will only work in Telegram versions released after
/// 16 April, 2022. Older clients will display unsupported message.
WebApp(WebAppInfo),
}