use std::fmt;
use serde::de::{IgnoredAny, MapAccess, Visitor};
use serde::ser::SerializeMap;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use super::business::{BusinessConnection, BusinessMessagesDeleted};
use super::callback_query::CallbackQuery;
use super::chat::Chat;
use super::chat_boost::{ChatBoostRemoved, ChatBoostUpdated};
use super::chat_join_request::ChatJoinRequest;
use super::chat_member_updated::ChatMemberUpdated;
use super::chosen_inline_result::ChosenInlineResult;
use super::inline::inline_query::InlineQuery;
use super::managed_bot::ManagedBotUpdated;
use super::message::Message;
use super::message_reaction_updated::{MessageReactionCountUpdated, MessageReactionUpdated};
use super::paid_media::PaidMediaPurchased;
use super::payment::pre_checkout_query::PreCheckoutQuery;
use super::payment::shipping_query::ShippingQuery;
use super::poll::{Poll, PollAnswer};
use super::user::User;
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[non_exhaustive]
pub struct Update {
pub update_id: i64,
#[serde(flatten, default)]
pub kind: UpdateKind,
}
#[derive(Debug, Clone, PartialEq, Default)]
#[non_exhaustive]
pub enum UpdateKind {
Message(Message),
EditedMessage(Message),
ChannelPost(Message),
EditedChannelPost(Message),
BusinessConnection(BusinessConnection),
BusinessMessage(Message),
EditedBusinessMessage(Message),
DeletedBusinessMessages(BusinessMessagesDeleted),
InlineQuery(InlineQuery),
ChosenInlineResult(ChosenInlineResult),
CallbackQuery(CallbackQuery),
ShippingQuery(ShippingQuery),
PreCheckoutQuery(PreCheckoutQuery),
PurchasedPaidMedia(PaidMediaPurchased),
Poll(Poll),
PollAnswer(PollAnswer),
MyChatMember(ChatMemberUpdated),
ChatMember(ChatMemberUpdated),
ChatJoinRequest(ChatJoinRequest),
ChatBoost(ChatBoostUpdated),
RemovedChatBoost(ChatBoostRemoved),
MessageReaction(MessageReactionUpdated),
MessageReactionCount(MessageReactionCountUpdated),
ManagedBot(ManagedBotUpdated),
#[default]
Unknown,
}
impl Serialize for UpdateKind {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
match self {
Self::Message(value) => {
serializer.serialize_newtype_variant("UpdateKind", 0, "message", value)
}
Self::EditedMessage(value) => {
serializer.serialize_newtype_variant("UpdateKind", 1, "edited_message", value)
}
Self::ChannelPost(value) => {
serializer.serialize_newtype_variant("UpdateKind", 2, "channel_post", value)
}
Self::EditedChannelPost(value) => {
serializer.serialize_newtype_variant("UpdateKind", 3, "edited_channel_post", value)
}
Self::BusinessConnection(value) => {
serializer.serialize_newtype_variant("UpdateKind", 4, "business_connection", value)
}
Self::BusinessMessage(value) => {
serializer.serialize_newtype_variant("UpdateKind", 5, "business_message", value)
}
Self::EditedBusinessMessage(value) => serializer.serialize_newtype_variant(
"UpdateKind",
6,
"edited_business_message",
value,
),
Self::DeletedBusinessMessages(value) => serializer.serialize_newtype_variant(
"UpdateKind",
7,
"deleted_business_messages",
value,
),
Self::InlineQuery(value) => {
serializer.serialize_newtype_variant("UpdateKind", 8, "inline_query", value)
}
Self::ChosenInlineResult(value) => {
serializer.serialize_newtype_variant("UpdateKind", 9, "chosen_inline_result", value)
}
Self::CallbackQuery(value) => {
serializer.serialize_newtype_variant("UpdateKind", 10, "callback_query", value)
}
Self::ShippingQuery(value) => {
serializer.serialize_newtype_variant("UpdateKind", 11, "shipping_query", value)
}
Self::PreCheckoutQuery(value) => {
serializer.serialize_newtype_variant("UpdateKind", 12, "pre_checkout_query", value)
}
Self::PurchasedPaidMedia(value) => serializer.serialize_newtype_variant(
"UpdateKind",
13,
"purchased_paid_media",
value,
),
Self::Poll(value) => {
serializer.serialize_newtype_variant("UpdateKind", 14, "poll", value)
}
Self::PollAnswer(value) => {
serializer.serialize_newtype_variant("UpdateKind", 15, "poll_answer", value)
}
Self::MyChatMember(value) => {
serializer.serialize_newtype_variant("UpdateKind", 16, "my_chat_member", value)
}
Self::ChatMember(value) => {
serializer.serialize_newtype_variant("UpdateKind", 17, "chat_member", value)
}
Self::ChatJoinRequest(value) => {
serializer.serialize_newtype_variant("UpdateKind", 18, "chat_join_request", value)
}
Self::ChatBoost(value) => {
serializer.serialize_newtype_variant("UpdateKind", 19, "chat_boost", value)
}
Self::RemovedChatBoost(value) => {
serializer.serialize_newtype_variant("UpdateKind", 20, "removed_chat_boost", value)
}
Self::MessageReaction(value) => {
serializer.serialize_newtype_variant("UpdateKind", 21, "message_reaction", value)
}
Self::MessageReactionCount(value) => serializer.serialize_newtype_variant(
"UpdateKind",
22,
"message_reaction_count",
value,
),
Self::ManagedBot(value) => {
serializer.serialize_newtype_variant("UpdateKind", 23, "managed_bot", value)
}
Self::Unknown => {
let map = serializer.serialize_map(Some(0))?;
map.end()
}
}
}
}
impl<'de> Deserialize<'de> for UpdateKind {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
stacker::maybe_grow(256 * 1024, 1024 * 1024, || {
deserializer.deserialize_map(UpdateKindVisitor)
})
}
}
struct UpdateKindVisitor;
impl<'de> Visitor<'de> for UpdateKindVisitor {
type Value = UpdateKind;
fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.write_str("a Telegram update payload")
}
fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
where
A: MapAccess<'de>,
{
let mut kind = None;
macro_rules! parse_kind {
($variant:ident, $ty:ty) => {{
if kind.is_none() {
kind = Some(UpdateKind::$variant(map.next_value::<$ty>()?));
} else {
map.next_value::<IgnoredAny>()?;
}
}};
}
while let Some(key) = map.next_key::<String>()? {
match key.as_str() {
"message" => parse_kind!(Message, Message),
"edited_message" => parse_kind!(EditedMessage, Message),
"channel_post" => parse_kind!(ChannelPost, Message),
"edited_channel_post" => parse_kind!(EditedChannelPost, Message),
"business_connection" => {
parse_kind!(BusinessConnection, BusinessConnection)
}
"business_message" => parse_kind!(BusinessMessage, Message),
"edited_business_message" => {
parse_kind!(EditedBusinessMessage, Message)
}
"deleted_business_messages" => {
parse_kind!(DeletedBusinessMessages, BusinessMessagesDeleted)
}
"inline_query" => parse_kind!(InlineQuery, InlineQuery),
"chosen_inline_result" => {
parse_kind!(ChosenInlineResult, ChosenInlineResult)
}
"callback_query" => parse_kind!(CallbackQuery, CallbackQuery),
"shipping_query" => parse_kind!(ShippingQuery, ShippingQuery),
"pre_checkout_query" => {
parse_kind!(PreCheckoutQuery, PreCheckoutQuery)
}
"purchased_paid_media" => {
parse_kind!(PurchasedPaidMedia, PaidMediaPurchased)
}
"poll" => parse_kind!(Poll, Poll),
"poll_answer" => parse_kind!(PollAnswer, PollAnswer),
"my_chat_member" => parse_kind!(MyChatMember, ChatMemberUpdated),
"chat_member" => parse_kind!(ChatMember, ChatMemberUpdated),
"chat_join_request" => parse_kind!(ChatJoinRequest, ChatJoinRequest),
"chat_boost" => parse_kind!(ChatBoost, ChatBoostUpdated),
"removed_chat_boost" => {
parse_kind!(RemovedChatBoost, ChatBoostRemoved)
}
"message_reaction" => {
parse_kind!(MessageReaction, MessageReactionUpdated)
}
"message_reaction_count" => {
parse_kind!(MessageReactionCount, MessageReactionCountUpdated)
}
"managed_bot" => parse_kind!(ManagedBot, ManagedBotUpdated),
"update_id" => {
map.next_value::<IgnoredAny>()?;
}
_ => {
map.next_value::<IgnoredAny>()?;
}
}
}
Ok(kind.unwrap_or(UpdateKind::Unknown))
}
}
macro_rules! update_kind_accessors {
($(($name:ident, $variant:ident, $ty:ty)),* $(,)?) => {
$(
/// Returns the payload if this update is of the corresponding variant.
#[must_use]
pub fn $name(&self) -> Option<&$ty> {
match &self.kind {
UpdateKind::$variant(value) => Some(value),
_ => None,
}
}
)*
};
}
impl Update {
#[must_use]
pub fn message(&self) -> Option<&Message> {
match &self.kind {
UpdateKind::Message(message)
| UpdateKind::EditedMessage(message)
| UpdateKind::ChannelPost(message)
| UpdateKind::EditedChannelPost(message)
| UpdateKind::BusinessMessage(message)
| UpdateKind::EditedBusinessMessage(message) => Some(message),
_ => None,
}
}
update_kind_accessors!(
(edited_message, EditedMessage, Message),
(channel_post, ChannelPost, Message),
(edited_channel_post, EditedChannelPost, Message),
(business_connection, BusinessConnection, BusinessConnection),
(business_message, BusinessMessage, Message),
(edited_business_message, EditedBusinessMessage, Message),
(
deleted_business_messages,
DeletedBusinessMessages,
BusinessMessagesDeleted
),
(inline_query, InlineQuery, InlineQuery),
(chosen_inline_result, ChosenInlineResult, ChosenInlineResult),
(callback_query, CallbackQuery, CallbackQuery),
(shipping_query, ShippingQuery, ShippingQuery),
(pre_checkout_query, PreCheckoutQuery, PreCheckoutQuery),
(purchased_paid_media, PurchasedPaidMedia, PaidMediaPurchased),
(poll, Poll, Poll),
(poll_answer, PollAnswer, PollAnswer),
(my_chat_member, MyChatMember, ChatMemberUpdated),
(chat_member, ChatMember, ChatMemberUpdated),
(chat_join_request, ChatJoinRequest, ChatJoinRequest),
(chat_boost, ChatBoost, ChatBoostUpdated),
(removed_chat_boost, RemovedChatBoost, ChatBoostRemoved),
(message_reaction, MessageReaction, MessageReactionUpdated),
(
message_reaction_count,
MessageReactionCount,
MessageReactionCountUpdated
),
(managed_bot, ManagedBot, ManagedBotUpdated),
);
#[must_use]
pub fn effective_user(&self) -> Option<&User> {
match &self.kind {
UpdateKind::Message(msg)
| UpdateKind::EditedMessage(msg)
| UpdateKind::BusinessMessage(msg)
| UpdateKind::EditedBusinessMessage(msg) => msg.from_user.as_ref(),
UpdateKind::CallbackQuery(cbq) => Some(&cbq.from_user),
UpdateKind::ChosenInlineResult(cir) => Some(&cir.from_user),
UpdateKind::InlineQuery(iq) => Some(&iq.from_user),
UpdateKind::ShippingQuery(sq) => Some(&sq.from_user),
UpdateKind::PreCheckoutQuery(pq) => Some(&pq.from_user),
UpdateKind::PollAnswer(pa) => pa.user.as_ref(),
UpdateKind::MyChatMember(cmu) | UpdateKind::ChatMember(cmu) => Some(&cmu.from_user),
UpdateKind::ChatJoinRequest(cjr) => Some(&cjr.from_user),
UpdateKind::MessageReaction(mru) => mru.user.as_ref(),
UpdateKind::BusinessConnection(bc) => Some(&bc.user),
UpdateKind::PurchasedPaidMedia(ppm) => Some(&ppm.from_user),
UpdateKind::ManagedBot(mbu) => Some(&mbu.user),
UpdateKind::ChannelPost(_)
| UpdateKind::EditedChannelPost(_)
| UpdateKind::DeletedBusinessMessages(_)
| UpdateKind::Poll(_)
| UpdateKind::ChatBoost(_)
| UpdateKind::RemovedChatBoost(_)
| UpdateKind::MessageReactionCount(_)
| UpdateKind::Unknown => None,
}
}
#[must_use]
pub fn effective_chat(&self) -> Option<&Chat> {
match &self.kind {
UpdateKind::Message(msg)
| UpdateKind::EditedMessage(msg)
| UpdateKind::ChannelPost(msg)
| UpdateKind::EditedChannelPost(msg)
| UpdateKind::BusinessMessage(msg)
| UpdateKind::EditedBusinessMessage(msg) => Some(&msg.chat),
UpdateKind::CallbackQuery(cbq) => cbq.message.as_deref().map(|message| message.chat()),
UpdateKind::MyChatMember(cmu) | UpdateKind::ChatMember(cmu) => Some(&cmu.chat),
UpdateKind::ChatJoinRequest(cjr) => Some(&cjr.chat),
UpdateKind::ChatBoost(cbu) => Some(&cbu.chat),
UpdateKind::RemovedChatBoost(cbr) => Some(&cbr.chat),
UpdateKind::MessageReaction(mru) => Some(&mru.chat),
UpdateKind::MessageReactionCount(mrcu) => Some(&mrcu.chat),
UpdateKind::DeletedBusinessMessages(dbm) => Some(&dbm.chat),
UpdateKind::BusinessConnection(_)
| UpdateKind::InlineQuery(_)
| UpdateKind::ChosenInlineResult(_)
| UpdateKind::ShippingQuery(_)
| UpdateKind::PreCheckoutQuery(_)
| UpdateKind::PurchasedPaidMedia(_)
| UpdateKind::Poll(_)
| UpdateKind::PollAnswer(_)
| UpdateKind::ManagedBot(_)
| UpdateKind::Unknown => None,
}
}
#[must_use]
pub fn effective_message(&self) -> Option<&Message> {
match &self.kind {
UpdateKind::Message(msg)
| UpdateKind::EditedMessage(msg)
| UpdateKind::ChannelPost(msg)
| UpdateKind::EditedChannelPost(msg)
| UpdateKind::BusinessMessage(msg)
| UpdateKind::EditedBusinessMessage(msg) => Some(msg),
UpdateKind::CallbackQuery(cbq) => cbq
.message
.as_ref()
.and_then(|message| message.as_message()),
UpdateKind::BusinessConnection(_)
| UpdateKind::DeletedBusinessMessages(_)
| UpdateKind::InlineQuery(_)
| UpdateKind::ChosenInlineResult(_)
| UpdateKind::ShippingQuery(_)
| UpdateKind::PreCheckoutQuery(_)
| UpdateKind::PurchasedPaidMedia(_)
| UpdateKind::Poll(_)
| UpdateKind::PollAnswer(_)
| UpdateKind::MyChatMember(_)
| UpdateKind::ChatMember(_)
| UpdateKind::ChatJoinRequest(_)
| UpdateKind::ChatBoost(_)
| UpdateKind::RemovedChatBoost(_)
| UpdateKind::MessageReaction(_)
| UpdateKind::MessageReactionCount(_)
| UpdateKind::ManagedBot(_)
| UpdateKind::Unknown => None,
}
}
}