Skip to content
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

Front-page example doesn't compile on Rust stable (1.2) #150

Closed
cmbrandenburg opened this issue Aug 31, 2015 · 3 comments
Closed

Front-page example doesn't compile on Rust stable (1.2) #150

cmbrandenburg opened this issue Aug 31, 2015 · 3 comments
Labels

Comments

@cmbrandenburg
Copy link
Contributor

I copied-and-pasted the front-page example for “Deserialization without Macros”—specifically the section on structs—and tried to compile it, but it fails to compile.

All but one of the compiler errors are due to the PointField type being referred to as Field. I fixed those errors, but there remains one compiler error, which is at line 92 in the list below.

src/main.rs:62:26: 62:31 error: use of undeclared type name `Field`
src/main.rs:62             type Value = Field;
                                        ^~~~~
src/main.rs:68:31: 68:39 error: failed to resolve. Use of undeclared type or module `Field`
src/main.rs:68                     "x" => Ok(Field::X),
                                             ^~~~~~~~
src/main.rs:68:31: 68:39 error: unresolved name `Field::X`
src/main.rs:68                     "x" => Ok(Field::X),
                                             ^~~~~~~~
src/main.rs:69:31: 69:39 error: failed to resolve. Use of undeclared type or module `Field`
src/main.rs:69                     "y" => Ok(Field::Y),
                                             ^~~~~~~~
src/main.rs:69:31: 69:39 error: unresolved name `Field::Y`
src/main.rs:69                     "y" => Ok(Field::Y),
                                             ^~~~~~~~
src/main.rs:92:5: 121:6 error: method `visit_struct` is not a member of trait `serde::de::Visitor`
src/main.rs:92     fn visit_struct<V>(&mut self,
src/main.rs:93                        _fields: &[&str],
src/main.rs:94                        mut visitor: V) -> Result<Point, V::Error>
src/main.rs:95         where V: serde::de::MapVisitor
src/main.rs:96     {
src/main.rs:97         let mut x = None;
               ...
src/main.rs:102:22: 102:30 error: unresolved enum variant, struct or const `X`
src/main.rs:102                 Some(Field::X) => { x = Some(try!(visitor.visit_value())); }
                                     ^~~~~~~~
src/main.rs:103:22: 103:30 error: unresolved enum variant, struct or const `Y`
src/main.rs:103                 Some(Field::Y) => { y = Some(try!(visitor.visit_value())); }

I looked through the Serde documentation and source code but was unable to figure out what the call to visit_struct is supposed to be. Perhaps this example has gotten lost in the Serde API changes?

I understand that the Serde Serialize and Deserialize macros are first-class and that applications shouldn't be rolling out custom visitors for serialization and deserialization. However, the macros don't support renaming fields (#140), handling elided fields during deserialization (#90, #44), nor eliding default values during serialization (#43), and I need these features. So until the macros catch up with my use case, I must fall back to custom visitors.

Can someone explain what the call to visit_struct is supposed to be?

And perhaps someone can explain what the _fields parameter in serde::de::Deserializer::visit_struct is for?

And maybe someone can explain what “elt” means, as in serde::ser::Serializer::visit_struct_elt?

@erickt erickt closed this as completed in 5f4a7e5 Aug 31, 2015
@erickt
Copy link
Member

erickt commented Aug 31, 2015

Oops sorry about that! I just pushed up a working example. I think this was just an older example I forgot to update.

I'm currently writing up documentation for serde, I'm sorry it's been taking so long. I personally think it's fine to write visitors, they are just a little complicated and I haven't yet figured out a great way to simplify them while keeping their performance. Anyway, some serializers and deserializers serialize structs differently than maps, such as bincode, which serializes structs essentially as a tuple with no field names. The visit_struct methods are hooks for those serializers to do something more optimal with these fields. The fields argument is a &[&str] of all the field names in a struct. The elt in visit_struct_elt is for serializing a single element of a struct. It serializes the field name and the field value as a pair in the serializer.

One thing that might help is to actually look at what serde_macros is generating. You can do this by writing up:

#![features(plugin)]
#![plugin(serde_macros)]

extern crate serde;

#[derive(Serialize, Deserialize)]
pub struct Point {
  x: usize,
  y: usize,
}

Then run: cargo build -v, grab the rustc command and run rustc ... -Z unstable-options --pretty expanded to pretty print out the whole crate. This isn't a long term requirement for writing complex visitors, but I hope it'll help you get started. Please let me know if there's more I can do to help.

@cmbrandenburg
Copy link
Contributor Author

Erick, thanks for the quick response!

The documentation isn't bad—aside from having up-to-date examples and more explanation for parameters and abbreviations.

Regarding visitors, what I found most confusing is the overloaded use of the word “visit.” While it's intuitive to have visitor types such as Visitor and MapVisitor with methods named visit, visit_struct, etc., I struggled at first with the Serializer and Deserializer types also having methods named visit*. It was unclear to me what was doing the visiting and what was being visited, though now, in hindsight, it's entirely clear.

In Go the idiom is to name interfaces with a noun ending in “-er.” E.g., a Reader has a Read method, a Closer has a Close method, and a Decoder has a Decode method. This is one of the many things that makes Go easy to use for beginners and experts alike.

Rust has traits instead of interfaces, but I think the “-er” naming scheme works well in many cases, just the same. For Serde, this suggests that, say, the Deserializer trait should have methods named deserialize*, not visit*. The specific names here don't matter, only that the API distinguishes between visitors and visitees. Just a thought.

@erickt
Copy link
Member

erickt commented Aug 31, 2015

Thanks, that's interesting idea, I've filed #151 to track it.

@dtolnay dtolnay added the docs label May 14, 2016
rubdos pushed a commit to rubdos/serde that referenced this issue Jun 20, 2017
bigint: small to_str_radix optimization

Before:
```
test fac_to_string     ... bench:       1,630 ns/iter (+/- 34)
test fib_to_string     ... bench:         359 ns/iter (+/- 11)
test to_str_radix_02   ... bench:       3,097 ns/iter (+/- 19)
test to_str_radix_08   ... bench:       1,146 ns/iter (+/- 38)
test to_str_radix_10   ... bench:       4,248 ns/iter (+/- 36)
test to_str_radix_16   ... bench:         881 ns/iter (+/- 44)
test to_str_radix_36   ... bench:       8,073 ns/iter (+/- 75)
```
After:
```
test fac_to_string     ... bench:       1,492 ns/iter (+/- 20)
test fib_to_string     ... bench:         368 ns/iter (+/- 7)
test to_str_radix_02   ... bench:       2,038 ns/iter (+/- 47)
test to_str_radix_08   ... bench:         812 ns/iter (+/- 9)
test to_str_radix_10   ... bench:       3,919 ns/iter (+/- 40)
test to_str_radix_16   ... bench:         703 ns/iter (+/- 58)
test to_str_radix_36   ... bench:       7,852 ns/iter (+/- 81)
```
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Development

No branches or pull requests

3 participants