use js_option::JsOption; use ruma_common::serde::from_raw_json_value; use serde::{de, ser::SerializeStruct, Deserialize, Serialize}; use serde_json::value::RawValue as RawJsonValue; use super::v3::{PusherAction, PusherPostData}; #[derive(Debug, Deserialize)] struct PusherPostDataDeHelper { #[serde(default)] append: bool, } impl<'de> Deserialize<'de> for PusherPostData { fn deserialize(deserializer: D) -> Result where D: de::Deserializer<'de>, { let json = Box::::deserialize(deserializer)?; let PusherPostDataDeHelper { append } = from_raw_json_value(&json)?; let pusher = from_raw_json_value(&json)?; Ok(Self { pusher, append }) } } impl Serialize for PusherAction { fn serialize(&self, serializer: S) -> Result where S: serde::Serializer, { match self { PusherAction::Post(pusher) => pusher.serialize(serializer), PusherAction::Delete(ids) => { let mut st = serializer.serialize_struct("PusherAction", 3)?; st.serialize_field("pushkey", &ids.pushkey)?; st.serialize_field("app_id", &ids.app_id)?; st.serialize_field("kind", &None::<&str>)?; st.end() } } } } #[derive(Debug, Deserialize)] struct PusherActionDeHelper { kind: JsOption, } impl<'de> Deserialize<'de> for PusherAction { fn deserialize(deserializer: D) -> Result where D: de::Deserializer<'de>, { let json = Box::::deserialize(deserializer)?; let PusherActionDeHelper { kind } = from_raw_json_value(&json)?; match kind { JsOption::Some(_) => Ok(Self::Post(from_raw_json_value(&json)?)), JsOption::Null => Ok(Self::Delete(from_raw_json_value(&json)?)), // This is unreachable because we don't use `#[serde(default)]` on the field. JsOption::Undefined => Err(de::Error::missing_field("kind")), } } } #[cfg(test)] mod tests { use assert_matches2::assert_matches; use serde_json::{from_value as from_json_value, json, to_value as to_json_value}; use super::PusherAction; use crate::push::{ set_pusher::v3::PusherPostData, EmailPusherData, Pusher, PusherIds, PusherKind, }; #[test] fn serialize_post() { let action = PusherAction::Post(PusherPostData { pusher: Pusher { ids: PusherIds::new("abcdef".to_owned(), "my.matrix.app".to_owned()), kind: PusherKind::Email(EmailPusherData::new()), app_display_name: "My Matrix App".to_owned(), device_display_name: "My Phone".to_owned(), profile_tag: None, lang: "en".to_owned(), }, append: false, }); assert_eq!( to_json_value(action).unwrap(), json!({ "pushkey": "abcdef", "app_id": "my.matrix.app", "kind": "email", "app_display_name": "My Matrix App", "device_display_name": "My Phone", "lang": "en", "data": {} }) ); } #[test] fn serialize_delete() { let action = PusherAction::Delete(PusherIds::new("abcdef".to_owned(), "my.matrix.app".to_owned())); assert_eq!( to_json_value(action).unwrap(), json!({ "pushkey": "abcdef", "app_id": "my.matrix.app", "kind": null, }) ); } #[test] fn deserialize_post() { let json = json!({ "pushkey": "abcdef", "app_id": "my.matrix.app", "kind": "email", "app_display_name": "My Matrix App", "device_display_name": "My Phone", "lang": "en", "data": {} }); assert_matches!(from_json_value(json).unwrap(), PusherAction::Post(post_data)); assert!(!post_data.append); let pusher = post_data.pusher; assert_eq!(pusher.ids.pushkey, "abcdef"); assert_eq!(pusher.ids.app_id, "my.matrix.app"); assert_matches!(pusher.kind, PusherKind::Email(_)); assert_eq!(pusher.app_display_name, "My Matrix App"); assert_eq!(pusher.device_display_name, "My Phone"); assert_eq!(pusher.profile_tag, None); assert_eq!(pusher.lang, "en"); } #[test] fn deserialize_delete() { let json = json!({ "pushkey": "abcdef", "app_id": "my.matrix.app", "kind": null, }); assert_matches!(from_json_value(json).unwrap(), PusherAction::Delete(ids)); assert_eq!(ids.pushkey, "abcdef"); assert_eq!(ids.app_id, "my.matrix.app"); } }