mirror of
https://github.com/teloxide/teloxide.git
synced 2025-01-11 04:21:12 +01:00
Merge pull request #156 from teloxide/tolerant_updates_for_all
Make update deserialization fault tolerant by default
This commit is contained in:
commit
dad5d5d4b1
15 changed files with 220 additions and 166 deletions
|
@ -19,6 +19,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
- `media_group_id` field to `MediaDocument` and `MediaAudio` ([#139][pr139])
|
||||
- `caption_entities` method to `InputMediaPhoto` ([#140][pr140])
|
||||
- `User::is_anonymous` and `User::is_channel` functions ([#151][pr151])
|
||||
- `UpdateKind::Error` ([#156][pr156])
|
||||
|
||||
[pr109]: https://github.com/teloxide/teloxide-core/pull/109
|
||||
[pr116]: https://github.com/teloxide/teloxide-core/pull/116
|
||||
|
@ -29,6 +30,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
[pr143]: https://github.com/teloxide/teloxide-core/pull/143
|
||||
[pr151]: https://github.com/teloxide/teloxide-core/pull/151
|
||||
[pr155]: https://github.com/teloxide/teloxide-core/pull/155
|
||||
[pr156]: https://github.com/teloxide/teloxide-core/pull/156
|
||||
[pr164]: https://github.com/teloxide/teloxide-core/pull/164
|
||||
|
||||
### Changed
|
||||
|
@ -79,6 +81,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
[issue473]: https://github.com/teloxide/teloxide/issues/473
|
||||
[issue427]: https://github.com/teloxide/teloxide/issues/427
|
||||
|
||||
### Removed
|
||||
|
||||
- `get_updates_fault_tolerant` method and `SemiparsedVec` ([#156][pr156])
|
||||
|
||||
## 0.3.3 - 2021-08-03
|
||||
|
||||
### Fixed
|
||||
|
|
|
@ -106,8 +106,7 @@ where
|
|||
set_sticker_set_thumb, send_invoice, answer_shipping_query,
|
||||
answer_pre_checkout_query, set_passport_data_errors, send_game,
|
||||
set_game_score, set_game_score_inline, get_game_high_scores,
|
||||
approve_chat_join_request, decline_chat_join_request,
|
||||
get_updates_fault_tolerant => f, fty
|
||||
approve_chat_join_request, decline_chat_join_request => f, fty
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -113,8 +113,7 @@ where
|
|||
set_sticker_set_thumb, send_invoice, answer_shipping_query,
|
||||
answer_pre_checkout_query, set_passport_data_errors, send_game,
|
||||
set_game_score, set_game_score_inline, get_game_high_scores,
|
||||
approve_chat_join_request, decline_chat_join_request,
|
||||
get_updates_fault_tolerant => f, fty
|
||||
approve_chat_join_request, decline_chat_join_request => f, fty
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -182,8 +182,7 @@ where
|
|||
set_sticker_set_thumb, send_invoice, answer_shipping_query,
|
||||
answer_pre_checkout_query, set_passport_data_errors, send_game,
|
||||
set_game_score, set_game_score_inline, get_game_high_scores,
|
||||
approve_chat_join_request, decline_chat_join_request,
|
||||
get_updates_fault_tolerant => fwd_erased, fty
|
||||
approve_chat_join_request, decline_chat_join_request => fwd_erased, fty
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -692,8 +691,6 @@ trait ErasableRequester<'a> {
|
|||
user_id: i64,
|
||||
target: TargetMessage,
|
||||
) -> ErasedRequest<'a, GetGameHighScores, Self::Err>;
|
||||
|
||||
fn get_updates_fault_tolerant(&self) -> ErasedRequest<'a, GetUpdatesFaultTolerant, Self::Err>;
|
||||
}
|
||||
|
||||
impl<'a, B> ErasableRequester<'a> for B
|
||||
|
@ -1401,8 +1398,4 @@ where
|
|||
) -> ErasedRequest<'a, GetGameHighScores, Self::Err> {
|
||||
Requester::get_game_high_scores(self, user_id, target).erase()
|
||||
}
|
||||
|
||||
fn get_updates_fault_tolerant(&self) -> ErasedRequest<'a, GetUpdatesFaultTolerant, Self::Err> {
|
||||
Requester::get_updates_fault_tolerant(self).erase()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -117,8 +117,7 @@ impl<B: Requester> Requester for DefaultParseMode<B> {
|
|||
set_sticker_set_thumb, send_invoice, answer_shipping_query,
|
||||
answer_pre_checkout_query, set_passport_data_errors, send_game,
|
||||
set_game_score, set_game_score_inline, get_game_high_scores,
|
||||
approve_chat_join_request, decline_chat_join_request,
|
||||
get_updates_fault_tolerant => fid, fty
|
||||
approve_chat_join_request, decline_chat_join_request => fid, fty
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -621,7 +621,7 @@ where
|
|||
set_sticker_set_thumb, answer_shipping_query, answer_pre_checkout_query,
|
||||
set_passport_data_errors, send_game, set_game_score, set_game_score_inline,
|
||||
approve_chat_join_request, decline_chat_join_request,
|
||||
get_game_high_scores, get_updates_fault_tolerant => fid, ftyid
|
||||
get_game_high_scores => fid, ftyid
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -138,8 +138,7 @@ where
|
|||
set_sticker_set_thumb, send_invoice, answer_shipping_query,
|
||||
answer_pre_checkout_query, set_passport_data_errors, send_game,
|
||||
set_game_score, set_game_score_inline, get_game_high_scores,
|
||||
approve_chat_join_request, decline_chat_join_request,
|
||||
get_updates_fault_tolerant => fwd_inner, fty
|
||||
approve_chat_join_request, decline_chat_join_request => fwd_inner, fty
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1106,13 +1106,4 @@ impl Requester for Bot {
|
|||
{
|
||||
Self::UnpinAllChatMessages::new(self.clone(), payloads::UnpinAllChatMessages::new(chat_id))
|
||||
}
|
||||
|
||||
type GetUpdatesFaultTolerant = JsonRequest<payloads::GetUpdatesFaultTolerant>;
|
||||
|
||||
fn get_updates_fault_tolerant(&self) -> Self::GetUpdatesFaultTolerant {
|
||||
Self::GetUpdatesFaultTolerant::new(
|
||||
self.clone(),
|
||||
payloads::GetUpdatesFaultTolerant(payloads::GetUpdates::new()),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1195,13 +1195,4 @@ macro_rules! requester_forward {
|
|||
$body!(get_game_high_scores this (user_id: i64, target: T))
|
||||
}
|
||||
};
|
||||
(@method get_updates_fault_tolerant $body:ident $ty:ident) => {
|
||||
type GetUpdatesFaultTolerant = $ty![GetUpdatesFaultTolerant];
|
||||
|
||||
fn get_updates_fault_tolerant(&self) -> Self::GetUpdatesFaultTolerant {
|
||||
let this = self;
|
||||
$body!(get_updates_fault_tolerant this ())
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -213,7 +213,3 @@ pub use unpin_chat_message::{UnpinChatMessage, UnpinChatMessageSetters};
|
|||
pub use upload_sticker_file::{UploadStickerFile, UploadStickerFileSetters};
|
||||
|
||||
// end of auto generated block
|
||||
|
||||
mod get_updates_fault_tolerant;
|
||||
|
||||
pub use get_updates_fault_tolerant::GetUpdatesFaultTolerant;
|
||||
|
|
|
@ -1,18 +0,0 @@
|
|||
use serde::Serialize;
|
||||
|
||||
use crate::{
|
||||
payloads::GetUpdates,
|
||||
requests::Payload,
|
||||
types::{SemiparsedVec, Update},
|
||||
};
|
||||
|
||||
/// The fault tolerant version of [`GetUpdates`].
|
||||
#[derive(Debug, PartialEq, Eq, Hash, Default, Clone, Serialize)]
|
||||
#[serde(transparent)]
|
||||
pub struct GetUpdatesFaultTolerant(pub GetUpdates);
|
||||
|
||||
impl Payload for GetUpdatesFaultTolerant {
|
||||
type Output = SemiparsedVec<Update>;
|
||||
|
||||
const NAME: &'static str = GetUpdates::NAME;
|
||||
}
|
|
@ -856,11 +856,6 @@ pub trait Requester {
|
|||
fn get_game_high_scores<T>(&self, user_id: i64, target: T) -> Self::GetGameHighScores
|
||||
where
|
||||
T: Into<TargetMessage>;
|
||||
|
||||
type GetUpdatesFaultTolerant: Request<Payload = GetUpdatesFaultTolerant, Err = Self::Err>;
|
||||
|
||||
/// For Telegram documentation see [`GetUpdatesFaultTolerant`].
|
||||
fn get_updates_fault_tolerant(&self) -> Self::GetUpdatesFaultTolerant;
|
||||
}
|
||||
|
||||
macro_rules! fty {
|
||||
|
@ -901,8 +896,7 @@ macro_rules! forward_all {
|
|||
set_sticker_set_thumb, send_invoice, answer_shipping_query,
|
||||
answer_pre_checkout_query, set_passport_data_errors, send_game,
|
||||
set_game_score, set_game_score_inline, get_game_high_scores,
|
||||
approve_chat_join_request, decline_chat_join_request,
|
||||
get_updates_fault_tolerant => fwd_deref, fty
|
||||
approve_chat_join_request, decline_chat_join_request => fwd_deref, fty
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -998,7 +992,6 @@ where
|
|||
set_sticker_set_thumb, send_invoice, answer_shipping_query,
|
||||
answer_pre_checkout_query, set_passport_data_errors, send_game,
|
||||
set_game_score, set_game_score_inline, get_game_high_scores,
|
||||
approve_chat_join_request, decline_chat_join_request,
|
||||
get_updates_fault_tolerant => fwd_either, fty_either
|
||||
approve_chat_join_request, decline_chat_join_request => fwd_either, fty_either
|
||||
}
|
||||
}
|
||||
|
|
|
@ -214,12 +214,11 @@ mod passport_data;
|
|||
mod passport_element_error;
|
||||
mod passport_file;
|
||||
|
||||
pub use non_telegram_types::{country_code::*, currency::*, semiparsed_vec::*, until_date::*};
|
||||
pub use non_telegram_types::{country_code::*, currency::*, until_date::*};
|
||||
mod non_telegram_types {
|
||||
pub(super) mod country_code;
|
||||
pub(super) mod currency;
|
||||
pub(crate) mod mime;
|
||||
pub(super) mod semiparsed_vec;
|
||||
pub(super) mod until_date;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,55 +0,0 @@
|
|||
use serde::de::DeserializeOwned;
|
||||
use serde_json::{from_value, Value};
|
||||
|
||||
/// A vector of possibly unparsed JSON objects.
|
||||
///
|
||||
/// Similar to `Vec<T>` but if it fails to deserialize element, it just saves
|
||||
/// `Err((serde_json::Value, serde_json::Error))`.
|
||||
#[derive(Debug, serde::Deserialize)]
|
||||
#[serde(from = "Vec<serde_json::Value>")]
|
||||
#[serde(bound = "T: DeserializeOwned")]
|
||||
pub struct SemiparsedVec<T>(pub Vec<Result<T, (serde_json::Value, serde_json::Error)>>);
|
||||
|
||||
impl<T: DeserializeOwned> From<Vec<serde_json::Value>> for SemiparsedVec<T> {
|
||||
fn from(vec: Vec<Value>) -> Self {
|
||||
Self(
|
||||
vec.into_iter()
|
||||
.map(|val| from_value(val.clone()).map_err(|e| (val, e)))
|
||||
.collect(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test() {
|
||||
use crate::types::Update;
|
||||
|
||||
let x: SemiparsedVec<Update> = serde_json::from_str(
|
||||
r#"[{
|
||||
"update_id": 923808447,
|
||||
"message": {
|
||||
"message_id": 361678,
|
||||
"from": {
|
||||
"id": 218485655,
|
||||
"is_bot": false,
|
||||
"first_name": "вафель",
|
||||
"last_name": "🧇",
|
||||
"username": "WaffleLapkin",
|
||||
"language_code": "en"
|
||||
},
|
||||
"chat": {
|
||||
"id": 218485655,
|
||||
"first_name": "вафель",
|
||||
"last_name": "🧇",
|
||||
"username": "WaffleLapkin",
|
||||
"type": "private"
|
||||
},
|
||||
"date": 1595860067,
|
||||
"text": "s"
|
||||
}
|
||||
}]"#,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
assert!(x.0.first().unwrap().is_ok())
|
||||
}
|
|
@ -1,12 +1,11 @@
|
|||
#![allow(clippy::large_enum_variant)]
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde::{de::MapAccess, Deserialize, Serialize, Serializer};
|
||||
use serde_json::Value;
|
||||
|
||||
use crate::types::{
|
||||
CallbackQuery, Chat, ChatJoinRequest, ChatMemberUpdated, ChosenInlineResult, InlineQuery,
|
||||
Message, Poll, PollAnswer, PreCheckoutQuery, ShippingQuery, User,
|
||||
};
|
||||
use serde_json::Value;
|
||||
|
||||
/// This [object] represents an incoming update.
|
||||
///
|
||||
|
@ -30,28 +29,33 @@ pub struct Update {
|
|||
}
|
||||
|
||||
impl Update {
|
||||
/// Tries to parse `value` into `Update`, logging an error on failure.
|
||||
///
|
||||
/// It is used to implement update listeners.
|
||||
pub fn try_parse(value: &Value) -> Result<Self, serde_json::Error> {
|
||||
match serde_json::from_value(value.clone()) {
|
||||
Ok(update) => Ok(update),
|
||||
Err(error) => {
|
||||
log::error!(
|
||||
"Cannot parse an update.\nError: {:?}\nValue: {}\n\
|
||||
This is a bug in teloxide-core, please open an issue here: \
|
||||
https://github.com/teloxide/teloxide-core/issues.",
|
||||
error,
|
||||
value
|
||||
);
|
||||
Err(error)
|
||||
}
|
||||
pub fn user(&self) -> Option<&User> {
|
||||
match &self.kind {
|
||||
UpdateKind::Message(m) => m.from(),
|
||||
UpdateKind::EditedMessage(m) => m.from(),
|
||||
UpdateKind::CallbackQuery(query) => Some(&query.from),
|
||||
UpdateKind::ChosenInlineResult(chosen) => Some(&chosen.from),
|
||||
UpdateKind::InlineQuery(query) => Some(&query.from),
|
||||
UpdateKind::ShippingQuery(query) => Some(&query.from),
|
||||
UpdateKind::PreCheckoutQuery(query) => Some(&query.from),
|
||||
UpdateKind::PollAnswer(answer) => Some(&answer.user),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn chat(&self) -> Option<&Chat> {
|
||||
match &self.kind {
|
||||
UpdateKind::Message(m) => Some(&m.chat),
|
||||
UpdateKind::EditedMessage(m) => Some(&m.chat),
|
||||
UpdateKind::ChannelPost(p) => Some(&p.chat),
|
||||
UpdateKind::EditedChannelPost(p) => Some(&p.chat),
|
||||
UpdateKind::CallbackQuery(q) => Some(&q.message.as_ref()?.chat),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub enum UpdateKind {
|
||||
/// New incoming message of any kind — text, photo, sticker, etc.
|
||||
Message(Message),
|
||||
|
@ -113,31 +117,173 @@ pub enum UpdateKind {
|
|||
/// can_invite_users administrator right in the chat to receive these
|
||||
/// updates.
|
||||
ChatJoinRequest(ChatJoinRequest),
|
||||
|
||||
/// An error that happened during deserialization.
|
||||
///
|
||||
/// This allows `teloxide` to continue working even if telegram adds a new
|
||||
/// kind of updates.
|
||||
Error(Value),
|
||||
}
|
||||
|
||||
impl Update {
|
||||
pub fn user(&self) -> Option<&User> {
|
||||
match &self.kind {
|
||||
UpdateKind::Message(m) => m.from(),
|
||||
UpdateKind::EditedMessage(m) => m.from(),
|
||||
UpdateKind::CallbackQuery(query) => Some(&query.from),
|
||||
UpdateKind::ChosenInlineResult(chosen) => Some(&chosen.from),
|
||||
UpdateKind::InlineQuery(query) => Some(&query.from),
|
||||
UpdateKind::ShippingQuery(query) => Some(&query.from),
|
||||
UpdateKind::PreCheckoutQuery(query) => Some(&query.from),
|
||||
UpdateKind::PollAnswer(answer) => Some(&answer.user),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
impl<'de> Deserialize<'de> for UpdateKind {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: serde::Deserializer<'de>,
|
||||
{
|
||||
struct Visitor;
|
||||
|
||||
pub fn chat(&self) -> Option<&Chat> {
|
||||
match &self.kind {
|
||||
UpdateKind::Message(m) => Some(&m.chat),
|
||||
UpdateKind::EditedMessage(m) => Some(&m.chat),
|
||||
UpdateKind::ChannelPost(p) => Some(&p.chat),
|
||||
UpdateKind::EditedChannelPost(p) => Some(&p.chat),
|
||||
UpdateKind::CallbackQuery(q) => Some(&q.message.as_ref()?.chat),
|
||||
_ => None,
|
||||
impl<'de> serde::de::Visitor<'de> for Visitor {
|
||||
type Value = UpdateKind;
|
||||
|
||||
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
formatter.write_str("a map")
|
||||
}
|
||||
|
||||
fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
|
||||
where
|
||||
A: MapAccess<'de>,
|
||||
{
|
||||
let mut tmp = None;
|
||||
|
||||
// Try to deserialize a borrowed-str key, or else try deserializing an owned
|
||||
// string key
|
||||
let k = map.next_key::<&str>().or_else(|_| {
|
||||
map.next_key::<String>().map(|k| {
|
||||
tmp = k;
|
||||
tmp.as_deref()
|
||||
})
|
||||
});
|
||||
|
||||
if let Ok(Some(k)) = k {
|
||||
let res = match k {
|
||||
"message" => dbg!(map
|
||||
.next_value::<Message>()
|
||||
.map(UpdateKind::Message)
|
||||
.map_err(|_| false)),
|
||||
"edited_message" => map
|
||||
.next_value::<Message>()
|
||||
.map(UpdateKind::EditedMessage)
|
||||
.map_err(|_| false),
|
||||
"channel_post" => map
|
||||
.next_value::<Message>()
|
||||
.map(UpdateKind::ChannelPost)
|
||||
.map_err(|_| false),
|
||||
"edited_channel_post" => map
|
||||
.next_value::<Message>()
|
||||
.map(UpdateKind::EditedChannelPost)
|
||||
.map_err(|_| false),
|
||||
"inline_query" => map
|
||||
.next_value::<InlineQuery>()
|
||||
.map(UpdateKind::InlineQuery)
|
||||
.map_err(|_| false),
|
||||
"chosen_inline_result" => map
|
||||
.next_value::<ChosenInlineResult>()
|
||||
.map(UpdateKind::ChosenInlineResult)
|
||||
.map_err(|_| false),
|
||||
"callback_query" => map
|
||||
.next_value::<CallbackQuery>()
|
||||
.map(UpdateKind::CallbackQuery)
|
||||
.map_err(|_| false),
|
||||
"shipping_query" => map
|
||||
.next_value::<ShippingQuery>()
|
||||
.map(UpdateKind::ShippingQuery)
|
||||
.map_err(|_| false),
|
||||
"pre_checkout_query" => map
|
||||
.next_value::<PreCheckoutQuery>()
|
||||
.map(UpdateKind::PreCheckoutQuery)
|
||||
.map_err(|_| false),
|
||||
"poll" => map
|
||||
.next_value::<Poll>()
|
||||
.map(UpdateKind::Poll)
|
||||
.map_err(|_| false),
|
||||
"poll_answer" => map
|
||||
.next_value::<PollAnswer>()
|
||||
.map(UpdateKind::PollAnswer)
|
||||
.map_err(|_| false),
|
||||
"my_chat_member" => map
|
||||
.next_value::<ChatMemberUpdated>()
|
||||
.map(UpdateKind::MyChatMember)
|
||||
.map_err(|_| false),
|
||||
"chat_member" => map
|
||||
.next_value::<ChatMemberUpdated>()
|
||||
.map(UpdateKind::ChatMember)
|
||||
.map_err(|_| false),
|
||||
"chat_join_request" => map
|
||||
.next_value::<ChatJoinRequest>()
|
||||
.map(UpdateKind::ChatJoinRequest)
|
||||
.map_err(|_| false),
|
||||
|
||||
_ => Err(true),
|
||||
};
|
||||
|
||||
let value_available = match res {
|
||||
Ok(ok) => return Ok(ok),
|
||||
Err(e) => e,
|
||||
};
|
||||
|
||||
let mut value = serde_json::Map::new();
|
||||
value.insert(
|
||||
k.to_owned(),
|
||||
if value_available {
|
||||
map.next_value::<Value>().unwrap_or(Value::Null)
|
||||
} else {
|
||||
Value::Null
|
||||
},
|
||||
);
|
||||
|
||||
while let Ok(Some((k, v))) = map.next_entry::<_, Value>() {
|
||||
value.insert(k, v);
|
||||
}
|
||||
|
||||
return Ok(UpdateKind::Error(Value::Object(value)));
|
||||
}
|
||||
|
||||
Ok(UpdateKind::Error(Value::Object(<_>::default())))
|
||||
}
|
||||
}
|
||||
|
||||
deserializer.deserialize_any(Visitor)
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for UpdateKind {
|
||||
fn serialize<S>(&self, s: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
let name = "UpdateKind";
|
||||
match self {
|
||||
UpdateKind::Message(v) => s.serialize_newtype_variant(name, 0, "message", v),
|
||||
UpdateKind::EditedMessage(v) => {
|
||||
s.serialize_newtype_variant(name, 1, "edited_message", v)
|
||||
}
|
||||
UpdateKind::ChannelPost(v) => s.serialize_newtype_variant(name, 2, "channel_post", v),
|
||||
UpdateKind::EditedChannelPost(v) => {
|
||||
s.serialize_newtype_variant(name, 3, "edited_channel_post", v)
|
||||
}
|
||||
UpdateKind::InlineQuery(v) => s.serialize_newtype_variant(name, 4, "inline_query", v),
|
||||
UpdateKind::ChosenInlineResult(v) => {
|
||||
s.serialize_newtype_variant(name, 5, "chosen_inline_result", v)
|
||||
}
|
||||
UpdateKind::CallbackQuery(v) => {
|
||||
s.serialize_newtype_variant(name, 6, "callback_query", v)
|
||||
}
|
||||
UpdateKind::ShippingQuery(v) => {
|
||||
s.serialize_newtype_variant(name, 7, "shipping_query", v)
|
||||
}
|
||||
UpdateKind::PreCheckoutQuery(v) => {
|
||||
s.serialize_newtype_variant(name, 8, "pre_checkout_query", v)
|
||||
}
|
||||
UpdateKind::Poll(v) => s.serialize_newtype_variant(name, 9, "poll", v),
|
||||
UpdateKind::PollAnswer(v) => s.serialize_newtype_variant(name, 10, "poll_answer", v),
|
||||
UpdateKind::MyChatMember(v) => {
|
||||
s.serialize_newtype_variant(name, 11, "my_chat_member", v)
|
||||
}
|
||||
UpdateKind::ChatMember(v) => s.serialize_newtype_variant(name, 12, "chat_member", v),
|
||||
UpdateKind::ChatJoinRequest(v) => {
|
||||
s.serialize_newtype_variant(name, 13, "chat_join_request", v)
|
||||
}
|
||||
UpdateKind::Error(v) => v.serialize(s),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -330,4 +476,20 @@ mod test {
|
|||
|
||||
serde_json::from_str::<Update>(json).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn new_update_kind_error() {
|
||||
let json = r#"{
|
||||
"new_update_kind": {"some_field_idk": 1},
|
||||
"update_id": 1
|
||||
}"#;
|
||||
|
||||
let Update { kind, .. } = serde_json::from_str(json).unwrap();
|
||||
|
||||
match kind {
|
||||
// Deserialization failed successfully
|
||||
UpdateKind::Error(_) => {}
|
||||
_ => panic!("Expected error"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue