mirror of
https://github.com/teloxide/teloxide.git
synced 2024-12-23 06:51:01 +01:00
Merge branch 'master' into fix_set_webhook_again
This commit is contained in:
commit
3d1cb9c665
24 changed files with 267 additions and 271 deletions
43
.github/workflows/ci.yml
vendored
43
.github/workflows/ci.yml
vendored
|
@ -17,17 +17,12 @@ env:
|
||||||
CARGO_NET_RETRY: 10
|
CARGO_NET_RETRY: 10
|
||||||
RUSTUP_MAX_RETRIES: 10
|
RUSTUP_MAX_RETRIES: 10
|
||||||
|
|
||||||
rust_nightly: nightly-2022-01-17
|
rust_nightly: nightly-2022-09-23
|
||||||
# When updating this, also update:
|
# When updating this, also update:
|
||||||
# - README.md
|
# - README.md
|
||||||
# - src/lib.rs
|
# - src/lib.rs
|
||||||
# - down below in a matrix
|
# - down below in a matrix
|
||||||
rust_msrv: 1.58.0
|
rust_msrv: 1.64.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
|
|
||||||
|
|
||||||
CI: 1
|
CI: 1
|
||||||
|
|
||||||
|
@ -43,7 +38,6 @@ jobs:
|
||||||
- check-examples
|
- check-examples
|
||||||
- clippy
|
- clippy
|
||||||
- doc
|
- doc
|
||||||
- msrv
|
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- run: exit 0
|
- run: exit 0
|
||||||
|
@ -82,7 +76,7 @@ jobs:
|
||||||
- stable
|
- stable
|
||||||
- beta
|
- beta
|
||||||
- nightly
|
- nightly
|
||||||
- msrv_dev
|
- msrv
|
||||||
|
|
||||||
include:
|
include:
|
||||||
- rust: stable
|
- rust: stable
|
||||||
|
@ -92,10 +86,10 @@ jobs:
|
||||||
toolchain: beta
|
toolchain: beta
|
||||||
features: "--features full"
|
features: "--features full"
|
||||||
- rust: nightly
|
- rust: nightly
|
||||||
toolchain: nightly-2022-01-17
|
toolchain: nightly-2022-09-23
|
||||||
features: "--all-features"
|
features: "--all-features"
|
||||||
- rust: msrv_dev
|
- rust: msrv
|
||||||
toolchain: 1.59.0
|
toolchain: 1.64.0
|
||||||
features: "--features full"
|
features: "--features full"
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
|
@ -108,6 +102,7 @@ jobs:
|
||||||
profile: minimal
|
profile: minimal
|
||||||
toolchain: ${{ matrix.toolchain }}
|
toolchain: ${{ matrix.toolchain }}
|
||||||
override: true
|
override: true
|
||||||
|
components: rustfmt # required by codegen
|
||||||
|
|
||||||
- name: Cache Dependencies
|
- name: Cache Dependencies
|
||||||
uses: Swatinem/rust-cache@v1
|
uses: Swatinem/rust-cache@v1
|
||||||
|
@ -194,27 +189,3 @@ jobs:
|
||||||
uses: actions-rs/cargo@v1
|
uses: actions-rs/cargo@v1
|
||||||
with:
|
with:
|
||||||
command: docs # from .cargo/config.toml
|
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
|
|
||||||
|
|
13
CHANGELOG.md
13
CHANGELOG.md
|
@ -7,6 +7,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||||
|
|
||||||
## unreleased
|
## 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
|
### Removed
|
||||||
|
|
||||||
- Methods for creating `InlineQuery` ([#246][pr244])
|
- 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
|
[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
|
## 0.7.1 - 2022-08-19
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
|
@ -24,7 +24,7 @@ exclude = [
|
||||||
futures = "0.3.5"
|
futures = "0.3.5"
|
||||||
tokio = { version = "1.12.0", features = ["fs"] }
|
tokio = { version = "1.12.0", features = ["fs"] }
|
||||||
tokio-util = { version = "0.7.0", features = ["codec"] }
|
tokio-util = { version = "0.7.0", features = ["codec"] }
|
||||||
pin-project = "1.0.3"
|
pin-project = "1.0.12"
|
||||||
bytes = "1.0.0"
|
bytes = "1.0.0"
|
||||||
reqwest = { version = "0.11.10", features = ["json", "stream", "multipart"], default-features = false }
|
reqwest = { version = "0.11.10", features = ["json", "stream", "multipart"], default-features = false }
|
||||||
url = { version = "2", features = ["serde"] }
|
url = { version = "2", features = ["serde"] }
|
||||||
|
@ -99,8 +99,8 @@ cargo-args = ["-Zunstable-options", "-Zrustdoc-scrape-examples=examples"]
|
||||||
|
|
||||||
[[example]]
|
[[example]]
|
||||||
name = "self_info"
|
name = "self_info"
|
||||||
required-features = ["tokio/macros", "tokio/rt-multi-thread", "auto_send"]
|
required-features = ["tokio/macros", "tokio/rt-multi-thread"]
|
||||||
|
|
||||||
[[example]]
|
[[example]]
|
||||||
name = "erased"
|
name = "erased"
|
||||||
required-features = ["tokio/macros", "tokio/rt-multi-thread", "auto_send", "erased"]
|
required-features = ["tokio/macros", "tokio/rt-multi-thread", "erased", "trace_adaptor"]
|
||||||
|
|
|
@ -27,7 +27,7 @@
|
||||||
```toml
|
```toml
|
||||||
teloxide-core = "0.7"
|
teloxide-core = "0.7"
|
||||||
```
|
```
|
||||||
_Compiler support: requires rustc 1.58+_.
|
_Compiler support: requires rustc 1.64+_.
|
||||||
|
|
||||||
[`teloxide`]: https://docs.rs/teloxide
|
[`teloxide`]: https://docs.rs/teloxide
|
||||||
[Telegram Bot API]: https://core.telegram.org/bots/api
|
[Telegram Bot API]: https://core.telegram.org/bots/api
|
||||||
|
|
|
@ -32,9 +32,9 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
log::info!("Trace settings: {:?}", trace_settings);
|
log::info!("Trace settings: {:?}", trace_settings);
|
||||||
|
|
||||||
let bot = if trace_settings.is_empty() {
|
let bot = if trace_settings.is_empty() {
|
||||||
Bot::from_env().erase().auto_send()
|
Bot::from_env().erase()
|
||||||
} else {
|
} 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?;
|
bot.send_chat_action(chat_id, ChatAction::Typing).await?;
|
||||||
|
|
|
@ -13,9 +13,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
.parse::<i64>()?,
|
.parse::<i64>()?,
|
||||||
);
|
);
|
||||||
|
|
||||||
let bot = Bot::from_env()
|
let bot = Bot::from_env().parse_mode(ParseMode::MarkdownV2);
|
||||||
.parse_mode(ParseMode::MarkdownV2)
|
|
||||||
.auto_send();
|
|
||||||
|
|
||||||
let Me { user: me, .. } = bot.get_me().await?;
|
let Me { user: me, .. } = bot.get_me().await?;
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
[toolchain]
|
[toolchain]
|
||||||
channel = "nightly-2022-01-17"
|
channel = "nightly-2022-09-23"
|
||||||
components = ["rustfmt", "clippy"]
|
components = ["rustfmt", "clippy"]
|
||||||
profile = "minimal"
|
profile = "minimal"
|
||||||
|
|
|
@ -3,17 +3,18 @@
|
||||||
//! Bot adaptors are very similar to the [`Iterator`] adaptors: they are bots
|
//! Bot adaptors are very similar to the [`Iterator`] adaptors: they are bots
|
||||||
//! wrapping other bots to alter existing or add new functionality.
|
//! 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
|
//! [`Requester`]: crate::requests::Requester
|
||||||
|
|
||||||
/// [`AutoSend`] bot adaptor which allows sending a request without calling
|
/// [`AutoSend`] bot adaptor which used to allow sending a request without
|
||||||
/// [`send`].
|
/// calling [`send`].
|
||||||
///
|
///
|
||||||
/// [`AutoSend`]: auto_send::AutoSend
|
/// [`AutoSend`]: auto_send::AutoSend
|
||||||
/// [`send`]: crate::requests::Request::send
|
/// [`send`]: crate::requests::Request::send
|
||||||
#[cfg(feature = "auto_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;
|
pub mod auto_send;
|
||||||
|
|
||||||
/// [`CacheMe`] bot adaptor which caches [`GetMe`] requests.
|
/// [`CacheMe`] bot adaptor which caches [`GetMe`] requests.
|
||||||
|
@ -47,6 +48,7 @@ pub mod throttle;
|
||||||
mod parse_mode;
|
mod parse_mode;
|
||||||
|
|
||||||
#[cfg(feature = "auto_send")]
|
#[cfg(feature = "auto_send")]
|
||||||
|
#[allow(deprecated)]
|
||||||
pub use auto_send::AutoSend;
|
pub use auto_send::AutoSend;
|
||||||
#[cfg(feature = "cache_me")]
|
#[cfg(feature = "cache_me")]
|
||||||
pub use cache_me::CacheMe;
|
pub use cache_me::CacheMe;
|
||||||
|
|
|
@ -1,10 +1,5 @@
|
||||||
use std::{
|
use std::future::IntoFuture;
|
||||||
future::Future,
|
|
||||||
pin::Pin,
|
|
||||||
task::{Context, Poll},
|
|
||||||
};
|
|
||||||
|
|
||||||
use futures::future::FusedFuture;
|
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
@ -12,32 +7,16 @@ use crate::{
|
||||||
types::*,
|
types::*,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Send requests automatically.
|
/// Previously was used to send requests automatically.
|
||||||
///
|
///
|
||||||
/// Requests returned by `<AutoSend<_> as `[`Requester`]`>` are [`Future`]s
|
/// Before addition of [`IntoFuture`] you could only `.await` [`Future`]s.
|
||||||
/// which means that you can simply `.await` them instead of using
|
/// This adaptor turned requests into futures, allowing to `.await` them,
|
||||||
/// `.send().await`.
|
/// without calling `.send()`.
|
||||||
///
|
///
|
||||||
/// Notes:
|
/// Now, however, all requests are required to implement `IntoFuture`, allowing
|
||||||
/// 1. This wrapper should be the most outer i.e.: `AutoSend<CacheMe<Bot>>`
|
/// you to `.await` them directly. This adaptor is noop, and shouldn't be used.
|
||||||
/// 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).
|
|
||||||
///
|
///
|
||||||
/// ## Examples
|
/// [`Future`]: std::future::Future
|
||||||
///
|
|
||||||
/// ```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>(()) };
|
|
||||||
/// ```
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct AutoSend<B> {
|
pub struct AutoSend<B> {
|
||||||
bot: B,
|
bot: B,
|
||||||
|
@ -192,33 +171,17 @@ download_forward! {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[must_use = "Futures are lazy and do nothing unless polled or awaited"]
|
#[must_use = "Futures are lazy and do nothing unless polled or awaited"]
|
||||||
#[pin_project::pin_project]
|
pub struct AutoRequest<R>(R);
|
||||||
pub struct AutoRequest<R: Request>(#[pin] Inner<R>);
|
|
||||||
|
|
||||||
impl<R> AutoRequest<R>
|
impl<R> AutoRequest<R>
|
||||||
where
|
where
|
||||||
R: Request,
|
R: Request,
|
||||||
{
|
{
|
||||||
pub fn new(inner: R) -> Self {
|
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>
|
impl<R> Request for AutoRequest<R>
|
||||||
where
|
where
|
||||||
R: Request,
|
R: Request,
|
||||||
|
@ -228,19 +191,20 @@ where
|
||||||
type SendRef = R::SendRef;
|
type SendRef = R::SendRef;
|
||||||
|
|
||||||
fn send(self) -> Self::Send {
|
fn send(self) -> Self::Send {
|
||||||
match self.0 {
|
self.0.send()
|
||||||
Inner::Request(req) => req.send(),
|
|
||||||
Inner::Future(fut) => fut,
|
|
||||||
Inner::Done => done_unreachable(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn send_ref(&self) -> Self::SendRef {
|
fn send_ref(&self) -> Self::SendRef {
|
||||||
match &self.0 {
|
self.0.send_ref()
|
||||||
Inner::Request(req) => req.send_ref(),
|
|
||||||
Inner::Future(_) => already_polled(),
|
|
||||||
Inner::Done => done_unreachable(),
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
type Payload = R::Payload;
|
||||||
|
|
||||||
fn payload_mut(&mut self) -> &mut Self::Payload {
|
fn payload_mut(&mut self) -> &mut Self::Payload {
|
||||||
match &mut self.0 {
|
self.0.payload_mut()
|
||||||
Inner::Request(req) => req.payload_mut(),
|
|
||||||
Inner::Future(_) => already_polled(),
|
|
||||||
Inner::Done => done_unreachable(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn payload_ref(&self) -> &Self::Payload {
|
fn payload_ref(&self) -> &Self::Payload {
|
||||||
match &self.0 {
|
self.0.payload_ref()
|
||||||
Inner::Request(req) => req.payload_ref(),
|
|
||||||
Inner::Future(_) => already_polled(),
|
|
||||||
Inner::Done => done_unreachable(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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")
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use std::{pin::Pin, sync::Arc};
|
use std::{future::IntoFuture, pin::Pin, sync::Arc};
|
||||||
|
|
||||||
use futures::{
|
use futures::{
|
||||||
future,
|
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>>;
|
type ReadyMe<Err> = Ready<Result<Me, Err>>;
|
||||||
|
|
||||||
#[pin_project::pin_project]
|
#[pin_project::pin_project]
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use std::sync::Arc;
|
use std::{future::IntoFuture, sync::Arc};
|
||||||
|
|
||||||
use futures::{future::BoxFuture, FutureExt};
|
use futures::{future::BoxFuture, FutureExt};
|
||||||
use reqwest::Url;
|
use reqwest::Url;
|
||||||
|
@ -51,7 +51,8 @@ pub struct ErasedRequest<'a, T, E> {
|
||||||
inner: Box<dyn ErasableRequest<'a, Payload = T, Err = E> + 'a>,
|
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 {
|
pub(crate) fn erase(request: impl Request<Payload = T, Err = E> + 'a) -> Self {
|
||||||
Self {
|
Self {
|
||||||
inner: Box::new(request),
|
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`].
|
/// Object safe version of [`Request`].
|
||||||
///
|
///
|
||||||
/// TODO(waffle): make [`Request`] object safe and remove this trait (this is a
|
/// TODO(waffle): make [`Request`] object safe and remove this trait (this is a
|
||||||
|
|
|
@ -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::{
|
use futures::{
|
||||||
future::BoxFuture,
|
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>
|
impl<R: Request> Future for ThrottlingSend<R>
|
||||||
where
|
where
|
||||||
R::Err: AsResponseParameters,
|
R::Err: AsResponseParameters,
|
||||||
|
@ -159,7 +178,7 @@ where
|
||||||
|
|
||||||
let res = match &mut request {
|
let res = match &mut request {
|
||||||
ShareableRequest::Shared(shared) => shared.send_ref().await,
|
ShareableRequest::Shared(shared) => shared.send_ref().await,
|
||||||
ShareableRequest::Owned(owned) => owned.take().unwrap().send().await,
|
ShareableRequest::Owned(owned) => owned.take().unwrap().await,
|
||||||
};
|
};
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
|
@ -178,7 +197,7 @@ where
|
||||||
request.send_ref().await
|
request.send_ref().await
|
||||||
}
|
}
|
||||||
(false, ShareableRequest::Shared(shared)) => shared.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);
|
let retry_after = res.as_ref().err().and_then(<_>::retry_after);
|
||||||
|
|
|
@ -9,7 +9,7 @@ use vecrem::VecExt;
|
||||||
use crate::{
|
use crate::{
|
||||||
adaptors::throttle::{request_lock::RequestLock, ChatIdHash, Limits, Settings},
|
adaptors::throttle::{request_lock::RequestLock, ChatIdHash, Limits, Settings},
|
||||||
errors::AsResponseParameters,
|
errors::AsResponseParameters,
|
||||||
requests::{Request, Requester},
|
requests::Requester,
|
||||||
};
|
};
|
||||||
|
|
||||||
const MINUTE: Duration = Duration::from_secs(60);
|
const MINUTE: Duration = Duration::from_secs(60);
|
||||||
|
@ -321,7 +321,7 @@ async fn freeze(
|
||||||
// TODO: maybe not call `get_chat` every time?
|
// TODO: maybe not call `get_chat` every time?
|
||||||
|
|
||||||
// At this point there isn't much we can do with the error besides ignoring
|
// 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() {
|
match chat.slow_mode_delay() {
|
||||||
Some(delay) => {
|
Some(delay) => {
|
||||||
let now = Instant::now();
|
let now = Instant::now();
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use std::{
|
use std::{
|
||||||
fmt::Debug,
|
fmt::Debug,
|
||||||
future::Future,
|
future::{Future, IntoFuture},
|
||||||
pin::Pin,
|
pin::Pin,
|
||||||
task::{self, Poll},
|
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]
|
#[pin_project::pin_project]
|
||||||
pub struct Send<F>
|
pub struct Send<F>
|
||||||
where
|
where
|
||||||
|
|
|
@ -29,7 +29,7 @@ const TELOXIDE_TOKEN: &str = "TELOXIDE_TOKEN";
|
||||||
/// use teloxide_core::prelude::*;
|
/// use teloxide_core::prelude::*;
|
||||||
///
|
///
|
||||||
/// let bot = Bot::new("TOKEN");
|
/// let bot = Bot::new("TOKEN");
|
||||||
/// dbg!(bot.get_me().send().await?);
|
/// dbg!(bot.get_me().await?);
|
||||||
/// # Ok::<_, teloxide_core::RequestError>(()) };
|
/// # Ok::<_, teloxide_core::RequestError>(()) };
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
|
@ -158,7 +158,7 @@ impl Bot {
|
||||||
/// let url = reqwest::Url::parse("https://localhost/tbas").unwrap();
|
/// let url = reqwest::Url::parse("https://localhost/tbas").unwrap();
|
||||||
/// let bot = Bot::new("TOKEN").set_api_url(url);
|
/// let bot = Bot::new("TOKEN").set_api_url(url);
|
||||||
/// // From now all methods will use "https://localhost/tbas" as an API URL.
|
/// // From now all methods will use "https://localhost/tbas" as an API URL.
|
||||||
/// bot.get_me().send().await
|
/// bot.get_me().await
|
||||||
/// # };
|
/// # };
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
|
|
|
@ -23,7 +23,7 @@ use xshell::{cmd, Shell};
|
||||||
|
|
||||||
fn ensure_rustfmt(sh: &Shell) {
|
fn ensure_rustfmt(sh: &Shell) {
|
||||||
// FIXME(waffle): find a better way to set toolchain
|
// 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")
|
let version = cmd!(sh, "rustup run {toolchain} rustfmt --version")
|
||||||
.read()
|
.read()
|
||||||
|
@ -38,7 +38,7 @@ fn ensure_rustfmt(sh: &Shell) {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn reformat(text: String) -> String {
|
pub fn reformat(text: String) -> String {
|
||||||
let toolchain = "nightly-2022-01-17";
|
let toolchain = "nightly-2022-09-23";
|
||||||
|
|
||||||
let sh = Shell::new().unwrap();
|
let sh = Shell::new().unwrap();
|
||||||
ensure_rustfmt(&sh);
|
ensure_rustfmt(&sh);
|
||||||
|
|
16
src/lib.rs
16
src/lib.rs
|
@ -7,10 +7,9 @@
|
||||||
//!```toml
|
//!```toml
|
||||||
//! teloxide_core = "0.7"
|
//! teloxide_core = "0.7"
|
||||||
//! ```
|
//! ```
|
||||||
//! _Compiler support: requires rustc 1.58+_.
|
//! _Compiler support: requires rustc 1.64+_.
|
||||||
//!
|
//!
|
||||||
//! ```
|
//! ```
|
||||||
//! # #[cfg(feature = "auto_send")]
|
|
||||||
//! # async {
|
//! # async {
|
||||||
//! # let chat_id = teloxide_core::types::ChatId(-1);
|
//! # let chat_id = teloxide_core::types::ChatId(-1);
|
||||||
//! use teloxide_core::{
|
//! use teloxide_core::{
|
||||||
|
@ -18,9 +17,7 @@
|
||||||
//! types::{DiceEmoji, ParseMode},
|
//! types::{DiceEmoji, ParseMode},
|
||||||
//! };
|
//! };
|
||||||
//!
|
//!
|
||||||
//! let bot = Bot::from_env()
|
//! let bot = Bot::from_env().parse_mode(ParseMode::MarkdownV2);
|
||||||
//! .parse_mode(ParseMode::MarkdownV2)
|
|
||||||
//! .auto_send();
|
|
||||||
//!
|
//!
|
||||||
//! let me = bot.get_me().await?;
|
//! let me = bot.get_me().await?;
|
||||||
//!
|
//!
|
||||||
|
@ -46,7 +43,6 @@
|
||||||
//! - `native-tls` = use [`native-tls`] tls implementation (**enabled by
|
//! - `native-tls` = use [`native-tls`] tls implementation (**enabled by
|
||||||
//! default**)
|
//! default**)
|
||||||
//! - `rustls` — use [`rustls`] tls implementation
|
//! - `rustls` — use [`rustls`] tls implementation
|
||||||
//! - `auto_send` — enables [`AutoSend`] bot adaptor
|
|
||||||
//! - `trace_adaptor` — enables [`Trace`] bot adaptor
|
//! - `trace_adaptor` — enables [`Trace`] bot adaptor
|
||||||
//! - `erased` — enables [`ErasedRequester`] bot adaptor
|
//! - `erased` — enables [`ErasedRequester`] bot adaptor
|
||||||
//! - `throttle` — enables [`Throttle`] bot adaptor
|
//! - `throttle` — enables [`Throttle`] bot adaptor
|
||||||
|
@ -55,6 +51,7 @@
|
||||||
//! - `nightly` — enables nightly-only features, currently:
|
//! - `nightly` — enables nightly-only features, currently:
|
||||||
//! - Removes some future boxing using `#![feature(type_alias_impl_trait)]`
|
//! - Removes some future boxing using `#![feature(type_alias_impl_trait)]`
|
||||||
//! - Used to built docs (`#![feature(doc_cfg, doc_notable_trait)]`)
|
//! - Used to built docs (`#![feature(doc_cfg, doc_notable_trait)]`)
|
||||||
|
//! - `auto_send` — enables [`AutoSend`] bot adaptor (deprecated)
|
||||||
//!
|
//!
|
||||||
//! [`AutoSend`]: adaptors::AutoSend
|
//! [`AutoSend`]: adaptors::AutoSend
|
||||||
//! [`Trace`]: adaptors::Trace
|
//! [`Trace`]: adaptors::Trace
|
||||||
|
@ -93,6 +90,13 @@
|
||||||
#![allow(clippy::return_self_not_must_use)]
|
#![allow(clippy::return_self_not_must_use)]
|
||||||
// Workaround for CI
|
// Workaround for CI
|
||||||
#![allow(rustdoc::bare_urls)]
|
#![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.
|
// The internal helper macros.
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
|
|
|
@ -42,7 +42,7 @@ pub trait Download<'w>
|
||||||
/// # async fn run() -> Result<(), Box<dyn std::error::Error>> {
|
/// # async fn run() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
/// let bot = Bot::new("TOKEN");
|
/// 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?;
|
/// let mut file = File::create("/tmp/test.png").await?;
|
||||||
/// bot.download_file(&file_path, &mut file).await?;
|
/// bot.download_file(&file_path, &mut file).await?;
|
||||||
/// # Ok(()) }
|
/// # Ok(()) }
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
use std::future::IntoFuture;
|
||||||
|
|
||||||
use serde::{de::DeserializeOwned, Serialize};
|
use serde::{de::DeserializeOwned, Serialize};
|
||||||
|
|
||||||
use crate::{
|
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>
|
impl<P> HasPayload for JsonRequest<P>
|
||||||
where
|
where
|
||||||
P: Payload,
|
P: Payload,
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
use std::future::IntoFuture;
|
||||||
|
|
||||||
use serde::{de::DeserializeOwned, Serialize};
|
use serde::{de::DeserializeOwned, Serialize};
|
||||||
|
|
||||||
use crate::{
|
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>
|
impl<P> HasPayload for MultipartRequest<P>
|
||||||
where
|
where
|
||||||
P: Payload,
|
P: Payload,
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use std::future::Future;
|
use std::future::{Future, IntoFuture};
|
||||||
|
|
||||||
use either::Either;
|
// use either::Either;
|
||||||
use futures::future;
|
// use futures::future;
|
||||||
|
|
||||||
use crate::requests::{HasPayload, Output};
|
use crate::requests::{HasPayload, Output};
|
||||||
|
|
||||||
|
@ -20,12 +20,11 @@ use crate::requests::{HasPayload, Output};
|
||||||
///
|
///
|
||||||
/// [`Throttle<B>`]: crate::adaptors::Throttle
|
/// [`Throttle<B>`]: crate::adaptors::Throttle
|
||||||
#[cfg_attr(all(any(docsrs, dep_docsrs), feature = "nightly"), doc(notable_trait))]
|
#[cfg_attr(all(any(docsrs, dep_docsrs), feature = "nightly"), doc(notable_trait))]
|
||||||
pub trait Request: HasPayload {
|
pub trait Request
|
||||||
/*
|
where
|
||||||
* Could be mostly `core::future::IntoFuture` though there is no reason to
|
Self: HasPayload,
|
||||||
* use it before it's integrated in async/await
|
Self: IntoFuture<Output = Result<Output<Self>, Self::Err>, IntoFuture = Self::Send>,
|
||||||
*/
|
{
|
||||||
|
|
||||||
/// The type of an error that may happen while sending a request to
|
/// The type of an error that may happen while sending a request to
|
||||||
/// Telegram.
|
/// Telegram.
|
||||||
type Err: std::error::Error + Send;
|
type Err: std::error::Error + Send;
|
||||||
|
@ -42,6 +41,7 @@ pub trait Request: HasPayload {
|
||||||
/// Send this request.
|
/// Send this request.
|
||||||
///
|
///
|
||||||
/// ## Examples
|
/// ## Examples
|
||||||
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # async {
|
/// # async {
|
||||||
/// use teloxide_core::{
|
/// use teloxide_core::{
|
||||||
|
@ -56,7 +56,11 @@ pub trait Request: HasPayload {
|
||||||
/// // Note: it's recommended to `Requester` instead of creating requests directly
|
/// // Note: it's recommended to `Requester` instead of creating requests directly
|
||||||
/// let method = GetMe::new();
|
/// let method = GetMe::new();
|
||||||
/// let request = JsonRequest::new(bot, method);
|
/// let request = JsonRequest::new(bot, method);
|
||||||
|
/// let request_clone = request.clone();
|
||||||
/// let _: Me = request.send().await.unwrap();
|
/// 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"]
|
#[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.)
|
/// and then serializing it, this method should just serialize the data.)
|
||||||
///
|
///
|
||||||
/// ## Examples
|
/// ## Examples
|
||||||
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # async {
|
/// # async {
|
||||||
/// use teloxide_core::{prelude::*, requests::Request, types::ChatId, Bot};
|
/// 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>
|
// FIXME: re-introduce `Either` impls once `Either: IntoFuture` (or make out own
|
||||||
where
|
// `Either`) (same for `Requester`)
|
||||||
L: Request,
|
|
||||||
R: Request<Payload = L::Payload, Err = L::Err>,
|
|
||||||
{
|
|
||||||
type Err = L::Err;
|
|
||||||
|
|
||||||
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 {
|
// type SendRef = future::Either<L::SendRef, R::SendRef>;
|
||||||
self.map_left(<_>::send)
|
|
||||||
.map_right(<_>::send)
|
|
||||||
.either(future::Either::Left, future::Either::Right)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn send_ref(&self) -> Self::SendRef {
|
// fn send(self) -> Self::Send {
|
||||||
self.as_ref()
|
// self.map_left(<_>::send)
|
||||||
.map_left(<_>::send_ref)
|
// .map_right(<_>::send)
|
||||||
.map_right(<_>::send_ref)
|
// .either(future::Either::Left, future::Either::Right)
|
||||||
.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)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
|
@ -32,8 +32,7 @@ use crate::{
|
||||||
/// bot.send_message(chat_id, "<b>Text</b>")
|
/// bot.send_message(chat_id, "<b>Text</b>")
|
||||||
/// // Optional parameters can be supplied by calling setters
|
/// // Optional parameters can be supplied by calling setters
|
||||||
/// .parse_mode(ParseMode::Html)
|
/// .parse_mode(ParseMode::Html)
|
||||||
/// // To send request to telegram you need to call `.send()` and await the resulting future
|
/// // To send request to telegram you need to `.await` the request
|
||||||
/// .send()
|
|
||||||
/// .await?;
|
/// .await?;
|
||||||
/// # Ok::<_, teloxide_core::RequestError>(())
|
/// # Ok::<_, teloxide_core::RequestError>(())
|
||||||
/// # };
|
/// # };
|
||||||
|
@ -51,7 +50,7 @@ use crate::{
|
||||||
/// where
|
/// where
|
||||||
/// R: Requester,
|
/// 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))]
|
#[cfg_attr(all(any(docsrs, dep_docsrs), feature = "nightly"), doc(notable_trait))]
|
||||||
|
@ -1090,30 +1089,30 @@ where
|
||||||
forward_all! {}
|
forward_all! {}
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! fty_either {
|
// macro_rules! fty_either {
|
||||||
($T:ident) => {
|
// ($T:ident) => {
|
||||||
either::Either<LR::$T, RR::$T>
|
// either::Either<LR::$T, RR::$T>
|
||||||
};
|
// };
|
||||||
}
|
// }
|
||||||
|
|
||||||
macro_rules! fwd_either {
|
// macro_rules! fwd_either {
|
||||||
($m:ident $this:ident ($($arg:ident : $T:ty),*)) => {
|
// ($m:ident $this:ident ($($arg:ident : $T:ty),*)) => {
|
||||||
match ($this) {
|
// match ($this) {
|
||||||
either::Either::Left(l) => either::Either::Left(l.$m($($arg),*)),
|
// either::Either::Left(l) => either::Either::Left(l.$m($($arg),*)),
|
||||||
either::Either::Right(r) => either::Either::Right(r.$m($($arg),*)),
|
// either::Either::Right(r) =>
|
||||||
}
|
// either::Either::Right(r.$m($($arg),*)), }
|
||||||
};
|
// };
|
||||||
}
|
// }
|
||||||
|
|
||||||
impl<LR, RR> Requester for either::Either<LR, RR>
|
// impl<LR, RR> Requester for either::Either<LR, RR>
|
||||||
where
|
// where
|
||||||
LR: Requester,
|
// LR: Requester,
|
||||||
RR: Requester<Err = LR::Err>,
|
// RR: Requester<Err = LR::Err>,
|
||||||
{
|
// {
|
||||||
type Err = LR::Err;
|
// type Err = LR::Err;
|
||||||
|
|
||||||
forward_all! { fwd_either, fty_either }
|
// forward_all! { fwd_either, fty_either }
|
||||||
}
|
// }
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn codegen_requester_methods() {
|
fn codegen_requester_methods() {
|
||||||
|
|
|
@ -4,6 +4,7 @@ use crate::{adaptors::DefaultParseMode, requests::Requester, types::ParseMode};
|
||||||
use crate::adaptors::CacheMe;
|
use crate::adaptors::CacheMe;
|
||||||
|
|
||||||
#[cfg(feature = "auto_send")]
|
#[cfg(feature = "auto_send")]
|
||||||
|
#[allow(deprecated)]
|
||||||
use crate::adaptors::AutoSend;
|
use crate::adaptors::AutoSend;
|
||||||
|
|
||||||
#[cfg(feature = "erased")]
|
#[cfg(feature = "erased")]
|
||||||
|
@ -28,6 +29,11 @@ pub trait RequesterExt: Requester {
|
||||||
|
|
||||||
/// Send requests automatically, see [`AutoSend`] for more.
|
/// Send requests automatically, see [`AutoSend`] for more.
|
||||||
#[cfg(feature = "auto_send")]
|
#[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>
|
fn auto_send(self) -> AutoSend<Self>
|
||||||
where
|
where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
|
|
|
@ -17,26 +17,8 @@ pub struct KeyboardButton {
|
||||||
|
|
||||||
/// Request something from user. This is available in private chats only.
|
/// 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
|
/// See [`ButtonRequest`] documentation for options on what can be
|
||||||
/// when the button is pressed.
|
/// requested.
|
||||||
/// - 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.
|
|
||||||
#[serde(flatten)]
|
#[serde(flatten)]
|
||||||
pub request: Option<ButtonRequest>,
|
pub request: Option<ButtonRequest>,
|
||||||
}
|
}
|
||||||
|
@ -61,13 +43,38 @@ impl KeyboardButton {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Serialize + Deserialize are implemented by hand
|
/// Request something from user, when a button is pressed.
|
||||||
// FIXME: add documentation
|
///
|
||||||
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
|
/// See individual variants documentation for more info.
|
||||||
|
#[derive(Clone, Debug, Eq, Hash, PartialEq /*, Serialize, Deserialize */)]
|
||||||
pub enum ButtonRequest {
|
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,
|
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,
|
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),
|
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),
|
WebApp(WebAppInfo),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue