diff --git a/src/gen.rs b/src/gen.rs index a41cc585..0b205d0f 100644 --- a/src/gen.rs +++ b/src/gen.rs @@ -145,7 +145,7 @@ impl ToTokens for RumaEvent { let event_type_field_count = if self.is_custom { 0 } else { 1 }; let field_count = event_fields.len() + event_type_field_count; - let mut from_str_field_values: Vec = Vec::with_capacity(event_fields.len()); + let mut try_from_field_values: Vec = Vec::with_capacity(event_fields.len()); let mut serialize_field_calls: Vec = Vec::with_capacity(event_fields.len()); for field in event_fields { @@ -159,7 +159,7 @@ impl ToTokens for RumaEvent { let span = field.span(); - let from_str_field_value = if ident == "content" { + let try_from_field_value = if ident == "content" { match &self.content { Content::Struct(content_fields) => { let mut content_field_values: Vec = @@ -225,7 +225,7 @@ impl ToTokens for RumaEvent { } }; - from_str_field_values.push(from_str_field_value); + try_from_field_values.push(try_from_field_value); let serialize_field_call = quote_spanned! {span=> state.serialize_field(#ident_str, &self.#ident)?; @@ -316,17 +316,28 @@ impl ToTokens for RumaEvent { #content - impl #name { + impl std::str::FromStr for #name { + type Err = crate::InvalidEvent; + /// Attempt to create `Self` from parsing a string of JSON data. - pub fn from_str(json: &str) -> Result { + fn from_str(json: &str) -> Result { let raw = serde_json::from_str::(json)?; Ok(Self { - #(#from_str_field_values)* + #(#try_from_field_values)* }) } } + impl<'a> std::convert::TryFrom<&'a str> for #name { + type Error = crate::InvalidEvent; + + /// Attempt to create `Self` from parsing a string of JSON data. + fn try_from(json: &'a str) -> Result { + std::str::FromStr::from_str(json) + } + } + use serde::ser::SerializeStruct as _; impl serde::Serialize for #name { diff --git a/src/lib.rs b/src/lib.rs index c0faab46..32617891 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -121,11 +121,14 @@ mod parse; /// the first. /// /// The event type and content type will have copies generated inside a private `raw` module. These -/// "raw" versions are the same, except they implement `serde::Deserialize`. An inherent method -/// called `from_str` will be generated for the event type that takes a `&str` of JSON and attempts -/// to deserialize the type using the "raw" version. If deserialization fails, an error is returned -/// to the user. If deserialization succeeds, a value of the public event type will be populated -/// from the raw version's fields and returned. +/// "raw" versions are the same, except they implement `serde::Deserialize`. An implementation of +/// `TryFrom<&str>` will be provided, which (through a blanket implementation in the standard +/// library for `FromStr` will allow the user to call `parse` on a string slice of JSON data in +/// attempt to convert into the event type. `TryFrom<&str>` attempts to deserialize the type using +/// the "raw" version. If deserialization fails, an error is returned to the user. If +/// deserialization succeeds, a value of the public event type will be populated from the raw +/// version's fields and returned. If any semantic error is found after deserialization, a +/// `serde_json::Value` of the deserialized data will be returned in an `InvalidEvent`. #[proc_macro] pub fn ruma_event(input: TokenStream) -> TokenStream { let ruma_event_input = syn::parse_macro_input!(input as RumaEventInput);