Merge branch 'master' into add-tracing

This commit is contained in:
aon 2023-10-01 11:28:01 -03:00
commit f69be7e4bb
155 changed files with 2579 additions and 1515 deletions

View file

@ -19,12 +19,12 @@ env:
# When updating this, also update:
# - crates/teloxide-core/src/codegen.rs
# - rust-toolchain.toml
rust_nightly: nightly-2022-12-23
rust_nightly: nightly-2023-09-27
# When updating this, also update:
# - **/README.md
# - **/src/lib.rs
# - down below in a matrix
rust_msrv: 1.64.0
rust_msrv: 1.65.0
CI: 1
@ -53,33 +53,29 @@ jobs:
uses: actions/checkout@v3
- name: Install Rust ${{ env.rust_nightly }}
uses: actions-rs/toolchain@v1
uses: dtolnay/rust-toolchain@master
with:
profile: minimal
toolchain: ${{ env.rust_nightly }}
override: true
components: rustfmt
- name: Cache Dependencies
uses: Swatinem/rust-cache@v1
uses: Swatinem/rust-cache@v2
- name: Check formatting
uses: actions-rs/cargo@v1
with:
command: fmt
args: --all -- --check
run: |
cargo fmt --all -- --check
test:
name: Test
runs-on: ubuntu-latest
strategy:
matrix:
rust:
rust:
- stable
- beta
- nightly
- msrv
include:
- rust: stable
toolchain: stable
@ -88,32 +84,28 @@ jobs:
toolchain: beta
features: "--features full"
- rust: nightly
toolchain: nightly-2022-12-23
toolchain: nightly-2023-09-27
features: "--features full nightly"
- rust: msrv
toolchain: 1.64.0
toolchain: 1.65.0
features: "--features full"
steps:
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Install Rust ${{ matrix.toolchain }}
uses: actions-rs/toolchain@v1
uses: dtolnay/rust-toolchain@master
with:
profile: minimal
toolchain: ${{ matrix.toolchain }}
override: true
- name: Cache Dependencies
uses: Swatinem/rust-cache@v1
uses: Swatinem/rust-cache@v2
# NB. Don't test (build) examples so we can use non-msrv features in them (--tests/--doc)
- name: Compile
uses: actions-rs/cargo@v1
with:
command: test
args: --tests --no-run --verbose ${{ matrix.features }}
- name: Compile
run: |
cargo +${{ matrix.toolchain }} test --tests --no-run --verbose ${{ matrix.features }}
- name: Setup redis
run: |
@ -121,19 +113,15 @@ jobs:
redis-server --port 7777 > /dev/null &
redis-server --port 7778 > /dev/null &
redis-server --port 7779 > /dev/null &
- name: Test unit & integration tests
uses: actions-rs/cargo@v1
with:
command: test
args: --tests --verbose ${{ matrix.features }}
- name: Test unit & integration tests
run: |
cargo +${{ matrix.toolchain }} test --tests --verbose ${{ matrix.features }}
- name: Test documentation tests
if: ${{ matrix.rust != 'msrv' }}
uses: actions-rs/cargo@v1
with:
command: test
args: --doc --verbose ${{ matrix.features }}
run: |
cargo +${{ matrix.toolchain }} test --doc --verbose ${{ matrix.features }}
check-examples:
runs-on: ubuntu-latest
@ -143,27 +131,21 @@ jobs:
uses: actions/checkout@v3
- name: Install Rust stable
uses: actions-rs/toolchain@v1
uses: dtolnay/rust-toolchain@master
with:
profile: minimal
toolchain: stable
override: true
- name: Cache Dependencies
uses: Swatinem/rust-cache@v1
uses: Swatinem/rust-cache@v2
- name: Check examples
uses: actions-rs/cargo@v1
with:
command: check
args: --examples --features full
run: |
cargo +stable check --examples --features full
# TODO: prolly move it to a separate step?
- name: Check with no default features
uses: actions-rs/cargo@v1
with:
command: check
args: --no-default-features
run: |
cargo +stable check --no-default-features
clippy:
name: Run linter
@ -174,21 +156,17 @@ jobs:
uses: actions/checkout@v3
- name: Install Rust ${{ env.rust_nightly }}
uses: actions-rs/toolchain@v1
uses: dtolnay/rust-toolchain@master
with:
profile: minimal
toolchain: ${{ env.rust_nightly }}
override: true
components: clippy
- name: Cache Dependencies
uses: Swatinem/rust-cache@v1
uses: Swatinem/rust-cache@v2
- name: clippy
uses: actions-rs/cargo@v1
with:
command: clippy
args: --all-targets --features "full nightly"
run: |
cargo clippy --all-targets --features "full nightly"
doc:
name: check docs
@ -199,16 +177,13 @@ jobs:
uses: actions/checkout@v3
- name: Install Rust ${{ env.rust_nightly }}
uses: actions-rs/toolchain@v1
uses: dtolnay/rust-toolchain@master
with:
profile: minimal
toolchain: ${{ env.rust_nightly }}
override: true
- name: Cache Dependencies
uses: Swatinem/rust-cache@v1
uses: Swatinem/rust-cache@v2
- name: rustdoc
uses: actions-rs/cargo@v1
with:
command: docs # from .cargo/config.toml
run: |
cargo docs # from .cargo/config.toml

View file

@ -7,8 +7,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## unreleased
### Added
- Add `MessageToCopyNotFound` error to `teloxide::errors::ApiError` ([PR 917](https://github.com/teloxide/teloxide/pull/917))
- Add `tracing` feature, that enables trait `UpdateHandlerExt` which instruments `UpdateHandler` with a custom `tracing::Span`
- `tracing` feature, that enabled trait `UpdateHandlerExt` that instruments `UpdateHandler` with a custom `tracing::Span`
### Fixed
- Use `UserId` instead of `i64` for `user_id` in `html::user_mention` and `markdown::user_mention` ([PR 896](https://github.com/teloxide/teloxide/pull/896))
- Greatly improved the speed of graceful shutdown (`^C`) ([PR 938](https://github.com/teloxide/teloxide/pull/938))
### Removed
- `UpdateListener::timeout_hint` and related APIs ([PR 938](https://github.com/teloxide/teloxide/pull/938))
## 0.12.2 - 2023-02-15

View file

@ -1,13 +1,17 @@
[workspace]
members = ["crates/*"]
resolver = "2"
# The settings below will be applied to all crates in the workspace
[workspace.package]
# MSRV (minimal supported Rust version).
rust-version = "1.64"
rust-version = "1.65"
edition = "2021"
license = "MIT"
homepage = "https://github.com/teloxide/teloxide"
repository = "https://github.com/teloxide/teloxide"
[workspace.metadata.release]
tag-message = "Release {{crate_name}} version {{version}}"
tag-name = "{{prefix}}v{{version}}"

View file

@ -58,7 +58,7 @@ $ set TELOXIDE_TOKEN=<Your token here>
$ $env:TELOXIDE_TOKEN=<Your token here>
```
4. Make sure that your Rust compiler is up to date (`teloxide` currently requires rustc at least version 1.64):
4. Make sure that your Rust compiler is up to date (`teloxide` currently requires rustc at least version 1.65):
```bash
# If you're using stable
$ rustup update stable
@ -82,7 +82,7 @@ tokio = { version = "1.8", features = ["rt-multi-thread", "macros"] }
### The dices bot
This bot replies with a die throw to each received message:
This bot replies with a dice to each received message:
[[`examples/throw_dice.rs`](crates/teloxide/examples/throw_dice.rs)]
@ -328,6 +328,8 @@ Feel free to propose your own bot to our collection!
- [`0xNima/Twideo`](https://github.com/0xNima/Twideo) — Simple Telegram Bot for downloading videos from Twitter via their links.
- [`mattrighetti/libgen-bot-rs`](https://github.com/mattrighetti/libgen-bot-rs) — Telegram bot to interface with libgen.
- [`zamazan4ik/npaperbot-telegram`](https://github.com/zamazan4ik/npaperbot-telegram) — Telegram bot for searching via C++ proposals.
- [`studentenherz/dlebot`](https://github.com/studentenherz/dlebot) — A bot to query definitions of words from the Spanish Language Dictionary.
- [`fr0staman/fr0staman_bot`](https://github.com/fr0staman/fr0staman_bot) — Feature rich Telegram game-like bot with pigs 🐽.
<details>
<summary>Show bots using `teloxide` older than v0.6.0</summary>

View file

@ -13,8 +13,66 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- `mentioned_users` functions for `CallbackQuery`, `Chat`, `ChatJoinRequest`, `ChatMemberUpdated`, `Game`, `Message`, `Poll`, `Update` which return all contained `User` instances ([#850][pr850])
- `Message::video_chat_participants_invited` ([#850][pr850])
- `Update::from`, a replacement for `Update::user` ([#850][pr850])
- `Seconds` type, which represents a duration is seconds ([#859][pr859])
- `VideoChatEnded::duration` field that was previously missed ([#859][pr859])
- `ThreadId` newtype over `MessageId`, used for identifying reply threads ([#887][pr887])
- `ChatId::as_user` ([#905][pr905])
- Implement `PartialEq<ChatId> for UserId` and `PartialEq<UserId> for ChatId` ([#905][pr905])
- `ChatId::{MIN, MAX}` ([#905][pr905])
[pr851]: https://github.com/teloxide/teloxide/pull/851
[pr887]: https://github.com/teloxide/teloxide/pull/887
[pr905]: https://github.com/teloxide/teloxide/pull/905
### Fixed
- Return types of `edit_message_live_location_inline`, `stop_message_live_location_inline`, and `set_game_score_inline`: `Message` => `True` ([#854][pr854])
- Remove `latitude` and `longitude` parameters from `stop_message_live_location` and `stop_message_live_location_inline` ([#854][pr854])
- Fix the type of `photo_size`,`photo_width` and `photo_height` in the `send_invoice` method ([#936][pr936])
[pr854]: https://github.com/teloxide/teloxide/pull/854
[pr936]: https://github.com/teloxide/teloxide/pull/936
### Changed
- Types of `Option<bool>` fields of `KeyboardMarkup`, `KeyboardRemove` and `ForceReply` to `bool` ([#853][pr853])
- Type of `KeyboardMarkup::input_field_placeholder`: `Option<String>` => `String` ([#853][pr853])
- The following fields now use `Seconds` type instead of `u32`, `u16` or `Duration` ([#859][pr859])
- `Animation::duration`
- `Audio::duration`
- `Chat::message_auto_delete_time`
- `Chat::slow_mode_delay`
- `InlineQueryResultLocation::live_period`
- `Location::live_period`
- `MessageAutoDeleteTimerChanged::message_auto_delete_time`
- `Poll::open_period`
- `Video::duration`
- `VideoNote::duration`
- `Voice::duration`
- `RequestError::MigrateToChatId` single fields type to `ChatId` ([#859][pr859])
- `RequestError::RetryAfter` single fields type to `Seconds` ([#859][pr859])
- `CallbackGame`, `ForumTopicClosed`, `ForumTopicReopened`, `GeneralForumTopicHidden`, `GeneralForumTopicUnhidden` and `WriteAccessAllowed` structures
are now defined as named (`struct S {}`) instead of unit (`struct S;`) in order to fix their deserialization ([#876][pr876])
- `Download` now uses GAT feature on the `Fut` and `Err` associated types, instead of a lifetime on the whole trait ([#885][pr885])
- MSRV (Minimal Supported Rust Version) was bumped from `1.64.0` to `1.65.0`
- Renamed `ForumTopic::message_thread_id` into `thread_id` ([#887][pr887])
- `ForumTopic::thread_id` and `Message::thread_id` now use `ThreadId` instead of `i32` ([#887][pr887])
- `message_thread_id` method parameters now use `ThreadId` instead of `i32` ([#887][pr887])
- `DiceEmoji` variant order ([#887][pr887])
- `Dice::value` now use `u8`, instead of `i32` ([#887][pr887])
- `Invoice::total_amount`, `LabeledPrice::amount`, `PreCheckoutQuery::total_amount`, `SuccessfulPayment::total_amout` now use `u32`, instead of `i32` ([#887][pr887])
- `Forward::message_id` and `Message::forward_from_message_id` now use `MessageId` instead of `i32` ([#887][pr887])
- `Poll::total_voter_count` and `PollOption::voter_count` now use `u32` instead of `i32` ([#887][pr887])
- `PollAnswer::option_ids` now use `u8` instead of `i32` ([#887][pr887])
- Use `u32` for sizes and `Seconds` for timespans in `InlineQueryResult*` ([#887][pr887])
- `SendGame::reply_to_message_id`, `SendSticker::reply_to_message_id` and `SendInvoice::reply_to_message_id` now use `MessageId` instead of `i32` ([#887][pr887])
- Use `UpdateId` for `Update::id` ([#892][pr892])
[pr852]: https://github.com/teloxide/teloxide/pull/853
[pr859]: https://github.com/teloxide/teloxide/pull/859
[pr876]: https://github.com/teloxide/teloxide/pull/876
[pr885]: https://github.com/teloxide/teloxide/pull/885
[pr892]: https://github.com/teloxide/teloxide/pull/892
### Deprecated
@ -22,6 +80,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
[pr850]: https://github.com/teloxide/teloxide/pull/850
### Fixed
- Deserialization of `ApiError::CantParseEntities` ([#839][pr839])
- Deserialization of empty (content-less) messages that can sometimes appear as a part of callback query ([#850][pr850], issue [#873][issue873])
[pr839]: https://github.com/teloxide/teloxide/pull/839
[pr879]: https://github.com/teloxide/teloxide/pull/879
[issue873]: https://github.com/teloxide/teloxide/issues/873
## 0.9.1 - 2023-02-15
### Fixed

View file

@ -72,7 +72,7 @@ takecell = "0.1"
take_mut = "0.2"
rc-box = "1.1.1"
never = "0.1.0"
chrono = { version = "0.4.19", default-features = false }
chrono = { version = "0.4.30", default-features = false }
either = "1.6.1"
bitflags = { version = "1.2" }
@ -98,6 +98,14 @@ rustdoc-args = ["--cfg", "docsrs", "-Znormalize-docs"]
# https://github.com/rust-lang/rust/issues/88791
cargo-args = ["-Zunstable-options", "-Zrustdoc-scrape-examples"]
[package.metadata.release]
tag-prefix = "core-"
enable-features = ["full"]
pre-release-replacements = [
{file="README.md", search="teloxide-core = \"[^\"]+\"", replace="teloxide-core = \"{{version}}\""},
{file="src/lib.rs", search="teloxide-core = \"[^\"]+\"", replace="teloxide-core = \"{{version}}\""},
{file="CHANGELOG.md", search="## unreleased", replace="## unreleased\n\n## {{version}} - {{date}}", exactly=1},
]
[[example]]
name = "self_info"

View file

@ -27,7 +27,7 @@
```toml
teloxide-core = "0.9"
```
_Compiler support: requires rustc 1.64+_.
_Compiler support: requires rustc 1.65+_.
[`teloxide`]: https://docs.rs/teloxide
[Telegram Bot API]: https://core.telegram.org/bots/api

View file

@ -232,7 +232,7 @@ Schema(
),
Param(
name: "message_thread_id",
ty: Option(i32),
ty: Option(RawTy("ThreadId")),
descr: Doc(md: "Unique identifier for the target message thread (topic) of the forum; for forum supergroups only"),
),
Param(
@ -311,7 +311,7 @@ Schema(
),
Param(
name: "message_thread_id",
ty: Option(i32),
ty: Option(RawTy("ThreadId")),
descr: Doc(md: "Unique identifier for the target message thread (topic) of the forum; for forum supergroups only"),
),
Param(
@ -356,7 +356,7 @@ Schema(
),
Param(
name: "message_thread_id",
ty: Option(i32),
ty: Option(RawTy("ThreadId")),
descr: Doc(md: "Unique identifier for the target message thread (topic) of the forum; for forum supergroups only"),
),
Param(
@ -440,7 +440,7 @@ Schema(
),
Param(
name: "message_thread_id",
ty: Option(i32),
ty: Option(RawTy("ThreadId")),
descr: Doc(md: "Unique identifier for the target message thread (topic) of the forum; for forum supergroups only"),
),
Param(
@ -530,7 +530,7 @@ Schema(
),
Param(
name: "message_thread_id",
ty: Option(i32),
ty: Option(RawTy("ThreadId")),
descr: Doc(md: "Unique identifier for the target message thread (topic) of the forum; for forum supergroups only"),
),
Param(
@ -635,7 +635,7 @@ Schema(
),
Param(
name: "message_thread_id",
ty: Option(i32),
ty: Option(RawTy("ThreadId")),
descr: Doc(md: "Unique identifier for the target message thread (topic) of the forum; for forum supergroups only"),
),
Param(
@ -733,7 +733,7 @@ Schema(
),
Param(
name: "message_thread_id",
ty: Option(i32),
ty: Option(RawTy("ThreadId")),
descr: Doc(md: "Unique identifier for the target message thread (topic) of the forum; for forum supergroups only"),
),
Param(
@ -849,7 +849,7 @@ Schema(
),
Param(
name: "message_thread_id",
ty: Option(i32),
ty: Option(RawTy("ThreadId")),
descr: Doc(md: "Unique identifier for the target message thread (topic) of the forum; for forum supergroups only"),
),
Param(
@ -963,7 +963,7 @@ Schema(
),
Param(
name: "message_thread_id",
ty: Option(i32),
ty: Option(RawTy("ThreadId")),
descr: Doc(md: "Unique identifier for the target message thread (topic) of the forum; for forum supergroups only"),
),
Param(
@ -1048,7 +1048,7 @@ Schema(
),
Param(
name: "message_thread_id",
ty: Option(i32),
ty: Option(RawTy("ThreadId")),
descr: Doc(md: "Unique identifier for the target message thread (topic) of the forum; for forum supergroups only"),
),
Param(
@ -1131,7 +1131,7 @@ Schema(
),
Param(
name: "message_thread_id",
ty: Option(i32),
ty: Option(RawTy("ThreadId")),
descr: Doc(md: "Unique identifier for the target message thread (topic) of the forum; for forum supergroups only"),
),
Param(
@ -1181,7 +1181,7 @@ Schema(
),
Param(
name: "message_thread_id",
ty: Option(i32),
ty: Option(RawTy("ThreadId")),
descr: Doc(md: "Unique identifier for the target message thread (topic) of the forum; for forum supergroups only"),
),
Param(
@ -1314,7 +1314,7 @@ Schema(
),
Method(
names: ("editMessageLiveLocationInline", "EditMessageLiveLocationInline", "edit_message_live_location_inline"),
return_ty: RawTy("Message"),
return_ty: True,
doc: Doc(
md: "Use this method to edit live location messages. A location can be edited until its live_period expires or editing is explicitly disabled by a call to [stopMessageLiveLocation]. On success, True is returned.",
md_links: {"stopMessageLiveLocation": "https://core.telegram.org/bots/api#stopmessagelivelocation"},
@ -1389,16 +1389,6 @@ Schema(
ty: RawTy("MessageId"),
descr: Doc(md: "Identifier of the message to edit")
),
Param(
name: "latitude",
ty: f64,
descr: Doc(md: "Latitude of new location"),
),
Param(
name: "longitude",
ty: f64,
descr: Doc(md: "Longitude of new location"),
),
Param(
name: "reply_markup",
ty: Option(RawTy("ReplyMarkup")),
@ -1415,7 +1405,7 @@ Schema(
),
Method(
names: ("stopMessageLiveLocationInline", "StopMessageLiveLocationInline", "stop_message_live_location_inline"),
return_ty: RawTy("Message"),
return_ty: True,
doc: Doc(
md: "Use this method to edit live location messages. A location can be edited until its live_period expires or editing is explicitly disabled by a call to [stopMessageLiveLocation]. On success, True is returned.",
md_links: {"stopMessageLiveLocation": "https://core.telegram.org/bots/api#stopmessagelivelocation"},
@ -1428,16 +1418,6 @@ Schema(
ty: String,
descr: Doc(md: "Identifier of the inline message"),
),
Param(
name: "latitude",
ty: f64,
descr: Doc(md: "Latitude of new location"),
),
Param(
name: "longitude",
ty: f64,
descr: Doc(md: "Longitude of new location"),
),
Param(
name: "reply_markup",
ty: Option(RawTy("ReplyMarkup")),
@ -1469,7 +1449,7 @@ Schema(
),
Param(
name: "message_thread_id",
ty: Option(i32),
ty: Option(RawTy("ThreadId")),
descr: Doc(md: "Unique identifier for the target message thread (topic) of the forum; for forum supergroups only"),
),
Param(
@ -1568,7 +1548,7 @@ Schema(
),
Param(
name: "message_thread_id",
ty: Option(i32),
ty: Option(RawTy("ThreadId")),
descr: Doc(md: "Unique identifier for the target message thread (topic) of the forum; for forum supergroups only"),
),
Param(
@ -1647,7 +1627,7 @@ Schema(
),
Param(
name: "message_thread_id",
ty: Option(i32),
ty: Option(RawTy("ThreadId")),
descr: Doc(md: "Unique identifier for the target message thread (topic) of the forum; for forum supergroups only"),
),
Param(
@ -1766,7 +1746,7 @@ Schema(
),
Param(
name: "message_thread_id",
ty: Option(i32),
ty: Option(RawTy("ThreadId")),
descr: Doc(md: "Unique identifier for the target message thread (topic) of the forum; for forum supergroups only"),
),
Param(
@ -1844,7 +1824,7 @@ Schema(
),
Param(
name: "message_thread_id",
ty: Option(i32),
ty: Option(RawTy("ThreadId")),
descr: Doc(md: "Unique identifier for the target message thread; supergroups only")
),
],
@ -2646,7 +2626,7 @@ Schema(
),
Param(
name: "message_thread_id",
ty: i32,
ty: RawTy("ThreadId"),
descr: Doc(md: "Unique identifier for the target message thread of the forum topic"),
),
Param(
@ -2675,7 +2655,7 @@ Schema(
),
Param(
name: "message_thread_id",
ty: i32,
ty: RawTy("ThreadId"),
descr: Doc(md: "Unique identifier for the target message thread of the forum topic"),
),
],
@ -2694,7 +2674,7 @@ Schema(
),
Param(
name: "message_thread_id",
ty: i32,
ty: RawTy("ThreadId"),
descr: Doc(md: "Unique identifier for the target message thread of the forum topic"),
),
],
@ -2713,7 +2693,7 @@ Schema(
),
Param(
name: "message_thread_id",
ty: i32,
ty: RawTy("ThreadId"),
descr: Doc(md: "Unique identifier for the target message thread of the forum topic"),
),
],
@ -2732,7 +2712,7 @@ Schema(
),
Param(
name: "message_thread_id",
ty: i32,
ty: RawTy("ThreadId"),
descr: Doc(md: "Unique identifier for the target message thread of the forum topic"),
),
],
@ -3431,7 +3411,7 @@ Schema(
),
Param(
name: "message_thread_id",
ty: Option(i32),
ty: Option(RawTy("ThreadId")),
descr: Doc(md: "Unique identifier for the target message thread (topic) of the forum; for forum supergroups only"),
),
Param(
@ -3457,7 +3437,7 @@ Schema(
),
Param(
name: "reply_to_message_id",
ty: Option(i32),
ty: Option(RawTy("MessageId")),
descr: Doc(md: "If the message is a reply, ID of the original message")
),
Param(
@ -3689,7 +3669,7 @@ Schema(
),
Param(
name: "message_thread_id",
ty: Option(i32),
ty: Option(RawTy("ThreadId")),
descr: Doc(md: "Unique identifier for the target message thread (topic) of the forum; for forum supergroups only"),
),
Param(
@ -3755,17 +3735,17 @@ Schema(
),
Param(
name: "photo_size",
ty: Option(String),
ty: Option(u32),
descr: Doc(md: "Photo size in bytes")
),
Param(
name: "photo_width",
ty: Option(String),
ty: Option(u32),
descr: Doc(md: "Photo width")
),
Param(
name: "photo_height",
ty: Option(String),
ty: Option(u32),
descr: Doc(md: "Photo height")
),
Param(
@ -3818,7 +3798,7 @@ Schema(
),
Param(
name: "reply_to_message_id",
ty: Option(i32),
ty: Option(RawTy("MessageId")),
descr: Doc(md: "If the message is a reply, ID of the original message")
),
Param(
@ -4046,7 +4026,7 @@ Schema(
),
Param(
name: "message_thread_id",
ty: Option(i32),
ty: Option(RawTy("ThreadId")),
descr: Doc(md: "Unique identifier for the target message thread (topic) of the forum; for forum supergroups only"),
),
Param(
@ -4069,7 +4049,7 @@ Schema(
),
Param(
name: "reply_to_message_id",
ty: Option(i32),
ty: Option(RawTy("MessageId")),
descr: Doc(md: "If the message is a reply, ID of the original message")
),
Param(
@ -4132,7 +4112,7 @@ Schema(
),
Method(
names: ("setGameScoreInline", "SetGameScoreInline", "set_game_score_inline"),
return_ty: RawTy("Message"),
return_ty: True,
doc: Doc(md: "Use this method to set the score of the specified user in a game. On success, returns _True_. Returns an error, if the new score is not greater than the user's current score in the chat and force is False."),
tg_doc: "https://core.telegram.org/bots/api#setgamescore",
tg_category: "Games",

View file

@ -177,7 +177,6 @@ where
}
download_forward! {
'w
B
AutoSend<B>
{ this => this.inner() }

View file

@ -201,7 +201,6 @@ where
}
download_forward! {
'w
B
CacheMe<B>
{ this => this.inner() }

View file

@ -402,15 +402,11 @@ trait ErasableRequester<'a> {
&self,
chat_id: Recipient,
message_id: MessageId,
latitude: f64,
longitude: f64,
) -> ErasedRequest<'a, StopMessageLiveLocation, Self::Err>;
fn stop_message_live_location_inline(
&self,
inline_message_id: String,
latitude: f64,
longitude: f64,
) -> ErasedRequest<'a, StopMessageLiveLocationInline, Self::Err>;
fn send_venue(
@ -632,31 +628,31 @@ trait ErasableRequester<'a> {
fn edit_forum_topic(
&self,
chat_id: Recipient,
message_thread_id: i32,
message_thread_id: ThreadId,
) -> ErasedRequest<'a, EditForumTopic, Self::Err>;
fn close_forum_topic(
&self,
chat_id: Recipient,
message_thread_id: i32,
message_thread_id: ThreadId,
) -> ErasedRequest<'a, CloseForumTopic, Self::Err>;
fn reopen_forum_topic(
&self,
chat_id: Recipient,
message_thread_id: i32,
message_thread_id: ThreadId,
) -> ErasedRequest<'a, ReopenForumTopic, Self::Err>;
fn delete_forum_topic(
&self,
chat_id: Recipient,
message_thread_id: i32,
message_thread_id: ThreadId,
) -> ErasedRequest<'a, DeleteForumTopic, Self::Err>;
fn unpin_all_forum_topic_messages(
&self,
chat_id: Recipient,
message_thread_id: i32,
message_thread_id: ThreadId,
) -> ErasedRequest<'a, UnpinAllForumTopicMessages, Self::Err>;
fn edit_general_forum_topic(
@ -1064,21 +1060,15 @@ where
&self,
chat_id: Recipient,
message_id: MessageId,
latitude: f64,
longitude: f64,
) -> ErasedRequest<'a, StopMessageLiveLocation, Self::Err> {
Requester::stop_message_live_location(self, chat_id, message_id, latitude, longitude)
.erase()
Requester::stop_message_live_location(self, chat_id, message_id).erase()
}
fn stop_message_live_location_inline(
&self,
inline_message_id: String,
latitude: f64,
longitude: f64,
) -> ErasedRequest<'a, StopMessageLiveLocationInline, Self::Err> {
Requester::stop_message_live_location_inline(self, inline_message_id, latitude, longitude)
.erase()
Requester::stop_message_live_location_inline(self, inline_message_id).erase()
}
fn send_venue(
@ -1378,7 +1368,7 @@ where
fn edit_forum_topic(
&self,
chat_id: Recipient,
message_thread_id: i32,
message_thread_id: ThreadId,
) -> ErasedRequest<'a, EditForumTopic, Self::Err> {
Requester::edit_forum_topic(self, chat_id, message_thread_id).erase()
}
@ -1386,7 +1376,7 @@ where
fn close_forum_topic(
&self,
chat_id: Recipient,
message_thread_id: i32,
message_thread_id: ThreadId,
) -> ErasedRequest<'a, CloseForumTopic, Self::Err> {
Requester::close_forum_topic(self, chat_id, message_thread_id).erase()
}
@ -1394,7 +1384,7 @@ where
fn reopen_forum_topic(
&self,
chat_id: Recipient,
message_thread_id: i32,
message_thread_id: ThreadId,
) -> ErasedRequest<'a, ReopenForumTopic, Self::Err> {
Requester::reopen_forum_topic(self, chat_id, message_thread_id).erase()
}
@ -1402,7 +1392,7 @@ where
fn delete_forum_topic(
&self,
chat_id: Recipient,
message_thread_id: i32,
message_thread_id: ThreadId,
) -> ErasedRequest<'a, DeleteForumTopic, Self::Err> {
Requester::delete_forum_topic(self, chat_id, message_thread_id).erase()
}
@ -1410,7 +1400,7 @@ where
fn unpin_all_forum_topic_messages(
&self,
chat_id: Recipient,
message_thread_id: i32,
message_thread_id: ThreadId,
) -> ErasedRequest<'a, UnpinAllForumTopicMessages, Self::Err> {
Requester::unpin_all_forum_topic_messages(self, chat_id, message_thread_id).erase()
}

View file

@ -196,7 +196,6 @@ impl<B: Requester> Requester for DefaultParseMode<B> {
}
download_forward! {
'w
B
DefaultParseMode<B>
{ this => this.inner() }

View file

@ -202,7 +202,7 @@ where
let retry_after = res.as_ref().err().and_then(<_>::retry_after);
if let Some(retry_after) = retry_after {
let after = retry_after;
let after = retry_after.duration();
let until = Instant::now() + after;
// If we'll retry, we check that worker hasn't died at the start of the loop

View file

@ -182,7 +182,6 @@ where
}
download_forward! {
'w
B
Throttle<B>
{ this => this.inner() }

View file

@ -155,18 +155,18 @@ pub(super) async fn worker<B>(
//
// Reasons (not to use `spawn_blocking`):
//
// 1. The work seems not very CPU-bound, it's not heavy computations,
// it's more like light computations.
// 1. The work seems not very CPU-bound, it's not heavy computations, it's more
// like light computations.
//
// 2. `spawn_blocking` is not zero-cost — it spawns a new system thread
// + do so other work. This may actually be *worse* then current
// "just do everything in this async fn" approach.
//
// 3. With `rt-threaded` feature, tokio uses [`num_cpus()`] threads
// which should be enough to work fine with one a-bit-blocking task.
// Crucially current behaviour will be problem mostly with
// single-threaded runtimes (and in case you're using one, you
// probably don't want to spawn unnecessary threads anyway).
// 3. With `rt-threaded` feature, tokio uses [`num_cpus()`] threads which should
// be enough to work fine with one a-bit-blocking task. Crucially current
// behaviour will be problem mostly with single-threaded runtimes (and in
// case you're using one, you probably don't want to spawn unnecessary
// threads anyway).
//
// I think if we'll ever change this behaviour, we need to make it
// _configurable_.
@ -316,7 +316,7 @@ async fn freeze(
match chat.slow_mode_delay() {
Some(delay) => {
let now = Instant::now();
let new_delay = Duration::from_secs(delay.into());
let new_delay = delay.duration();
slow_mode.insert(hash, (new_delay, now));
}
None => {

View file

@ -6,7 +6,7 @@ use crate::{
requests::{JsonRequest, MultipartRequest},
types::{
BotCommand, ChatId, ChatPermissions, InlineQueryResult, InputFile, InputMedia,
InputSticker, LabeledPrice, MessageId, Recipient, UserId,
InputSticker, LabeledPrice, MessageId, Recipient, ThreadId, UserId,
},
Bot,
};
@ -198,15 +198,13 @@ impl Requester for Bot {
&self,
chat_id: C,
message_id: MessageId,
latitude: f64,
longitude: f64,
) -> Self::StopMessageLiveLocation
where
C: Into<Recipient>,
{
Self::StopMessageLiveLocation::new(
self.clone(),
payloads::StopMessageLiveLocation::new(chat_id, message_id, latitude, longitude),
payloads::StopMessageLiveLocation::new(chat_id, message_id),
)
}
@ -215,15 +213,13 @@ impl Requester for Bot {
fn stop_message_live_location_inline<I>(
&self,
inline_message_id: I,
latitude: f64,
longitude: f64,
) -> Self::StopMessageLiveLocationInline
where
I: Into<String>,
{
Self::StopMessageLiveLocationInline::new(
self.clone(),
payloads::StopMessageLiveLocationInline::new(inline_message_id, latitude, longitude),
payloads::StopMessageLiveLocationInline::new(inline_message_id),
)
}
@ -675,7 +671,7 @@ impl Requester for Bot {
type EditForumTopic = JsonRequest<payloads::EditForumTopic>;
fn edit_forum_topic<C>(&self, chat_id: C, message_thread_id: i32) -> Self::EditForumTopic
fn edit_forum_topic<C>(&self, chat_id: C, message_thread_id: ThreadId) -> Self::EditForumTopic
where
C: Into<Recipient>,
{
@ -687,7 +683,7 @@ impl Requester for Bot {
type CloseForumTopic = JsonRequest<payloads::CloseForumTopic>;
fn close_forum_topic<C>(&self, chat_id: C, message_thread_id: i32) -> Self::CloseForumTopic
fn close_forum_topic<C>(&self, chat_id: C, message_thread_id: ThreadId) -> Self::CloseForumTopic
where
C: Into<Recipient>,
{
@ -699,7 +695,11 @@ impl Requester for Bot {
type ReopenForumTopic = JsonRequest<payloads::ReopenForumTopic>;
fn reopen_forum_topic<C>(&self, chat_id: C, message_thread_id: i32) -> Self::ReopenForumTopic
fn reopen_forum_topic<C>(
&self,
chat_id: C,
message_thread_id: ThreadId,
) -> Self::ReopenForumTopic
where
C: Into<Recipient>,
{
@ -711,7 +711,11 @@ impl Requester for Bot {
type DeleteForumTopic = JsonRequest<payloads::DeleteForumTopic>;
fn delete_forum_topic<C>(&self, chat_id: C, message_thread_id: i32) -> Self::DeleteForumTopic
fn delete_forum_topic<C>(
&self,
chat_id: C,
message_thread_id: ThreadId,
) -> Self::DeleteForumTopic
where
C: Into<Recipient>,
{
@ -726,7 +730,7 @@ impl Requester for Bot {
fn unpin_all_forum_topic_messages<C>(
&self,
chat_id: C,
message_thread_id: i32,
message_thread_id: ThreadId,
) -> Self::UnpinAllForumTopicMessages
where
C: Into<Recipient>,

View file

@ -8,18 +8,18 @@ use crate::{
DownloadError,
};
impl<'w> Download<'w> for Bot {
type Err = DownloadError;
impl Download for Bot {
type Err<'dst> = DownloadError;
// I would like to unbox this, but my coworkers will kill me if they'll see yet
// another hand written `Future`. (waffle)
type Fut = BoxFuture<'w, Result<(), Self::Err>>;
type Fut<'dst> = BoxFuture<'dst, Result<(), Self::Err<'dst>>>;
fn download_file(
fn download_file<'dst>(
&self,
path: &str,
destination: &'w mut (dyn AsyncWrite + Unpin + Send),
) -> Self::Fut {
destination: &'dst mut (dyn AsyncWrite + Unpin + Send),
) -> Self::Fut<'dst> {
net::download_file(
&self.client,
reqwest::Url::clone(&*self.api_url),

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-12-23";
let toolchain = "nightly-2023-09-27";
let version = cmd!(sh, "rustup run {toolchain} rustfmt --version").read().unwrap_or_default();
@ -36,7 +36,7 @@ fn ensure_rustfmt(sh: &Shell) {
}
pub fn reformat(text: String) -> String {
let toolchain = "nightly-2022-12-23";
let toolchain = "nightly-2023-09-27";
let sh = Shell::new().unwrap();
ensure_rustfmt(&sh);

File diff suppressed because it is too large Load diff

View file

@ -5,9 +5,9 @@
//! asynchronous and built using [`tokio`].
//!
//!```toml
//! teloxide_core = "0.9"
//! teloxide-core = "0.9"
//! ```
//! _Compiler support: requires rustc 1.64+_.
//! _Compiler support: requires rustc 1.65+_.
//!
//! ```
//! # async {

View file

@ -372,26 +372,26 @@ macro_rules! impl_payload {
}
macro_rules! download_forward {
($l:lifetime $T:ident $S:ty {$this:ident => $inner:expr}) => {
impl<$l, $T: $crate::net::Download<$l>> $crate::net::Download<$l> for $S {
type Err = <$T as $crate::net::Download<$l>>::Err;
($T:ident $S:ty {$this:ident => $inner:expr}) => {
impl<$T: $crate::net::Download> $crate::net::Download for $S {
type Err<'dst> = <$T as $crate::net::Download>::Err<'dst>;
type Fut = <$T as $crate::net::Download<$l>>::Fut;
type Fut<'dst> = <$T as $crate::net::Download>::Fut<'dst>;
fn download_file(
fn download_file<'dst>(
&self,
path: &str,
destination: &'w mut (dyn tokio::io::AsyncWrite
+ core::marker::Unpin
+ core::marker::Send),
) -> Self::Fut {
destination: &'dst mut (dyn tokio::io::AsyncWrite
+ core::marker::Unpin
+ core::marker::Send),
) -> Self::Fut<'dst> {
let $this = self;
($inner).download_file(path, destination)
}
type StreamErr = <$T as $crate::net::Download<$l>>::StreamErr;
type StreamErr = <$T as $crate::net::Download>::StreamErr;
type Stream = <$T as $crate::net::Download<$l>>::Stream;
type Stream = <$T as $crate::net::Download>::Stream;
fn download_file_stream(&self, path: &str) -> Self::Stream {
let $this = self;
@ -588,17 +588,17 @@ macro_rules! requester_forward {
(@method stop_message_live_location $body:ident $ty:ident) => {
type StopMessageLiveLocation = $ty![StopMessageLiveLocation];
fn stop_message_live_location<C>(&self, chat_id: C, message_id: MessageId, latitude: f64, longitude: f64) -> Self::StopMessageLiveLocation where C: Into<Recipient> {
fn stop_message_live_location<C>(&self, chat_id: C, message_id: MessageId) -> Self::StopMessageLiveLocation where C: Into<Recipient> {
let this = self;
$body!(stop_message_live_location this (chat_id: C, message_id: MessageId, latitude: f64, longitude: f64))
$body!(stop_message_live_location this (chat_id: C, message_id: MessageId))
}
};
(@method stop_message_live_location_inline $body:ident $ty:ident) => {
type StopMessageLiveLocationInline = $ty![StopMessageLiveLocationInline];
fn stop_message_live_location_inline<I>(&self, inline_message_id: I, latitude: f64, longitude: f64) -> Self::StopMessageLiveLocationInline where I: Into<String> {
fn stop_message_live_location_inline<I>(&self, inline_message_id: I) -> Self::StopMessageLiveLocationInline where I: Into<String> {
let this = self;
$body!(stop_message_live_location_inline this (inline_message_id: I, latitude: f64, longitude: f64))
$body!(stop_message_live_location_inline this (inline_message_id: I))
}
};
(@method send_venue $body:ident $ty:ident) => {
@ -931,41 +931,41 @@ macro_rules! requester_forward {
(@method edit_forum_topic $body:ident $ty:ident) => {
type EditForumTopic = $ty![EditForumTopic];
fn edit_forum_topic<C>(&self, chat_id: C, message_thread_id: i32) -> Self::EditForumTopic where C: Into<Recipient> {
fn edit_forum_topic<C>(&self, chat_id: C, message_thread_id: ThreadId) -> Self::EditForumTopic where C: Into<Recipient> {
let this = self;
$body!(edit_forum_topic this (chat_id: C, message_thread_id: i32))
$body!(edit_forum_topic this (chat_id: C, message_thread_id: ThreadId))
}
};
(@method close_forum_topic $body:ident $ty:ident) => {
type CloseForumTopic = $ty![CloseForumTopic];
fn close_forum_topic<C>(&self, chat_id: C, message_thread_id: i32) -> Self::CloseForumTopic where C: Into<Recipient> {
fn close_forum_topic<C>(&self, chat_id: C, message_thread_id: ThreadId) -> Self::CloseForumTopic where C: Into<Recipient> {
let this = self;
$body!(close_forum_topic this (chat_id: C, message_thread_id: i32))
$body!(close_forum_topic this (chat_id: C, message_thread_id: ThreadId))
}
};
(@method reopen_forum_topic $body:ident $ty:ident) => {
type ReopenForumTopic = $ty![ReopenForumTopic];
fn reopen_forum_topic<C>(&self, chat_id: C, message_thread_id: i32) -> Self::ReopenForumTopic where C: Into<Recipient> {
fn reopen_forum_topic<C>(&self, chat_id: C, message_thread_id: ThreadId) -> Self::ReopenForumTopic where C: Into<Recipient> {
let this = self;
$body!(reopen_forum_topic this (chat_id: C, message_thread_id: i32))
$body!(reopen_forum_topic this (chat_id: C, message_thread_id: ThreadId))
}
};
(@method delete_forum_topic $body:ident $ty:ident) => {
type DeleteForumTopic = $ty![DeleteForumTopic];
fn delete_forum_topic<C>(&self, chat_id: C, message_thread_id: i32) -> Self::DeleteForumTopic where C: Into<Recipient> {
fn delete_forum_topic<C>(&self, chat_id: C, message_thread_id: ThreadId) -> Self::DeleteForumTopic where C: Into<Recipient> {
let this = self;
$body!(delete_forum_topic this (chat_id: C, message_thread_id: i32))
$body!(delete_forum_topic this (chat_id: C, message_thread_id: ThreadId))
}
};
(@method unpin_all_forum_topic_messages $body:ident $ty:ident) => {
type UnpinAllForumTopicMessages = $ty![UnpinAllForumTopicMessages];
fn unpin_all_forum_topic_messages<C>(&self, chat_id: C, message_thread_id: i32) -> Self::UnpinAllForumTopicMessages where C: Into<Recipient> {
fn unpin_all_forum_topic_messages<C>(&self, chat_id: C, message_thread_id: ThreadId) -> Self::UnpinAllForumTopicMessages where C: Into<Recipient> {
let this = self;
$body!(unpin_all_forum_topic_messages this (chat_id: C, message_thread_id: i32))
$body!(unpin_all_forum_topic_messages this (chat_id: C, message_thread_id: ThreadId))
}
};
(@method edit_general_forum_topic $body:ident $ty:ident) => {
@ -1333,6 +1333,8 @@ macro_rules! requester_forward {
}
#[test]
// waffle: efficiency is not important here, and I don't want to rewrite this
#[allow(clippy::format_collect)]
fn codegen_requester_forward() {
use crate::codegen::{
add_hidden_preamble,

View file

@ -12,15 +12,17 @@ use tokio::io::{AsyncWrite, AsyncWriteExt};
use crate::{errors::DownloadError, net::file_url};
/// A trait for downloading files from Telegram.
pub trait Download<'w>
/* FIXME(waffle): ideally, this lifetime ('w) shouldn't be here, but we can't help it without
* GATs */
{
pub trait Download {
/// An error returned from [`download_file`](Self::download_file).
type Err;
type Err<'dst>;
/// A future returned from [`download_file`](Self::download_file).
type Fut: Future<Output = Result<(), Self::Err>> + Send;
type Fut<'dst>: Future<Output = Result<(), Self::Err<'dst>>> + Send;
// NOTE: We currently only allow borrowing `dst` in the future,
// however we could also allow borrowing `self` or `path`.
// This doesn't seem useful for our current implementers of
// `Download`, but we could.
/// Download a file from Telegram into `destination`.
///
@ -50,11 +52,11 @@ pub trait Download<'w>
///
/// [`GetFile`]: crate::payloads::GetFile
/// [`download_file_stream`]: Self::download_file_stream
fn download_file(
fn download_file<'dst>(
&self,
path: &str,
destination: &'w mut (dyn AsyncWrite + Unpin + Send),
) -> Self::Fut;
destination: &'dst mut (dyn AsyncWrite + Unpin + Send),
) -> Self::Fut<'dst>;
/// An error returned from
/// [`download_file_stream`](Self::download_file_stream).

View file

@ -162,13 +162,11 @@ where
#[cfg(test)]
mod tests {
use std::time::Duration;
use cool_asserts::assert_matches;
use crate::{
net::request::deserialize_response,
types::{True, Update, UpdateKind},
types::{ChatId, Seconds, True, Update, UpdateId, UpdateKind},
ApiError, RequestError,
};
@ -194,7 +192,7 @@ mod tests {
let json = r#"{"ok":false,"description":"this string is ignored","parameters":{"migrate_to_chat_id":123456}}"#.to_owned();
let res = deserialize_response::<True>(json);
assert_matches!(res, Err(RequestError::MigrateToChatId(123456)));
assert_matches!(res, Err(RequestError::MigrateToChatId(ChatId(123456))));
}
#[test]
@ -202,7 +200,7 @@ mod tests {
let json = r#"{"ok":false,"description":"this string is ignored","parameters":{"retry_after":123456}}"#.to_owned();
let res = deserialize_response::<True>(json);
assert_matches!(res, Err(RequestError::RetryAfter(duration)) if duration == Duration::from_secs(123456));
assert_matches!(res, Err(RequestError::RetryAfter(duration)) if duration == Seconds::from_seconds(123456));
}
#[test]
@ -223,7 +221,7 @@ mod tests {
.to_owned();
let res = deserialize_response::<Vec<Update>>(json).unwrap();
assert_matches!(res, [Update { id: 0, kind: UpdateKind::PollAnswer(_) }]);
assert_matches!(res, [Update { id: UpdateId(0), kind: UpdateKind::PollAnswer(_) }]);
}
/// Check that `get_updates` can work with malformed updates.
@ -264,10 +262,10 @@ mod tests {
assert_matches!(
res,
[
Update { id: 0, kind: UpdateKind::PollAnswer(_) },
Update { id: 1, kind: UpdateKind::Error(v) } if v.is_object(),
Update { id: 2, kind: UpdateKind::PollAnswer(_) },
Update { id: 3, kind: UpdateKind::Error(v) } if v.is_object(),
Update { id: UpdateId(0), kind: UpdateKind::PollAnswer(_) },
Update { id: UpdateId(1), kind: UpdateKind::Error(v) } if v.is_object(),
Update { id: UpdateId(2), kind: UpdateKind::PollAnswer(_) },
Update { id: UpdateId(3), kind: UpdateKind::Error(v) } if v.is_object(),
]
);
}

View file

@ -2,7 +2,7 @@
use serde::Serialize;
use crate::types::{Recipient, True};
use crate::types::{Recipient, ThreadId, True};
impl_payload! {
/// Use this method to close an open topic in a forum supergroup chat. The bot must be an administrator in the chat for this to work and must have the _can\_manage\_topics_ administrator rights, unless it is the creator of the topic. Returns True on success.
@ -12,7 +12,7 @@ impl_payload! {
/// Unique identifier for the target chat or username of the target channel (in the format `@channelusername`)
pub chat_id: Recipient [into],
/// Unique identifier for the target message thread of the forum topic
pub message_thread_id: i32,
pub message_thread_id: ThreadId,
}
}
}

View file

@ -1,3 +1,6 @@
// waffle: efficiency is not important here, and I don't want to rewrite this
#![allow(clippy::format_collect)]
use std::{borrow::Borrow, collections::HashSet, ops::Deref};
use itertools::Itertools;
@ -51,7 +54,7 @@ fn codegen_payloads() {
let multipart = multipart_input_file_fields(&method)
.map(|field| format!(" @[multipart = {}]\n", field.join(", ")))
.unwrap_or_else(String::new);
.unwrap_or_default();
let derive = if !multipart.is_empty()
|| matches!(

View file

@ -2,7 +2,7 @@
use serde::Serialize;
use crate::types::{MessageEntity, MessageId, ParseMode, Recipient, ReplyMarkup};
use crate::types::{MessageEntity, MessageId, ParseMode, Recipient, ReplyMarkup, ThreadId};
impl_payload! {
/// Use this method to copy messages of any kind. The method is analogous to the method forwardMessage, but the copied message doesn't have a link to the original message. Returns the [`MessageId`] of the sent message on success.
@ -21,7 +21,7 @@ impl_payload! {
}
optional {
/// Unique identifier for the target message thread (topic) of the forum; for forum supergroups only
pub message_thread_id: i32,
pub message_thread_id: ThreadId,
/// New caption for media, 0-1024 characters after entities parsing. If not specified, the original caption is kept
pub caption: String [into],
/// Mode for parsing entities in the photo caption. See [formatting options] for more details.

View file

@ -2,7 +2,7 @@
use serde::Serialize;
use crate::types::{Recipient, True};
use crate::types::{Recipient, ThreadId, True};
impl_payload! {
/// Use this method to delete a forum topic along with all its messages in a forum supergroup chat. The bot must be an administrator in the chat for this to work and must have the _can\_delete\_messages_ administrator rights. Returns True on success.
@ -12,7 +12,7 @@ impl_payload! {
/// Unique identifier for the target chat or username of the target channel (in the format `@channelusername`)
pub chat_id: Recipient [into],
/// Unique identifier for the target message thread of the forum topic
pub message_thread_id: i32,
pub message_thread_id: ThreadId,
}
}
}

View file

@ -2,7 +2,7 @@
use serde::Serialize;
use crate::types::{Recipient, True};
use crate::types::{Recipient, ThreadId, True};
impl_payload! {
/// Use this method to edit name and icon of a topic in a forum supergroup chat. The bot must be an administrator in the chat for this to work and must have _can\_manage\_topics_ administrator rights, unless it is the creator of the topic. Returns True on success.
@ -12,7 +12,7 @@ impl_payload! {
/// Unique identifier for the target chat or username of the target channel (in the format `@channelusername`)
pub chat_id: Recipient [into],
/// Unique identifier for the target message thread of the forum topic
pub message_thread_id: i32,
pub message_thread_id: ThreadId,
}
optional {
/// Topic name, 0-128 characters. If not specified or empty, the current name of the topic will be kept

View file

@ -2,7 +2,7 @@
use serde::Serialize;
use crate::types::{Message, ReplyMarkup};
use crate::types::{ReplyMarkup, True};
impl_payload! {
/// Use this method to edit live location messages. A location can be edited until its live_period expires or editing is explicitly disabled by a call to [`StopMessageLiveLocation`]. On success, True is returned.
@ -11,7 +11,7 @@ impl_payload! {
///
/// [`StopMessageLiveLocation`]: crate::payloads::StopMessageLiveLocation
#[derive(Debug, PartialEq, Clone, Serialize)]
pub EditMessageLiveLocationInline (EditMessageLiveLocationInlineSetters) => Message {
pub EditMessageLiveLocationInline (EditMessageLiveLocationInlineSetters) => True {
required {
/// Identifier of the inline message
pub inline_message_id: String [into],

View file

@ -2,7 +2,7 @@
use serde::Serialize;
use crate::types::{Message, MessageId, Recipient};
use crate::types::{Message, MessageId, Recipient, ThreadId};
impl_payload! {
/// Use this method to forward messages of any kind. On success, the sent [`Message`] is returned.
@ -21,7 +21,7 @@ impl_payload! {
}
optional {
/// Unique identifier for the target message thread (topic) of the forum; for forum supergroups only
pub message_thread_id: i32,
pub message_thread_id: ThreadId,
/// Sends the message [silently]. Users will receive a notification with no sound.
///
/// [silently]: https://telegram.org/blog/channels-2-0#silent-messages

View file

@ -2,7 +2,7 @@
use serde::Serialize;
use crate::types::{Recipient, True};
use crate::types::{Recipient, ThreadId, True};
impl_payload! {
/// Use this method to reopen a closed topic in a forum supergroup chat. The bot must be an administrator in the chat for this to work and must have the _can\_manage\_topics_ administrator rights, unless it is the creator of the topic. Returns True on success.
@ -12,7 +12,7 @@ impl_payload! {
/// Unique identifier for the target chat or username of the target channel (in the format `@channelusername`)
pub chat_id: Recipient [into],
/// Unique identifier for the target message thread of the forum topic
pub message_thread_id: i32,
pub message_thread_id: ThreadId,
}
}
}

View file

@ -3,7 +3,7 @@
use serde::Serialize;
use crate::types::{
InputFile, Message, MessageEntity, MessageId, ParseMode, Recipient, ReplyMarkup,
InputFile, Message, MessageEntity, MessageId, ParseMode, Recipient, ReplyMarkup, ThreadId,
};
impl_payload! {
@ -23,7 +23,7 @@ impl_payload! {
}
optional {
/// Unique identifier for the target message thread (topic) of the forum; for forum supergroups only
pub message_thread_id: i32,
pub message_thread_id: ThreadId,
/// Duration of the animation in seconds
pub duration: u32,
/// Animation width

View file

@ -3,7 +3,7 @@
use serde::Serialize;
use crate::types::{
InputFile, Message, MessageEntity, MessageId, ParseMode, Recipient, ReplyMarkup,
InputFile, Message, MessageEntity, MessageId, ParseMode, Recipient, ReplyMarkup, ThreadId,
};
impl_payload! {
@ -26,7 +26,7 @@ impl_payload! {
}
optional {
/// Unique identifier for the target message thread (topic) of the forum; for forum supergroups only
pub message_thread_id: i32,
pub message_thread_id: ThreadId,
/// Audio caption, 0-1024 characters after entities parsing
pub caption: String [into],
/// Mode for parsing entities in the audio caption. See [formatting options] for more details.

View file

@ -2,7 +2,7 @@
use serde::Serialize;
use crate::types::{ChatAction, Recipient, True};
use crate::types::{ChatAction, Recipient, ThreadId, True};
impl_payload! {
/// Use this method when you need to tell the user that something is happening on the bot's side. The status is set for 5 seconds or less (when a message arrives from your bot, Telegram clients clear its typing status). Returns True on success.
@ -31,7 +31,7 @@ impl_payload! {
}
optional {
/// Unique identifier for the target message thread; supergroups only
pub message_thread_id: i32,
pub message_thread_id: ThreadId,
}
}
}

View file

@ -2,7 +2,7 @@
use serde::Serialize;
use crate::types::{Message, MessageId, Recipient, ReplyMarkup};
use crate::types::{Message, MessageId, Recipient, ReplyMarkup, ThreadId};
impl_payload! {
/// Use this method to send phone contacts. On success, the sent [`Message`] is returned.
@ -20,7 +20,7 @@ impl_payload! {
}
optional {
/// Unique identifier for the target message thread (topic) of the forum; for forum supergroups only
pub message_thread_id: i32,
pub message_thread_id: ThreadId,
/// Contact's last name
pub last_name: String [into],
/// Additional data about the contact in the form of a [vCard], 0-2048 bytes

View file

@ -2,7 +2,7 @@
use serde::Serialize;
use crate::types::{DiceEmoji, Message, MessageId, Recipient, ReplyMarkup};
use crate::types::{DiceEmoji, Message, MessageId, Recipient, ReplyMarkup, ThreadId};
impl_payload! {
/// Use this method to send an animated emoji that will display a random value. On success, the sent [`Message`] is returned.
@ -16,7 +16,7 @@ impl_payload! {
}
optional {
/// Unique identifier for the target message thread (topic) of the forum; for forum supergroups only
pub message_thread_id: i32,
pub message_thread_id: ThreadId,
/// Emoji on which the dice throw animation is based. Currently, must be one of “🎲”, “🎯”, “🏀”, “⚽”, “🎳”, or “🎰”. Dice can have values 1-6 for “🎲”, “🎯” and “🎳”, values 1-5 for “🏀” and “⚽”, and values 1-64 for “🎰”. Defaults to “🎲”
pub emoji: DiceEmoji,
/// Sends the message [silently]. Users will receive a notification with no sound.

View file

@ -3,7 +3,7 @@
use serde::Serialize;
use crate::types::{
InputFile, Message, MessageEntity, MessageId, ParseMode, Recipient, ReplyMarkup,
InputFile, Message, MessageEntity, MessageId, ParseMode, Recipient, ReplyMarkup, ThreadId,
};
impl_payload! {
@ -23,7 +23,7 @@ impl_payload! {
}
optional {
/// Unique identifier for the target message thread (topic) of the forum; for forum supergroups only
pub message_thread_id: i32,
pub message_thread_id: ThreadId,
/// Thumbnail of the file sent; can be ignored if thumbnail generation for the file is supported server-side. The thumbnail should be in JPEG format and less than 200 kB in size. A thumbnail's width and height should not exceed 320. Ignored if the file is not uploaded using multipart/form-data. Thumbnails can't be reused and can be only uploaded as a new file, so you can pass “attach://<file_attach_name>” if the thumbnail was uploaded using multipart/form-data under <file_attach_name>. [More info on Sending Files »]
///
/// [More info on Sending Files »]: crate::types::InputFile

View file

@ -2,7 +2,7 @@
use serde::Serialize;
use crate::types::{Message, ReplyMarkup};
use crate::types::{Message, MessageId, ReplyMarkup, ThreadId};
impl_payload! {
/// Use this method to send a game. On success, the sent [`Message`] is returned.
@ -18,7 +18,7 @@ impl_payload! {
}
optional {
/// Unique identifier for the target message thread (topic) of the forum; for forum supergroups only
pub message_thread_id: i32,
pub message_thread_id: ThreadId,
/// Sends the message [silently]. Users will receive a notification with no sound.
///
/// [silently]: https://telegram.org/blog/channels-2-0#silent-messages
@ -26,7 +26,8 @@ impl_payload! {
/// Protects the contents of sent messages from forwarding and saving
pub protect_content: bool,
/// If the message is a reply, ID of the original message
pub reply_to_message_id: i32,
#[serde(serialize_with = "crate::types::serialize_reply_to_message_id")]
pub reply_to_message_id: MessageId,
/// Pass _True_, if the message should be sent even if the specified replied-to message is not found
pub allow_sending_without_reply: bool,
/// A JSON-serialized object for an [inline keyboard]. If empty, one 'Play game_title' button will be shown. If not empty, the first button must launch the game.

View file

@ -3,7 +3,7 @@
use serde::Serialize;
use url::Url;
use crate::types::{InlineKeyboardMarkup, LabeledPrice, Message, Recipient};
use crate::types::{InlineKeyboardMarkup, LabeledPrice, Message, MessageId, Recipient, ThreadId};
impl_payload! {
/// Use this method to send invoices. On success, the sent [`Message`] is returned.
@ -31,7 +31,7 @@ impl_payload! {
}
optional {
/// Unique identifier for the target message thread (topic) of the forum; for forum supergroups only
pub message_thread_id: i32,
pub message_thread_id: ThreadId,
/// The maximum accepted amount for tips in the smallest units of the currency (integer, **not** float/double). For example, for a maximum tip of `US$ 1.45` pass `max_tip_amount = 145`. See the exp parameter in [`currencies.json`], it shows the number of digits past the decimal point for each currency (2 for the majority of currencies). Defaults to 0
///
/// [`currencies.json`]: https://core.telegram.org/bots/payments/currencies.json
@ -45,11 +45,11 @@ impl_payload! {
/// URL of the product photo for the invoice. Can be a photo of the goods or a marketing image for a service. People like it better when they see what they are paying for.
pub photo_url: Url,
/// Photo size in bytes
pub photo_size: String [into],
pub photo_size: u32,
/// Photo width
pub photo_width: String [into],
pub photo_width: u32,
/// Photo height
pub photo_height: String [into],
pub photo_height: u32,
/// Pass _True_, if you require the user's full name to complete the order
pub need_name: bool,
/// Pass _True_, if you require the user's phone number to complete the order
@ -71,7 +71,8 @@ impl_payload! {
/// Protects the contents of sent messages from forwarding and saving
pub protect_content: bool,
/// If the message is a reply, ID of the original message
pub reply_to_message_id: i32,
#[serde(serialize_with = "crate::types::serialize_reply_to_message_id")]
pub reply_to_message_id: MessageId,
/// Pass _True_, if the message should be sent even if the specified replied-to message is not found
pub allow_sending_without_reply: bool,
/// A JSON-serialized object for an [inline keyboard]. If empty, one 'Pay `total price`' button will be shown. If not empty, the first button must be a Pay button.

View file

@ -2,7 +2,7 @@
use serde::Serialize;
use crate::types::{Message, MessageId, Recipient, ReplyMarkup};
use crate::types::{Message, MessageId, Recipient, ReplyMarkup, ThreadId};
impl_payload! {
/// Use this method to send point on the map. On success, the sent [`Message`] is returned.
@ -20,7 +20,7 @@ impl_payload! {
}
optional {
/// Unique identifier for the target message thread (topic) of the forum; for forum supergroups only
pub message_thread_id: i32,
pub message_thread_id: ThreadId,
/// The radius of uncertainty for the location, measured in meters; 0-1500
pub horizontal_accuracy: f64,
/// Period in seconds for which the location will be updated (see [Live Locations], should be between 60 and 86400.

View file

@ -2,7 +2,7 @@
use serde::Serialize;
use crate::types::{InputMedia, Message, MessageId, Recipient};
use crate::types::{InputMedia, Message, MessageId, Recipient, ThreadId};
impl_payload! {
/// Use this method to send a group of photos, videos, documents or audios as an album. Documents and audio files can be only grouped in an album with messages of the same type. On success, an array of [`Message`]s that were sent is returned.
@ -18,7 +18,7 @@ impl_payload! {
}
optional {
/// Unique identifier for the target message thread (topic) of the forum; for forum supergroups only
pub message_thread_id: i32,
pub message_thread_id: ThreadId,
/// Sends the message [silently]. Users will receive a notification with no sound.
///
/// [silently]: https://telegram.org/blog/channels-2-0#silent-messages

View file

@ -2,7 +2,9 @@
use serde::Serialize;
use crate::types::{Message, MessageEntity, MessageId, ParseMode, Recipient, ReplyMarkup};
use crate::types::{
Message, MessageEntity, MessageId, ParseMode, Recipient, ReplyMarkup, ThreadId,
};
impl_payload! {
/// Use this method to send text messages. On success, the sent [`Message`] is returned.
@ -18,7 +20,7 @@ impl_payload! {
}
optional {
/// Unique identifier for the target message thread (topic) of the forum; for forum supergroups only
pub message_thread_id: i32,
pub message_thread_id: ThreadId,
/// Mode for parsing entities in the message text. See [formatting options] for more details.
///
/// [formatting options]: https://core.telegram.org/bots/api#formatting-options

View file

@ -3,7 +3,7 @@
use serde::Serialize;
use crate::types::{
InputFile, Message, MessageEntity, MessageId, ParseMode, Recipient, ReplyMarkup,
InputFile, Message, MessageEntity, MessageId, ParseMode, Recipient, ReplyMarkup, ThreadId,
};
impl_payload! {
@ -23,7 +23,7 @@ impl_payload! {
}
optional {
/// Unique identifier for the target message thread (topic) of the forum; for forum supergroups only
pub message_thread_id: i32,
pub message_thread_id: ThreadId,
/// Photo caption (may also be used when resending photos by _file\_id_), 0-1024 characters after entities parsing
pub caption: String [into],
/// Mode for parsing entities in the photo caption. See [formatting options] for more details.

View file

@ -4,7 +4,7 @@ use chrono::{DateTime, Utc};
use serde::Serialize;
use crate::types::{
Message, MessageEntity, MessageId, ParseMode, PollType, Recipient, ReplyMarkup,
Message, MessageEntity, MessageId, ParseMode, PollType, Recipient, ReplyMarkup, ThreadId,
};
impl_payload! {
@ -23,7 +23,7 @@ impl_payload! {
}
optional {
/// Unique identifier for the target message thread (topic) of the forum; for forum supergroups only
pub message_thread_id: i32,
pub message_thread_id: ThreadId,
/// True, if the poll needs to be anonymous, defaults to True
pub is_anonymous: bool,
/// Poll type, “quiz” or “regular”, defaults to “regular”

View file

@ -2,7 +2,7 @@
use serde::Serialize;
use crate::types::{InputFile, Message, Recipient, ReplyMarkup};
use crate::types::{InputFile, Message, MessageId, Recipient, ReplyMarkup, ThreadId};
impl_payload! {
@[multipart = sticker]
@ -21,7 +21,7 @@ impl_payload! {
}
optional {
/// Unique identifier for the target message thread (topic) of the forum; for forum supergroups only
pub message_thread_id: i32,
pub message_thread_id: ThreadId,
/// Sends the message [silently]. Users will receive a notification with no sound.
///
/// [silently]: https://telegram.org/blog/channels-2-0#silent-messages
@ -29,7 +29,8 @@ impl_payload! {
/// Protects the contents of sent messages from forwarding and saving
pub protect_content: bool,
/// If the message is a reply, ID of the original message
pub reply_to_message_id: i32,
#[serde(serialize_with = "crate::types::serialize_reply_to_message_id")]
pub reply_to_message_id: MessageId,
/// Pass _True_, if the message should be sent even if the specified replied-to message is not found
pub allow_sending_without_reply: bool,
/// Additional interface options. A JSON-serialized object for an [inline keyboard], [custom reply keyboard], instructions to remove reply keyboard or to force a reply from the user.

View file

@ -2,7 +2,7 @@
use serde::Serialize;
use crate::types::{Message, MessageId, Recipient, ReplyMarkup};
use crate::types::{Message, MessageId, Recipient, ReplyMarkup, ThreadId};
impl_payload! {
/// Use this method to send information about a venue. On success, the sent [`Message`] is returned.
@ -24,7 +24,7 @@ impl_payload! {
}
optional {
/// Unique identifier for the target message thread (topic) of the forum; for forum supergroups only
pub message_thread_id: i32,
pub message_thread_id: ThreadId,
/// Foursquare identifier of the venue
pub foursquare_id: String [into],
/// Foursquare type of the venue, if known. (For example, “arts_entertainment/default”, “arts_entertainment/aquarium” or “food/icecream”.)

View file

@ -3,7 +3,7 @@
use serde::Serialize;
use crate::types::{
InputFile, Message, MessageEntity, MessageId, ParseMode, Recipient, ReplyMarkup,
InputFile, Message, MessageEntity, MessageId, ParseMode, Recipient, ReplyMarkup, ThreadId,
};
impl_payload! {
@ -24,7 +24,7 @@ impl_payload! {
}
optional {
/// Unique identifier for the target message thread (topic) of the forum; for forum supergroups only
pub message_thread_id: i32,
pub message_thread_id: ThreadId,
/// Duration of the video in seconds
pub duration: u32,
/// Video width

View file

@ -2,7 +2,7 @@
use serde::Serialize;
use crate::types::{InputFile, Message, MessageId, Recipient, ReplyMarkup};
use crate::types::{InputFile, Message, MessageId, Recipient, ReplyMarkup, ThreadId};
impl_payload! {
@[multipart = video_note, thumb]
@ -22,7 +22,7 @@ impl_payload! {
}
optional {
/// Unique identifier for the target message thread (topic) of the forum; for forum supergroups only
pub message_thread_id: i32,
pub message_thread_id: ThreadId,
/// Duration of the video in seconds
pub duration: u32,
/// Video width and height, i.e. diameter of the video message

View file

@ -3,7 +3,7 @@
use serde::Serialize;
use crate::types::{
InputFile, Message, MessageEntity, MessageId, ParseMode, Recipient, ReplyMarkup,
InputFile, Message, MessageEntity, MessageId, ParseMode, Recipient, ReplyMarkup, ThreadId,
};
impl_payload! {
@ -25,7 +25,7 @@ impl_payload! {
}
optional {
/// Unique identifier for the target message thread (topic) of the forum; for forum supergroups only
pub message_thread_id: i32,
pub message_thread_id: ThreadId,
/// Voice message caption, 0-1024 characters after entities parsing
pub caption: String [into],
/// Mode for parsing entities in the voice message caption. See [formatting options] for more details.

View file

@ -2,14 +2,14 @@
use serde::Serialize;
use crate::types::{Message, UserId};
use crate::types::{True, UserId};
impl_payload! {
/// Use this method to set the score of the specified user in a game. On success, returns _True_. Returns an error, if the new score is not greater than the user's current score in the chat and force is False.
///
/// See also: [`SetGameScore`](crate::payloads::SetGameScore)
#[derive(Debug, PartialEq, Eq, Hash, Clone, Serialize)]
pub SetGameScoreInline (SetGameScoreInlineSetters) => Message {
pub SetGameScoreInline (SetGameScoreInlineSetters) => True {
required {
/// User identifier
pub user_id: UserId,

View file

@ -11,7 +11,7 @@ impl_payload! {
///
/// [`Message`]: crate::types::Message
/// [`StopMessageLiveLocation`]: crate::payloads::StopMessageLiveLocation
#[derive(Debug, PartialEq, Clone, Serialize)]
#[derive(Debug, PartialEq, Eq, Hash, Clone, Serialize)]
pub StopMessageLiveLocation (StopMessageLiveLocationSetters) => Message {
required {
/// Unique identifier for the target chat or username of the target channel (in the format `@channelusername`)
@ -19,10 +19,6 @@ impl_payload! {
/// Identifier of the message to edit
#[serde(flatten)]
pub message_id: MessageId,
/// Latitude of new location
pub latitude: f64,
/// Longitude of new location
pub longitude: f64,
}
optional {
/// Additional interface options. A JSON-serialized object for an [inline keyboard], [custom reply keyboard], instructions to remove reply keyboard or to force a reply from the user.

View file

@ -2,7 +2,7 @@
use serde::Serialize;
use crate::types::{Message, ReplyMarkup};
use crate::types::{ReplyMarkup, True};
impl_payload! {
/// Use this method to edit live location messages. A location can be edited until its live_period expires or editing is explicitly disabled by a call to [`StopMessageLiveLocation`]. On success, True is returned.
@ -10,15 +10,11 @@ impl_payload! {
/// See also: [`StopMessageLiveLocation`](crate::payloads::StopMessageLiveLocation)
///
/// [`StopMessageLiveLocation`]: crate::payloads::StopMessageLiveLocation
#[derive(Debug, PartialEq, Clone, Serialize)]
pub StopMessageLiveLocationInline (StopMessageLiveLocationInlineSetters) => Message {
#[derive(Debug, PartialEq, Eq, Hash, Clone, Serialize)]
pub StopMessageLiveLocationInline (StopMessageLiveLocationInlineSetters) => True {
required {
/// Identifier of the inline message
pub inline_message_id: String [into],
/// Latitude of new location
pub latitude: f64,
/// Longitude of new location
pub longitude: f64,
}
optional {
/// Additional interface options. A JSON-serialized object for an [inline keyboard], [custom reply keyboard], instructions to remove reply keyboard or to force a reply from the user.

View file

@ -2,7 +2,7 @@
use serde::Serialize;
use crate::types::{Recipient, True};
use crate::types::{Recipient, ThreadId, True};
impl_payload! {
/// Use this method to clear the list of pinned messages in a forum topic. The bot must be an administrator in the chat for this to work and must have the _can\_pin\_messages_ administrator right in the supergroup. Returns True on success.
@ -12,7 +12,7 @@ impl_payload! {
/// Unique identifier for the target chat or username of the target channel (in the format `@channelusername`)
pub chat_id: Recipient [into],
/// Unique identifier for the target message thread of the forum topic
pub message_thread_id: i32,
pub message_thread_id: ThreadId,
}
}
}

View file

@ -319,8 +319,6 @@ pub trait Requester {
&self,
chat_id: C,
message_id: MessageId,
latitude: f64,
longitude: f64,
) -> Self::StopMessageLiveLocation
where
C: Into<Recipient>;
@ -334,8 +332,6 @@ pub trait Requester {
fn stop_message_live_location_inline<I>(
&self,
inline_message_id: I,
latitude: f64,
longitude: f64,
) -> Self::StopMessageLiveLocationInline
where
I: Into<String>;
@ -682,28 +678,40 @@ pub trait Requester {
type EditForumTopic: Request<Payload = EditForumTopic, Err = Self::Err>;
/// For Telegram documentation see [`EditForumTopic`].
fn edit_forum_topic<C>(&self, chat_id: C, message_thread_id: i32) -> Self::EditForumTopic
fn edit_forum_topic<C>(&self, chat_id: C, message_thread_id: ThreadId) -> Self::EditForumTopic
where
C: Into<Recipient>;
type CloseForumTopic: Request<Payload = CloseForumTopic, Err = Self::Err>;
/// For Telegram documentation see [`CloseForumTopic`].
fn close_forum_topic<C>(&self, chat_id: C, message_thread_id: i32) -> Self::CloseForumTopic
fn close_forum_topic<C>(
&self,
chat_id: C,
message_thread_id: ThreadId,
) -> Self::CloseForumTopic
where
C: Into<Recipient>;
type ReopenForumTopic: Request<Payload = ReopenForumTopic, Err = Self::Err>;
/// For Telegram documentation see [`ReopenForumTopic`].
fn reopen_forum_topic<C>(&self, chat_id: C, message_thread_id: i32) -> Self::ReopenForumTopic
fn reopen_forum_topic<C>(
&self,
chat_id: C,
message_thread_id: ThreadId,
) -> Self::ReopenForumTopic
where
C: Into<Recipient>;
type DeleteForumTopic: Request<Payload = DeleteForumTopic, Err = Self::Err>;
/// For Telegram documentation see [`DeleteForumTopic`].
fn delete_forum_topic<C>(&self, chat_id: C, message_thread_id: i32) -> Self::DeleteForumTopic
fn delete_forum_topic<C>(
&self,
chat_id: C,
message_thread_id: ThreadId,
) -> Self::DeleteForumTopic
where
C: Into<Recipient>;
@ -713,7 +721,7 @@ pub trait Requester {
fn unpin_all_forum_topic_messages<C>(
&self,
chat_id: C,
message_thread_id: i32,
message_thread_id: ThreadId,
) -> Self::UnpinAllForumTopicMessages
where
C: Into<Recipient>;
@ -1329,6 +1337,8 @@ where
// }
#[test]
// waffle: efficiency is not important here, and I don't want to rewrite this
#[allow(clippy::format_collect)]
fn codegen_requester_methods() {
use crate::codegen::{
add_hidden_preamble,

View file

@ -100,6 +100,7 @@ pub use sticker::*;
pub use sticker_set::*;
pub use successful_payment::*;
pub use target_message::*;
pub use thread_id::*;
pub use unit_false::*;
pub use unit_true::*;
pub use update::*;
@ -191,6 +192,7 @@ mod sticker;
mod sticker_set;
mod successful_payment;
mod target_message;
mod thread_id;
mod unit_false;
mod unit_true;
mod update;
@ -248,10 +250,12 @@ mod non_telegram_types {
mod chat_id;
mod recipient;
mod seconds;
mod user_id;
pub use chat_id::*;
pub use recipient::*;
pub use seconds::*;
pub use user_id::*;
use serde::Serialize;
@ -265,7 +269,7 @@ pub(crate) fn serde_timestamp<E: serde::de::Error>(
NaiveDateTime::from_timestamp_opt(timestamp, 0)
.ok_or_else(|| E::custom("invalid timestump"))
.map(|naive| DateTime::from_utc(naive, Utc))
.map(|naive| DateTime::from_naive_utc_and_offset(naive, Utc))
}
pub(crate) mod serde_opt_date_from_unix_timestamp {
@ -301,15 +305,17 @@ pub(crate) mod serde_opt_date_from_unix_timestamp {
{
let json = r#"{"date":1}"#;
let expected =
DateTime::from_utc(chrono::NaiveDateTime::from_timestamp_opt(1, 0).unwrap(), Utc);
let expected = DateTime::from_naive_utc_and_offset(
chrono::NaiveDateTime::from_timestamp_opt(1, 0).unwrap(),
Utc,
);
let Struct { date } = serde_json::from_str(json).unwrap();
assert_eq!(date, Some(expected));
}
{
let json = r#"{}"#;
let json = "{}";
let Struct { date } = serde_json::from_str(json).unwrap();
assert_eq!(date, None);
@ -382,48 +388,38 @@ pub(crate) mod option_url_from_string {
}
}
pub(crate) mod duration_secs {
use std::time::Duration;
pub(crate) mod option_msg_id_as_int {
use crate::types::MessageId;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
pub(crate) fn serialize<S>(this: &Duration, serializer: S) -> Result<S::Ok, S::Error>
pub(crate) fn serialize<S>(this: &Option<MessageId>, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
this.as_secs().serialize(serializer)
this.map(|MessageId(id)| id).serialize(serializer)
}
pub(crate) fn deserialize<'de, D>(deserializer: D) -> Result<Duration, D::Error>
pub(crate) fn deserialize<'de, D>(deserializer: D) -> Result<Option<MessageId>, D::Error>
where
D: Deserializer<'de>,
{
u64::deserialize(deserializer).map(Duration::from_secs)
Option::<i32>::deserialize(deserializer).map(|r| r.map(MessageId))
}
#[test]
fn test() {
#[derive(Serialize, Deserialize)]
struct Struct {
#[serde(with = "crate::types::duration_secs")]
duration: Duration,
#[serde(with = "crate::types::option_msg_id_as_int")]
id: Option<MessageId>,
}
{
let json = r#"{"duration":0}"#;
let duration: Struct = serde_json::from_str(json).unwrap();
assert_eq!(duration.duration, Duration::from_secs(0));
assert_eq!(serde_json::to_string(&duration).unwrap(), json.to_owned());
let json = r#"{"duration":12}"#;
let duration: Struct = serde_json::from_str(json).unwrap();
assert_eq!(duration.duration, Duration::from_secs(12));
assert_eq!(serde_json::to_string(&duration).unwrap(), json.to_owned());
let json = r#"{"duration":1234}"#;
let duration: Struct = serde_json::from_str(json).unwrap();
assert_eq!(duration.duration, Duration::from_secs(1234));
assert_eq!(serde_json::to_string(&duration).unwrap(), json.to_owned());
let json = r#"{"id":123}"#;
let id: Struct = serde_json::from_str(json).unwrap();
assert_eq!(id.id, Some(MessageId(123)));
assert_eq!(serde_json::to_string(&id).unwrap(), json.to_owned());
}
}
}

View file

@ -1,7 +1,7 @@
use mime::Mime;
use serde::{Deserialize, Serialize};
use crate::types::{FileMeta, PhotoSize};
use crate::types::{FileMeta, PhotoSize, Seconds};
/// This object represents an animation file (GIF or H.264/MPEG-4 AVC video
/// without sound).
@ -21,7 +21,7 @@ pub struct Animation {
pub height: u32,
/// A duration of the video in seconds as defined by a sender.
pub duration: u32,
pub duration: Seconds,
/// An animation thumbnail as defined by a sender.
pub thumb: Option<PhotoSize>,
@ -62,7 +62,7 @@ mod tests {
file: FileMeta { id: "id".to_string(), unique_id: "".to_string(), size: 6500 },
width: 320,
height: 320,
duration: 59,
duration: Seconds::from_seconds(59),
thumb: Some(PhotoSize {
file: FileMeta { id: "id".to_owned(), unique_id: "".to_owned(), size: 3452 },
width: 320,

View file

@ -1,7 +1,7 @@
use mime::Mime;
use serde::{Deserialize, Serialize};
use crate::types::{FileMeta, PhotoSize};
use crate::types::{FileMeta, PhotoSize, Seconds};
/// This object represents an audio file to be treated as music by the Telegram
/// clients.
@ -15,7 +15,7 @@ pub struct Audio {
pub file: FileMeta,
/// A duration of the audio in seconds as defined by a sender.
pub duration: u32,
pub duration: Seconds,
/// A performer of the audio as defined by a sender or by audio tags.
pub performer: Option<String>,
@ -36,7 +36,7 @@ pub struct Audio {
#[cfg(test)]
mod tests {
use crate::types::FileMeta;
use crate::types::{FileMeta, Seconds};
use super::*;
@ -60,7 +60,7 @@ mod tests {
}"#;
let expected = Audio {
file: FileMeta { id: "id".to_string(), unique_id: "".to_string(), size: 123_456 },
duration: 60,
duration: Seconds::from_seconds(60),
performer: Some("Performer".to_string()),
title: Some("Title".to_string()),
mime_type: Some("application/zip".parse().unwrap()),

View file

@ -3,6 +3,7 @@ use serde::{Deserialize, Serialize};
/// This object represents a bot command.
///
/// [The official docs](https://core.telegram.org/bots/api#botcommand).
#[serde_with_macros::skip_serializing_none]
#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
pub struct BotCommand {
/// Text of the command, 1-32 characters.

View file

@ -8,5 +8,6 @@ use serde::{Deserialize, Serialize};
/// Use [@Botfather] to set up your game.
///
/// [@Botfather]: https://t.me/botfather
#[serde_with_macros::skip_serializing_none]
#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
pub struct CallbackGame;
pub struct CallbackGame {}

View file

@ -1,6 +1,8 @@
use serde::{Deserialize, Serialize};
use crate::types::{ChatId, ChatLocation, ChatPermissions, ChatPhoto, Message, True, User};
use crate::types::{
ChatId, ChatLocation, ChatPermissions, ChatPhoto, Message, Seconds, True, User,
};
/// This object represents a chat.
///
@ -29,7 +31,7 @@ pub struct Chat {
/// deleted; in seconds. Returned only in [`GetChat`].
///
/// [`GetChat`]: crate::payloads::GetChat
pub message_auto_delete_time: Option<u32>,
pub message_auto_delete_time: Option<Seconds>,
/// `true`, if non-administrators can only get the list of bots and
/// administrators in the chat. Returned only in [`GetChat`].
@ -202,7 +204,7 @@ pub struct PublicChatSupergroup {
/// unpriviledged user. Returned only from [`GetChat`].
///
/// [`GetChat`]: crate::payloads::GetChat
pub slow_mode_delay: Option<u32>,
pub slow_mode_delay: Option<Seconds>,
/// Unique identifier for the linked chat, i.e. the discussion group
/// identifier for a channel and vice versa. Returned only in [`GetChat`].
@ -355,7 +357,7 @@ impl Chat {
///
/// [`GetChat`]: crate::payloads::GetChat
#[must_use]
pub fn slow_mode_delay(&self) -> Option<u32> {
pub fn slow_mode_delay(&self) -> Option<Seconds> {
if let ChatKind::Public(this) = &self.kind {
if let PublicChatKind::Supergroup(this) = &this.kind {
return this.slow_mode_delay;

View file

@ -1,6 +1,7 @@
use serde::{Deserialize, Serialize};
/// Represents the rights of an administrator in a chat.
#[serde_with_macros::skip_serializing_none]
#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
pub struct ChatAdministratorRights {
/// `true`, if the user's presence in the chat is hidden

View file

@ -50,6 +50,15 @@ impl ChatId {
matches!(self.to_bare(), BareChatId::Channel(_))
}
/// Returns user id, if this is an id of a user.
#[must_use]
pub fn as_user(self) -> Option<UserId> {
match self.to_bare() {
BareChatId::User(u) => Some(u),
BareChatId::Group(_) | BareChatId::Channel(_) => None,
}
}
/// Converts this id to "bare" MTProto peer id.
///
/// See [`BareChatId`] for more.
@ -73,6 +82,12 @@ impl From<UserId> for ChatId {
}
}
impl PartialEq<UserId> for ChatId {
fn eq(&self, other: &UserId) -> bool {
self.is_user() && *self == ChatId::from(*other)
}
}
impl BareChatId {
/// Converts bare chat id back to normal bot API [`ChatId`].
#[allow(unused)]
@ -92,8 +107,8 @@ const MIN_MARKED_CHANNEL_ID: i64 = -1997852516352;
const MAX_MARKED_CHANNEL_ID: i64 = -1000000000000;
const MIN_MARKED_CHAT_ID: i64 = MAX_MARKED_CHANNEL_ID + 1;
const MAX_MARKED_CHAT_ID: i64 = MIN_USER_ID - 1;
const MIN_USER_ID: i64 = 0;
const MAX_USER_ID: i64 = (1 << 40) - 1;
pub(crate) const MIN_USER_ID: i64 = 0;
pub(crate) const MAX_USER_ID: i64 = (1 << 40) - 1;
#[cfg(test)]
mod tests {
@ -143,4 +158,16 @@ mod tests {
fn display() {
assert_eq!(ChatId(1).to_string(), "1");
}
#[test]
fn user_id_eq() {
assert_eq!(ChatId(12), UserId(12));
assert_eq!(ChatId(4652762), UserId(4652762));
assert_ne!(ChatId(17), UserId(42));
// The user id is not well formed, so even though `-1 == max` is true,
// we don't want user id to match
assert_eq!(-1i64, u64::MAX as i64);
assert_ne!(ChatId(-1), UserId(u64::MAX));
}
}

View file

@ -3,6 +3,7 @@ use serde::{Deserialize, Serialize};
use crate::types::User;
#[serde_with_macros::skip_serializing_none]
#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
pub struct ChatInviteLink {
/// The invite link. If the link was created by another chat administrator,

View file

@ -4,6 +4,7 @@ use serde::{Deserialize, Serialize};
use crate::types::{Chat, ChatInviteLink, User};
/// Represents a join request sent to a chat.
#[serde_with_macros::skip_serializing_none]
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct ChatJoinRequest {
/// Chat to which the request was sent

View file

@ -3,6 +3,7 @@ use serde::{Deserialize, Serialize};
use crate::types::Location;
/// Represents a location to which a chat is connected.
#[serde_with_macros::skip_serializing_none]
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct ChatLocation {
/// The location to which the supergroup is connected. Can't be a live

View file

@ -7,6 +7,7 @@ use crate::types::{UntilDate, User};
/// This object contains information about one member of the chat.
///
/// [The official docs](https://core.telegram.org/bots/api#chatmember).
#[serde_with_macros::skip_serializing_none]
#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
pub struct ChatMember {
/// Information about the user.
@ -32,6 +33,7 @@ pub enum ChatMemberKind {
}
/// Owner of the group. This struct is part of the [`ChatMemberKind`] enum.
#[serde_with_macros::skip_serializing_none]
#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
pub struct Owner {
/// Custom title for this user.
@ -43,6 +45,7 @@ pub struct Owner {
/// Administrator of the group. This struct is part of the [`ChatMemberKind`]
/// enum.
#[serde_with_macros::skip_serializing_none]
#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
pub struct Administrator {
/// Custom title for this user.
@ -104,6 +107,7 @@ pub struct Administrator {
/// User, restricted in the group. This struct is part of the [`ChatMemberKind`]
/// enum.
#[serde_with_macros::skip_serializing_none]
#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
pub struct Restricted {
/// Date when restrictions will be lifted for this user.
@ -148,6 +152,7 @@ pub struct Restricted {
/// User that was banned in the chat and can't return to it or view chat
/// messages. This struct is part of the [`ChatMemberKind`] enum.
#[serde_with_macros::skip_serializing_none]
#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
pub struct Banned {
/// Date when restrictions will be lifted for this user.

View file

@ -3,6 +3,7 @@ use serde::{Deserialize, Serialize};
use crate::types::{Chat, ChatInviteLink, ChatMember, User};
#[serde_with_macros::skip_serializing_none]
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct ChatMemberUpdated {
/// Chat the user belongs to

View file

@ -3,6 +3,7 @@ use serde::{Deserialize, Serialize};
/// This object represents a chat photo.
///
/// [The official docs](https://core.telegram.org/bots/api#chatphoto).
#[serde_with_macros::skip_serializing_none]
#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
pub struct ChatPhoto {
/// A file identifier of small (160x160) chat photo. This file_id can be

View file

@ -11,11 +11,7 @@ pub struct Dice {
/// Value of the dice.
///
/// 1-6 for [`DiceEmoji::Dice`] and [`DiceEmoji::Darts`], 1-5 for
/// [`DiceEmoji::Basketball`].
///
/// [`DiceEmoji::Dice`]: crate::types::DiceEmoji::Dice
/// [`DiceEmoji::Darts`]:crate::types::DiceEmoji::Darts
/// [`DiceEmoji::Basketball`]:crate::types::DiceEmoji::Basketball
pub value: i32,
/// Value of the dice, 1-6 for 🎲, 🎯 and 🎳 base emoji, 1-5 for 🏀 and ⚽
/// base emoji, 1-64 for 🎰 base emoji
pub value: u8,
}

View file

@ -2,27 +2,27 @@ use serde::{Deserialize, Serialize};
#[derive(Copy, Debug, Clone, PartialEq, Eq, Hash, Deserialize, Serialize)]
pub enum DiceEmoji {
/// Values from 1-6. Defaults to this variant.
/// "🎲" emoji. Values from 1-6. Defaults to this variant.
#[serde(rename = "🎲")]
Dice,
/// Values from 1-6.
/// "🎯" emoji. Values from 1-6.
#[serde(rename = "🎯")]
Darts,
/// Values from 1-5.
#[serde(rename = "🏀")]
Basketball,
/// Values 1-5
#[serde(rename = "")]
Football,
/// Values 1-5
/// "🎳" emoji. Values 1-6
#[serde(rename = "🎳")]
Bowling,
/// Values 1-64
/// "🏀" emoji. Values from 1-5.
#[serde(rename = "🏀")]
Basketball,
/// "⚽" emoji. Values 1-5
#[serde(rename = "")]
Football,
/// "🎰" emoji. Values 1-64
#[serde(rename = "🎰")]
SlotMachine,
}

View file

@ -6,6 +6,7 @@ use super::PassportFile;
/// shared with the bot by the user.
///
/// [The official docs](https://core.telegram.org/bots/api#encryptedpassportelement).
#[serde_with_macros::skip_serializing_none]
#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
pub struct EncryptedPassportElement {
/// Base64-encoded element hash for using in

View file

@ -29,26 +29,28 @@ pub struct ForceReply {
/// (has reply_to_message_id), sender of the original message.
///
/// [`Message`]: crate::types::Message
pub selective: Option<bool>,
#[serde(skip_serializing_if = "std::ops::Not::not")]
pub selective: bool,
}
impl ForceReply {
#[must_use]
pub const fn new() -> Self {
Self { force_reply: True, input_field_placeholder: None, selective: None }
Self { force_reply: True, input_field_placeholder: None, selective: false }
}
pub fn input_field_placeholder<T>(mut self, val: T) -> Self
pub fn input_field_placeholder<T>(self, val: T) -> Self
where
T: Into<Option<String>>,
{
self.input_field_placeholder = val.into();
self
Self { input_field_placeholder: val.into(), ..self }
}
/// Sets [`selective`] to `true`.
///
/// [`selective`]: ForceReply::selective
#[must_use]
pub const fn selective(mut self, val: bool) -> Self {
self.selective = Some(val);
self
pub fn selective(self) -> Self {
Self { selective: true, ..self }
}
}

View file

@ -1,3 +1,5 @@
use crate::types::ThreadId;
use serde::{Deserialize, Serialize};
/// This object represents a forum topic.
@ -7,8 +9,8 @@ use serde::{Deserialize, Serialize};
#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
pub struct ForumTopic {
/// Unique identifier of the forum topic
// FIXME: MessageThreadId or something
pub message_thread_id: i32,
#[serde(rename = "message_thread_id")]
pub thread_id: ThreadId,
/// Name of the topic.
pub name: String,

View file

@ -6,4 +6,4 @@ use serde::{Deserialize, Serialize};
/// [The official docs](https://core.telegram.org/bots/api#forumtopicclosed).
#[serde_with_macros::skip_serializing_none]
#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
pub struct ForumTopicClosed;
pub struct ForumTopicClosed {}

View file

@ -6,4 +6,4 @@ use serde::{Deserialize, Serialize};
/// [The official docs](https://core.telegram.org/bots/api#forumtopicreopened).
#[serde_with_macros::skip_serializing_none]
#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
pub struct ForumTopicReopened;
pub struct ForumTopicReopened {}

View file

@ -5,6 +5,7 @@ use crate::types::user::User;
/// This object represents one row of the high scores table for a game.
///
/// [The official docs](https://core.telegram.org/bots/api#gamehighscore).
#[serde_with_macros::skip_serializing_none]
#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
pub struct GameHighScore {
/// Position in high score table for the game.

View file

@ -6,4 +6,4 @@ use serde::{Deserialize, Serialize};
/// [The official docs](https://core.telegram.org/bots/api#generalforumtopichidden).
#[serde_with_macros::skip_serializing_none]
#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
pub struct GeneralForumTopicHidden;
pub struct GeneralForumTopicHidden {}

View file

@ -6,4 +6,4 @@ use serde::{Deserialize, Serialize};
/// [The official docs](https://core.telegram.org/bots/api#generalforumtopicunhidden).
#[serde_with_macros::skip_serializing_none]
#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
pub struct GeneralForumTopicUnhidden;
pub struct GeneralForumTopicUnhidden {}

View file

@ -4,6 +4,7 @@ use serde::{Deserialize, Serialize};
/// This object represents one button of an inline keyboard.
///
/// [The official docs](https://core.telegram.org/bots/api#inlinekeyboardbutton).
#[serde_with_macros::skip_serializing_none]
#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
pub struct InlineKeyboardButton {
/// Label text on the button.

View file

@ -11,6 +11,7 @@ use crate::types::InlineKeyboardButton;
/// [The official docs](https://core.telegram.org/bots/api#inlinekeyboardmarkup).
///
/// [inline keyboard]: https://core.telegram.org/bots#inline-keyboards-and-on-the-fly-updating
#[serde_with_macros::skip_serializing_none]
#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize, Default)]
pub struct InlineKeyboardMarkup {
/// Array of button rows, each represented by an array of

View file

@ -34,10 +34,10 @@ pub struct InlineQueryResultArticle {
pub thumb_url: Option<reqwest::Url>,
/// Thumbnail width.
pub thumb_width: Option<i32>,
pub thumb_width: Option<u32>,
/// Thumbnail height.
pub thumb_height: Option<i32>,
pub thumb_height: Option<u32>,
}
impl InlineQueryResultArticle {
@ -115,13 +115,13 @@ impl InlineQueryResultArticle {
}
#[must_use]
pub fn thumb_width(mut self, val: i32) -> Self {
pub fn thumb_width(mut self, val: u32) -> Self {
self.thumb_width = Some(val);
self
}
#[must_use]
pub fn thumb_height(mut self, val: i32) -> Self {
pub fn thumb_height(mut self, val: u32) -> Self {
self.thumb_height = Some(val);
self
}

View file

@ -42,10 +42,10 @@ pub struct InlineQueryResultContact {
pub thumb_url: Option<reqwest::Url>,
/// Thumbnail width.
pub thumb_width: Option<i32>,
pub thumb_width: Option<u32>,
/// Thumbnail height.
pub thumb_height: Option<i32>,
pub thumb_height: Option<u32>,
}
impl InlineQueryResultContact {
@ -128,13 +128,13 @@ impl InlineQueryResultContact {
}
#[must_use]
pub fn thumb_width(mut self, val: i32) -> Self {
pub fn thumb_width(mut self, val: u32) -> Self {
self.thumb_width = Some(val);
self
}
#[must_use]
pub fn thumb_height(mut self, val: i32) -> Self {
pub fn thumb_height(mut self, val: u32) -> Self {
self.thumb_height = Some(val);
self
}

View file

@ -56,10 +56,10 @@ pub struct InlineQueryResultDocument {
pub thumb_url: Option<reqwest::Url>,
/// Thumbnail width.
pub thumb_width: Option<i32>,
pub thumb_width: Option<u32>,
/// Thumbnail height.
pub thumb_height: Option<i32>,
pub thumb_height: Option<u32>,
}
impl InlineQueryResultDocument {
@ -140,13 +140,13 @@ impl InlineQueryResultDocument {
}
#[must_use]
pub fn thumb_width(mut self, val: i32) -> Self {
pub fn thumb_width(mut self, val: u32) -> Self {
self.thumb_width = Some(val);
self
}
#[must_use]
pub fn thumb_height(mut self, val: i32) -> Self {
pub fn thumb_height(mut self, val: u32) -> Self {
self.thumb_height = Some(val);
self
}

View file

@ -1,6 +1,6 @@
use serde::{Deserialize, Serialize};
use crate::types::{InlineKeyboardMarkup, InputMessageContent, MessageEntity, ParseMode};
use crate::types::{InlineKeyboardMarkup, InputMessageContent, MessageEntity, ParseMode, Seconds};
/// Represents a link to an animated GIF file.
///
@ -19,13 +19,13 @@ pub struct InlineQueryResultGif {
pub gif_url: reqwest::Url,
/// Width of the GIF.
pub gif_width: Option<i32>,
pub gif_width: Option<u32>,
/// Height of the GIFv.
pub gif_height: Option<i32>,
pub gif_height: Option<u32>,
/// Duration of the GIF.
pub gif_duration: Option<i32>,
pub gif_duration: Option<Seconds>,
/// URL of the static thumbnail for the result (jpeg or gif).
pub thumb_url: reqwest::Url,
@ -93,19 +93,19 @@ impl InlineQueryResultGif {
}
#[must_use]
pub fn gif_width(mut self, val: i32) -> Self {
pub fn gif_width(mut self, val: u32) -> Self {
self.gif_width = Some(val);
self
}
#[must_use]
pub fn gif_height(mut self, val: i32) -> Self {
pub fn gif_height(mut self, val: u32) -> Self {
self.gif_height = Some(val);
self
}
#[must_use]
pub fn gif_duration(mut self, val: i32) -> Self {
pub fn gif_duration(mut self, val: Seconds) -> Self {
self.gif_duration = Some(val);
self
}

View file

@ -29,7 +29,7 @@ pub struct InlineQueryResultLocation {
/// Period in seconds for which the location can be updated, should be
/// between 60 and 86400.
pub live_period: Option<i32>,
pub live_period: Option<u32>,
/// For live locations, a direction in which the user is moving, in degrees.
/// Must be between 1 and 360 if specified.
@ -116,7 +116,7 @@ impl InlineQueryResultLocation {
}
#[must_use]
pub fn live_period(mut self, val: i32) -> Self {
pub fn live_period(mut self, val: u32) -> Self {
self.live_period = Some(val);
self
}

View file

@ -1,6 +1,6 @@
use serde::{Deserialize, Serialize};
use crate::types::{InlineKeyboardMarkup, InputMessageContent, MessageEntity, ParseMode};
use crate::types::{InlineKeyboardMarkup, InputMessageContent, MessageEntity, ParseMode, Seconds};
/// Represents a link to a video animation (H.264/MPEG-4 AVC video without
/// sound).
@ -16,17 +16,19 @@ pub struct InlineQueryResultMpeg4Gif {
/// Unique identifier for this result, 1-64 bytes.
pub id: String,
// FIXME: rename everything so that it doesn't have `mpeg4_` (and similarly for other
// `InlineQueryResult*`)
/// A valid URL for the MP4 file. File size must not exceed 1MB.
pub mpeg4_url: reqwest::Url,
/// Video width.
pub mpeg4_width: Option<i32>,
pub mpeg4_width: Option<u32>,
/// Video height.
pub mpeg4_height: Option<i32>,
pub mpeg4_height: Option<u32>,
/// Video duration.
pub mpeg4_duration: Option<i32>,
pub mpeg4_duration: Option<Seconds>,
/// URL of the static thumbnail (jpeg or gif) for the result.
pub thumb_url: reqwest::Url,
@ -94,19 +96,19 @@ impl InlineQueryResultMpeg4Gif {
}
#[must_use]
pub fn mpeg4_width(mut self, val: i32) -> Self {
pub fn mpeg4_width(mut self, val: u32) -> Self {
self.mpeg4_width = Some(val);
self
}
#[must_use]
pub fn mpeg4_height(mut self, val: i32) -> Self {
pub fn mpeg4_height(mut self, val: u32) -> Self {
self.mpeg4_height = Some(val);
self
}
#[must_use]
pub fn mpeg4_duration(mut self, val: i32) -> Self {
pub fn mpeg4_duration(mut self, val: Seconds) -> Self {
self.mpeg4_duration = Some(val);
self
}

View file

@ -23,10 +23,10 @@ pub struct InlineQueryResultPhoto {
pub thumb_url: reqwest::Url,
/// Width of the photo.
pub photo_width: Option<i32>,
pub photo_width: Option<u32>,
/// Height of the photo.
pub photo_height: Option<i32>,
pub photo_height: Option<u32>,
/// Title for the result.
pub title: Option<String>,
@ -100,13 +100,13 @@ impl InlineQueryResultPhoto {
}
#[must_use]
pub fn photo_width(mut self, val: i32) -> Self {
pub fn photo_width(mut self, val: u32) -> Self {
self.photo_width = Some(val);
self
}
#[must_use]
pub fn photo_height(mut self, val: i32) -> Self {
pub fn photo_height(mut self, val: u32) -> Self {
self.photo_height = Some(val);
self
}

View file

@ -55,10 +55,10 @@ pub struct InlineQueryResultVenue {
pub thumb_url: Option<reqwest::Url>,
/// Thumbnail width.
pub thumb_width: Option<i32>,
pub thumb_width: Option<u32>,
/// Thumbnail height.
pub thumb_height: Option<i32>,
pub thumb_height: Option<u32>,
}
impl InlineQueryResultVenue {
@ -173,13 +173,13 @@ impl InlineQueryResultVenue {
}
#[must_use]
pub fn thumb_width(mut self, val: i32) -> Self {
pub fn thumb_width(mut self, val: u32) -> Self {
self.thumb_width = Some(val);
self
}
#[must_use]
pub fn thumb_height(mut self, val: i32) -> Self {
pub fn thumb_height(mut self, val: u32) -> Self {
self.thumb_height = Some(val);
self
}

View file

@ -1,7 +1,7 @@
use mime::Mime;
use serde::{Deserialize, Serialize};
use crate::types::{InlineKeyboardMarkup, InputMessageContent, MessageEntity, ParseMode};
use crate::types::{InlineKeyboardMarkup, InputMessageContent, MessageEntity, ParseMode, Seconds};
/// Represents a link to a page containing an embedded video player or a video
/// file.
@ -46,13 +46,13 @@ pub struct InlineQueryResultVideo {
pub caption_entities: Option<Vec<MessageEntity>>,
/// Video width.
pub video_width: Option<i32>,
pub video_width: Option<u32>,
/// Video height.
pub video_height: Option<i32>,
pub video_height: Option<u32>,
/// Video duration in seconds.
pub video_duration: Option<i32>,
pub video_duration: Option<Seconds>,
/// Short description of the result.
pub description: Option<String>,
@ -158,19 +158,19 @@ impl InlineQueryResultVideo {
}
#[must_use]
pub fn video_width(mut self, val: i32) -> Self {
pub fn video_width(mut self, val: u32) -> Self {
self.video_width = Some(val);
self
}
#[must_use]
pub fn video_height(mut self, val: i32) -> Self {
pub fn video_height(mut self, val: u32) -> Self {
self.video_height = Some(val);
self
}
#[must_use]
pub fn video_duration(mut self, val: i32) -> Self {
pub fn video_duration(mut self, val: Seconds) -> Self {
self.video_duration = Some(val);
self
}

View file

@ -1,6 +1,6 @@
use serde::{Deserialize, Serialize};
use crate::types::{InlineKeyboardMarkup, InputMessageContent, MessageEntity, ParseMode};
use crate::types::{InlineKeyboardMarkup, InputMessageContent, MessageEntity, ParseMode, Seconds};
/// Represents a link to a voice recording in an .ogg container encoded with
/// OPUS.
@ -38,7 +38,7 @@ pub struct InlineQueryResultVoice {
pub caption_entities: Option<Vec<MessageEntity>>,
/// Recording duration in seconds.
pub voice_duration: Option<i32>,
pub voice_duration: Option<Seconds>,
/// [Inline keyboard] attached to the message.
///
@ -113,7 +113,7 @@ impl InlineQueryResultVoice {
}
#[must_use]
pub fn voice_duration(mut self, value: i32) -> Self {
pub fn voice_duration(mut self, value: Seconds) -> Self {
self.voice_duration = Some(value);
self
}

View file

@ -3,6 +3,7 @@ use serde::{Deserialize, Serialize};
/// This object contains basic information about an invoice.
///
/// [The official docs](https://core.telegram.org/bots/api#invoice).
#[serde_with_macros::skip_serializing_none]
#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
pub struct Invoice {
/// Product name.
@ -25,5 +26,5 @@ pub struct Invoice {
/// majority of currencies).
///
/// [`currencies.json`]: https://core.telegram.org/bots/payments/currencies.json
pub total_amount: i32,
pub total_amount: u32,
}

View file

@ -3,6 +3,7 @@ use serde::{Deserialize, Serialize};
/// This object represents a portion of the price for goods or services.
///
/// [The official docs](https://core.telegram.org/bots/api#labeledprice).
#[serde_with_macros::skip_serializing_none]
#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
pub struct LabeledPrice {
/// Portion label.
@ -16,11 +17,11 @@ pub struct LabeledPrice {
///
/// [currency]: https://core.telegram.org/bots/payments#supported-currencies
/// [`currencies.json`]: https://core.telegram.org/bots/payments/currencies.json
pub amount: i32,
pub amount: u32,
}
impl LabeledPrice {
pub fn new<S>(label: S, amount: i32) -> Self
pub fn new<S>(label: S, amount: u32) -> Self
where
S: Into<String>,
{
@ -36,7 +37,7 @@ impl LabeledPrice {
}
#[must_use]
pub fn amount(mut self, val: i32) -> Self {
pub fn amount(mut self, val: u32) -> Self {
self.amount = val;
self
}

View file

@ -1,6 +1,9 @@
use serde::{Deserialize, Serialize};
use crate::types::Seconds;
/// This object represents a point on the map.
#[serde_with_macros::skip_serializing_none]
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct Location {
/// Longitude as defined by sender.
@ -14,7 +17,7 @@ pub struct Location {
/// Time relative to the message sending date, during which the location can
/// be updated, in seconds. For active live locations only.
pub live_period: Option<u32>,
pub live_period: Option<Seconds>,
/// The direction in which user is moving, in degrees; 1-360. For active
/// live locations only.

View file

@ -4,6 +4,7 @@ use serde::{Deserialize, Serialize};
/// default.
///
/// [The official docs](https://core.telegram.org/bots/api#maskposition).
#[serde_with_macros::skip_serializing_none]
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct MaskPosition {
/// The part of the face relative to which the mask should be placed. One

View file

@ -7,6 +7,7 @@ use crate::types::User;
/// Returned only in [`GetMe`].
///
/// [`GetMe`]: crate::payloads::GetMe
#[serde_with_macros::skip_serializing_none]
#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
pub struct Me {
#[serde(flatten)]

View file

@ -9,14 +9,15 @@ use crate::types::{
ForumTopicCreated, ForumTopicEdited, ForumTopicReopened, Game, GeneralForumTopicHidden,
GeneralForumTopicUnhidden, InlineKeyboardMarkup, Invoice, Location,
MessageAutoDeleteTimerChanged, MessageEntity, MessageEntityRef, MessageId, PassportData,
PhotoSize, Poll, ProximityAlertTriggered, Sticker, SuccessfulPayment, True, User, Venue, Video,
VideoChatEnded, VideoChatParticipantsInvited, VideoChatScheduled, VideoChatStarted, VideoNote,
Voice, WebAppData, WriteAccessAllowed,
PhotoSize, Poll, ProximityAlertTriggered, Sticker, SuccessfulPayment, ThreadId, True, User,
Venue, Video, VideoChatEnded, VideoChatParticipantsInvited, VideoChatScheduled,
VideoChatStarted, VideoNote, Voice, WebAppData, WriteAccessAllowed,
};
/// This object represents a message.
///
/// [The official docs](https://core.telegram.org/bots/api#message).
#[serde_with_macros::skip_serializing_none]
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct Message {
/// Unique message identifier inside this chat.
@ -25,9 +26,8 @@ pub struct Message {
/// Unique identifier of a message thread to which the message belongs; for
/// supergroups only.
// FIXME: MessageThreadId or such
#[serde(rename = "message_thread_id")]
pub thread_id: Option<i32>,
pub thread_id: Option<ThreadId>,
/// Date the message was sent in Unix time.
#[serde(with = "crate::types::serde_date_from_unix_timestamp")]
@ -78,6 +78,9 @@ pub enum MessageKind {
VideoChatEnded(MessageVideoChatEnded),
VideoChatParticipantsInvited(MessageVideoChatParticipantsInvited),
WebAppData(MessageWebAppData),
/// An empty, content-less message, that can appear in callback queries
/// attached to old messages.
Empty {},
}
#[serde_with_macros::skip_serializing_none]
@ -119,19 +122,20 @@ pub struct MessageCommon {
/// `true`, if the message is sent to a forum topic.
// FIXME: `is_topic_message` is included even in service messages, like ForumTopicCreated.
// more this to `Message`
#[serde(default)]
#[serde(default, skip_serializing_if = "std::ops::Not::not")]
pub is_topic_message: bool,
/// `true`, if the message is a channel post that was automatically
/// forwarded to the connected discussion group.
#[serde(default)]
#[serde(default, skip_serializing_if = "std::ops::Not::not")]
pub is_automatic_forward: bool,
/// `true`, if the message can't be forwarded.
#[serde(default)]
#[serde(default, skip_serializing_if = "std::ops::Not::not")]
pub has_protected_content: bool,
}
#[serde_with_macros::skip_serializing_none]
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct MessageNewChatMembers {
/// New members that were added to the group or supergroup and
@ -140,6 +144,7 @@ pub struct MessageNewChatMembers {
pub new_chat_members: Vec<User>,
}
#[serde_with_macros::skip_serializing_none]
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct MessageLeftChatMember {
/// A member was removed from the group, information about them (this
@ -147,30 +152,35 @@ pub struct MessageLeftChatMember {
pub left_chat_member: User,
}
#[serde_with_macros::skip_serializing_none]
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct MessageNewChatTitle {
/// A chat title was changed to this value.
pub new_chat_title: String,
}
#[serde_with_macros::skip_serializing_none]
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct MessageNewChatPhoto {
/// A chat photo was change to this value.
pub new_chat_photo: Vec<PhotoSize>,
}
#[serde_with_macros::skip_serializing_none]
#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
pub struct MessageDeleteChatPhoto {
/// Service message: the chat photo was deleted.
pub delete_chat_photo: True,
}
#[serde_with_macros::skip_serializing_none]
#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
pub struct MessageGroupChatCreated {
/// Service message: the group has been created.
pub group_chat_created: True,
}
#[serde_with_macros::skip_serializing_none]
#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
pub struct MessageSupergroupChatCreated {
/// Service message: the supergroup has been created. This field cant
@ -181,6 +191,7 @@ pub struct MessageSupergroupChatCreated {
pub supergroup_chat_created: True,
}
#[serde_with_macros::skip_serializing_none]
#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
pub struct MessageChannelChatCreated {
/// Service message: the channel has been created. This field cant be
@ -191,6 +202,7 @@ pub struct MessageChannelChatCreated {
pub channel_chat_created: True,
}
#[serde_with_macros::skip_serializing_none]
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct MessageMessageAutoDeleteTimerChanged {
/// Service message: auto-delete timer settings changed in the chat.
@ -225,6 +237,7 @@ pub enum ChatMigration {
},
}
#[serde_with_macros::skip_serializing_none]
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct MessagePinned {
/// Specified message was pinned. Note that the Message object in this
@ -234,6 +247,7 @@ pub struct MessagePinned {
pub pinned: Box<Message>,
}
#[serde_with_macros::skip_serializing_none]
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct MessageInvoice {
/// Message is an invoice for a [payment], information about the
@ -244,6 +258,7 @@ pub struct MessageInvoice {
pub invoice: Invoice,
}
#[serde_with_macros::skip_serializing_none]
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct MessageSuccessfulPayment {
/// Message is a service message about a successful payment,
@ -253,6 +268,7 @@ pub struct MessageSuccessfulPayment {
pub successful_payment: SuccessfulPayment,
}
#[serde_with_macros::skip_serializing_none]
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct MessageConnectedWebsite {
/// The domain name of the website on which the user has logged in.
@ -262,6 +278,7 @@ pub struct MessageConnectedWebsite {
pub connected_website: String,
}
#[serde_with_macros::skip_serializing_none]
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct MessagePassportData {
/// Telegram Passport data.
@ -269,6 +286,7 @@ pub struct MessagePassportData {
}
/// Information about forwarded message.
#[serde_with_macros::skip_serializing_none]
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct Forward {
/// Date the original message was sent in Unix time.
@ -288,8 +306,13 @@ pub struct Forward {
/// For messages forwarded from channels, identifier of the original message
/// in the channel
#[serde(rename = "forward_from_message_id")]
pub message_id: Option<i32>,
#[serde(
rename = "forward_from_message_id",
with = "crate::types::option_msg_id_as_int",
default,
skip_serializing_if = "Option::is_none"
)]
pub message_id: Option<MessageId>,
}
/// The entity that sent the original message that later was forwarded.
@ -336,6 +359,7 @@ pub enum MediaKind {
Migration(ChatMigration),
}
#[serde_with_macros::skip_serializing_none]
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct MediaAnimation {
/// Message is an animation, information about the animation. For
@ -348,7 +372,7 @@ pub struct MediaAnimation {
/// For messages with a caption, special entities like usernames, URLs,
/// bot commands, etc. that appear in the caption.
#[serde(default = "Vec::new")]
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub caption_entities: Vec<MessageEntity>,
/// `true`, if the message media is covered by a spoiler animation.
@ -368,7 +392,7 @@ pub struct MediaAudio {
/// For messages with a caption, special entities like usernames, URLs,
/// bot commands, etc. that appear in the caption.
#[serde(default = "Vec::new")]
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub caption_entities: Vec<MessageEntity>,
/// The unique identifier of a media message group this message belongs
@ -376,6 +400,7 @@ pub struct MediaAudio {
pub media_group_id: Option<String>,
}
#[serde_with_macros::skip_serializing_none]
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct MediaContact {
/// Message is a shared contact, information about the contact.
@ -393,7 +418,7 @@ pub struct MediaDocument {
/// For messages with a caption, special entities like usernames, URLs,
/// bot commands, etc. that appear in the caption.
#[serde(default)]
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub caption_entities: Vec<MessageEntity>,
/// The unique identifier of a media message group this message belongs
@ -401,6 +426,7 @@ pub struct MediaDocument {
pub media_group_id: Option<String>,
}
#[serde_with_macros::skip_serializing_none]
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct MediaGame {
/// Message is a game, information about the game. [More
@ -410,6 +436,7 @@ pub struct MediaGame {
pub game: Game,
}
#[serde_with_macros::skip_serializing_none]
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct MediaLocation {
/// Message is a shared location, information about the location.
@ -427,7 +454,7 @@ pub struct MediaPhoto {
/// For messages with a caption, special entities like usernames, URLs,
/// bot commands, etc. that appear in the caption.
#[serde(default = "Vec::new")]
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub caption_entities: Vec<MessageEntity>,
/// `true`, if the message media is covered by a spoiler animation.
@ -439,18 +466,21 @@ pub struct MediaPhoto {
pub media_group_id: Option<String>,
}
#[serde_with_macros::skip_serializing_none]
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct MediaPoll {
/// Message is a native poll, information about the poll.
pub poll: Poll,
}
#[serde_with_macros::skip_serializing_none]
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct MediaSticker {
/// Message is a sticker, information about the sticker.
pub sticker: Sticker,
}
#[serde_with_macros::skip_serializing_none]
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct MediaText {
/// For text messages, the actual UTF-8 text of the message, 0-4096
@ -459,7 +489,7 @@ pub struct MediaText {
/// For text messages, special entities like usernames, URLs, bot
/// commands, etc. that appear in the text.
#[serde(default = "Vec::new")]
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub entities: Vec<MessageEntity>,
}
@ -474,7 +504,7 @@ pub struct MediaVideo {
/// For messages with a caption, special entities like usernames, URLs,
/// bot commands, etc. that appear in the caption.
#[serde(default = "Vec::new")]
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub caption_entities: Vec<MessageEntity>,
/// `true`, if the message media is covered by a spoiler animation.
@ -486,6 +516,7 @@ pub struct MediaVideo {
pub media_group_id: Option<String>,
}
#[serde_with_macros::skip_serializing_none]
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct MediaVideoNote {
/// Message is a [video note], information about the video message.
@ -505,7 +536,7 @@ pub struct MediaVoice {
/// For messages with a caption, special entities like usernames, URLs,
/// bot commands, etc. that appear in the caption.
#[serde(default = "Vec::new")]
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub caption_entities: Vec<MessageEntity>,
}
@ -516,12 +547,14 @@ pub struct MediaVenue {
// Note: for backward compatibility telegram also sends `location` field, but we ignore it
}
#[serde_with_macros::skip_serializing_none]
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct MessageDice {
/// Message is a dice with random value from 1 to 6.
pub dice: Dice,
}
#[serde_with_macros::skip_serializing_none]
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct MessageProximityAlertTriggered {
/// Service message. A user in the chat triggered another user's proximity
@ -529,6 +562,7 @@ pub struct MessageProximityAlertTriggered {
pub proximity_alert_triggered: ProximityAlertTriggered,
}
#[serde_with_macros::skip_serializing_none]
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct MessageWriteAccessAllowed {
/// Service message: the user allowed the bot added to the attachment menu
@ -536,66 +570,77 @@ pub struct MessageWriteAccessAllowed {
pub write_access_allowed: WriteAccessAllowed,
}
#[serde_with_macros::skip_serializing_none]
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct MessageForumTopicCreated {
/// Service message: forum topic created.
pub forum_topic_created: ForumTopicCreated,
}
#[serde_with_macros::skip_serializing_none]
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct MessageForumTopicEdited {
/// Service message: forum topic edited.
pub forum_topic_edited: ForumTopicEdited,
}
#[serde_with_macros::skip_serializing_none]
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct MessageForumTopicClosed {
/// Service message: forum topic closed.
pub forum_topic_closed: ForumTopicClosed,
}
#[serde_with_macros::skip_serializing_none]
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct MessageForumTopicReopened {
/// Service message: forum topic reopened.
pub forum_topic_reopened: ForumTopicReopened,
}
#[serde_with_macros::skip_serializing_none]
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct MessageGeneralForumTopicHidden {
/// Service message: the 'General' forum topic hidden.
pub general_forum_topic_hidden: GeneralForumTopicHidden,
}
#[serde_with_macros::skip_serializing_none]
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct MessageGeneralForumTopicUnhidden {
/// Service message: the 'General' forum topic unhidden.
pub general_forum_topic_unhidden: GeneralForumTopicUnhidden,
}
#[serde_with_macros::skip_serializing_none]
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct MessageVideoChatScheduled {
/// Service message: video chat scheduled
pub video_chat_scheduled: VideoChatScheduled,
}
#[serde_with_macros::skip_serializing_none]
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct MessageVideoChatStarted {
/// Service message: video chat started.
pub video_chat_started: VideoChatStarted,
}
#[serde_with_macros::skip_serializing_none]
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct MessageVideoChatEnded {
/// Service message: video chat ended.
pub video_chat_ended: VideoChatEnded,
}
#[serde_with_macros::skip_serializing_none]
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct MessageVideoChatParticipantsInvited {
/// Service message: new participants invited to a video chat.
pub video_chat_participants_invited: VideoChatParticipantsInvited,
}
#[serde_with_macros::skip_serializing_none]
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct MessageWebAppData {
/// Service message: data sent by a Web App.
@ -612,10 +657,10 @@ mod getters {
MediaLocation, MediaPhoto, MediaPoll, MediaSticker, MediaText, MediaVenue, MediaVideo,
MediaVideoNote, MediaVoice, Message, MessageChannelChatCreated, MessageCommon,
MessageConnectedWebsite, MessageDeleteChatPhoto, MessageDice, MessageEntity,
MessageGroupChatCreated, MessageInvoice, MessageLeftChatMember, MessageNewChatMembers,
MessageNewChatPhoto, MessageNewChatTitle, MessagePassportData, MessagePinned,
MessageProximityAlertTriggered, MessageSuccessfulPayment, MessageSupergroupChatCreated,
MessageVideoChatParticipantsInvited, PhotoSize, True, User,
MessageGroupChatCreated, MessageId, MessageInvoice, MessageLeftChatMember,
MessageNewChatMembers, MessageNewChatPhoto, MessageNewChatTitle, MessagePassportData,
MessagePinned, MessageProximityAlertTriggered, MessageSuccessfulPayment,
MessageSupergroupChatCreated, MessageVideoChatParticipantsInvited, PhotoSize, True, User,
};
/// Getters for [Message] fields from [telegram docs].
@ -694,7 +739,7 @@ mod getters {
}
#[must_use]
pub fn forward_from_message_id(&self) -> Option<i32> {
pub fn forward_from_message_id(&self) -> Option<MessageId> {
self.forward().and_then(|f| f.message_id)
}
@ -1446,6 +1491,7 @@ impl Message {
#[cfg(test)]
mod tests {
use cool_asserts::assert_matches;
use serde_json::from_str;
use crate::types::*;
@ -1920,4 +1966,37 @@ mod tests {
let _: Message = serde_json::from_str(json).unwrap();
}
/// Regression test for <https://github.com/teloxide/teloxide/issues/873>
#[test]
fn empty_message() {
let json = r#"{"chat": {"first_name": "FN", "id": 1234567890, "type": "private"}, "date": 0, "message_id": 875400}"#;
let msg: Message = serde_json::from_str(json).unwrap();
assert_matches!(msg.kind, MessageKind::Empty {})
}
#[test]
fn issue_874() {
let json = r#"{
"chat": {
"id": -1001840751935,
"is_forum": true,
"title": "AI",
"type": "supergroup"
},
"date": 1682191229,
"forum_topic_closed": {},
"from": {
"first_name": "Владислав",
"id": 112455916,
"is_bot": false,
"language_code": "en",
"username": "scv977"
},
"message_id": 62
}"#;
let _: Message = serde_json::from_str(json).unwrap();
}
}

View file

@ -1,9 +1,12 @@
use serde::{Deserialize, Serialize};
use crate::types::Seconds;
/// This object represents a service message about a change in auto-delete timer
/// settings.
#[serde_with_macros::skip_serializing_none]
#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
pub struct MessageAutoDeleteTimerChanged {
/// New auto-delete time for messages in the chat
pub message_auto_delete_time: u32,
pub message_auto_delete_time: Seconds,
}

View file

@ -9,6 +9,7 @@ use crate::types::{User, UserId};
/// For example, hashtags, usernames, URLs, etc.
///
/// [The official docs](https://core.telegram.org/bots/api#messageentity).
#[serde_with_macros::skip_serializing_none]
#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
pub struct MessageEntity {
#[serde(flatten)]

View file

@ -5,6 +5,13 @@ use serde::{Deserialize, Serialize};
#[serde(from = "MessageIdRaw", into = "MessageIdRaw")]
pub struct MessageId(pub i32);
// N.B. we [de]serialize `MessageId` as `{"message_id":n}`, which means that if
// you want just an integer, you need to special case it with something
// like `serde(with = "crate::types::option_msg_id_as_int")]`
//
// (we can't change the default format of `MessageId` because it's returned
// by some methods and we can't change serialization there)
#[derive(Serialize, Deserialize)]
struct MessageIdRaw {
message_id: i32,

View file

@ -5,6 +5,7 @@ use crate::types::ShippingAddress;
/// This object represents information about an order.
///
/// [The official docs](https://core.telegram.org/bots/api#orderinfo).
#[serde_with_macros::skip_serializing_none]
#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize, Default)]
pub struct OrderInfo {
/// User's name.

Some files were not shown because too many files have changed in this diff Show more