-
Notifications
You must be signed in to change notification settings - Fork 748
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Revamp Map/Seq serialization #437
Conversation
Visitor is "pull", while `MapSerializer` and `SeqSerializer` are "push" like the rest of the API.
@@ -363,8 +305,11 @@ impl<A> Serialize for ops::Range<A> | |||
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error> | |||
where S: Serializer, | |||
{ | |||
let len = iter::Step::steps_between(&self.start, &self.end, &A::one()); | |||
serializer.serialize_seq(SeqIteratorVisitor::new(self.clone(), len)) | |||
let mut seq_serializer = try!(serializer.serialize_seq(Some(self.len()))); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are you sure this is the same len
as the original code?
iter::Step::steps_between(&self.start, &self.end, &A::one())
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
copy paste error
Oh, so you went with a route of getting everything into Just for learning purposes: did you hit any blockers with the breaking up API into |
I am so excited for this. I only made it partway through but I like the approach. I will review more thoroughly tonight or tomorrow. This may make tuples and structs a lot faster because they no longer have to do try!(serializer.serialize_seq(Some(self.len()));
for e in self.iter() {
try!(serializer.serialize_seq_elt(e));
}
serializer.serialize_seq_end(Some(self.len())) ... something like this: let mut seq_state = try!(serializer.serialize_seq(Some(self.len())));
for e in self.iter() {
try!(serializer.serialize_seq_elt(&mut seq_state, e));
}
serializer.serialize_seq_end(seq_state) ... or equivalently: let mut seq_ser = try!(serializer.serialize_seq(Some(self.len())));
for e in self.iter() {
try!(seq_ser.elt(e));
}
seq_ser.end() I think the last one is more similar to some of the proposals in #386. I would like to have working commits against serde_json, bincode, serde_yaml and maybe one more before merging this, just so we validate it against fairly different use cases. |
@dtolnay : Yes, so last version you posted:
Has a problem of how will What I've mentioned in #386 , where But I guess the problem is that
would have to become:
or something like that. Would that hinder the API too much? Does this introduce additional copying? Nice alternative where What about:
This way
and user can forget about calling |
I tried a few variations of having separate SeqSerializer and MapSerializer rather than having all the methods on the Serializer trait, and they were all confusing or limited. I am satisfied with the approach in this PR. I still think it will be beneficial to some serializers to have associated types in which they can track state - we can default them to // I don't know which of these really need to be distinct types...
type SeqState = ();
type MapState = ();
type StructState = ();
type TupleState = ();
type StructVariantState = ();
type TupleVariantState = ();
type FixedSizeArrayState = (); let mut seq_state = try!(serializer.serialize_seq(Some(self.len())));
for e in self.iter() {
try!(serializer.serialize_seq_elt(&mut seq_state, e));
}
serializer.serialize_seq_end(seq_state) Also I noticed that YAML does something weird where it calls the visitor using a Serializer that is different from the one on which serialize_tuple_variant/serialize_struct_variant were called: yaml/src/ser.rs#L168-L171. We need to figure out how that maps to the new API. |
actually that was my first design, but it got very tedious to keep it in sync with my very frequent changes to adapt to situations I hadn't considered. We can add this without a problem, but during the design phase I'd rather stay with manual control. @dpc: borrowing from the fn serialize_seq<'a>(&'a mut self) -> Result<SeqSerializer<'a, Self>, Self::Error> The final If we ever need the Also I'll add a clippy lint that warns about mis-use. These checks combined should keep everyone from mis-using the API. |
I don't think that works if the Serializer has an explicit lifetime as in serde-yaml because the trait can't require the Serializer's lifetime to outlive |
I can take care of trying this out on serde-yaml. I filed dtolnay/serde-yaml#21 to track that. |
Jup, json-value can profit from it and I'll add it now |
sadly not on stable rust
|
toml works now, adjusting the others is trivial (just add the |
where V: Serialize, | ||
{ | ||
/// By default, structs are serialized as a map with the field name as the key. | ||
fn serialize_struct_variant_elt<K, V>(&mut self, key: K, value: V) -> Result<(), Self::Error> where K: Serialize, V: Serialize { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same questions as on serialize_struct_elt
.
David's take on Serializer
|
all serializers have been brought up to date. One more experiment would be to check if we now can get rid of the stack in the serde-value serializer |
This is so cool. You all are awesome. We never quite got to the whole "the type system enforces the serde protocol" so might as well not constrain ourselves to having all these visitors. Have you also considered how this approach might affect the deserialization API? |
I'm a +1 on this (once the tests pass), and definitely curious if this has any performance implications as well. Great work. |
I've just looked and Nice. I'm happy about the result. |
I merged this along with 855f3d9 to remind us that master is no longer 0.7. I made an 0.7.x branch in case we need any more 0.7 releases. |
A bit late to the party, but looking through this it looks like it'll eliminate a lot of code in my manual struct serialisation 👍 I'm guessing it'll still be a little while before this hits crates.io since codegen will need updating? |
Codegen has been updated in this PR. I would expect sometime next week - there are a few other fixes we want in 0.8. |
For those subscribed to this issue - I filed #447 to track the release of these changes. |
I took the liberty of also simplifying some of serde codegen (mainly the parts where we do a lot of effort to create types that are going to get optimized out). I think all that was necessary to fit the visitor pattern. The new system as imagined by @dpc is much easier to implement, although it requires additional helper objects
fixes #386
cc @dpc
Serializers compatible with the new API