Skip serializing options.
This commit is contained in:
parent
d9039db8df
commit
e34ea05445
58
src/gen.rs
58
src/gen.rs
@ -7,7 +7,7 @@ use syn::{
|
|||||||
parse_quote,
|
parse_quote,
|
||||||
punctuated::Punctuated,
|
punctuated::Punctuated,
|
||||||
spanned::Spanned,
|
spanned::Spanned,
|
||||||
Attribute, Field, Ident, Path, Token,
|
Attribute, Field, Ident, Path, Token, Type,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::parse::{Content, EventKind, RumaEventInput};
|
use crate::parse::{Content, EventKind, RumaEventInput};
|
||||||
@ -142,8 +142,11 @@ impl ToTokens for RumaEvent {
|
|||||||
|
|
||||||
// Custom events will already have an event_type field. All other events need to account
|
// Custom events will already have an event_type field. All other events need to account
|
||||||
// for this field being manually inserted in `Serialize` impls.
|
// for this field being manually inserted in `Serialize` impls.
|
||||||
let event_type_field_count = if self.is_custom { 0 } else { 1 };
|
let mut base_field_count: usize = if self.is_custom { 0 } else { 1 };
|
||||||
let field_count = event_fields.len() + event_type_field_count;
|
|
||||||
|
// Keep track of all the optional fields, because we'll need to check at runtime if they
|
||||||
|
// are `Some` in order to increase the number of fields we tell serde to serialize.
|
||||||
|
let mut optional_field_idents = Vec::with_capacity(event_fields.len());
|
||||||
|
|
||||||
let mut try_from_field_values: Vec<TokenStream> = Vec::with_capacity(event_fields.len());
|
let mut try_from_field_values: Vec<TokenStream> = Vec::with_capacity(event_fields.len());
|
||||||
let mut serialize_field_calls: Vec<TokenStream> = Vec::with_capacity(event_fields.len());
|
let mut serialize_field_calls: Vec<TokenStream> = Vec::with_capacity(event_fields.len());
|
||||||
@ -227,8 +230,21 @@ impl ToTokens for RumaEvent {
|
|||||||
|
|
||||||
try_from_field_values.push(try_from_field_value);
|
try_from_field_values.push(try_from_field_value);
|
||||||
|
|
||||||
let serialize_field_call = quote_spanned! {span=>
|
// Does the same thing as #[serde(skip_serializing_if = "Option::is_none")]
|
||||||
state.serialize_field(#ident_str, &self.#ident)?;
|
let serialize_field_call = if is_option(&field.ty) {
|
||||||
|
optional_field_idents.push(ident.clone());
|
||||||
|
|
||||||
|
quote_spanned! {span=>
|
||||||
|
if self.#ident.is_some() {
|
||||||
|
state.serialize_field(#ident_str, &self.#ident)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
base_field_count += 1;
|
||||||
|
|
||||||
|
quote_spanned! {span=>
|
||||||
|
state.serialize_field(#ident_str, &self.#ident)?;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
serialize_field_calls.push(serialize_field_call);
|
serialize_field_calls.push(serialize_field_call);
|
||||||
@ -251,6 +267,27 @@ impl ToTokens for RumaEvent {
|
|||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let increment_struct_len_statements: Vec<TokenStream> = optional_field_idents
|
||||||
|
.iter()
|
||||||
|
.map(|ident| {
|
||||||
|
let span = ident.span();
|
||||||
|
|
||||||
|
quote_spanned! {span=>
|
||||||
|
if self.#ident.is_some() {
|
||||||
|
len += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let set_up_struct_serializer = quote! {
|
||||||
|
let mut len = #base_field_count;
|
||||||
|
|
||||||
|
#(#increment_struct_len_statements)*
|
||||||
|
|
||||||
|
let mut state = serializer.serialize_struct(#name_str, len)?;
|
||||||
|
};
|
||||||
|
|
||||||
let impl_room_event = match self.kind {
|
let impl_room_event = match self.kind {
|
||||||
EventKind::RoomEvent | EventKind::StateEvent => {
|
EventKind::RoomEvent | EventKind::StateEvent => {
|
||||||
quote! {
|
quote! {
|
||||||
@ -347,7 +384,7 @@ impl ToTokens for RumaEvent {
|
|||||||
{
|
{
|
||||||
#import_event_in_serialize_impl
|
#import_event_in_serialize_impl
|
||||||
|
|
||||||
let mut state = serializer.serialize_struct(#name_str, #field_count)?;
|
#set_up_struct_serializer
|
||||||
|
|
||||||
#(#serialize_field_calls)*
|
#(#serialize_field_calls)*
|
||||||
#manually_serialize_type_field
|
#manually_serialize_type_field
|
||||||
@ -490,6 +527,15 @@ fn is_custom_event_type(event_type: &Path) -> bool {
|
|||||||
event_type.segments.last().unwrap().value().ident == "Custom"
|
event_type.segments.last().unwrap().value().ident == "Custom"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Checks if a type is an `Option`.
|
||||||
|
fn is_option(ty: &Type) -> bool {
|
||||||
|
if let Type::Path(ref type_path) = ty {
|
||||||
|
type_path.path.segments.first().unwrap().value().ident == "Option"
|
||||||
|
} else {
|
||||||
|
panic!("struct field had unexpected non-path type");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// A wrapper around `syn::Field` that makes it possible to parse `Punctuated<Field, Token![,]>`
|
/// A wrapper around `syn::Field` that makes it possible to parse `Punctuated<Field, Token![,]>`
|
||||||
/// from a `TokenStream`.
|
/// from a `TokenStream`.
|
||||||
///
|
///
|
||||||
|
Loading…
x
Reference in New Issue
Block a user