1use serde::{Deserialize, Serialize};
2
3use crate::background::ChatBackground;
4use crate::chat::{Chat, Location, Venue};
5use crate::checklist::{Checklist, ChecklistTasksAdded, ChecklistTasksDone};
6use crate::community::{CommunityChatAdded, CommunityChatRemoved};
7use crate::direct_messages::{
8 DirectMessagePriceChanged, DirectMessagesTopic, PaidMessagePriceChanged,
9};
10use crate::file::{Animation, Audio, Document, LivePhoto, PhotoSize, Video, VideoNote, Voice};
11use crate::forum::{
12 ForumTopicClosed, ForumTopicCreated, ForumTopicEdited, ForumTopicReopened,
13 GeneralForumTopicHidden, GeneralForumTopicUnhidden,
14};
15use crate::games::Game;
16use crate::gifts::{GiftInfo, UniqueGiftInfo};
17use crate::giveaway::{Giveaway, GiveawayCompleted, GiveawayCreated, GiveawayWinners};
18use crate::keyboard::InlineKeyboardMarkup;
19use crate::managed_bot::ManagedBotCreated;
20use crate::passport::PassportData;
21use crate::payments::{Invoice, PaidMediaInfo, RefundedPayment, SuccessfulPayment};
22use crate::poll::{Poll, PollOptionAdded, PollOptionDeleted};
23use crate::rich_message::RichMessage;
24use crate::shared::{ChatShared, UsersShared};
25use crate::sticker::Sticker;
26use crate::story::Story;
27use crate::suggested_post::{
28 SuggestedPostApprovalFailed, SuggestedPostApproved, SuggestedPostDeclined, SuggestedPostInfo,
29 SuggestedPostPaid, SuggestedPostRefunded,
30};
31use crate::update::ChatBoostAdded;
32use crate::user::User;
33use crate::video_chat::{
34 VideoChatEnded, VideoChatParticipantsInvited, VideoChatScheduled, VideoChatStarted,
35};
36
37#[derive(Debug, Clone, Default, Serialize, Deserialize)]
53#[non_exhaustive]
54pub struct Message {
55 pub message_id: i64,
60
61 #[serde(skip_serializing_if = "Option::is_none")]
63 pub receiver_user: Option<User>,
64
65 #[serde(skip_serializing_if = "Option::is_none")]
69 pub ephemeral_message_id: Option<i64>,
70
71 #[serde(skip_serializing_if = "Option::is_none")]
73 pub message_thread_id: Option<i64>,
74
75 #[serde(skip_serializing_if = "Option::is_none")]
77 pub direct_messages_topic: Option<DirectMessagesTopic>,
78
79 #[serde(skip_serializing_if = "Option::is_none")]
81 pub from: Option<User>,
82
83 #[serde(skip_serializing_if = "Option::is_none")]
85 pub sender_chat: Option<Chat>,
86
87 #[serde(skip_serializing_if = "Option::is_none")]
89 pub sender_boost_count: Option<u32>,
90
91 #[serde(skip_serializing_if = "Option::is_none")]
93 pub sender_business_bot: Option<User>,
94
95 #[serde(skip_serializing_if = "Option::is_none")]
97 pub sender_tag: Option<String>,
98
99 pub date: i64,
101
102 #[serde(skip_serializing_if = "Option::is_none")]
104 pub business_connection_id: Option<String>,
105
106 pub chat: Chat,
108
109 #[serde(skip_serializing_if = "Option::is_none")]
111 pub forward_origin: Option<MessageOrigin>,
112
113 #[serde(skip_serializing_if = "Option::is_none")]
115 pub is_topic_message: Option<bool>,
116
117 #[serde(skip_serializing_if = "Option::is_none")]
120 pub is_automatic_forward: Option<bool>,
121
122 #[serde(skip_serializing_if = "Option::is_none")]
126 pub reply_to_message: Option<Box<Message>>,
127
128 #[serde(skip_serializing_if = "Option::is_none")]
130 pub external_reply: Option<ExternalReplyInfo>,
131
132 #[serde(skip_serializing_if = "Option::is_none")]
134 pub quote: Option<TextQuote>,
135
136 #[serde(skip_serializing_if = "Option::is_none")]
138 pub reply_to_story: Option<Story>,
139
140 #[serde(skip_serializing_if = "Option::is_none")]
142 pub reply_to_checklist_task_id: Option<i64>,
143
144 #[serde(skip_serializing_if = "Option::is_none")]
146 pub reply_to_poll_option_id: Option<String>,
147
148 #[serde(skip_serializing_if = "Option::is_none")]
150 pub via_bot: Option<User>,
151
152 #[serde(skip_serializing_if = "Option::is_none")]
154 pub edit_date: Option<i64>,
155
156 #[serde(skip_serializing_if = "Option::is_none")]
158 pub has_protected_content: Option<bool>,
159
160 #[serde(skip_serializing_if = "Option::is_none")]
162 pub is_from_offline: Option<bool>,
163
164 #[serde(skip_serializing_if = "Option::is_none")]
168 pub is_paid_post: Option<bool>,
169
170 #[serde(skip_serializing_if = "Option::is_none")]
172 pub media_group_id: Option<String>,
173
174 #[serde(skip_serializing_if = "Option::is_none")]
176 pub author_signature: Option<String>,
177
178 #[serde(skip_serializing_if = "Option::is_none")]
180 pub paid_star_count: Option<i64>,
181
182 #[serde(skip_serializing_if = "Option::is_none")]
184 pub text: Option<String>,
185
186 #[serde(skip_serializing_if = "Option::is_none")]
188 pub rich_message: Option<RichMessage>,
189
190 #[serde(skip_serializing_if = "Option::is_none")]
192 pub entities: Option<Vec<MessageEntity>>,
193
194 #[serde(skip_serializing_if = "Option::is_none")]
196 pub link_preview_options: Option<LinkPreviewOptions>,
197
198 #[serde(skip_serializing_if = "Option::is_none")]
201 pub suggested_post_info: Option<SuggestedPostInfo>,
202
203 #[serde(skip_serializing_if = "Option::is_none")]
205 pub effect_id: Option<String>,
206
207 #[serde(skip_serializing_if = "Option::is_none")]
210 pub animation: Option<Animation>,
211 #[serde(skip_serializing_if = "Option::is_none")]
213 pub audio: Option<Audio>,
214 #[serde(skip_serializing_if = "Option::is_none")]
216 pub document: Option<Document>,
217 #[serde(skip_serializing_if = "Option::is_none")]
219 pub paid_media: Option<PaidMediaInfo>,
220 #[serde(skip_serializing_if = "Option::is_none")]
222 pub photo: Option<Vec<PhotoSize>>,
223 #[serde(skip_serializing_if = "Option::is_none")]
225 pub live_photo: Option<LivePhoto>,
226 #[serde(skip_serializing_if = "Option::is_none")]
228 pub sticker: Option<Sticker>,
229 #[serde(skip_serializing_if = "Option::is_none")]
231 pub story: Option<Story>,
232 #[serde(skip_serializing_if = "Option::is_none")]
234 pub video: Option<Video>,
235 #[serde(skip_serializing_if = "Option::is_none")]
237 pub video_note: Option<VideoNote>,
238 #[serde(skip_serializing_if = "Option::is_none")]
240 pub voice: Option<Voice>,
241
242 #[serde(skip_serializing_if = "Option::is_none")]
244 pub caption: Option<String>,
245
246 #[serde(skip_serializing_if = "Option::is_none")]
248 pub caption_entities: Option<Vec<MessageEntity>>,
249
250 #[serde(skip_serializing_if = "Option::is_none")]
252 pub show_caption_above_media: Option<bool>,
253
254 #[serde(skip_serializing_if = "Option::is_none")]
256 pub has_media_spoiler: Option<bool>,
257
258 #[serde(skip_serializing_if = "Option::is_none")]
260 pub checklist: Option<Checklist>,
261
262 #[serde(skip_serializing_if = "Option::is_none")]
265 pub contact: Option<Contact>,
266 #[serde(skip_serializing_if = "Option::is_none")]
268 pub dice: Option<Dice>,
269 #[serde(skip_serializing_if = "Option::is_none")]
271 pub game: Option<Game>,
272 #[serde(skip_serializing_if = "Option::is_none")]
274 pub poll: Option<Poll>,
275 #[serde(skip_serializing_if = "Option::is_none")]
277 pub venue: Option<Venue>,
278 #[serde(skip_serializing_if = "Option::is_none")]
280 pub location: Option<Location>,
281
282 #[serde(skip_serializing_if = "Option::is_none")]
285 pub new_chat_members: Option<Vec<User>>,
286 #[serde(skip_serializing_if = "Option::is_none")]
288 pub left_chat_member: Option<User>,
289 #[serde(skip_serializing_if = "Option::is_none")]
291 pub chat_owner_left: Option<ChatOwnerLeft>,
292 #[serde(skip_serializing_if = "Option::is_none")]
294 pub chat_owner_changed: Option<ChatOwnerChanged>,
295 #[serde(skip_serializing_if = "Option::is_none")]
297 pub new_chat_title: Option<String>,
298 #[serde(skip_serializing_if = "Option::is_none")]
300 pub new_chat_photo: Option<Vec<PhotoSize>>,
301 #[serde(skip_serializing_if = "Option::is_none")]
303 pub delete_chat_photo: Option<bool>,
304 #[serde(skip_serializing_if = "Option::is_none")]
306 pub group_chat_created: Option<bool>,
307 #[serde(skip_serializing_if = "Option::is_none")]
309 pub supergroup_chat_created: Option<bool>,
310 #[serde(skip_serializing_if = "Option::is_none")]
312 pub channel_chat_created: Option<bool>,
313 #[serde(skip_serializing_if = "Option::is_none")]
315 pub community_chat_added: Option<CommunityChatAdded>,
316 #[serde(skip_serializing_if = "Option::is_none")]
318 pub community_chat_removed: Option<CommunityChatRemoved>,
319 #[serde(skip_serializing_if = "Option::is_none")]
321 pub message_auto_delete_timer_changed: Option<MessageAutoDeleteTimerChanged>,
322 #[serde(skip_serializing_if = "Option::is_none")]
324 pub migrate_to_chat_id: Option<i64>,
325 #[serde(skip_serializing_if = "Option::is_none")]
327 pub migrate_from_chat_id: Option<i64>,
328 #[serde(skip_serializing_if = "Option::is_none")]
330 pub pinned_message: Option<Box<Message>>,
331
332 #[serde(skip_serializing_if = "Option::is_none")]
334 pub reply_markup: Option<InlineKeyboardMarkup>,
335
336 #[serde(skip_serializing_if = "Option::is_none")]
339 pub invoice: Option<Invoice>,
340 #[serde(skip_serializing_if = "Option::is_none")]
342 pub successful_payment: Option<SuccessfulPayment>,
343 #[serde(skip_serializing_if = "Option::is_none")]
345 pub refunded_payment: Option<RefundedPayment>,
346
347 #[serde(skip_serializing_if = "Option::is_none")]
350 pub web_app_data: Option<WebAppData>,
351
352 #[serde(skip_serializing_if = "Option::is_none")]
355 pub forum_topic_created: Option<ForumTopicCreated>,
356 #[serde(skip_serializing_if = "Option::is_none")]
358 pub forum_topic_edited: Option<ForumTopicEdited>,
359 #[serde(skip_serializing_if = "Option::is_none")]
361 pub forum_topic_closed: Option<ForumTopicClosed>,
362 #[serde(skip_serializing_if = "Option::is_none")]
364 pub forum_topic_reopened: Option<ForumTopicReopened>,
365 #[serde(skip_serializing_if = "Option::is_none")]
367 pub general_forum_topic_hidden: Option<GeneralForumTopicHidden>,
368 #[serde(skip_serializing_if = "Option::is_none")]
370 pub general_forum_topic_unhidden: Option<GeneralForumTopicUnhidden>,
371
372 #[serde(skip_serializing_if = "Option::is_none")]
375 pub users_shared: Option<UsersShared>,
376 #[serde(skip_serializing_if = "Option::is_none")]
378 pub chat_shared: Option<ChatShared>,
379 #[serde(skip_serializing_if = "Option::is_none")]
381 pub connected_website: Option<String>,
382 #[serde(skip_serializing_if = "Option::is_none")]
384 pub write_access_allowed: Option<WriteAccessAllowed>,
385 #[serde(skip_serializing_if = "Option::is_none")]
387 pub passport_data: Option<PassportData>,
388 #[serde(skip_serializing_if = "Option::is_none")]
390 pub proximity_alert_triggered: Option<ProximityAlertTriggered>,
391 #[serde(skip_serializing_if = "Option::is_none")]
393 pub boost_added: Option<ChatBoostAdded>,
394 #[serde(skip_serializing_if = "Option::is_none")]
396 pub chat_background_set: Option<ChatBackground>,
397
398 #[serde(skip_serializing_if = "Option::is_none")]
401 pub gift: Option<GiftInfo>,
402 #[serde(skip_serializing_if = "Option::is_none")]
404 pub unique_gift: Option<UniqueGiftInfo>,
405 #[serde(skip_serializing_if = "Option::is_none")]
407 pub gift_upgrade_sent: Option<GiftInfo>,
408 #[serde(skip_serializing_if = "Option::is_none")]
410 pub giveaway_created: Option<GiveawayCreated>,
411 #[serde(skip_serializing_if = "Option::is_none")]
413 pub giveaway: Option<Giveaway>,
414 #[serde(skip_serializing_if = "Option::is_none")]
416 pub giveaway_winners: Option<GiveawayWinners>,
417 #[serde(skip_serializing_if = "Option::is_none")]
419 pub giveaway_completed: Option<GiveawayCompleted>,
420
421 #[serde(skip_serializing_if = "Option::is_none")]
424 pub video_chat_scheduled: Option<VideoChatScheduled>,
425 #[serde(skip_serializing_if = "Option::is_none")]
427 pub video_chat_started: Option<VideoChatStarted>,
428 #[serde(skip_serializing_if = "Option::is_none")]
430 pub video_chat_ended: Option<VideoChatEnded>,
431 #[serde(skip_serializing_if = "Option::is_none")]
433 pub video_chat_participants_invited: Option<VideoChatParticipantsInvited>,
434
435 #[serde(skip_serializing_if = "Option::is_none")]
438 pub managed_bot_created: Option<ManagedBotCreated>,
439
440 #[serde(skip_serializing_if = "Option::is_none")]
443 pub poll_option_added: Option<PollOptionAdded>,
444 #[serde(skip_serializing_if = "Option::is_none")]
446 pub poll_option_deleted: Option<PollOptionDeleted>,
447
448 #[serde(skip_serializing_if = "Option::is_none")]
451 pub checklist_tasks_done: Option<ChecklistTasksDone>,
452 #[serde(skip_serializing_if = "Option::is_none")]
454 pub checklist_tasks_added: Option<ChecklistTasksAdded>,
455
456 #[serde(skip_serializing_if = "Option::is_none")]
459 pub direct_message_price_changed: Option<DirectMessagePriceChanged>,
460 #[serde(skip_serializing_if = "Option::is_none")]
462 pub paid_message_price_changed: Option<PaidMessagePriceChanged>,
463
464 #[serde(skip_serializing_if = "Option::is_none")]
467 pub suggested_post_approved: Option<SuggestedPostApproved>,
468 #[serde(skip_serializing_if = "Option::is_none")]
470 pub suggested_post_approval_failed: Option<SuggestedPostApprovalFailed>,
471 #[serde(skip_serializing_if = "Option::is_none")]
473 pub suggested_post_declined: Option<SuggestedPostDeclined>,
474 #[serde(skip_serializing_if = "Option::is_none")]
476 pub suggested_post_paid: Option<SuggestedPostPaid>,
477 #[serde(skip_serializing_if = "Option::is_none")]
479 pub suggested_post_refunded: Option<SuggestedPostRefunded>,
480
481 #[serde(skip_serializing_if = "Option::is_none")]
484 pub guest_bot_caller_user: Option<User>,
485
486 #[serde(skip_serializing_if = "Option::is_none")]
488 pub guest_bot_caller_chat: Option<crate::chat::Chat>,
489
490 #[serde(skip_serializing_if = "Option::is_none")]
496 pub guest_query_id: Option<String>,
497}
498
499impl Message {
500 #[must_use]
502 pub fn effective_text(&self) -> Option<&str> {
503 self.text.as_deref().or(self.caption.as_deref())
504 }
505
506 #[must_use]
508 pub fn is_command(&self) -> bool {
509 self.entities
510 .as_deref()
511 .unwrap_or_default()
512 .iter()
513 .any(|e| e.kind == MessageEntityKind::BotCommand && e.offset == 0)
514 }
515
516 #[must_use]
518 pub fn command(&self) -> Option<&str> {
519 let text = self.text.as_deref()?;
520 let entity = self
521 .entities
522 .as_deref()?
523 .iter()
524 .find(|e| e.kind == MessageEntityKind::BotCommand && e.offset == 0)?;
525 let raw = &text[..entity.length as usize];
526 Some(
528 raw.find('@')
529 .map_or(raw, |i| &raw[..i])
530 .trim_start_matches('/'),
531 )
532 }
533}
534
535#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
537#[serde(rename_all = "snake_case")]
538pub enum MessageEntityKind {
539 Mention,
541 Hashtag,
543 Cashtag,
545 BotCommand,
547 Url,
549 Email,
551 PhoneNumber,
553 Bold,
555 Italic,
557 Underline,
559 Strikethrough,
561 Spoiler,
563 Blockquote,
565 ExpandableBlockquote,
567 Code,
569 Pre,
571 TextLink,
573 TextMention,
575 CustomEmoji,
577 DateTime,
579}
580
581#[derive(Debug, Clone, Serialize, Deserialize)]
583pub struct MessageEntity {
584 #[serde(rename = "type")]
586 pub kind: MessageEntityKind,
587 pub offset: u32,
589 pub length: u32,
591 #[serde(skip_serializing_if = "Option::is_none")]
593 pub url: Option<String>,
594 #[serde(skip_serializing_if = "Option::is_none")]
596 pub user: Option<User>,
597 #[serde(skip_serializing_if = "Option::is_none")]
599 pub language: Option<String>,
600 #[serde(skip_serializing_if = "Option::is_none")]
602 pub custom_emoji_id: Option<String>,
603 #[serde(skip_serializing_if = "Option::is_none")]
605 pub unix_time: Option<i64>,
606 #[serde(skip_serializing_if = "Option::is_none")]
608 pub date_time_format: Option<String>,
609}
610
611#[derive(Debug, Clone, Serialize, Deserialize)]
613#[serde(tag = "type", rename_all = "snake_case")]
614pub enum MessageOrigin {
615 User {
617 date: i64,
619 sender_user: User,
621 },
622 HiddenUser {
624 date: i64,
626 sender_user_name: String,
628 },
629 Chat {
631 date: i64,
633 sender_chat: Chat,
635 #[serde(skip_serializing_if = "Option::is_none")]
637 author_signature: Option<String>,
638 },
639 Channel {
641 date: i64,
643 chat: Chat,
645 message_id: i64,
647 #[serde(skip_serializing_if = "Option::is_none")]
649 author_signature: Option<String>,
650 },
651}
652
653#[derive(Debug, Clone, Serialize, Deserialize)]
655pub struct ReplyParameters {
656 #[serde(skip_serializing_if = "Option::is_none")]
660 pub message_id: Option<i64>,
661 #[serde(skip_serializing_if = "Option::is_none")]
665 pub ephemeral_message_id: Option<i64>,
666 #[serde(skip_serializing_if = "Option::is_none")]
670 pub chat_id: Option<crate::user::ChatId>,
671 #[serde(skip_serializing_if = "Option::is_none")]
676 pub allow_sending_without_reply: Option<bool>,
677 #[serde(skip_serializing_if = "Option::is_none")]
682 pub quote: Option<String>,
683 #[serde(skip_serializing_if = "Option::is_none")]
685 pub quote_parse_mode: Option<ParseMode>,
686 #[serde(skip_serializing_if = "Option::is_none")]
688 pub quote_entities: Option<Vec<MessageEntity>>,
689 #[serde(skip_serializing_if = "Option::is_none")]
691 pub quote_position: Option<u32>,
692 #[serde(skip_serializing_if = "Option::is_none")]
694 pub poll_option_id: Option<String>,
695 #[serde(skip_serializing_if = "Option::is_none")]
697 pub checklist_task_id: Option<i64>,
698}
699
700#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
702pub enum ParseMode {
703 MarkdownV2,
705 HTML,
707 Markdown,
709}
710
711#[derive(Debug, Clone, Serialize, Deserialize)]
713#[serde(tag = "type", rename_all = "snake_case")]
714pub enum ReactionType {
715 Emoji {
717 emoji: String,
719 },
720 CustomEmoji {
722 custom_emoji_id: String,
724 },
725 Paid,
727}
728
729#[derive(Debug, Clone, Default, Serialize, Deserialize)]
731pub struct LinkPreviewOptions {
732 #[serde(skip_serializing_if = "Option::is_none")]
734 pub is_disabled: Option<bool>,
735 #[serde(skip_serializing_if = "Option::is_none")]
737 pub url: Option<String>,
738 #[serde(skip_serializing_if = "Option::is_none")]
740 pub prefer_small_media: Option<bool>,
741 #[serde(skip_serializing_if = "Option::is_none")]
743 pub prefer_large_media: Option<bool>,
744 #[serde(skip_serializing_if = "Option::is_none")]
746 pub show_above_text: Option<bool>,
747}
748
749#[derive(Debug, Clone, Serialize, Deserialize)]
751pub struct TextQuote {
752 pub text: String,
754 #[serde(skip_serializing_if = "Option::is_none")]
756 pub entities: Option<Vec<MessageEntity>>,
757 pub position: u32,
759 #[serde(skip_serializing_if = "Option::is_none")]
761 pub is_manual: Option<bool>,
762}
763
764#[derive(Debug, Clone, Serialize, Deserialize)]
773#[non_exhaustive]
774pub struct ExternalReplyInfo {
775 pub origin: MessageOrigin,
777 #[serde(skip_serializing_if = "Option::is_none")]
779 pub chat: Option<Chat>,
780 #[serde(skip_serializing_if = "Option::is_none")]
782 pub message_id: Option<i64>,
783 #[serde(skip_serializing_if = "Option::is_none")]
785 pub link_preview_options: Option<LinkPreviewOptions>,
786 #[serde(skip_serializing_if = "Option::is_none")]
788 pub animation: Option<Animation>,
789 #[serde(skip_serializing_if = "Option::is_none")]
791 pub audio: Option<Audio>,
792 #[serde(skip_serializing_if = "Option::is_none")]
794 pub document: Option<Document>,
795 #[serde(skip_serializing_if = "Option::is_none")]
797 pub photo: Option<Vec<PhotoSize>>,
798 #[serde(skip_serializing_if = "Option::is_none")]
800 pub live_photo: Option<LivePhoto>,
801 #[serde(skip_serializing_if = "Option::is_none")]
803 pub sticker: Option<Sticker>,
804 #[serde(skip_serializing_if = "Option::is_none")]
806 pub video: Option<Video>,
807 #[serde(skip_serializing_if = "Option::is_none")]
809 pub video_note: Option<VideoNote>,
810 #[serde(skip_serializing_if = "Option::is_none")]
812 pub voice: Option<Voice>,
813 #[serde(skip_serializing_if = "Option::is_none")]
815 pub has_media_spoiler: Option<bool>,
816 #[serde(skip_serializing_if = "Option::is_none")]
818 pub checklist: Option<Checklist>,
819 #[serde(skip_serializing_if = "Option::is_none")]
821 pub paid_media: Option<PaidMediaInfo>,
822 #[serde(skip_serializing_if = "Option::is_none")]
824 pub story: Option<Story>,
825 #[serde(skip_serializing_if = "Option::is_none")]
827 pub game: Option<Game>,
828 #[serde(skip_serializing_if = "Option::is_none")]
830 pub giveaway: Option<Giveaway>,
831 #[serde(skip_serializing_if = "Option::is_none")]
833 pub giveaway_winners: Option<GiveawayWinners>,
834 #[serde(skip_serializing_if = "Option::is_none")]
836 pub invoice: Option<Invoice>,
837 #[serde(skip_serializing_if = "Option::is_none")]
839 pub contact: Option<Contact>,
840 #[serde(skip_serializing_if = "Option::is_none")]
842 pub dice: Option<Dice>,
843 #[serde(skip_serializing_if = "Option::is_none")]
845 pub location: Option<Location>,
846 #[serde(skip_serializing_if = "Option::is_none")]
848 pub venue: Option<Venue>,
849 #[serde(skip_serializing_if = "Option::is_none")]
851 pub poll: Option<Poll>,
852}
853
854#[derive(Debug, Clone, Serialize, Deserialize)]
856pub struct Contact {
857 pub phone_number: String,
859 pub first_name: String,
861 #[serde(skip_serializing_if = "Option::is_none")]
863 pub last_name: Option<String>,
864 #[serde(skip_serializing_if = "Option::is_none")]
866 pub user_id: Option<i64>,
867 #[serde(skip_serializing_if = "Option::is_none")]
869 pub vcard: Option<String>,
870}
871
872#[derive(Debug, Clone, Serialize, Deserialize)]
874pub struct Dice {
875 pub emoji: String,
877 pub value: u8,
879}
880
881#[derive(Debug, Clone, Serialize, Deserialize)]
883pub struct WebAppData {
884 pub data: String,
886 pub button_text: String,
888}
889
890#[derive(Debug, Clone, Serialize, Deserialize)]
892pub struct WebAppInfo {
893 pub url: String,
895}
896
897#[derive(Debug, Clone, Default, Serialize, Deserialize)]
900#[non_exhaustive]
901pub struct ProximityAlertTriggered {
902 pub traveler: User,
904 pub watcher: User,
906 pub distance: u32,
908}
909
910#[derive(Debug, Clone, Default, Serialize, Deserialize)]
912#[non_exhaustive]
913pub struct MessageAutoDeleteTimerChanged {
914 pub message_auto_delete_time: u32,
916}
917
918#[derive(Debug, Clone, Default, Serialize, Deserialize)]
924#[non_exhaustive]
925pub struct WriteAccessAllowed {
926 #[serde(skip_serializing_if = "Option::is_none")]
929 pub from_request: Option<bool>,
930 #[serde(skip_serializing_if = "Option::is_none")]
932 pub web_app_name: Option<String>,
933 #[serde(skip_serializing_if = "Option::is_none")]
936 pub from_attachment_menu: Option<bool>,
937}
938
939#[derive(Debug, Clone, Default, Serialize, Deserialize)]
941#[non_exhaustive]
942pub struct InaccessibleMessage {
943 pub chat: Chat,
945 pub message_id: i64,
947 pub date: i64,
949}
950
951#[derive(Debug, Clone, Serialize)]
959#[serde(untagged)]
960pub enum MaybeInaccessibleMessage {
961 Message(Box<Message>),
963 Inaccessible(InaccessibleMessage),
965}
966
967impl<'de> Deserialize<'de> for MaybeInaccessibleMessage {
968 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
969 where
970 D: serde::Deserializer<'de>,
971 {
972 let value = serde_json::Value::deserialize(deserializer)?;
973 let is_inaccessible = value.get("date").and_then(serde_json::Value::as_i64) == Some(0);
974 if is_inaccessible {
975 InaccessibleMessage::deserialize(value)
976 .map(Self::Inaccessible)
977 .map_err(serde::de::Error::custom)
978 } else {
979 Message::deserialize(value)
980 .map(|m| Self::Message(Box::new(m)))
981 .map_err(serde::de::Error::custom)
982 }
983 }
984}
985
986#[derive(Debug, Clone, Serialize, Deserialize)]
988pub struct MessageId {
989 pub message_id: i64,
991}
992
993#[derive(Debug, Clone, Serialize, Deserialize)]
995pub struct ChatOwnerLeft {
996 #[serde(skip_serializing_if = "Option::is_none")]
998 pub new_owner: Option<User>,
999}
1000
1001#[derive(Debug, Clone, Serialize, Deserialize)]
1003pub struct ChatOwnerChanged {
1004 pub new_owner: User,
1006}