Fix deriving traits for fully generic types.

Closes #100
This commit is contained in:
Erick Tryzelaar 2015-07-23 07:25:27 -07:00
parent 8663435a05
commit b0512a4479
2 changed files with 65 additions and 34 deletions

View File

@ -55,10 +55,7 @@ pub fn expand_derive_serialize(
&builder,
&item,
&impl_generics,
builder.ty()
.ref_()
.lifetime("'__a")
.build_ty(ty.clone()),
ty.clone(),
);
let where_clause = &impl_generics.where_clause;
@ -184,7 +181,10 @@ fn serialize_tuple_struct(
cx,
builder,
ty.clone(),
ty,
builder.ty()
.ref_()
.lifetime("'__a")
.build_ty(ty.clone()),
fields,
impl_generics,
);
@ -197,7 +197,7 @@ fn serialize_tuple_struct(
serializer.visit_tuple_struct($type_name, Visitor {
value: self,
state: 0,
_structure_ty: ::std::marker::PhantomData,
_structure_ty: ::std::marker::PhantomData::<&$ty>,
})
})
}
@ -215,7 +215,10 @@ fn serialize_struct(
cx,
builder,
ty.clone(),
ty,
builder.ty()
.ref_()
.lifetime("'__a")
.build_ty(ty.clone()),
struct_def,
impl_generics,
fields.iter().map(|field| quote_expr!(cx, &self.value.$field)),
@ -229,7 +232,7 @@ fn serialize_struct(
serializer.visit_struct($type_name, Visitor {
value: self,
state: 0,
_structure_ty: ::std::marker::PhantomData,
_structure_ty: ::std::marker::PhantomData::<&$ty>,
})
})
}
@ -383,7 +386,7 @@ fn serialize_tuple_variant(
let (visitor_struct, visitor_impl) = serialize_tuple_struct_visitor(
cx,
builder,
structure_ty,
structure_ty.clone(),
variant_ty,
args.len(),
generics,
@ -392,9 +395,7 @@ fn serialize_tuple_variant(
let value_expr = builder.expr().tuple()
.with_exprs(
fields.iter().map(|field| {
builder.expr()
.addr_of()
.id(field)
builder.expr().id(field)
})
)
.build();
@ -405,7 +406,7 @@ fn serialize_tuple_variant(
serializer.visit_enum_seq($type_name, $variant_index, $variant_name, Visitor {
value: $value_expr,
state: 0,
_structure_ty: ::std::marker::PhantomData,
_structure_ty: ::std::marker::PhantomData::<&$structure_ty>,
})
})
}
@ -435,9 +436,7 @@ fn serialize_struct_variant(
let value_expr = builder.expr().tuple()
.with_exprs(
fields.iter().map(|field| {
builder.expr()
.addr_of()
.id(field)
builder.expr().id(field)
})
)
.build();
@ -445,7 +444,7 @@ fn serialize_struct_variant(
let (visitor_struct, visitor_impl) = serialize_struct_visitor(
cx,
builder,
structure_ty,
structure_ty.clone(),
value_ty,
struct_def,
generics,
@ -462,7 +461,7 @@ fn serialize_struct_variant(
serializer.visit_enum_map($type_name, $variant_index, $variant_name, Visitor {
value: $value_expr,
state: 0,
_structure_ty: ::std::marker::PhantomData,
_structure_ty: ::std::marker::PhantomData::<&$structure_ty>,
})
})
}
@ -502,19 +501,12 @@ fn serialize_tuple_struct_visitor(
.strip_bounds()
.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,
struct Visitor $visitor_impl_generics $where_clause {
state: usize,
value: $variant_ty,
_structure_ty: $structure_ty,
_structure_ty: ::std::marker::PhantomData<&'__a $structure_ty>,
}
).unwrap(),
@ -590,19 +582,12 @@ fn serialize_struct_visitor<I>(
.strip_bounds()
.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,
struct Visitor $visitor_impl_generics $where_clause {
state: usize,
value: $variant_ty,
_structure_ty: $structure_ty,
_structure_ty: ::std::marker::PhantomData<&'__a $structure_ty>,
}
).unwrap(),

View File

@ -131,6 +131,26 @@ enum Lifetimes<'a> {
NoLifetimeMap { a: i32 },
}
#[derive(Debug, PartialEq, Serialize, Deserialize)]
pub struct GenericStruct<T> {
x: T,
}
#[derive(Debug, PartialEq, Serialize, Deserialize)]
pub struct GenericTupleStruct<T>(T);
#[derive(Debug, PartialEq, Serialize, Deserialize)]
pub enum GenericEnumSeq<T, E> {
Ok(T),
Err(E),
}
#[derive(Debug, PartialEq, Serialize, Deserialize)]
pub enum GenericEnumMap<T, E> {
Ok { x: T },
Err { x: E },
}
#[test]
fn test_named_unit() {
let named_unit = NamedUnit;
@ -475,3 +495,29 @@ fn test_lifetimes() {
"{\"NoLifetimeMap\":{\"a\":5}}"
);
}
#[test]
fn test_generic() {
macro_rules! declare_tests {
($($ty:ty : $value:expr => $str:expr,)+) => {
$({
let value: $ty = $value;
let string = serde_json::to_string(&value).unwrap();
assert_eq!(string, $str);
let expected: $ty = serde_json::from_str(&string).unwrap();
assert_eq!(value, expected);
})+
}
}
declare_tests!(
GenericStruct<u32> : GenericStruct { x: 5 } => "{\"x\":5}",
GenericTupleStruct<u32> : GenericTupleStruct(5) => "[5]",
GenericEnumSeq<u32, u32> : GenericEnumSeq::Ok(5) => "{\"Ok\":[5]}",
GenericEnumSeq<u32, u32> : GenericEnumSeq::Err(5) => "{\"Err\":[5]}",
GenericEnumMap<u32, u32> : GenericEnumMap::Ok { x: 5 } => "{\"Ok\":{\"x\":5}}",
GenericEnumMap<u32, u32> : GenericEnumMap::Err { x: 5 } => "{\"Err\":{\"x\":5}}",
);
}