mirror of
https://github.com/pezkuwichain/serde.git
synced 2026-06-14 04:41:01 +00:00
Do not generate bounds from recursive types
This commit is contained in:
@@ -70,6 +70,7 @@ pub fn with_bound<F>(
|
|||||||
.map(|&(ref field, _)| &field.ty)
|
.map(|&(ref field, _)| &field.ty)
|
||||||
// TODO this filter can be removed later, see comment on function
|
// TODO this filter can be removed later, see comment on function
|
||||||
.filter(|ty| contains_generic(ty, generics))
|
.filter(|ty| contains_generic(ty, generics))
|
||||||
|
.filter(|ty| !contains_recursion(ty, item.ident))
|
||||||
.map(|ty| strip_reference(ty))
|
.map(|ty| strip_reference(ty))
|
||||||
.map(|ty| builder.where_predicate()
|
.map(|ty| builder.where_predicate()
|
||||||
// the type that is being bounded e.g. T
|
// the type that is being bounded e.g. T
|
||||||
@@ -159,6 +160,50 @@ fn contains_generic(ty: &ast::Ty, generics: &ast::Generics) -> bool {
|
|||||||
visitor.found_generic
|
visitor.found_generic
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We do not attempt to generate any bounds based on field types that are
|
||||||
|
// directly recursive, as in:
|
||||||
|
//
|
||||||
|
// struct Test<D> {
|
||||||
|
// next: Box<Test<D>>,
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// This does not catch field types that are mutually recursive with some other
|
||||||
|
// type. For those, we require bounds to be specified by a `where` attribute if
|
||||||
|
// the inferred ones are not correct.
|
||||||
|
//
|
||||||
|
// struct Test<D> {
|
||||||
|
// #[serde(where="D: Serialize + Deserialize")]
|
||||||
|
// next: Box<Other<D>>,
|
||||||
|
// }
|
||||||
|
// struct Other<D> {
|
||||||
|
// #[serde(where="D: Serialize + Deserialize")]
|
||||||
|
// next: Box<Test<D>>,
|
||||||
|
// }
|
||||||
|
fn contains_recursion(ty: &ast::Ty, ident: ast::Ident) -> bool {
|
||||||
|
struct FindRecursion {
|
||||||
|
ident: ast::Ident,
|
||||||
|
found_recursion: bool,
|
||||||
|
}
|
||||||
|
impl<'v> visit::Visitor<'v> for FindRecursion {
|
||||||
|
fn visit_path(&mut self, path: &'v ast::Path, _id: ast::NodeId) {
|
||||||
|
if !path.global
|
||||||
|
&& path.segments.len() == 1
|
||||||
|
&& path.segments[0].identifier == self.ident {
|
||||||
|
self.found_recursion = true;
|
||||||
|
} else {
|
||||||
|
visit::walk_path(self, path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut visitor = FindRecursion {
|
||||||
|
ident: ident,
|
||||||
|
found_recursion: false,
|
||||||
|
};
|
||||||
|
visit::walk_ty(&mut visitor, ty);
|
||||||
|
visitor.found_recursion
|
||||||
|
}
|
||||||
|
|
||||||
// This is required to handle types that use both a reference and a value of
|
// This is required to handle types that use both a reference and a value of
|
||||||
// the same type, as in:
|
// the same type, as in:
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -75,7 +75,6 @@ struct Tuple<T>(
|
|||||||
);
|
);
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
#[serde(where(serialize="D: Serialize", deserialize="D: Deserialize"))]
|
|
||||||
enum TreeNode<D> {
|
enum TreeNode<D> {
|
||||||
Split {
|
Split {
|
||||||
left: Box<TreeNode<D>>,
|
left: Box<TreeNode<D>>,
|
||||||
@@ -89,17 +88,33 @@ enum TreeNode<D> {
|
|||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
struct ListNode<D> {
|
struct ListNode<D> {
|
||||||
data: D,
|
data: D,
|
||||||
#[serde(where="")]
|
|
||||||
next: Box<ListNode<D>>,
|
next: Box<ListNode<D>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
struct SerializeWithTrait<D> {
|
#[serde(where="D: SerializeWith + DeserializeWith")]
|
||||||
|
struct WithTraits1<D, E> {
|
||||||
|
#[serde(serialize_with="SerializeWith::serialize_with",
|
||||||
|
deserialize_with="DeserializeWith::deserialize_with")]
|
||||||
|
d: D,
|
||||||
#[serde(serialize_with="SerializeWith::serialize_with",
|
#[serde(serialize_with="SerializeWith::serialize_with",
|
||||||
deserialize_with="DeserializeWith::deserialize_with",
|
deserialize_with="DeserializeWith::deserialize_with",
|
||||||
where(serialize="D: SerializeWith",
|
where="E: SerializeWith + DeserializeWith")]
|
||||||
deserialize="D: DeserializeWith"))]
|
e: E,
|
||||||
data: D,
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
#[serde(where(serialize="D: SerializeWith",
|
||||||
|
deserialize="D: DeserializeWith"))]
|
||||||
|
struct WithTraits2<D, E> {
|
||||||
|
#[serde(serialize_with="SerializeWith::serialize_with",
|
||||||
|
deserialize_with="DeserializeWith::deserialize_with")]
|
||||||
|
d: D,
|
||||||
|
#[serde(serialize_with="SerializeWith::serialize_with",
|
||||||
|
deserialize_with="DeserializeWith::deserialize_with",
|
||||||
|
where(serialize="E: SerializeWith",
|
||||||
|
deserialize="E: DeserializeWith"))]
|
||||||
|
e: E,
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|||||||
Reference in New Issue
Block a user