serde-rs / serde

Serialization framework for Rust
https://serde.rs/
Apache License 2.0
9.16k stars 774 forks source link

Deserializing custom types from a binary via visitors #556

Closed Relrin closed 8 years ago

Relrin commented 8 years ago

I'm trying to make a call for a custom visitor, which will be deserialize passed binary data to the BertBigInteger:

// this is a method, which is the part of my default Deserializer
#[inline]
fn parse_big_integer<V: Visitor>(
    &mut self, header: u8, mut visitor: V
) -> Result<V::Value> {
    visitor.visit_newtype_struct(BertBigNumberVisitor::new(self, header))
}

// Concrete implementation for the BertBigNumber
struct BertBigNumberVisitor<'a, R: 'a + Read> {
    de: &'a mut Deserializer<R>,
    header: u8,
}

impl<'a, R: 'a + Read> BertBigNumberVisitor<'a, R> {
    #[inline]
    fn new(de: &'a mut Deserializer<R>, header: u8) -> Self {
        BertBigNumberVisitor { de: de, header: header }
    }
}

impl<'a, R: 'a + Read> de::Visitor for BertBigNumberVisitor<'a, R> {
    type Value = BertBigInteger;

    #[inline]
    fn visit_newtype_struct<D>(&mut self, _: &mut D) -> StdResult<BertBigInteger, D::Error>
        where D: de::Deserializer
    {
        let n = match self.header {
            110 => try!(self.de.read_u8()),
            111 => try!(self.de.read_u32::<BigEndian>())
        };
        let sign_int = try!(self.de.read_u8());
        let sign = match sign_int {
            0 => Sign::Plus,
            _ => Sign::Minus
        };
        let bytes = try!(self.de.read_exact(n as u64));
        let bigint = BigInt::from_bytes_le(sign, bytes.as_ref());
        Ok(BertBigInteger(bigint))
    }
}

If we try to build this code, then compiler will show the following error:

src/deserializers.rs:259:24: 259:35 error: the trait bound `types::BertBigInteger: serde::Deserialize` is not satisfied [E0277]
src/deserializers.rs:259 impl<'a, R: 'a + Read> de::Visitor for BertBigNumberVisitor<'a, R> {
                                                ^~~~~~~~~~~
src/deserializers.rs:259:24: 259:35 help: run `rustc --explain E0277` to see a detailed explanation
src/deserializers.rs:259:24: 259:35 note: required by `serde::de::Visitor`

The compiler said, that he can't build this code because couldn't find implemented trait for it. I'd tried to add something like this:

impl Deserialize for BertBigInteger {
    fn deserialize<D>(deserializer: &mut D) -> StdResult<BertBigInteger, D::Error>
        where D: de::Deserializer
    {
        deserializer.deserialize_newtype_struct(
            self, BertBigNumberVisitor::new(deserializer, deserializer.header)
        )
    }
}

But this not compiled. As far as I understand from this article from the docs, I must implement the Deserialize trait with the corresponding visitor (which is BertBigNumberVisitor in our case), right? If it so, then how to make a call to this custom visitor+deserializer for a passed data via visitor function?

Relrin commented 8 years ago

@dtolnay Could help me with this issue?

Relrin commented 8 years ago

The problems is around implementing the impl Deserialize for BertBigInteger. Why I can't pass some arguments of a provided deserializer (in our case thats my implementation of Deserializer) further?

oli-obk commented 8 years ago

But this not compiled.

what's the error you are getting?

Relrin commented 8 years ago

I'm getting the following errors:

src/deserializers.rs:287:13: 287:17 error: `self` is not available in a static method. Maybe a `self` argument is missing? [E0424]
src/deserializers.rs:287             self, BertBigNumberVisitor::new(deserializer, deserializer.header)
                                     ^~~~
src/deserializers.rs:287:13: 287:17 help: run `rustc --explain E0424` to see a detailed explanation
src/deserializers.rs:150:38: 150:77 error: mismatched types [E0308]
src/deserializers.rs:150         visitor.visit_newtype_struct(BertBigNumberVisitor::new(self, header))
                                                              ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/deserializers.rs:150:38: 150:77 help: run `rustc --explain E0308` to see a detailed explanation
src/deserializers.rs:150:38: 150:77 note: expected type `&mut _`
src/deserializers.rs:150:38: 150:77 note:    found type `deserializers::BertBigNumberVisitor<'_, R>`
src/deserializers.rs:287:45: 287:57 error: mismatched types [E0308]
src/deserializers.rs:287             self, BertBigNumberVisitor::new(deserializer, deserializer.header)
                                                                     ^~~~~~~~~~~~
src/deserializers.rs:287:45: 287:57 help: run `rustc --explain E0308` to see a detailed explanation
src/deserializers.rs:287:45: 287:57 note: expected type `&mut deserializers::Deserializer<_>`
src/deserializers.rs:287:45: 287:57 note:    found type `&mut D`
src/deserializers.rs:287:59: 287:78 error: attempted access of field `header` on type `&mut D`, but no field with that name was found
src/deserializers.rs:287             self, BertBigNumberVisitor::new(deserializer, deserializer.header)
                                                                                   ^~~~~~~~~~~~~~~~~~~

Also I have tried to change to self parameter to the "BertBigInteger". That removed the first error from the output, but all following errors remained.

oli-obk commented 8 years ago

the second error has nothing to do with serde, just slap a &mut before the expression and you should be fine.

the third error contains types I don't know about, so I can't help you there except say that even if you fix the type errors, you will get borrow check errors, because you are borrowing the deserializer mutably twice. The Visitors created in a Deserialize impl should not borrow the deserializer, but only values created inside the method itself (or no values at all). You probably need two visitors.

Relrin commented 8 years ago

I have tried to fix the second error. It leads to a greater number of errors, like this:

src/deserializers.rs:287:13: 287:17 error: `self` is not available in a static method. Maybe a `self` argument is missing? [E0424]
src/deserializers.rs:287             self, BertBigNumberVisitor::new(deserializer, deserializer.header)
                                     ^~~~
src/deserializers.rs:287:13: 287:17 help: run `rustc --explain E0424` to see a detailed explanation
src/deserializers.rs:150:38: 150:77 error: mismatched types [E0308]
src/deserializers.rs:150         visitor.visit_newtype_struct(BertBigNumberVisitor::new(self, header))
                                                              ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/deserializers.rs:150:38: 150:77 help: run `rustc --explain E0308` to see a detailed explanation
src/deserializers.rs:150:38: 150:77 note: expected type `&mut _`
src/deserializers.rs:150:38: 150:77 note:    found type `deserializers::BertBigNumberVisitor<'_, R>`
<std macros>:6:1: 6:35 error: the trait bound `<D as serde::Deserializer>::Error: std::convert::From<std::io::Error>` is not satisfied [E0277]
<std macros>:6 $ crate :: convert :: From :: from ( err ) ) } } )
               ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/deserializers.rs:267:20: 267:43 note: in this expansion of try! (defined in <std macros>)
<std macros>:6:1: 6:35 help: run `rustc --explain E0277` to see a detailed explanation
<std macros>:6:1: 6:35 help: consider adding a `where <D as serde::Deserializer>::Error: std::convert::From<std::io::Error>` bound
<std macros>:6:1: 6:35 note: required by `std::convert::From::from`
<std macros>:6:1: 6:35 error: the trait bound `<D as serde::Deserializer>::Error: std::convert::From<std::io::Error>` is not satisfied [E0277]
<std macros>:6 $ crate :: convert :: From :: from ( err ) ) } } )
               ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/deserializers.rs:268:20: 268:57 note: in this expansion of try! (defined in <std macros>)
<std macros>:6:1: 6:35 help: run `rustc --explain E0277` to see a detailed explanation
<std macros>:6:1: 6:35 help: consider adding a `where <D as serde::Deserializer>::Error: std::convert::From<std::io::Error>` bound
<std macros>:6:1: 6:35 note: required by `std::convert::From::from`
src/deserializers.rs:266:17: 269:10 error: match arms have incompatible types [E0308]
src/deserializers.rs:266         let n = match self.header {
                                         ^
src/deserializers.rs:266:17: 269:10 help: run `rustc --explain E0308` to see a detailed explanation
src/deserializers.rs:266:17: 269:10 note: expected type `u8`
src/deserializers.rs:266:17: 269:10 note:    found type `u32`
<std macros>:2:1: 6:49 note: match arm with an incompatible type
<std macros>:2 match $ expr {
               ^
src/deserializers.rs:268:20: 268:57 note: in this expansion of try! (defined in <std macros>)
<std macros>:6:1: 6:35 error: the trait bound `<D as serde::Deserializer>::Error: std::convert::From<std::io::Error>` is not satisfied [E0277]
<std macros>:6 $ crate :: convert :: From :: from ( err ) ) } } )
               ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/deserializers.rs:270:24: 270:47 note: in this expansion of try! (defined in <std macros>)
<std macros>:6:1: 6:35 help: run `rustc --explain E0277` to see a detailed explanation
<std macros>:6:1: 6:35 help: consider adding a `where <D as serde::Deserializer>::Error: std::convert::From<std::io::Error>` bound
<std macros>:6:1: 6:35 note: required by `std::convert::From::from`
<std macros>:6:1: 6:35 error: the trait bound `<D as serde::Deserializer>::Error: std::convert::From<std::io::Error>` is not satisfied [E0277]
<std macros>:6 $ crate :: convert :: From :: from ( err ) ) } } )
               ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/deserializers.rs:275:21: 275:55 note: in this expansion of try! (defined in <std macros>)
<std macros>:6:1: 6:35 help: run `rustc --explain E0277` to see a detailed explanation
<std macros>:6:1: 6:35 help: consider adding a `where <D as serde::Deserializer>::Error: std::convert::From<std::io::Error>` bound
<std macros>:6:1: 6:35 note: required by `std::convert::From::from`
src/deserializers.rs:287:45: 287:57 error: mismatched types [E0308]
src/deserializers.rs:287             self, BertBigNumberVisitor::new(deserializer, deserializer.header)
                                                                     ^~~~~~~~~~~~
src/deserializers.rs:287:45: 287:57 help: run `rustc --explain E0308` to see a detailed explanation
src/deserializers.rs:287:45: 287:57 note: expected type `&mut deserializers::Deserializer<_>`
src/deserializers.rs:287:45: 287:57 note:    found type `&mut D`
src/deserializers.rs:287:59: 287:78 error: attempted access of field `header` on type `&mut D`, but no field with that name was found
src/deserializers.rs:287             self, BertBigNumberVisitor::new(deserializer, deserializer.header)

@oli-obk @dtolnay About other errors (1st, 3rd and 4th):

You probably need two visitors.

It sounds too complex and make further code harder in maintaining. Especially when someone will be trying to read that code, I think. Even that will be a little difficult for me.

In general I don't know how to do this serializer better (because of the small experience with the Rust language). Can we somehow make it easier and more readable that the current state of code? Does Serde provide some special implementations of visitors/deserializers which let me to do what I would make?

P.S. You can look onto actual state of code here. It is a pull request for making support Serde deserializers for the BERT types. Any suggestions for code are welcome :)