From abf735093cef5a3a7e83e8bab01334f6a5eb0ef2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Commaille?= <76261501+zecakeh@users.noreply.github.com> Date: Mon, 9 May 2022 12:41:22 +0200 Subject: [PATCH] events: Fix serde of event types with suffix --- .../src/events/secret_storage/key.rs | 60 +++++++++++- .../ruma-macros/src/events/event_content.rs | 95 ++++++++++++------- crates/ruma-macros/src/events/event_type.rs | 2 +- 3 files changed, 120 insertions(+), 37 deletions(-) diff --git a/crates/ruma-common/src/events/secret_storage/key.rs b/crates/ruma-common/src/events/secret_storage/key.rs index d2706e61..babff6d8 100644 --- a/crates/ruma-common/src/events/secret_storage/key.rs +++ b/crates/ruma-common/src/events/secret_storage/key.rs @@ -101,7 +101,7 @@ mod tests { use serde_json::{from_value as from_json_value, json, to_value as to_json_value}; use super::{PassPhrase, SecretEncryptionAlgorithm, SecretStorageKeyEventContent}; - use crate::{serde::Base64, KeyDerivationAlgorithm}; + use crate::{events::GlobalAccountDataEvent, serde::Base64, KeyDerivationAlgorithm}; #[test] fn test_key_description_serialization() { @@ -218,4 +218,62 @@ mod tests { && bits == uint!(256) ) } + + #[test] + fn test_event_serialization() { + let event = GlobalAccountDataEvent { + content: SecretStorageKeyEventContent::new( + "my_key_id".into(), + "my_key".into(), + SecretEncryptionAlgorithm::SecretStorageV1AesHmacSha2 { + iv: Base64::parse("YWJjZGVmZ2hpamtsbW5vcA").unwrap(), + mac: Base64::parse("aWRvbnRrbm93d2hhdGFtYWNsb29rc2xpa2U").unwrap(), + }, + ), + }; + + let json = json!({ + "type": "m.secret_storage.key.my_key_id", + "content": { + "name": "my_key", + "algorithm": "m.secret_storage.v1.aes-hmac-sha2", + "iv": "YWJjZGVmZ2hpamtsbW5vcA", + "mac": "aWRvbnRrbm93d2hhdGFtYWNsb29rc2xpa2U" + } + }); + + assert_eq!(to_json_value(&event).unwrap(), json); + } + + #[test] + fn test_event_deserialization() { + let json = json!({ + "type": "m.secret_storage.key.my_key_id", + "content": { + "name": "my_key", + "algorithm": "m.secret_storage.v1.aes-hmac-sha2", + "iv": "YWJjZGVmZ2hpamtsbW5vcA", + "mac": "aWRvbnRrbm93d2hhdGFtYWNsb29rc2xpa2U" + } + }); + + assert_matches!( + from_json_value(json).unwrap(), + GlobalAccountDataEvent { + content: SecretStorageKeyEventContent { + key_id, + name, + algorithm: SecretEncryptionAlgorithm::SecretStorageV1AesHmacSha2 { + iv, + mac, + }, + passphrase: None, + } + } + if key_id == *"my_key_id" + && name == *"my_key" + && iv == Base64::parse("YWJjZGVmZ2hpamtsbW5vcA").unwrap() + && mac == Base64::parse("aWRvbnRrbm93d2hhdGFtYWNsb29rc2xpa2U").unwrap() + ) + } } diff --git a/crates/ruma-macros/src/events/event_content.rs b/crates/ruma-macros/src/events/event_content.rs index ed98c1b8..6370d5ec 100644 --- a/crates/ruma-macros/src/events/event_content.rs +++ b/crates/ruma-macros/src/events/event_content.rs @@ -483,41 +483,47 @@ fn generate_event_content_impl<'a>( let (event_type_ty_decl, event_type_ty, event_type_fn_impl); + let type_suffix_data = event_type + .value() + .strip_suffix('*') + .map(|type_prefix| { + let type_fragment_field = fields + .find_map(|f| { + f.attrs.iter().filter(|a| a.path.is_ident("ruma_event")).find_map(|a| { + match a.parse_args() { + Ok(EventMeta::TypeFragment) => Some(Ok(f)), + Ok(_) => None, + Err(e) => Some(Err(e)), + } + }) + }) + .transpose()? + .ok_or_else(|| { + syn::Error::new_spanned( + event_type, + "event type with a `.*` suffix requires there to be a \ + `#[ruma_event(type_fragment)]` field", + ) + })? + .ident + .as_ref() + .expect("type fragment field needs to have a name"); + + >::Ok((type_prefix.to_owned(), type_fragment_field)) + }) + .transpose()?; + match event_kind { Some(kind) => { let i = kind.to_event_type_enum(); event_type_ty_decl = None; event_type_ty = quote! { #ruma_common::events::#i }; - event_type_fn_impl = match event_type.value().strip_suffix(".*") { - Some(type_prefix) => { - let type_fragment_field = fields - .find_map(|f| { - f.attrs.iter().filter(|a| a.path.is_ident("ruma_event")).find_map(|a| { - match a.parse_args() { - Ok(EventMeta::TypeFragment) => Some(Ok(f)), - Ok(_) => None, - Err(e) => Some(Err(e)), - } - }) - }) - .transpose()?; - - let f = type_fragment_field - .ok_or_else(|| { - syn::Error::new_spanned( - event_type, - "event type with a `.*` suffix requires there to be a \ - `#[ruma_event(type_fragment)]` field", - ) - })? - .ident - .as_ref() - .expect("type fragment field needs to have a name"); - - let format = type_prefix.to_owned() + ".{}"; + event_type_fn_impl = match &type_suffix_data { + Some((type_prefix, type_fragment_field)) => { + let format = type_prefix.to_owned() + "{}"; quote! { - ::std::convert::From::from(::std::format!(#format, self.#f)) + ::std::convert::From::from(::std::format!(#format, self.#type_fragment_field)) } } None => quote! { ::std::convert::From::from(#event_type) }, @@ -559,6 +565,31 @@ fn generate_event_content_impl<'a>( } }); + let from_parts_fn_impl = if let Some((type_prefix, type_fragment_field)) = &type_suffix_data { + quote! { + if let Some(type_fragment) = ev_type.strip_prefix(#type_prefix) { + let mut content: Self = #serde_json::from_str(content.get())?; + content.#type_fragment_field = type_fragment.to_owned(); + + ::std::result::Result::Ok(content) + } else { + ::std::result::Result::Err(#serde::de::Error::custom( + ::std::format!("expected event type starting with `{}`, found `{}`", #type_prefix, ev_type) + )) + } + } + } else { + quote! { + if ev_type != #event_type { + return ::std::result::Result::Err(#serde::de::Error::custom( + ::std::format!("expected event type `{}`, found `{}`", #event_type, ev_type) + )); + } + + #serde_json::from_str(content.get()) + } + }; + Ok(quote! { #event_type_ty_decl @@ -574,13 +605,7 @@ fn generate_event_content_impl<'a>( ev_type: &::std::primitive::str, content: &#serde_json::value::RawValue, ) -> #serde_json::Result { - if ev_type != #event_type { - return ::std::result::Result::Err(#serde::de::Error::custom( - ::std::format!("expected event type `{}`, found `{}`", #event_type, ev_type) - )); - } - - #serde_json::from_str(content.get()) + #from_parts_fn_impl } } diff --git a/crates/ruma-macros/src/events/event_type.rs b/crates/ruma-macros/src/events/event_type.rs index d6f2ceb3..056aed7c 100644 --- a/crates/ruma-macros/src/events/event_type.rs +++ b/crates/ruma-macros/src/events/event_type.rs @@ -131,7 +131,7 @@ fn generate_enum( let ev_type = &e.ev_type; Ok(if let Some(prefix) = ev_type.value().strip_suffix(".*") { - let fstr = prefix.to_owned() + "{}"; + let fstr = prefix.to_owned() + ".{}"; quote! { #start(_s) => ::std::borrow::Cow::Owned(::std::format!(#fstr, _s)) } } else { quote! { #start => ::std::borrow::Cow::Borrowed(#ev_type) }