Fix serializing generic enums
This fixes generic enums with variants that don't use all lifetime and typarams. Closes #88.
This commit is contained in:
parent
b09c0fc653
commit
ed5b4d7319
@ -55,7 +55,10 @@ pub fn expand_derive_serialize(
|
|||||||
&builder,
|
&builder,
|
||||||
&item,
|
&item,
|
||||||
&impl_generics,
|
&impl_generics,
|
||||||
ty.clone(),
|
builder.ty()
|
||||||
|
.ref_()
|
||||||
|
.lifetime("'__a")
|
||||||
|
.build_ty(ty.clone()),
|
||||||
);
|
);
|
||||||
|
|
||||||
let where_clause = &impl_generics.where_clause;
|
let where_clause = &impl_generics.where_clause;
|
||||||
@ -98,6 +101,7 @@ fn serialize_body(
|
|||||||
builder,
|
builder,
|
||||||
item.ident,
|
item.ident,
|
||||||
impl_generics,
|
impl_generics,
|
||||||
|
ty,
|
||||||
enum_def,
|
enum_def,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -176,15 +180,11 @@ fn serialize_tuple_struct(
|
|||||||
ty: P<ast::Ty>,
|
ty: P<ast::Ty>,
|
||||||
fields: usize,
|
fields: usize,
|
||||||
) -> P<ast::Expr> {
|
) -> P<ast::Expr> {
|
||||||
let value_ty = builder.ty()
|
|
||||||
.ref_()
|
|
||||||
.lifetime("'__a")
|
|
||||||
.build_ty(ty);
|
|
||||||
|
|
||||||
let (visitor_struct, visitor_impl) = serialize_tuple_struct_visitor(
|
let (visitor_struct, visitor_impl) = serialize_tuple_struct_visitor(
|
||||||
cx,
|
cx,
|
||||||
builder,
|
builder,
|
||||||
value_ty,
|
ty.clone(),
|
||||||
|
ty,
|
||||||
fields,
|
fields,
|
||||||
impl_generics,
|
impl_generics,
|
||||||
);
|
);
|
||||||
@ -197,6 +197,7 @@ fn serialize_tuple_struct(
|
|||||||
serializer.visit_named_seq($type_name, Visitor {
|
serializer.visit_named_seq($type_name, Visitor {
|
||||||
value: self,
|
value: self,
|
||||||
state: 0,
|
state: 0,
|
||||||
|
_structure_ty: ::std::marker::PhantomData,
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -210,15 +211,11 @@ fn serialize_struct(
|
|||||||
struct_def: &StructDef,
|
struct_def: &StructDef,
|
||||||
fields: Vec<Ident>,
|
fields: Vec<Ident>,
|
||||||
) -> P<ast::Expr> {
|
) -> P<ast::Expr> {
|
||||||
let value_ty = builder.ty()
|
|
||||||
.ref_()
|
|
||||||
.lifetime("'__a")
|
|
||||||
.build_ty(ty.clone());
|
|
||||||
|
|
||||||
let (visitor_struct, visitor_impl) = serialize_struct_visitor(
|
let (visitor_struct, visitor_impl) = serialize_struct_visitor(
|
||||||
cx,
|
cx,
|
||||||
builder,
|
builder,
|
||||||
value_ty,
|
ty.clone(),
|
||||||
|
ty,
|
||||||
struct_def,
|
struct_def,
|
||||||
impl_generics,
|
impl_generics,
|
||||||
fields.iter().map(|field| quote_expr!(cx, &self.value.$field)),
|
fields.iter().map(|field| quote_expr!(cx, &self.value.$field)),
|
||||||
@ -232,6 +229,7 @@ fn serialize_struct(
|
|||||||
serializer.visit_named_map($type_name, Visitor {
|
serializer.visit_named_map($type_name, Visitor {
|
||||||
value: self,
|
value: self,
|
||||||
state: 0,
|
state: 0,
|
||||||
|
_structure_ty: ::std::marker::PhantomData,
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -241,6 +239,7 @@ fn serialize_item_enum(
|
|||||||
builder: &aster::AstBuilder,
|
builder: &aster::AstBuilder,
|
||||||
type_ident: Ident,
|
type_ident: Ident,
|
||||||
impl_generics: &ast::Generics,
|
impl_generics: &ast::Generics,
|
||||||
|
ty: P<ast::Ty>,
|
||||||
enum_def: &ast::EnumDef,
|
enum_def: &ast::EnumDef,
|
||||||
) -> P<ast::Expr> {
|
) -> P<ast::Expr> {
|
||||||
let arms: Vec<ast::Arm> = enum_def.variants.iter()
|
let arms: Vec<ast::Arm> = enum_def.variants.iter()
|
||||||
@ -250,6 +249,7 @@ fn serialize_item_enum(
|
|||||||
builder,
|
builder,
|
||||||
type_ident,
|
type_ident,
|
||||||
impl_generics,
|
impl_generics,
|
||||||
|
ty.clone(),
|
||||||
variant,
|
variant,
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
@ -267,6 +267,7 @@ fn serialize_variant(
|
|||||||
builder: &aster::AstBuilder,
|
builder: &aster::AstBuilder,
|
||||||
type_ident: Ident,
|
type_ident: Ident,
|
||||||
generics: &ast::Generics,
|
generics: &ast::Generics,
|
||||||
|
ty: P<ast::Ty>,
|
||||||
variant: &ast::Variant,
|
variant: &ast::Variant,
|
||||||
) -> ast::Arm {
|
) -> ast::Arm {
|
||||||
let type_name = builder.expr().str(type_ident);
|
let type_name = builder.expr().str(type_ident);
|
||||||
@ -305,6 +306,7 @@ fn serialize_variant(
|
|||||||
type_name,
|
type_name,
|
||||||
variant_name,
|
variant_name,
|
||||||
generics,
|
generics,
|
||||||
|
ty,
|
||||||
args,
|
args,
|
||||||
fields,
|
fields,
|
||||||
);
|
);
|
||||||
@ -340,6 +342,7 @@ fn serialize_variant(
|
|||||||
type_name,
|
type_name,
|
||||||
variant_name,
|
variant_name,
|
||||||
generics,
|
generics,
|
||||||
|
ty,
|
||||||
struct_def,
|
struct_def,
|
||||||
fields,
|
fields,
|
||||||
);
|
);
|
||||||
@ -355,10 +358,11 @@ fn serialize_tuple_variant(
|
|||||||
type_name: P<ast::Expr>,
|
type_name: P<ast::Expr>,
|
||||||
variant_name: P<ast::Expr>,
|
variant_name: P<ast::Expr>,
|
||||||
generics: &ast::Generics,
|
generics: &ast::Generics,
|
||||||
|
structure_ty: P<ast::Ty>,
|
||||||
args: &[ast::VariantArg],
|
args: &[ast::VariantArg],
|
||||||
fields: Vec<Ident>,
|
fields: Vec<Ident>,
|
||||||
) -> P<ast::Expr> {
|
) -> P<ast::Expr> {
|
||||||
let value_ty = builder.ty().tuple()
|
let variant_ty = builder.ty().tuple()
|
||||||
.with_tys(
|
.with_tys(
|
||||||
args.iter().map(|arg| {
|
args.iter().map(|arg| {
|
||||||
builder.ty()
|
builder.ty()
|
||||||
@ -369,6 +373,15 @@ fn serialize_tuple_variant(
|
|||||||
)
|
)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
|
let (visitor_struct, visitor_impl) = serialize_tuple_struct_visitor(
|
||||||
|
cx,
|
||||||
|
builder,
|
||||||
|
structure_ty,
|
||||||
|
variant_ty,
|
||||||
|
args.len(),
|
||||||
|
generics,
|
||||||
|
);
|
||||||
|
|
||||||
let value_expr = builder.expr().tuple()
|
let value_expr = builder.expr().tuple()
|
||||||
.with_exprs(
|
.with_exprs(
|
||||||
fields.iter().map(|field| {
|
fields.iter().map(|field| {
|
||||||
@ -379,20 +392,13 @@ fn serialize_tuple_variant(
|
|||||||
)
|
)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
let (visitor_struct, visitor_impl) = serialize_tuple_struct_visitor(
|
|
||||||
cx,
|
|
||||||
builder,
|
|
||||||
value_ty,
|
|
||||||
args.len(),
|
|
||||||
generics,
|
|
||||||
);
|
|
||||||
|
|
||||||
quote_expr!(cx, {
|
quote_expr!(cx, {
|
||||||
$visitor_struct
|
$visitor_struct
|
||||||
$visitor_impl
|
$visitor_impl
|
||||||
serializer.visit_enum_seq($type_name, $variant_name, Visitor {
|
serializer.visit_enum_seq($type_name, $variant_name, Visitor {
|
||||||
value: $value_expr,
|
value: $value_expr,
|
||||||
state: 0,
|
state: 0,
|
||||||
|
_structure_ty: ::std::marker::PhantomData,
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -403,6 +409,7 @@ fn serialize_struct_variant(
|
|||||||
type_name: P<ast::Expr>,
|
type_name: P<ast::Expr>,
|
||||||
variant_name: P<ast::Expr>,
|
variant_name: P<ast::Expr>,
|
||||||
generics: &ast::Generics,
|
generics: &ast::Generics,
|
||||||
|
structure_ty: P<ast::Ty>,
|
||||||
struct_def: &ast::StructDef,
|
struct_def: &ast::StructDef,
|
||||||
fields: Vec<Ident>,
|
fields: Vec<Ident>,
|
||||||
) -> P<ast::Expr> {
|
) -> P<ast::Expr> {
|
||||||
@ -430,6 +437,7 @@ fn serialize_struct_variant(
|
|||||||
let (visitor_struct, visitor_impl) = serialize_struct_visitor(
|
let (visitor_struct, visitor_impl) = serialize_struct_visitor(
|
||||||
cx,
|
cx,
|
||||||
builder,
|
builder,
|
||||||
|
structure_ty,
|
||||||
value_ty,
|
value_ty,
|
||||||
struct_def,
|
struct_def,
|
||||||
generics,
|
generics,
|
||||||
@ -446,6 +454,7 @@ fn serialize_struct_variant(
|
|||||||
serializer.visit_enum_map($type_name, $variant_name, Visitor {
|
serializer.visit_enum_map($type_name, $variant_name, Visitor {
|
||||||
value: $value_expr,
|
value: $value_expr,
|
||||||
state: 0,
|
state: 0,
|
||||||
|
_structure_ty: ::std::marker::PhantomData,
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -453,7 +462,8 @@ fn serialize_struct_variant(
|
|||||||
fn serialize_tuple_struct_visitor(
|
fn serialize_tuple_struct_visitor(
|
||||||
cx: &ExtCtxt,
|
cx: &ExtCtxt,
|
||||||
builder: &aster::AstBuilder,
|
builder: &aster::AstBuilder,
|
||||||
value_ty: P<ast::Ty>,
|
structure_ty: P<ast::Ty>,
|
||||||
|
variant_ty: P<ast::Ty>,
|
||||||
fields: usize,
|
fields: usize,
|
||||||
generics: &ast::Generics
|
generics: &ast::Generics
|
||||||
) -> (P<ast::Item>, P<ast::Item>) {
|
) -> (P<ast::Item>, P<ast::Item>) {
|
||||||
@ -484,11 +494,19 @@ fn serialize_tuple_struct_visitor(
|
|||||||
.strip_bounds()
|
.strip_bounds()
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
|
// Variants don't necessarily reference all generic lifetimes and type parameters,
|
||||||
|
// so to avoid a compilation failure, we'll just add a phantom type to capture these
|
||||||
|
// unused values.
|
||||||
|
let structure_ty = builder.ty()
|
||||||
|
.phantom_data()
|
||||||
|
.build(structure_ty);
|
||||||
|
|
||||||
(
|
(
|
||||||
quote_item!(cx,
|
quote_item!(cx,
|
||||||
struct Visitor $visitor_impl_generics $where_clause {
|
struct Visitor $visitor_impl_generics $where_clause {
|
||||||
state: usize,
|
state: usize,
|
||||||
value: $value_ty,
|
value: $variant_ty,
|
||||||
|
_structure_ty: $structure_ty,
|
||||||
}
|
}
|
||||||
).unwrap(),
|
).unwrap(),
|
||||||
|
|
||||||
@ -518,7 +536,8 @@ fn serialize_tuple_struct_visitor(
|
|||||||
fn serialize_struct_visitor<I>(
|
fn serialize_struct_visitor<I>(
|
||||||
cx: &ExtCtxt,
|
cx: &ExtCtxt,
|
||||||
builder: &aster::AstBuilder,
|
builder: &aster::AstBuilder,
|
||||||
value_ty: P<ast::Ty>,
|
structure_ty: P<ast::Ty>,
|
||||||
|
variant_ty: P<ast::Ty>,
|
||||||
struct_def: &StructDef,
|
struct_def: &StructDef,
|
||||||
generics: &ast::Generics,
|
generics: &ast::Generics,
|
||||||
value_exprs: I,
|
value_exprs: I,
|
||||||
@ -563,11 +582,19 @@ fn serialize_struct_visitor<I>(
|
|||||||
.strip_bounds()
|
.strip_bounds()
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
|
// Variants don't necessarily reference all generic lifetimes and type parameters,
|
||||||
|
// so to avoid a compilation failure, we'll just add a phantom type to capture these
|
||||||
|
// unused values.
|
||||||
|
let structure_ty = builder.ty()
|
||||||
|
.phantom_data()
|
||||||
|
.build(structure_ty);
|
||||||
|
|
||||||
(
|
(
|
||||||
quote_item!(cx,
|
quote_item!(cx,
|
||||||
struct Visitor $visitor_impl_generics $where_clause {
|
struct Visitor $visitor_impl_generics $where_clause {
|
||||||
state: usize,
|
state: usize,
|
||||||
value: $value_ty,
|
value: $variant_ty,
|
||||||
|
_structure_ty: $structure_ty,
|
||||||
}
|
}
|
||||||
).unwrap(),
|
).unwrap(),
|
||||||
|
|
||||||
|
@ -1,7 +1,11 @@
|
|||||||
|
/*
|
||||||
mod test_annotations;
|
mod test_annotations;
|
||||||
mod test_bytes;
|
mod test_bytes;
|
||||||
mod test_de;
|
mod test_de;
|
||||||
mod test_json;
|
mod test_json;
|
||||||
mod test_json_builder;
|
mod test_json_builder;
|
||||||
|
*/
|
||||||
mod test_macros;
|
mod test_macros;
|
||||||
|
/*
|
||||||
mod test_ser;
|
mod test_ser;
|
||||||
|
*/
|
||||||
|
@ -123,6 +123,14 @@ enum DeEnum<B, C: /* Trait */, D> /* where D: Trait */ {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize)]
|
||||||
|
enum Lifetimes<'a> {
|
||||||
|
LifetimeSeq(&'a i32),
|
||||||
|
NoLifetimeSeq(i32),
|
||||||
|
LifetimeMap { a: &'a i32 },
|
||||||
|
NoLifetimeMap { a: i32 },
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_named_unit() {
|
fn test_named_unit() {
|
||||||
let named_unit = NamedUnit;
|
let named_unit = NamedUnit;
|
||||||
@ -438,3 +446,32 @@ fn test_de_enum_map() {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_lifetimes() {
|
||||||
|
let value = 5;
|
||||||
|
let lifetime = Lifetimes::LifetimeSeq(&value);
|
||||||
|
assert_eq!(
|
||||||
|
json::to_string(&lifetime).unwrap(),
|
||||||
|
"{\"LifetimeSeq\":[5]}"
|
||||||
|
);
|
||||||
|
|
||||||
|
let lifetime = Lifetimes::NoLifetimeSeq(5);
|
||||||
|
assert_eq!(
|
||||||
|
json::to_string(&lifetime).unwrap(),
|
||||||
|
"{\"NoLifetimeSeq\":[5]}"
|
||||||
|
);
|
||||||
|
|
||||||
|
let value = 5;
|
||||||
|
let lifetime = Lifetimes::LifetimeMap { a: &value };
|
||||||
|
assert_eq!(
|
||||||
|
json::to_string(&lifetime).unwrap(),
|
||||||
|
"{\"LifetimeMap\":{\"a\":5}}"
|
||||||
|
);
|
||||||
|
|
||||||
|
let lifetime = Lifetimes::NoLifetimeMap { a: 5 };
|
||||||
|
assert_eq!(
|
||||||
|
json::to_string(&lifetime).unwrap(),
|
||||||
|
"{\"NoLifetimeMap\":{\"a\":5}}"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user