Add inherent impl with from_str method.

This commit is contained in:
Jimmy Cuadra 2019-06-19 21:14:49 -07:00
parent 78e25552fb
commit be0f1d0363
2 changed files with 91 additions and 2 deletions

View File

@ -71,6 +71,9 @@ impl From<RumaEventInput> for RumaEvent {
}
impl ToTokens for RumaEvent {
// TODO: Maybe break this off into functions so it's not so large. Then remove the clippy
// allowance.
#[allow(clippy::cognitive_complexity)]
fn to_tokens(&self, tokens: &mut TokenStream) {
let attrs = &self.attrs;
let content_name = &self.content_name;
@ -116,17 +119,84 @@ impl ToTokens for RumaEvent {
let field_count = event_fields.len() + 1; // + 1 because of manually adding `event_type`
let mut from_str_field_values: Vec<TokenStream> = Vec::with_capacity(event_fields.len());
let mut serialize_field_calls: Vec<TokenStream> = Vec::with_capacity(event_fields.len());
for field in event_fields {
let ident = field.ident.clone().unwrap();
let ident_str = format!("{}", ident);
let token_stream = quote! {
let from_str_field_value = if ident == "content" {
match &self.content {
Content::Struct(content_fields) => {
let mut content_field_values: Vec<TokenStream> =
Vec::with_capacity(content_fields.len());
for content_field in content_fields {
let content_field_ident = content_field.ident.clone().unwrap();
let token_stream = quote! {
#content_field_ident: raw.content.#content_field_ident,
};
content_field_values.push(token_stream);
}
quote! {
content: #content_name {
#(#content_field_values),*
},
}
}
Content::Typedef(_) => {
quote! {
content: raw.content,
}
}
}
} else if ident == "prev_content" {
match &self.content {
Content::Struct(content_fields) => {
let mut content_field_values: Vec<TokenStream> =
Vec::with_capacity(content_fields.len());
for content_field in content_fields {
let content_field_ident = content_field.ident.clone().unwrap();
let token_stream = quote! {
#content_field_ident: prev.#content_field_ident,
};
content_field_values.push(token_stream);
}
quote! {
prev_content: raw.prev_content.map(|prev| {
#content_name {
#(#content_field_values),*
}
}),
}
}
Content::Typedef(_) => {
quote! {
content: raw.content,
}
}
}
} else {
quote! {
#ident: raw.#ident,
}
};
from_str_field_values.push(from_str_field_value);
let serialize_field_call = quote! {
state.serialize_field(#ident_str, &self.#ident)?;
};
serialize_field_calls.push(token_stream);
serialize_field_calls.push(serialize_field_call);
}
let output = quote!(
@ -138,6 +208,17 @@ impl ToTokens for RumaEvent {
#content
impl #name {
/// Attempt to create `Self` from parsing a string of JSON data.
pub fn from_str(json: &str) -> Result<Self, crate::InvalidEvent> {
let raw = serde_json::from_str::<raw::#name>(json)?;
Ok(Self {
#(#from_str_field_values)*
})
}
}
use serde::ser::SerializeStruct as _;
impl serde::Serialize for #name {

View File

@ -35,6 +35,14 @@ where
}
}
pub struct InvalidEvent;
impl From<serde_json::Error> for InvalidEvent {
fn from(_: serde_json::Error) -> Self {
Self
}
}
// See note about wrapping macro expansion in a module from `src/lib.rs`
pub mod common_case {
use super::Event;