diff --git a/crates/teloxide-core/CHANGELOG.md b/crates/teloxide-core/CHANGELOG.md index 6e2a1a00..98ddb797 100644 --- a/crates/teloxide-core/CHANGELOG.md +++ b/crates/teloxide-core/CHANGELOG.md @@ -55,6 +55,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `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]) [pr852]: https://github.com/teloxide/teloxide/pull/853 [pr859]: https://github.com/teloxide/teloxide/pull/859 diff --git a/crates/teloxide-core/src/types.rs b/crates/teloxide-core/src/types.rs index 96ae48ea..371ab4c4 100644 --- a/crates/teloxide-core/src/types.rs +++ b/crates/teloxide-core/src/types.rs @@ -386,6 +386,42 @@ pub(crate) mod option_url_from_string { } } +pub(crate) mod option_msg_id_as_int { + use crate::types::MessageId; + + use serde::{Deserialize, Deserializer, Serialize, Serializer}; + + pub(crate) fn serialize(this: &Option, serializer: S) -> Result + where + S: Serializer, + { + this.map(|MessageId(id)| id).serialize(serializer) + } + + pub(crate) fn deserialize<'de, D>(deserializer: D) -> Result, D::Error> + where + D: Deserializer<'de>, + { + Option::::deserialize(deserializer).map(|r| r.map(MessageId)) + } + + #[test] + fn test() { + #[derive(Serialize, Deserialize)] + struct Struct { + #[serde(with = "crate::types::option_msg_id_as_int")] + id: Option, + } + + { + 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()); + } + } +} + pub(crate) fn serialize_reply_to_message_id( this: &Option, serializer: S, diff --git a/crates/teloxide-core/src/types/message.rs b/crates/teloxide-core/src/types/message.rs index bce58b21..889bfccc 100644 --- a/crates/teloxide-core/src/types/message.rs +++ b/crates/teloxide-core/src/types/message.rs @@ -9,9 +9,9 @@ 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, ThreadId, + PhotoSize, Poll, ProximityAlertTriggered, Sticker, SuccessfulPayment, ThreadId, True, User, + Venue, Video, VideoChatEnded, VideoChatParticipantsInvited, VideoChatScheduled, + VideoChatStarted, VideoNote, Voice, WebAppData, WriteAccessAllowed, }; /// This object represents a message. @@ -290,8 +290,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, + #[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, } /// The entity that sent the original message that later was forwarded. @@ -614,10 +619,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]. @@ -696,7 +701,7 @@ mod getters { } #[must_use] - pub fn forward_from_message_id(&self) -> Option { + pub fn forward_from_message_id(&self) -> Option { self.forward().and_then(|f| f.message_id) } diff --git a/crates/teloxide-core/src/types/message_id.rs b/crates/teloxide-core/src/types/message_id.rs index c9c405ae..d0f1212b 100644 --- a/crates/teloxide-core/src/types/message_id.rs +++ b/crates/teloxide-core/src/types/message_id.rs @@ -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,