refactor(ast): generated Serialize impls flatten struct fields (#8904)

In generated `impl Serialize` for AST types, flatten the fields of `Span` directly in the `serialize` method.

Before:

```rs
self.span.serialize(serde::__private::ser::FlatMapSerializer(&mut map))?;
```

After:

```rs
map.serialize_entry("start", &self.span.start)?;
map.serialize_entry("end", &self.span.end)?;
```

Serde's derive macro can't do this, because it only knows about the type it's deriving the impl for, so it has no idea what the fields of `Span` are. But `oxc_ast_tools` knows the entire AST, so it can use that information.

I doubt this will have a runtime perf impact, but it may help compile times.

Also, shorten generated code for `Serialize` impls on enums.
This commit is contained in:
overlookmotel committed 2025-02-05 07:09:20 +00:00
1 parent 0c55dd684e
commit cbb4e9c598
6 files changed
+1125 -1032

No files matched your search

File diff suppressed because it is too large. Load diff
@@ -3,7 +3,9 @@
#![allow(unused_imports, clippy::match_same_arms)]
use serde::{ser::SerializeMap, Serialize, Serializer};
use serde::{__private::ser::FlatMapSerializer, ser::SerializeMap, Serialize, Serializer};
use oxc_estree::ser::AppendTo;
use crate::ast::*;
@@ -11,7 +13,8 @@ impl Serialize for Pattern<'_> {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
let mut map = serializer.serialize_map(None)?;
map.serialize_entry("type", "Pattern")?;
self.span.serialize(serde::__private::ser::FlatMapSerializer(&mut map))?;
map.serialize_entry("start", &self.span.start)?;
map.serialize_entry("end", &self.span.end)?;
map.serialize_entry("body", &self.body)?;
map.end()
}
@@ -21,7 +24,8 @@ impl Serialize for Disjunction<'_> {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
let mut map = serializer.serialize_map(None)?;
map.serialize_entry("type", "Disjunction")?;
self.span.serialize(serde::__private::ser::FlatMapSerializer(&mut map))?;
map.serialize_entry("start", &self.span.start)?;
map.serialize_entry("end", &self.span.end)?;
map.serialize_entry("body", &self.body)?;
map.end()
}
@@ -31,7 +35,8 @@ impl Serialize for Alternative<'_> {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
let mut map = serializer.serialize_map(None)?;
map.serialize_entry("type", "Alternative")?;
self.span.serialize(serde::__private::ser::FlatMapSerializer(&mut map))?;
map.serialize_entry("start", &self.span.start)?;
map.serialize_entry("end", &self.span.end)?;
map.serialize_entry("body", &self.body)?;
map.end()
}
@@ -40,18 +45,18 @@ impl Serialize for Alternative<'_> {
impl Serialize for Term<'_> {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
match self {
Term::BoundaryAssertion(it) => Serialize::serialize(it, serializer),
Term::LookAroundAssertion(it) => Serialize::serialize(it, serializer),
Term::Quantifier(it) => Serialize::serialize(it, serializer),
Term::Character(it) => Serialize::serialize(it, serializer),
Term::Dot(it) => Serialize::serialize(it, serializer),
Term::CharacterClassEscape(it) => Serialize::serialize(it, serializer),
Term::UnicodePropertyEscape(it) => Serialize::serialize(it, serializer),
Term::CharacterClass(it) => Serialize::serialize(it, serializer),
Term::CapturingGroup(it) => Serialize::serialize(it, serializer),
Term::IgnoreGroup(it) => Serialize::serialize(it, serializer),
Term::IndexedReference(it) => Serialize::serialize(it, serializer),
Term::NamedReference(it) => Serialize::serialize(it, serializer),
Term::BoundaryAssertion(it) => it.serialize(serializer),
Term::LookAroundAssertion(it) => it.serialize(serializer),
Term::Quantifier(it) => it.serialize(serializer),
Term::Character(it) => it.serialize(serializer),
Term::Dot(it) => it.serialize(serializer),
Term::CharacterClassEscape(it) => it.serialize(serializer),
Term::UnicodePropertyEscape(it) => it.serialize(serializer),
Term::CharacterClass(it) => it.serialize(serializer),
Term::CapturingGroup(it) => it.serialize(serializer),
Term::IgnoreGroup(it) => it.serialize(serializer),
Term::IndexedReference(it) => it.serialize(serializer),
Term::NamedReference(it) => it.serialize(serializer),
}
}
}
@@ -60,7 +65,8 @@ impl Serialize for BoundaryAssertion {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
let mut map = serializer.serialize_map(None)?;
map.serialize_entry("type", "BoundaryAssertion")?;
self.span.serialize(serde::__private::ser::FlatMapSerializer(&mut map))?;
map.serialize_entry("start", &self.span.start)?;
map.serialize_entry("end", &self.span.end)?;
map.serialize_entry("kind", &self.kind)?;
map.end()
}
@@ -68,7 +74,7 @@ impl Serialize for BoundaryAssertion {
impl Serialize for BoundaryAssertionKind {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
match *self {
match self {
BoundaryAssertionKind::Start => {
serializer.serialize_unit_variant("BoundaryAssertionKind", 0, "start")
}
@@ -89,7 +95,8 @@ impl Serialize for LookAroundAssertion<'_> {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
let mut map = serializer.serialize_map(None)?;
map.serialize_entry("type", "LookAroundAssertion")?;
self.span.serialize(serde::__private::ser::FlatMapSerializer(&mut map))?;
map.serialize_entry("start", &self.span.start)?;
map.serialize_entry("end", &self.span.end)?;
map.serialize_entry("kind", &self.kind)?;
map.serialize_entry("body", &self.body)?;
map.end()
@@ -98,7 +105,7 @@ impl Serialize for LookAroundAssertion<'_> {
impl Serialize for LookAroundAssertionKind {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
match *self {
match self {
LookAroundAssertionKind::Lookahead => {
serializer.serialize_unit_variant("LookAroundAssertionKind", 0, "lookahead")
}
@@ -121,7 +128,8 @@ impl Serialize for Quantifier<'_> {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
let mut map = serializer.serialize_map(None)?;
map.serialize_entry("type", "Quantifier")?;
self.span.serialize(serde::__private::ser::FlatMapSerializer(&mut map))?;
map.serialize_entry("start", &self.span.start)?;
map.serialize_entry("end", &self.span.end)?;
map.serialize_entry("min", &self.min)?;
map.serialize_entry("max", &self.max)?;
map.serialize_entry("greedy", &self.greedy)?;
@@ -134,7 +142,8 @@ impl Serialize for Character {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
let mut map = serializer.serialize_map(None)?;
map.serialize_entry("type", "Character")?;
self.span.serialize(serde::__private::ser::FlatMapSerializer(&mut map))?;
map.serialize_entry("start", &self.span.start)?;
map.serialize_entry("end", &self.span.end)?;
map.serialize_entry("kind", &self.kind)?;
map.serialize_entry("value", &self.value)?;
map.end()
@@ -143,7 +152,7 @@ impl Serialize for Character {
impl Serialize for CharacterKind {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
match *self {
match self {
CharacterKind::ControlLetter => {
serializer.serialize_unit_variant("CharacterKind", 0, "controlLetter")
}
@@ -180,7 +189,8 @@ impl Serialize for CharacterClassEscape {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
let mut map = serializer.serialize_map(None)?;
map.serialize_entry("type", "CharacterClassEscape")?;
self.span.serialize(serde::__private::ser::FlatMapSerializer(&mut map))?;
map.serialize_entry("start", &self.span.start)?;
map.serialize_entry("end", &self.span.end)?;
map.serialize_entry("kind", &self.kind)?;
map.end()
}
@@ -188,7 +198,7 @@ impl Serialize for CharacterClassEscape {
impl Serialize for CharacterClassEscapeKind {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
match *self {
match self {
CharacterClassEscapeKind::D => {
serializer.serialize_unit_variant("CharacterClassEscapeKind", 0, "d")
}
@@ -215,7 +225,8 @@ impl Serialize for UnicodePropertyEscape<'_> {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
let mut map = serializer.serialize_map(None)?;
map.serialize_entry("type", "UnicodePropertyEscape")?;
self.span.serialize(serde::__private::ser::FlatMapSerializer(&mut map))?;
map.serialize_entry("start", &self.span.start)?;
map.serialize_entry("end", &self.span.end)?;
map.serialize_entry("negative", &self.negative)?;
map.serialize_entry("strings", &self.strings)?;
map.serialize_entry("name", &self.name)?;
@@ -228,7 +239,8 @@ impl Serialize for Dot {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
let mut map = serializer.serialize_map(None)?;
map.serialize_entry("type", "Dot")?;
self.span.serialize(serde::__private::ser::FlatMapSerializer(&mut map))?;
map.serialize_entry("start", &self.span.start)?;
map.serialize_entry("end", &self.span.end)?;
map.end()
}
}
@@ -237,7 +249,8 @@ impl Serialize for CharacterClass<'_> {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
let mut map = serializer.serialize_map(None)?;
map.serialize_entry("type", "CharacterClass")?;
self.span.serialize(serde::__private::ser::FlatMapSerializer(&mut map))?;
map.serialize_entry("start", &self.span.start)?;
map.serialize_entry("end", &self.span.end)?;
map.serialize_entry("negative", &self.negative)?;
map.serialize_entry("strings", &self.strings)?;
map.serialize_entry("kind", &self.kind)?;
@@ -248,7 +261,7 @@ impl Serialize for CharacterClass<'_> {
impl Serialize for CharacterClassContentsKind {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
match *self {
match self {
CharacterClassContentsKind::Union => {
serializer.serialize_unit_variant("CharacterClassContentsKind", 0, "union")
}
@@ -265,20 +278,12 @@ impl Serialize for CharacterClassContentsKind {
impl Serialize for CharacterClassContents<'_> {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
match self {
CharacterClassContents::CharacterClassRange(it) => Serialize::serialize(it, serializer),
CharacterClassContents::CharacterClassEscape(it) => {
Serialize::serialize(it, serializer)
}
CharacterClassContents::UnicodePropertyEscape(it) => {
Serialize::serialize(it, serializer)
}
CharacterClassContents::Character(it) => Serialize::serialize(it, serializer),
CharacterClassContents::NestedCharacterClass(it) => {
Serialize::serialize(it, serializer)
}
CharacterClassContents::ClassStringDisjunction(it) => {
Serialize::serialize(it, serializer)
}
CharacterClassContents::CharacterClassRange(it) => it.serialize(serializer),
CharacterClassContents::CharacterClassEscape(it) => it.serialize(serializer),
CharacterClassContents::UnicodePropertyEscape(it) => it.serialize(serializer),
CharacterClassContents::Character(it) => it.serialize(serializer),
CharacterClassContents::NestedCharacterClass(it) => it.serialize(serializer),
CharacterClassContents::ClassStringDisjunction(it) => it.serialize(serializer),
}
}
}
@@ -287,7 +292,8 @@ impl Serialize for CharacterClassRange {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
let mut map = serializer.serialize_map(None)?;
map.serialize_entry("type", "CharacterClassRange")?;
self.span.serialize(serde::__private::ser::FlatMapSerializer(&mut map))?;
map.serialize_entry("start", &self.span.start)?;
map.serialize_entry("end", &self.span.end)?;
map.serialize_entry("min", &self.min)?;
map.serialize_entry("max", &self.max)?;
map.end()
@@ -298,7 +304,8 @@ impl Serialize for ClassStringDisjunction<'_> {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
let mut map = serializer.serialize_map(None)?;
map.serialize_entry("type", "ClassStringDisjunction")?;
self.span.serialize(serde::__private::ser::FlatMapSerializer(&mut map))?;
map.serialize_entry("start", &self.span.start)?;
map.serialize_entry("end", &self.span.end)?;
map.serialize_entry("strings", &self.strings)?;
map.serialize_entry("body", &self.body)?;
map.end()
@@ -309,7 +316,8 @@ impl Serialize for ClassString<'_> {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
let mut map = serializer.serialize_map(None)?;
map.serialize_entry("type", "ClassString")?;
self.span.serialize(serde::__private::ser::FlatMapSerializer(&mut map))?;
map.serialize_entry("start", &self.span.start)?;
map.serialize_entry("end", &self.span.end)?;
map.serialize_entry("strings", &self.strings)?;
map.serialize_entry("body", &self.body)?;
map.end()
@@ -320,7 +328,8 @@ impl Serialize for CapturingGroup<'_> {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
let mut map = serializer.serialize_map(None)?;
map.serialize_entry("type", "CapturingGroup")?;
self.span.serialize(serde::__private::ser::FlatMapSerializer(&mut map))?;
map.serialize_entry("start", &self.span.start)?;
map.serialize_entry("end", &self.span.end)?;
map.serialize_entry("name", &self.name)?;
map.serialize_entry("body", &self.body)?;
map.end()
@@ -331,7 +340,8 @@ impl Serialize for IgnoreGroup<'_> {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
let mut map = serializer.serialize_map(None)?;
map.serialize_entry("type", "IgnoreGroup")?;
self.span.serialize(serde::__private::ser::FlatMapSerializer(&mut map))?;
map.serialize_entry("start", &self.span.start)?;
map.serialize_entry("end", &self.span.end)?;
map.serialize_entry("modifiers", &self.modifiers)?;
map.serialize_entry("body", &self.body)?;
map.end()
@@ -342,7 +352,8 @@ impl Serialize for Modifiers {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
let mut map = serializer.serialize_map(None)?;
map.serialize_entry("type", "Modifiers")?;
self.span.serialize(serde::__private::ser::FlatMapSerializer(&mut map))?;
map.serialize_entry("start", &self.span.start)?;
map.serialize_entry("end", &self.span.end)?;
map.serialize_entry("enabling", &self.enabling)?;
map.serialize_entry("disabling", &self.disabling)?;
map.end()
@@ -364,7 +375,8 @@ impl Serialize for IndexedReference {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
let mut map = serializer.serialize_map(None)?;
map.serialize_entry("type", "IndexedReference")?;
self.span.serialize(serde::__private::ser::FlatMapSerializer(&mut map))?;
map.serialize_entry("start", &self.span.start)?;
map.serialize_entry("end", &self.span.end)?;
map.serialize_entry("index", &self.index)?;
map.end()
}
@@ -374,7 +386,8 @@ impl Serialize for NamedReference<'_> {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
let mut map = serializer.serialize_map(None)?;
map.serialize_entry("type", "NamedReference")?;
self.span.serialize(serde::__private::ser::FlatMapSerializer(&mut map))?;
map.serialize_entry("start", &self.span.start)?;
map.serialize_entry("end", &self.span.end)?;
map.serialize_entry("name", &self.name)?;
map.end()
}
@@ -3,7 +3,9 @@
#![allow(unused_imports, clippy::match_same_arms)]
use serde::{ser::SerializeMap, Serialize, Serializer};
use serde::{__private::ser::FlatMapSerializer, ser::SerializeMap, Serialize, Serializer};
use oxc_estree::ser::AppendTo;
use crate::source_type::*;
use crate::span::*;
@@ -29,7 +31,7 @@ impl Serialize for SourceType {
impl Serialize for Language {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
match *self {
match self {
Language::JavaScript => serializer.serialize_unit_variant("Language", 0, "javascript"),
Language::TypeScript => serializer.serialize_unit_variant("Language", 1, "typescript"),
Language::TypeScriptDefinition => {
@@ -41,7 +43,7 @@ impl Serialize for Language {
impl Serialize for ModuleKind {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
match *self {
match self {
ModuleKind::Script => serializer.serialize_unit_variant("ModuleKind", 0, "script"),
ModuleKind::Module => serializer.serialize_unit_variant("ModuleKind", 1, "module"),
ModuleKind::Unambiguous => {
@@ -53,7 +55,7 @@ impl Serialize for ModuleKind {
impl Serialize for LanguageVariant {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
match *self {
match self {
LanguageVariant::Standard => {
serializer.serialize_unit_variant("LanguageVariant", 0, "standard")
}
@@ -3,13 +3,15 @@
#![allow(unused_imports, clippy::match_same_arms)]
use serde::{ser::SerializeMap, Serialize, Serializer};
use serde::{__private::ser::FlatMapSerializer, ser::SerializeMap, Serialize, Serializer};
use oxc_estree::ser::AppendTo;
use crate::operator::*;
impl Serialize for AssignmentOperator {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
match *self {
match self {
AssignmentOperator::Assign => {
serializer.serialize_unit_variant("AssignmentOperator", 0, "=")
}
@@ -64,7 +66,7 @@ impl Serialize for AssignmentOperator {
impl Serialize for BinaryOperator {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
match *self {
match self {
BinaryOperator::Equality => {
serializer.serialize_unit_variant("BinaryOperator", 0, "==")
}
@@ -131,7 +133,7 @@ impl Serialize for BinaryOperator {
impl Serialize for LogicalOperator {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
match *self {
match self {
LogicalOperator::Or => serializer.serialize_unit_variant("LogicalOperator", 0, "||"),
LogicalOperator::And => serializer.serialize_unit_variant("LogicalOperator", 1, "&&"),
LogicalOperator::Coalesce => {
@@ -143,7 +145,7 @@ impl Serialize for LogicalOperator {
impl Serialize for UnaryOperator {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
match *self {
match self {
UnaryOperator::UnaryPlus => serializer.serialize_unit_variant("UnaryOperator", 0, "+"),
UnaryOperator::UnaryNegation => {
serializer.serialize_unit_variant("UnaryOperator", 1, "-")
@@ -163,7 +165,7 @@ impl Serialize for UnaryOperator {
impl Serialize for UpdateOperator {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
match *self {
match self {
UpdateOperator::Increment => {
serializer.serialize_unit_variant("UpdateOperator", 0, "++")
}
+105 -74
View File
@@ -54,7 +54,14 @@ impl Derive for DeriveESTree {
#![allow(unused_imports, clippy::match_same_arms)]
///@@line_break
use serde::{Serialize, Serializer, ser::SerializeMap};
use serde::{
__private::ser::FlatMapSerializer,
ser::SerializeMap,
Serialize, Serializer
};
///@@line_break
use oxc_estree::ser::AppendTo;
}
}
@@ -179,55 +186,107 @@ fn generate_body_for_struct(struct_def: &StructDef, schema: &Schema) -> TokenStr
};
}
let mut stmts = quote!();
let mut gen = StructSerializerGenerator::new(!struct_def.estree.no_type, schema);
gen.generate_stmts_for_struct(struct_def, &quote!(self));
if should_add_type_field_to_struct(struct_def) {
let type_field = if gen.add_type_field {
let type_name = struct_def.estree.rename.as_deref().unwrap_or_else(|| struct_def.name());
stmts.extend(quote!( map.serialize_entry("type", #type_name)?; ));
}
for field in &struct_def.fields {
if !should_skip_field(field, schema) {
stmts.extend(generate_stmt_for_struct_field(field, struct_def, schema));
quote! {
map.serialize_entry("type", #type_name)?;
}
}
} else {
quote!()
};
let stmts = gen.stmts;
quote! {
let mut map = serializer.serialize_map(None)?;
#type_field
#stmts
map.end()
}
}
/// Generate code to serialize a struct field.
fn generate_stmt_for_struct_field(
field: &FieldDef,
struct_def: &StructDef,
schema: &Schema,
) -> TokenStream {
let field_name_ident = field.ident();
/// Generator for stmts to serialize fields of a struct.
///
/// Recursively enters any flattened fields which contain a struct,
/// and generates statements for each of the flattened struct's fields too.
///
/// If a field called `type` is found, `add_type_field` is set to `false`.
struct StructSerializerGenerator<'s> {
/// `serialize` statements
stmts: TokenStream,
/// `true` if a `type` field should be added.
/// `false` one already exists (or if `#[estree(no_type)]` attr on struct).
add_type_field: bool,
/// Schema
schema: &'s Schema,
}
if should_flatten_field(field, schema) {
return quote! {
self.#field_name_ident.serialize(serde::__private::ser::FlatMapSerializer(&mut map))?;
};
impl<'s> StructSerializerGenerator<'s> {
/// Create new [`StructSerializerGenerator`].
fn new(add_type_field: bool, schema: &'s Schema) -> Self {
Self { stmts: quote!(), add_type_field, schema }
}
let field_camel_name = get_struct_field_name(field);
let mut value = quote!( &self.#field_name_ident );
if let Some(via_str) = field.estree.via.as_deref() {
let via_ty = parse_str::<Type>(via_str).unwrap();
value = quote!( &#via_ty::from(#value) );
} else if let Some(append_field_index) = field.estree.append_field_index {
let append_from_ident = struct_def.fields[append_field_index].ident();
value = quote! {
&oxc_estree::ser::AppendTo { array: #value, after: &self.#append_from_ident }
};
/// Generate code to serialize all fields in a struct.
fn generate_stmts_for_struct(&mut self, struct_def: &StructDef, self_path: &TokenStream) {
for field in &struct_def.fields {
self.generate_stmts_for_field(field, struct_def, self_path);
}
}
quote! {
map.serialize_entry(#field_camel_name, #value)?;
/// Generate code to serialize a struct field.
fn generate_stmts_for_field(
&mut self,
field: &FieldDef,
struct_def: &StructDef,
self_path: &TokenStream,
) {
if should_skip_field(field, self.schema) {
return;
}
let field_name_ident = field.ident();
if should_flatten_field(field, self.schema) {
match field.type_def(self.schema) {
TypeDef::Struct(inner_struct_def) => {
self.generate_stmts_for_struct(
inner_struct_def,
&quote!(#self_path.#field_name_ident),
);
}
TypeDef::Enum(_) => {
self.stmts.extend(quote! {
#self_path.#field_name_ident.serialize(FlatMapSerializer(&mut map))?;
});
}
_ => panic!("Cannot flatten a field which is not a struct or enum"),
}
return;
}
let field_camel_name = get_struct_field_name(field);
if field_camel_name == "type" {
self.add_type_field = false;
}
let mut value = quote!( #self_path.#field_name_ident );
if let Some(via_str) = field.estree.via.as_deref() {
let via_ty = parse_str::<Type>(via_str).unwrap();
value = quote!( #via_ty::from(&#value) );
} else if let Some(append_field_index) = field.estree.append_field_index {
let append_from_ident = struct_def.fields[append_field_index].ident();
value = quote! {
AppendTo { array: &#value, after: &#self_path.#append_from_ident }
};
}
self.stmts.extend(quote! {
map.serialize_entry(#field_camel_name, &#value)?;
});
}
}
@@ -235,57 +294,29 @@ fn generate_stmt_for_struct_field(
fn generate_body_for_enum(enum_def: &EnumDef, schema: &Schema) -> TokenStream {
let enum_ident = enum_def.ident();
if enum_def.is_fieldless() {
let enum_name = enum_def.name();
let match_branches = enum_def.all_variants(schema).map(|variant| {
let variant_ident = variant.ident();
let match_branches = enum_def.all_variants(schema).map(|variant| {
let variant_ident = variant.ident();
if variant.is_fieldless() {
let enum_name = enum_def.name();
let discriminant = number_lit(variant.discriminant);
let value = get_fieldless_variant_value(enum_def, variant);
quote! {
#enum_ident::#variant_ident => {
serializer.serialize_unit_variant(#enum_name, #discriminant, #value)
}
#enum_ident::#variant_ident => serializer.serialize_unit_variant(#enum_name, #discriminant, #value),
}
});
quote! {
match *self {
#(#match_branches)*
} else {
quote! {
#enum_ident::#variant_ident(it) => it.serialize(serializer),
}
}
} else {
let match_branches = enum_def.all_variants(schema).map(|variant| {
let variant_ident = variant.ident();
quote! {
#enum_ident::#variant_ident(it) => {
Serialize::serialize(it, serializer)
}
}
});
});
quote! {
match self {
#(#match_branches)*
}
quote! {
match self {
#(#match_branches)*
}
}
}
/// Get if should generate a `type` field.
///
/// Type field should be added unless struct has an `#[estree(no_type)]` attr
/// or struct has an existing field called `type`.
///
/// This function also used by Typescript generator.
pub fn should_add_type_field_to_struct(struct_def: &StructDef) -> bool {
if struct_def.estree.no_type {
false
} else {
!struct_def.fields.iter().any(|field| matches!(field.name(), "type"))
}
}
/// Get if a struct field should be skipped when serializing.
///
/// Returns `true` if either the field has an `#[estree(skip)]` attr on it,
+13 -2
View File
@@ -6,8 +6,7 @@ use itertools::Itertools;
use crate::{
derives::estree::{
get_fieldless_variant_value, get_struct_field_name, should_add_type_field_to_struct,
should_flatten_field, should_skip_field,
get_fieldless_variant_value, get_struct_field_name, should_flatten_field, should_skip_field,
},
output::Output,
schema::{Def, EnumDef, FieldDef, Schema, StructDef, TypeDef},
@@ -234,3 +233,15 @@ fn get_field_type_name<'s>(field: &'s FieldDef, schema: &'s Schema) -> Cow<'s, s
ts_type_name(field_type, schema)
}
}
/// Get if should generate a `type` field.
///
/// Type field should be added unless struct has an `#[estree(no_type)]` attr
/// or struct has an existing field called `type`.
fn should_add_type_field_to_struct(struct_def: &StructDef) -> bool {
if struct_def.estree.no_type {
false
} else {
!struct_def.fields.iter().any(|field| matches!(field.name(), "type"))
}
}