Revert " Remove event_enum! and only use event_content_enum"
This reverts commit 2a91dc1eb7215a762bd2204bc103ef172258d2d9. Also * Add back type defs and Any*Event enums * Move EventDeHelper and from_raw_json_value to lib make pub so event_enum! macro can use them and test. * Fix Any*Event enum deserialization error * Remove event_content_enum! macro and ruma-events-macros/src/content_enum.rs * Use serde's IgnoreAny to skip Unknown field's value * Clean up imports and test names for state_event
This commit is contained in:
		
							parent
							
								
									f9639e110e
								
							
						
					
					
						commit
						184aafa5f6
					
				| @ -244,7 +244,9 @@ fn expand_deserialize_event( | |||||||
| 
 | 
 | ||||||
|                         while let Some(key) = map.next_key()? { |                         while let Some(key) = map.next_key()? { | ||||||
|                             match key { |                             match key { | ||||||
|                                 Field::Unknown => continue, |                                 Field::Unknown => { | ||||||
|  |                                     let _: ::serde::de::IgnoredAny = map.next_value()?; | ||||||
|  |                                 }, | ||||||
|                                 Field::Type => { |                                 Field::Type => { | ||||||
|                                     if event_type.is_some() { |                                     if event_type.is_some() { | ||||||
|                                         return Err(::serde::de::Error::duplicate_field("type")); |                                         return Err(::serde::de::Error::duplicate_field("type")); | ||||||
|  | |||||||
| @ -1,4 +1,4 @@ | |||||||
| //! Implementation of the content_enum type macro.
 | //! Implementation of event enum and event content enum macros.
 | ||||||
| 
 | 
 | ||||||
| use proc_macro2::TokenStream; | use proc_macro2::TokenStream; | ||||||
| use quote::quote; | use quote::quote; | ||||||
| @ -7,16 +7,69 @@ use syn::{ | |||||||
|     Attribute, Expr, ExprLit, Ident, Lit, LitStr, Token, |     Attribute, Expr, ExprLit, Ident, Lit, LitStr, Token, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| /// Create a content enum from `ContentEnumInput`.
 | /// Create a content enum from `EventEnumInput`.
 | ||||||
| ///
 | pub fn expand_event_enum(input: EventEnumInput) -> syn::Result<TokenStream> { | ||||||
| /// This is the internals of the `event_content_enum!` macro.
 |  | ||||||
| pub fn expand_content_enum(input: ContentEnumInput) -> syn::Result<TokenStream> { |  | ||||||
|     let attrs = &input.attrs; |     let attrs = &input.attrs; | ||||||
|     let ident = &input.name; |     let ident = &input.name; | ||||||
| 
 |  | ||||||
|     let event_type_str = &input.events; |     let event_type_str = &input.events; | ||||||
| 
 | 
 | ||||||
|     let variants = input.events.iter().map(to_camel_case).collect::<Vec<_>>(); |     let variants = input.events.iter().map(to_camel_case).collect::<syn::Result<Vec<_>>>()?; | ||||||
|  |     let content = input.events.iter().map(to_event_path).collect::<Vec<_>>(); | ||||||
|  | 
 | ||||||
|  |     let event_enum = quote! { | ||||||
|  |         #( #attrs )* | ||||||
|  |         #[derive(Clone, Debug, ::serde::Serialize)] | ||||||
|  |         #[serde(untagged)] | ||||||
|  |         #[allow(clippy::large_enum_variant)] | ||||||
|  |         pub enum #ident { | ||||||
|  |             #( | ||||||
|  |                 #[doc = #event_type_str] | ||||||
|  |                 #variants(#content), | ||||||
|  |             )* | ||||||
|  |         } | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     let event_deserialize_impl = quote! { | ||||||
|  |         impl<'de> ::serde::de::Deserialize<'de> for #ident { | ||||||
|  |             fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> | ||||||
|  |             where | ||||||
|  |                 D: ::serde::de::Deserializer<'de>, | ||||||
|  |             { | ||||||
|  |                 use ::serde::de::Error as _; | ||||||
|  | 
 | ||||||
|  |                 let json = Box::<::serde_json::value::RawValue>::deserialize(deserializer)?; | ||||||
|  |                 let ::ruma_events::EventDeHelper { ev_type } = ::ruma_events::from_raw_json_value(&json)?; | ||||||
|  |                 match ev_type.as_str() { | ||||||
|  |                     #( | ||||||
|  |                         #event_type_str => { | ||||||
|  |                             let event = ::serde_json::from_str::<#content>(json.get()).map_err(D::Error::custom)?; | ||||||
|  |                             Ok(#ident::#variants(event)) | ||||||
|  |                         }, | ||||||
|  |                     )* | ||||||
|  |                     _ => Err(D::Error::custom(format!("event type `{}` is not a valid event", ev_type))) | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     let event_content_enum = expand_content_enum(input)?; | ||||||
|  | 
 | ||||||
|  |     Ok(quote! { | ||||||
|  |         #event_enum | ||||||
|  | 
 | ||||||
|  |         #event_deserialize_impl | ||||||
|  | 
 | ||||||
|  |         #event_content_enum | ||||||
|  |     }) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /// Create a content enum from `EventEnumInput`.
 | ||||||
|  | pub fn expand_content_enum(input: EventEnumInput) -> syn::Result<TokenStream> { | ||||||
|  |     let attrs = &input.attrs; | ||||||
|  |     let ident = Ident::new(&format!("{}Content", input.name.to_string()), input.name.span()); | ||||||
|  |     let event_type_str = &input.events; | ||||||
|  | 
 | ||||||
|  |     let variants = input.events.iter().map(to_camel_case).collect::<syn::Result<Vec<_>>>()?; | ||||||
|     let content = input.events.iter().map(to_event_content_path).collect::<Vec<_>>(); |     let content = input.events.iter().map(to_event_content_path).collect::<Vec<_>>(); | ||||||
| 
 | 
 | ||||||
|     let content_enum = quote! { |     let content_enum = quote! { | ||||||
| @ -29,8 +82,8 @@ pub fn expand_content_enum(input: ContentEnumInput) -> syn::Result<TokenStream> | |||||||
|                 #[doc = #event_type_str] |                 #[doc = #event_type_str] | ||||||
|                 #variants(#content), |                 #variants(#content), | ||||||
|             )* |             )* | ||||||
|             #[doc = "Represents any event not defined in the Matrix spec."] |             /// Any custom event.
 | ||||||
|             Custom(::ruma_events::custom::CustomEventContent) |             Custom(::ruma_events::custom::CustomEventContent), | ||||||
|         } |         } | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
| @ -39,14 +92,11 @@ pub fn expand_content_enum(input: ContentEnumInput) -> syn::Result<TokenStream> | |||||||
|             fn event_type(&self) -> &str { |             fn event_type(&self) -> &str { | ||||||
|                 match self { |                 match self { | ||||||
|                     #( Self::#variants(content) => content.event_type(), )* |                     #( Self::#variants(content) => content.event_type(), )* | ||||||
|                     #ident::Custom(content) => content.event_type(), |                     Self::Custom(content) => content.event_type(), | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             fn from_parts( |             fn from_parts(event_type: &str, input: Box<::serde_json::value::RawValue>) -> Result<Self, ::serde_json::Error> { | ||||||
|                 event_type: &str, |  | ||||||
|                 input: Box<::serde_json::value::RawValue>, |  | ||||||
|             ) -> Result<Self, ::serde_json::Error> { |  | ||||||
|                 match event_type { |                 match event_type { | ||||||
|                     #( |                     #( | ||||||
|                         #event_type_str => { |                         #event_type_str => { | ||||||
| @ -74,7 +124,7 @@ pub fn expand_content_enum(input: ContentEnumInput) -> syn::Result<TokenStream> | |||||||
|         } |         } | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|     let marker_trait_impls = marker_traits(ident); |     let marker_trait_impls = marker_traits(&ident); | ||||||
| 
 | 
 | ||||||
|     Ok(quote! { |     Ok(quote! { | ||||||
|         #content_enum |         #content_enum | ||||||
| @ -107,9 +157,28 @@ fn marker_traits(ident: &Ident) -> TokenStream { | |||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| fn to_event_content_path( | fn to_event_path(name: &LitStr) -> TokenStream { | ||||||
|     name: &LitStr, |     let span = name.span(); | ||||||
| ) -> syn::punctuated::Punctuated<syn::Token![::], syn::PathSegment> { |     let name = name.value(); | ||||||
|  | 
 | ||||||
|  |     assert_eq!(&name[..2], "m."); | ||||||
|  | 
 | ||||||
|  |     let path = name[2..].split('.').collect::<Vec<_>>(); | ||||||
|  | 
 | ||||||
|  |     let event_str = path.last().unwrap(); | ||||||
|  |     let event = event_str | ||||||
|  |         .split('_') | ||||||
|  |         .map(|s| s.chars().next().unwrap().to_uppercase().to_string() + &s[1..]) | ||||||
|  |         .collect::<String>(); | ||||||
|  | 
 | ||||||
|  |     let content_str = Ident::new(&format!("{}Event", event), span); | ||||||
|  |     let path = path.iter().map(|s| Ident::new(s, span)); | ||||||
|  |     quote! { | ||||||
|  |         ::ruma_events::#( #path )::*::#content_str | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn to_event_content_path(name: &LitStr) -> TokenStream { | ||||||
|     let span = name.span(); |     let span = name.span(); | ||||||
|     let name = name.value(); |     let name = name.value(); | ||||||
| 
 | 
 | ||||||
| @ -125,56 +194,60 @@ fn to_event_content_path( | |||||||
| 
 | 
 | ||||||
|     let content_str = Ident::new(&format!("{}EventContent", event), span); |     let content_str = Ident::new(&format!("{}EventContent", event), span); | ||||||
|     let path = path.iter().map(|s| Ident::new(s, span)); |     let path = path.iter().map(|s| Ident::new(s, span)); | ||||||
|     syn::parse_quote! { |     quote! { | ||||||
|         ::ruma_events::#( #path )::*::#content_str |         ::ruma_events::#( #path )::*::#content_str | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /// Splits the given `event_type` string on `.` and `_` removing the `m.room.` then
 | /// Splits the given `event_type` string on `.` and `_` removing the `m.room.` then
 | ||||||
| /// camel casing to give the `EventContent` struct name.
 | /// camel casing to give the `Event` struct name.
 | ||||||
| pub(crate) fn to_camel_case(name: &LitStr) -> Ident { | pub(crate) fn to_camel_case(name: &LitStr) -> syn::Result<Ident> { | ||||||
|     let span = name.span(); |     let span = name.span(); | ||||||
|     let name = name.value(); |     let name = name.value(); | ||||||
| 
 | 
 | ||||||
|     if &name[..2] != "m." { |     if &name[..2] != "m." { | ||||||
|         panic!("well-known matrix events have to start with `m.` found `{}`", name,) |         return Err(syn::Error::new( | ||||||
|  |             span, | ||||||
|  |             format!("well-known matrix events have to start with `m.` found `{}`", name), | ||||||
|  |         )); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     let s = name[2..] |     let s = name[2..] | ||||||
|         .split(&['.', '_'] as &[char]) |         .split(&['.', '_'] as &[char]) | ||||||
|         .map(|s| s.chars().next().unwrap().to_uppercase().to_string() + &s[1..]) |         .map(|s| s.chars().next().unwrap().to_uppercase().to_string() + &s[1..]) | ||||||
|         .collect::<String>(); |         .collect::<String>(); | ||||||
|     Ident::new(&s, span) | 
 | ||||||
|  |     Ok(Ident::new(&s, span)) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /// Custom keywords for the `event_content_content_enum!` macro
 | /// Custom keywords for the `event_enum!` macro
 | ||||||
| mod kw { | mod kw { | ||||||
|     syn::custom_keyword!(name); |     syn::custom_keyword!(name); | ||||||
|     syn::custom_keyword!(events); |     syn::custom_keyword!(events); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /// The entire `event_content_content_enum!` macro structure directly as it appears in the source code..
 | /// The entire `event_enum!` macro structure directly as it appears in the source code.
 | ||||||
| pub struct ContentEnumInput { | pub struct EventEnumInput { | ||||||
|     /// Outer attributes on the field, such as a docstring.
 |     /// Outer attributes on the field, such as a docstring.
 | ||||||
|     pub attrs: Vec<Attribute>, |     pub attrs: Vec<Attribute>, | ||||||
| 
 | 
 | ||||||
|     /// The name of the event.
 |     /// The name of the event.
 | ||||||
|     pub name: Ident, |     pub name: Ident, | ||||||
| 
 | 
 | ||||||
|     /// An array of valid matrix event types. This will generate the variants of the event content type "name".
 |     /// An array of valid matrix event types. This will generate the variants of the event type "name".
 | ||||||
|     /// There needs to be a corresponding variant in `ruma_events::EventType` for
 |     /// There needs to be a corresponding variant in `ruma_events::EventType` for
 | ||||||
|     /// this event (converted to a valid Rust-style type name by stripping `m.`, replacing the
 |     /// this event (converted to a valid Rust-style type name by stripping `m.`, replacing the
 | ||||||
|     /// remaining dots by underscores and then converting from snake_case to CamelCase).
 |     /// remaining dots by underscores and then converting from snake_case to CamelCase).
 | ||||||
|     pub events: Vec<LitStr>, |     pub events: Vec<LitStr>, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl Parse for ContentEnumInput { | impl Parse for EventEnumInput { | ||||||
|     fn parse(input: ParseStream<'_>) -> parse::Result<Self> { |     fn parse(input: ParseStream<'_>) -> parse::Result<Self> { | ||||||
|         let attrs = input.call(Attribute::parse_outer)?; |         let attrs = input.call(Attribute::parse_outer)?; | ||||||
|         // name field
 |         // name field
 | ||||||
|         input.parse::<kw::name>()?; |         input.parse::<kw::name>()?; | ||||||
|         input.parse::<Token![:]>()?; |         input.parse::<Token![:]>()?; | ||||||
|         // the name of our content_enum enum
 |         // the name of our event enum
 | ||||||
|         let name: Ident = input.parse()?; |         let name: Ident = input.parse()?; | ||||||
|         input.parse::<Token![,]>()?; |         input.parse::<Token![,]>()?; | ||||||
| 
 | 
 | ||||||
| @ -11,26 +11,27 @@ use proc_macro::TokenStream; | |||||||
| use syn::{parse_macro_input, DeriveInput}; | use syn::{parse_macro_input, DeriveInput}; | ||||||
| 
 | 
 | ||||||
| use self::{ | use self::{ | ||||||
|     content_enum::{expand_content_enum, ContentEnumInput}, |  | ||||||
|     event::expand_event, |     event::expand_event, | ||||||
|     event_content::{ |     event_content::{ | ||||||
|         expand_basic_event_content, expand_ephemeral_room_event_content, expand_event_content, |         expand_basic_event_content, expand_ephemeral_room_event_content, expand_event_content, | ||||||
|         expand_message_event_content, expand_room_event_content, expand_state_event_content, |         expand_message_event_content, expand_room_event_content, expand_state_event_content, | ||||||
|     }, |     }, | ||||||
|  |     event_enum::{expand_event_enum, EventEnumInput}, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| mod content_enum; |  | ||||||
| mod event; | mod event; | ||||||
| mod event_content; | mod event_content; | ||||||
|  | mod event_enum; | ||||||
| 
 | 
 | ||||||
| /// Generates a content enum to represent the various Matrix event types.
 | /// Generates an enum to represent the various Matrix event types.
 | ||||||
| ///
 | ///
 | ||||||
| /// This macro also implements the necessary traits for the type to serialize and deserialize
 | /// This macro also implements the necessary traits for the type to serialize and deserialize
 | ||||||
| /// itself.
 | /// itself.
 | ||||||
|  | // TODO more docs/example
 | ||||||
| #[proc_macro] | #[proc_macro] | ||||||
| pub fn event_content_enum(input: TokenStream) -> TokenStream { | pub fn event_enum(input: TokenStream) -> TokenStream { | ||||||
|     let content_enum_input = syn::parse_macro_input!(input as ContentEnumInput); |     let event_enum_input = syn::parse_macro_input!(input as EventEnumInput); | ||||||
|     expand_content_enum(content_enum_input).unwrap_or_else(|err| err.to_compile_error()).into() |     expand_event_enum(event_enum_input).unwrap_or_else(|err| err.to_compile_error()).into() | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /// Generates an implementation of `ruma_events::EventContent`.
 | /// Generates an implementation of `ruma_events::EventContent`.
 | ||||||
|  | |||||||
| @ -1,35 +1,32 @@ | |||||||
| use ruma_events_macros::event_content_enum; | use ruma_events_macros::event_enum; | ||||||
| use serde::{ | use serde::{ | ||||||
|     de::{self, DeserializeOwned, Error as _}, |     de::{self, Error}, | ||||||
|     Deserialize, Serialize, |     Serialize, | ||||||
| }; | }; | ||||||
| use serde_json::value::RawValue as RawJsonValue; | use serde_json::value::RawValue as RawJsonValue; | ||||||
| 
 | 
 | ||||||
| use crate::{ | use crate::{ | ||||||
|     event_kinds::{ |     event_kinds::{MessageEventStub, StateEventStub, StrippedStateEventStub}, | ||||||
|         BasicEvent, EphemeralRoomEvent, MessageEvent, MessageEventStub, StateEvent, StateEventStub, |     from_raw_json_value, EventDeHelper, | ||||||
|         StrippedStateEventStub, ToDeviceEvent, |  | ||||||
|     }, |  | ||||||
|     presence::PresenceEvent, |  | ||||||
|     room::redaction::{RedactionEvent, RedactionEventStub}, |  | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| event_content_enum! { | event_enum! { | ||||||
|     /// Any basic event.
 |     /// Any basic event.
 | ||||||
|     name: AnyBasicEventContent, |     name: AnyBasicEvent, | ||||||
|     events: [ |     events: [ | ||||||
|         "m.direct", |         "m.direct", | ||||||
|         "m.dummy", |         "m.dummy", | ||||||
|         "m.ignored_user_list", |         "m.ignored_user_list", | ||||||
|  |         "m.presence", | ||||||
|         "m.push_rules", |         "m.push_rules", | ||||||
|         "m.room_key", |         "m.room_key", | ||||||
|         "m.tag", |         "m.tag", | ||||||
|     ] |     ] | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| event_content_enum! { | event_enum! { | ||||||
|     /// Any ephemeral room event.
 |     /// Any ephemeral room event.
 | ||||||
|     name: AnyEphemeralRoomEventContent, |     name: AnyEphemeralRoomEvent, | ||||||
|     events: [ |     events: [ | ||||||
|         "m.fully_read", |         "m.fully_read", | ||||||
|         "m.receipt", |         "m.receipt", | ||||||
| @ -37,24 +34,25 @@ event_content_enum! { | |||||||
|     ] |     ] | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| event_content_enum! { | event_enum! { | ||||||
|     /// Any message event.
 |     /// Any message event.
 | ||||||
|     name: AnyMessageEventContent, |     name: AnyMessageEvent, | ||||||
|     events: [ |     events: [ | ||||||
|         "m.call.answer", |         "m.call.answer", | ||||||
|         "m.call.invite", |         "m.call.invite", | ||||||
|         "m.call.hangup", |         "m.call.hangup", | ||||||
|         "m.call.candidates", |         "m.call.candidates", | ||||||
|         "m.room.encrypted", |  | ||||||
|         "m.room.message", |         "m.room.message", | ||||||
|         "m.room.message.feedback", |         "m.room.message.feedback", | ||||||
|  |         "m.room.redaction", | ||||||
|         "m.sticker", |         "m.sticker", | ||||||
|  | 
 | ||||||
|     ] |     ] | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| event_content_enum! { | event_enum! { | ||||||
|     /// Any state event.
 |     /// Any state event.
 | ||||||
|     name: AnyStateEventContent, |     name: AnyStateEvent, | ||||||
|     events: [ |     events: [ | ||||||
|         "m.room.aliases", |         "m.room.aliases", | ||||||
|         "m.room.avatar", |         "m.room.avatar", | ||||||
| @ -76,9 +74,9 @@ event_content_enum! { | |||||||
|     ] |     ] | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| event_content_enum! { | event_enum! { | ||||||
|     /// Any to-device event.
 |     /// Any to-device event.
 | ||||||
|     name: AnyToDeviceEventContent, |     name: AnyToDeviceEvent, | ||||||
|     events: [ |     events: [ | ||||||
|         "m.dummy", |         "m.dummy", | ||||||
|         "m.room_key", |         "m.room_key", | ||||||
| @ -94,21 +92,9 @@ event_content_enum! { | |||||||
|     ] |     ] | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /// Any basic event, one that has no (well-known) fields outside of `content`.
 |  | ||||||
| pub type AnyBasicEvent = BasicEvent<AnyBasicEventContent>; |  | ||||||
| 
 |  | ||||||
| /// Any ephemeral room event.
 |  | ||||||
| pub type AnyEphemeralRoomEvent = EphemeralRoomEvent<AnyEphemeralRoomEventContent>; |  | ||||||
| 
 |  | ||||||
| /// Any message event.
 |  | ||||||
| pub type AnyMessageEvent = MessageEvent<AnyMessageEventContent>; |  | ||||||
| 
 |  | ||||||
| /// Any message event stub (message event without a `room_id`, as returned in `/sync` responses)
 | /// Any message event stub (message event without a `room_id`, as returned in `/sync` responses)
 | ||||||
| pub type AnyMessageEventStub = MessageEventStub<AnyMessageEventContent>; | pub type AnyMessageEventStub = MessageEventStub<AnyMessageEventContent>; | ||||||
| 
 | 
 | ||||||
| /// Any state event.
 |  | ||||||
| pub type AnyStateEvent = StateEvent<AnyStateEventContent>; |  | ||||||
| 
 |  | ||||||
| /// Any state event stub (state event without a `room_id`, as returned in `/sync` responses)
 | /// Any state event stub (state event without a `room_id`, as returned in `/sync` responses)
 | ||||||
| pub type AnyStateEventStub = StateEventStub<AnyStateEventContent>; | pub type AnyStateEventStub = StateEventStub<AnyStateEventContent>; | ||||||
| 
 | 
 | ||||||
| @ -116,23 +102,16 @@ pub type AnyStateEventStub = StateEventStub<AnyStateEventContent>; | |||||||
| /// been invited to in `/sync` responses)
 | /// been invited to in `/sync` responses)
 | ||||||
| pub type AnyStrippedStateEventStub = StrippedStateEventStub<AnyStateEventContent>; | pub type AnyStrippedStateEventStub = StrippedStateEventStub<AnyStateEventContent>; | ||||||
| 
 | 
 | ||||||
| /// Any to-device event.
 |  | ||||||
| pub type AnyToDeviceEvent = ToDeviceEvent<AnyToDeviceEventContent>; |  | ||||||
| 
 |  | ||||||
| /// Any event.
 | /// Any event.
 | ||||||
| #[derive(Clone, Debug, Serialize)] | #[derive(Clone, Debug, Serialize)] | ||||||
| #[serde(untagged)] | #[serde(untagged)] | ||||||
| pub enum AnyEvent { | pub enum AnyEvent { | ||||||
|     /// Any basic event.
 |     /// Any basic event.
 | ||||||
|     Basic(AnyBasicEvent), |     Basic(AnyBasicEvent), | ||||||
|     /// `"m.presence"`, the only non-room event with a `sender` field.
 |  | ||||||
|     Presence(PresenceEvent), |  | ||||||
|     /// Any ephemeral room event.
 |     /// Any ephemeral room event.
 | ||||||
|     Ephemeral(AnyEphemeralRoomEvent), |     Ephemeral(AnyEphemeralRoomEvent), | ||||||
|     /// Any message event.
 |     /// Any message event.
 | ||||||
|     Message(AnyMessageEvent), |     Message(AnyMessageEvent), | ||||||
|     /// `"m.room.redaction"`, the only room event with a `redacts` field.
 |  | ||||||
|     Redaction(RedactionEvent), |  | ||||||
|     /// Any state event.
 |     /// Any state event.
 | ||||||
|     State(AnyStateEvent), |     State(AnyStateEvent), | ||||||
| } | } | ||||||
| @ -143,8 +122,6 @@ pub enum AnyEvent { | |||||||
| pub enum AnyRoomEvent { | pub enum AnyRoomEvent { | ||||||
|     /// Any message event.
 |     /// Any message event.
 | ||||||
|     Message(AnyMessageEvent), |     Message(AnyMessageEvent), | ||||||
|     /// `"m.room.redaction"`, the only room event with a `redacts` field.
 |  | ||||||
|     Redaction(RedactionEvent), |  | ||||||
|     /// Any state event.
 |     /// Any state event.
 | ||||||
|     State(AnyStateEvent), |     State(AnyStateEvent), | ||||||
| } | } | ||||||
| @ -155,26 +132,10 @@ pub enum AnyRoomEvent { | |||||||
| pub enum AnyRoomEventStub { | pub enum AnyRoomEventStub { | ||||||
|     /// Any message event stub
 |     /// Any message event stub
 | ||||||
|     Message(AnyMessageEventStub), |     Message(AnyMessageEventStub), | ||||||
|     /// `"m.room.redaction"` stub
 |  | ||||||
|     Redaction(RedactionEventStub), |  | ||||||
|     /// Any state event stub
 |     /// Any state event stub
 | ||||||
|     State(AnyStateEventStub), |     State(AnyStateEventStub), | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #[derive(Deserialize)] |  | ||||||
| struct EventDeHelper { |  | ||||||
|     #[serde(rename = "type")] |  | ||||||
|     ev_type: String, |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| fn from_raw_json_value<T, E>(val: &RawJsonValue) -> Result<T, E> |  | ||||||
| where |  | ||||||
|     T: DeserializeOwned, |  | ||||||
|     E: de::Error, |  | ||||||
| { |  | ||||||
|     serde_json::from_str(val.get()).map_err(E::custom) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // FIXME `#[serde(untagged)]` deserialization fails for these enums which
 | // FIXME `#[serde(untagged)]` deserialization fails for these enums which
 | ||||||
| // is odd as we are doing basically the same thing here, investigate?
 | // is odd as we are doing basically the same thing here, investigate?
 | ||||||
| impl<'de> de::Deserialize<'de> for AnyEvent { | impl<'de> de::Deserialize<'de> for AnyEvent { | ||||||
| @ -186,8 +147,6 @@ impl<'de> de::Deserialize<'de> for AnyEvent { | |||||||
|         let EventDeHelper { ev_type } = from_raw_json_value(&json)?; |         let EventDeHelper { ev_type } = from_raw_json_value(&json)?; | ||||||
| 
 | 
 | ||||||
|         match ev_type.as_str() { |         match ev_type.as_str() { | ||||||
|             "m.room.redaction" => Ok(AnyEvent::Redaction(from_raw_json_value(&json)?)), |  | ||||||
|             "m.presence" => Ok(AnyEvent::Presence(from_raw_json_value(&json)?)), |  | ||||||
|             ev_type if AnyBasicEventContent::is_compatible(ev_type) => { |             ev_type if AnyBasicEventContent::is_compatible(ev_type) => { | ||||||
|                 Ok(AnyEvent::Basic(from_raw_json_value(&json)?)) |                 Ok(AnyEvent::Basic(from_raw_json_value(&json)?)) | ||||||
|             } |             } | ||||||
| @ -214,7 +173,6 @@ impl<'de> de::Deserialize<'de> for AnyRoomEvent { | |||||||
|         let EventDeHelper { ev_type } = from_raw_json_value(&json)?; |         let EventDeHelper { ev_type } = from_raw_json_value(&json)?; | ||||||
| 
 | 
 | ||||||
|         match ev_type.as_str() { |         match ev_type.as_str() { | ||||||
|             "m.room.redaction" => Ok(AnyRoomEvent::Redaction(from_raw_json_value(&json)?)), |  | ||||||
|             ev_type if AnyMessageEventContent::is_compatible(ev_type) => { |             ev_type if AnyMessageEventContent::is_compatible(ev_type) => { | ||||||
|                 Ok(AnyRoomEvent::Message(from_raw_json_value(&json)?)) |                 Ok(AnyRoomEvent::Message(from_raw_json_value(&json)?)) | ||||||
|             } |             } | ||||||
| @ -235,7 +193,6 @@ impl<'de> de::Deserialize<'de> for AnyRoomEventStub { | |||||||
|         let EventDeHelper { ev_type } = from_raw_json_value(&json)?; |         let EventDeHelper { ev_type } = from_raw_json_value(&json)?; | ||||||
| 
 | 
 | ||||||
|         match ev_type.as_str() { |         match ev_type.as_str() { | ||||||
|             "m.room.redaction" => Ok(AnyRoomEventStub::Redaction(from_raw_json_value(&json)?)), |  | ||||||
|             ev_type if AnyMessageEventContent::is_compatible(ev_type) => { |             ev_type if AnyMessageEventContent::is_compatible(ev_type) => { | ||||||
|                 Ok(AnyRoomEventStub::Message(from_raw_json_value(&json)?)) |                 Ok(AnyRoomEventStub::Message(from_raw_json_value(&json)?)) | ||||||
|             } |             } | ||||||
|  | |||||||
| @ -120,7 +120,7 @@ | |||||||
| use std::fmt::Debug; | use std::fmt::Debug; | ||||||
| 
 | 
 | ||||||
| use js_int::Int; | use js_int::Int; | ||||||
| use serde::{Deserialize, Serialize}; | use serde::{de, Deserialize, Serialize}; | ||||||
| use serde_json::value::RawValue as RawJsonValue; | use serde_json::value::RawValue as RawJsonValue; | ||||||
| 
 | 
 | ||||||
| use self::room::redaction::RedactionEvent; | use self::room::redaction::RedactionEvent; | ||||||
| @ -234,3 +234,21 @@ pub trait MessageEventContent: RoomEventContent {} | |||||||
| 
 | 
 | ||||||
| /// Marker trait for the content of a state event.
 | /// Marker trait for the content of a state event.
 | ||||||
| pub trait StateEventContent: RoomEventContent {} | pub trait StateEventContent: RoomEventContent {} | ||||||
|  | 
 | ||||||
|  | /// Helper struct to obtain the event type from a serde_json::value::RawValue.
 | ||||||
|  | #[doc(hidden)] | ||||||
|  | #[derive(Debug, Deserialize)] | ||||||
|  | pub struct EventDeHelper { | ||||||
|  |     #[serde(rename = "type")] | ||||||
|  |     pub ev_type: String, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /// Helper function for serde_json::value::RawValue deserialization.
 | ||||||
|  | #[doc(hidden)] | ||||||
|  | pub fn from_raw_json_value<T, E>(val: &RawJsonValue) -> Result<T, E> | ||||||
|  | where | ||||||
|  |     T: de::DeserializeOwned, | ||||||
|  |     E: de::Error, | ||||||
|  | { | ||||||
|  |     serde_json::from_str(val.get()).map_err(E::custom) | ||||||
|  | } | ||||||
|  | |||||||
| @ -10,8 +10,9 @@ use ruma_events::{ | |||||||
|         message::{MessageEventContent, TextMessageEventContent}, |         message::{MessageEventContent, TextMessageEventContent}, | ||||||
|         power_levels::PowerLevelsEventContent, |         power_levels::PowerLevelsEventContent, | ||||||
|     }, |     }, | ||||||
|     AnyEvent, AnyMessageEventContent, AnyRoomEvent, AnyRoomEventStub, AnyStateEventContent, |     AnyEvent, AnyMessageEvent, AnyMessageEventContent, AnyRoomEvent, AnyRoomEventStub, | ||||||
|     MessageEvent, MessageEventStub, StateEvent, StateEventStub, |     AnyStateEvent, AnyStateEventContent, MessageEvent, MessageEventStub, StateEvent, | ||||||
|  |     StateEventStub, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| fn message_event() -> JsonValue { | fn message_event() -> JsonValue { | ||||||
| @ -175,14 +176,14 @@ fn message_room_event_deserialization() { | |||||||
|     assert_matches!( |     assert_matches!( | ||||||
|         from_json_value::<AnyRoomEvent>(json_data), |         from_json_value::<AnyRoomEvent>(json_data), | ||||||
|         Ok(AnyRoomEvent::Message( |         Ok(AnyRoomEvent::Message( | ||||||
|             MessageEvent { |             AnyMessageEvent::RoomMessage(MessageEvent { | ||||||
|                 content: AnyMessageEventContent::RoomMessage(MessageEventContent::Text(TextMessageEventContent { |                 content: MessageEventContent::Text(TextMessageEventContent { | ||||||
|                     body, |                     body, | ||||||
|                     formatted: Some(formatted), |                     formatted: Some(formatted), | ||||||
|                     relates_to: None, |                     relates_to: None, | ||||||
|                 })), |                 }), | ||||||
|                 .. |                 .. | ||||||
|             } |             }) | ||||||
|         )) |         )) | ||||||
|         if body == "baba" && formatted.body == "<strong>baba</strong>" |         if body == "baba" && formatted.body == "<strong>baba</strong>" | ||||||
|     ); |     ); | ||||||
| @ -195,12 +196,12 @@ fn alias_room_event_deserialization() { | |||||||
|     assert_matches!( |     assert_matches!( | ||||||
|         from_json_value::<AnyRoomEvent>(json_data), |         from_json_value::<AnyRoomEvent>(json_data), | ||||||
|         Ok(AnyRoomEvent::State( |         Ok(AnyRoomEvent::State( | ||||||
|             StateEvent { |             AnyStateEvent::RoomAliases(StateEvent { | ||||||
|                 content: AnyStateEventContent::RoomAliases(AliasesEventContent { |                 content: AliasesEventContent { | ||||||
|                     aliases, |                     aliases, | ||||||
|                 }), |                 }, | ||||||
|                 .. |                 .. | ||||||
|             } |             }) | ||||||
|         )) |         )) | ||||||
|         if aliases == vec![ RoomAliasId::try_from("#somewhere:localhost").unwrap() ] |         if aliases == vec![ RoomAliasId::try_from("#somewhere:localhost").unwrap() ] | ||||||
|     ); |     ); | ||||||
| @ -213,14 +214,14 @@ fn message_event_deserialization() { | |||||||
|     assert_matches!( |     assert_matches!( | ||||||
|         from_json_value::<AnyEvent>(json_data), |         from_json_value::<AnyEvent>(json_data), | ||||||
|         Ok(AnyEvent::Message( |         Ok(AnyEvent::Message( | ||||||
|             MessageEvent { |             AnyMessageEvent::RoomMessage(MessageEvent { | ||||||
|                 content: AnyMessageEventContent::RoomMessage(MessageEventContent::Text(TextMessageEventContent { |                 content: MessageEventContent::Text(TextMessageEventContent { | ||||||
|                     body, |                     body, | ||||||
|                     formatted: Some(formatted), |                     formatted: Some(formatted), | ||||||
|                     relates_to: None, |                     relates_to: None, | ||||||
|                 })), |                 }), | ||||||
|                 .. |                 .. | ||||||
|             } |             }) | ||||||
|         )) |         )) | ||||||
|         if body == "baba" && formatted.body == "<strong>baba</strong>" |         if body == "baba" && formatted.body == "<strong>baba</strong>" | ||||||
|     ); |     ); | ||||||
| @ -233,12 +234,12 @@ fn alias_event_deserialization() { | |||||||
|     assert_matches!( |     assert_matches!( | ||||||
|         from_json_value::<AnyEvent>(json_data), |         from_json_value::<AnyEvent>(json_data), | ||||||
|         Ok(AnyEvent::State( |         Ok(AnyEvent::State( | ||||||
|             StateEvent { |             AnyStateEvent::RoomAliases(StateEvent { | ||||||
|                 content: AnyStateEventContent::RoomAliases(AliasesEventContent { |                 content: AliasesEventContent { | ||||||
|                     aliases, |                     aliases, | ||||||
|                 }), |                 }, | ||||||
|                 .. |                 .. | ||||||
|             } |             }) | ||||||
|         )) |         )) | ||||||
|         if aliases == vec![ RoomAliasId::try_from("#somewhere:localhost").unwrap() ] |         if aliases == vec![ RoomAliasId::try_from("#somewhere:localhost").unwrap() ] | ||||||
|     ); |     ); | ||||||
|  | |||||||
							
								
								
									
										124
									
								
								ruma-events/tests/event_enums.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										124
									
								
								ruma-events/tests/event_enums.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,124 @@ | |||||||
|  | use std::{ | ||||||
|  |     convert::TryFrom, | ||||||
|  |     time::{Duration, UNIX_EPOCH}, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | use js_int::UInt; | ||||||
|  | use matches::assert_matches; | ||||||
|  | use ruma_identifiers::{EventId, RoomId, UserId}; | ||||||
|  | use serde_json::{from_value as from_json_value, json, to_value as to_json_value}; | ||||||
|  | 
 | ||||||
|  | use ruma_events::{ | ||||||
|  |     call::{answer::AnswerEventContent, SessionDescription, SessionDescriptionType}, | ||||||
|  |     room::{ImageInfo, ThumbnailInfo}, | ||||||
|  |     sticker::StickerEventContent, | ||||||
|  |     AnyMessageEvent, MessageEvent, UnsignedData, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | #[test] | ||||||
|  | fn ui() { | ||||||
|  |     let t = trybuild::TestCases::new(); | ||||||
|  |     t.pass("tests/ui/07-enum-sanity-check.rs"); | ||||||
|  |     t.compile_fail("tests/ui/08-enum-invalid-path.rs"); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[test] | ||||||
|  | fn deserialize_message_event() { | ||||||
|  |     let json_data = json!({ | ||||||
|  |         "content": { | ||||||
|  |             "answer": { | ||||||
|  |                 "type": "answer", | ||||||
|  |                 "sdp": "Hello" | ||||||
|  |             }, | ||||||
|  |             "call_id": "foofoo", | ||||||
|  |             "version": 1 | ||||||
|  |         }, | ||||||
|  |         "event_id": "$h29iv0s8:example.com", | ||||||
|  |         "origin_server_ts": 1, | ||||||
|  |         "room_id": "!roomid:room.com", | ||||||
|  |         "sender": "@carl:example.com", | ||||||
|  |         "type": "m.call.answer" | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     assert_matches!( | ||||||
|  |         from_json_value::<AnyMessageEvent>(json_data) | ||||||
|  |             .unwrap(), | ||||||
|  |         AnyMessageEvent::CallAnswer(MessageEvent { | ||||||
|  |             content: AnswerEventContent { | ||||||
|  |                 answer: SessionDescription { | ||||||
|  |                     session_type: SessionDescriptionType::Answer, | ||||||
|  |                     sdp, | ||||||
|  |                 }, | ||||||
|  |                 call_id, | ||||||
|  |                 version, | ||||||
|  |             }, | ||||||
|  |             event_id, | ||||||
|  |             origin_server_ts, | ||||||
|  |             room_id, | ||||||
|  |             sender, | ||||||
|  |             unsigned, | ||||||
|  |         }) if sdp == "Hello" && call_id == "foofoo" && version == UInt::new(1).unwrap() | ||||||
|  |             && event_id == EventId::try_from("$h29iv0s8:example.com").unwrap() | ||||||
|  |             && origin_server_ts == UNIX_EPOCH + Duration::from_millis(1) | ||||||
|  |             && room_id == RoomId::try_from("!roomid:room.com").unwrap() | ||||||
|  |             && sender == UserId::try_from("@carl:example.com").unwrap() | ||||||
|  |             && unsigned.is_empty() | ||||||
|  |     ); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[test] | ||||||
|  | fn serialize_message_event() { | ||||||
|  |     let aliases_event = AnyMessageEvent::Sticker(MessageEvent { | ||||||
|  |         content: StickerEventContent { | ||||||
|  |             body: "Hello".into(), | ||||||
|  |             info: ImageInfo { | ||||||
|  |                 height: UInt::new(423), | ||||||
|  |                 width: UInt::new(1011), | ||||||
|  |                 mimetype: Some("image/png".into()), | ||||||
|  |                 size: UInt::new(84242), | ||||||
|  |                 thumbnail_info: Some(Box::new(ThumbnailInfo { | ||||||
|  |                     width: UInt::new(800), | ||||||
|  |                     height: UInt::new(334), | ||||||
|  |                     mimetype: Some("image/png".into()), | ||||||
|  |                     size: UInt::new(82595), | ||||||
|  |                 })), | ||||||
|  |                 thumbnail_url: Some("mxc://matrix.org".into()), | ||||||
|  |                 thumbnail_file: None, | ||||||
|  |             }, | ||||||
|  |             url: "http://www.matrix.org".into(), | ||||||
|  |         }, | ||||||
|  |         event_id: EventId::try_from("$h29iv0s8:example.com").unwrap(), | ||||||
|  |         origin_server_ts: UNIX_EPOCH + Duration::from_millis(1), | ||||||
|  |         room_id: RoomId::try_from("!roomid:room.com").unwrap(), | ||||||
|  |         sender: UserId::try_from("@carl:example.com").unwrap(), | ||||||
|  |         unsigned: UnsignedData::default(), | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     let actual = to_json_value(&aliases_event).unwrap(); | ||||||
|  |     let expected = json!({ | ||||||
|  |         "content": { | ||||||
|  |             "body": "Hello", | ||||||
|  |             "info": { | ||||||
|  |                 "h": 423, | ||||||
|  |                 "mimetype": "image/png", | ||||||
|  |                 "size": 84242, | ||||||
|  |                 "thumbnail_info": { | ||||||
|  |                 "h": 334, | ||||||
|  |                 "mimetype": "image/png", | ||||||
|  |                 "size": 82595, | ||||||
|  |                 "w": 800 | ||||||
|  |                 }, | ||||||
|  |                 "thumbnail_url": "mxc://matrix.org", | ||||||
|  |                 "w": 1011 | ||||||
|  |             }, | ||||||
|  |             "url": "http://www.matrix.org" | ||||||
|  |         }, | ||||||
|  |         "event_id": "$h29iv0s8:example.com", | ||||||
|  |         "origin_server_ts": 1, | ||||||
|  |         "room_id": "!roomid:room.com", | ||||||
|  |         "sender": "@carl:example.com", | ||||||
|  |         "type": "m.sticker", | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     assert_eq!(actual, expected); | ||||||
|  | } | ||||||
| @ -7,7 +7,8 @@ use js_int::UInt; | |||||||
| use matches::assert_matches; | use matches::assert_matches; | ||||||
| use ruma_events::{ | use ruma_events::{ | ||||||
|     room::{aliases::AliasesEventContent, avatar::AvatarEventContent, ImageInfo, ThumbnailInfo}, |     room::{aliases::AliasesEventContent, avatar::AvatarEventContent, ImageInfo, ThumbnailInfo}, | ||||||
|     AnyStateEventContent, EventJson, StateEvent, StateEventStub, UnsignedData, |     AnyRoomEvent, AnyStateEvent, AnyStateEventContent, EventJson, StateEvent, StateEventStub, | ||||||
|  |     UnsignedData, | ||||||
| }; | }; | ||||||
| use ruma_identifiers::{EventId, RoomAliasId, RoomId, UserId}; | use ruma_identifiers::{EventId, RoomAliasId, RoomId, UserId}; | ||||||
| use serde_json::{ | use serde_json::{ | ||||||
| @ -236,3 +237,48 @@ fn deserialize_avatar_without_prev_content() { | |||||||
|             && unsigned.is_empty() |             && unsigned.is_empty() | ||||||
|     ); |     ); | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | #[test] | ||||||
|  | fn deserialize_member_event_with_top_level_membership_field() { | ||||||
|  |     let json_data = json!({ | ||||||
|  |         "content": { | ||||||
|  |             "avatar_url": null, | ||||||
|  |             "displayname": "example", | ||||||
|  |             "membership": "join" | ||||||
|  |         }, | ||||||
|  |         "event_id": "$h29iv0s8:example.com", | ||||||
|  |         "membership": "join", | ||||||
|  |         "room_id": "!room:localhost", | ||||||
|  |         "origin_server_ts": 1, | ||||||
|  |         "sender": "@example:localhost", | ||||||
|  |         "state_key": "@example:localhost", | ||||||
|  |         "type": "m.room.member", | ||||||
|  |         "unsigned": { | ||||||
|  |             "age": 1, | ||||||
|  |             "replaces_state": "$151800111315tsynI:localhost", | ||||||
|  |             "prev_content": { | ||||||
|  |                 "avatar_url": null, | ||||||
|  |                 "displayname": "example", | ||||||
|  |                 "membership": "invite" | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     assert_matches!( | ||||||
|  |         from_json_value::<AnyRoomEvent>(json_data) | ||||||
|  |             .unwrap(), | ||||||
|  |         AnyRoomEvent::State( | ||||||
|  |             AnyStateEvent::RoomMember(StateEvent { | ||||||
|  |                 content, | ||||||
|  |                 event_id, | ||||||
|  |                 origin_server_ts, | ||||||
|  |                 prev_content: None, | ||||||
|  |                 sender, | ||||||
|  |                 .. | ||||||
|  |             } | ||||||
|  |         )) if event_id == EventId::try_from("$h29iv0s8:example.com").unwrap() | ||||||
|  |             && origin_server_ts == UNIX_EPOCH + Duration::from_millis(1) | ||||||
|  |             && sender == UserId::try_from("@example:localhost").unwrap() | ||||||
|  |             && content.displayname == Some("example".to_string()) | ||||||
|  |     ); | ||||||
|  | } | ||||||
|  | |||||||
| @ -1,8 +1,8 @@ | |||||||
| use ruma_events_macros::event_content_enum; | use ruma_events_macros::event_enum; | ||||||
| 
 | 
 | ||||||
| event_content_enum! { | event_enum! { | ||||||
|     /// Any basic event.
 |     /// Any basic event.
 | ||||||
|     name: AnyBasicEventContent, |     name: AnyBasicEvent, | ||||||
|     events: [ |     events: [ | ||||||
|         "m.direct", |         "m.direct", | ||||||
|         "m.dummy", |         "m.dummy", | ||||||
|  | |||||||
| @ -1,13 +1,13 @@ | |||||||
| use ruma_events_macros::event_content_enum; | use ruma_events_macros::event_enum; | ||||||
| 
 | 
 | ||||||
| event_content_enum! { | event_enum! { | ||||||
|     name: InvalidEvent, |     name: InvalidEvent, | ||||||
|     events: [ |     events: [ | ||||||
|         "m.not.a.path", |         "m.not.a.path", | ||||||
|     ] |     ] | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| event_content_enum! { | event_enum! { | ||||||
|     name: InvalidEvent, |     name: InvalidEvent, | ||||||
|     events: [ |     events: [ | ||||||
|         "not.a.path", |         "not.a.path", | ||||||
|  | |||||||
| @ -1,15 +1,8 @@ | |||||||
| error: proc macro panicked | error: well-known matrix events have to start with `m.` found `not.a.path` | ||||||
|   --> $DIR/08-enum-invalid-path.rs:10:1 |   --> $DIR/08-enum-invalid-path.rs:13:9 | ||||||
|    | |    | | ||||||
| 10 | / event_content_enum! { | 13 |         "not.a.path", | ||||||
| 11 | |     name: InvalidEvent, |    |         ^^^^^^^^^^^^ | ||||||
| 12 | |     events: [ |  | ||||||
| 13 | |         "not.a.path", |  | ||||||
| 14 | |     ] |  | ||||||
| 15 | | } |  | ||||||
|    | |_^ |  | ||||||
|    | |  | ||||||
|    = help: message: well-known matrix events have to start with `m.` found `not.a.path` |  | ||||||
| 
 | 
 | ||||||
| error[E0433]: failed to resolve: could not find `not` in `ruma_events` | error[E0433]: failed to resolve: could not find `not` in `ruma_events` | ||||||
|  --> $DIR/08-enum-invalid-path.rs:6:9 |  --> $DIR/08-enum-invalid-path.rs:6:9 | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user