serde-rs / serde

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

Invoking `serialize_bytes` for &[u8] instead of `serialize_seq` #518

Closed Relrin closed 8 years ago

Relrin commented 8 years ago

I'm trying to implement serializing bytes in my own crate, which using as a base serde module. So, I have a serializer which has the next overridden method:

#[inline]
fn serialize_bytes(&mut self, data: &[u8]) -> Result<()> {
    let length = value.len();

    let mut header = vec![BertTag::Binary as u8];
    header.write_i32::<BigEndian>(length as i32).unwrap();
    try!(self.writer.write_all(header.as_slice()));

    let mut state = State::First;
    for element in data {
        try!(self.serialize_seq_elt(&mut state, element));
    };

    self.serialize_seq_end(state)
}

// tests
// ...
#[test]
fn test_serialize_bytes() {
    let empty_bytes_list: [u8; 0] = [];

    assert_eq!(
        term_to_binary(&empty_bytes_list).unwrap(),
        vec![
            131u8,
            109,                            // binary
            0, 0, 0, 0                      // length
        ]
    );

    let bytes_vec: [u8; 3] = [1u8, 2u8, 3u8];

    assert_eq!(
        term_to_binary(&bytes_vec).unwrap(),
        vec![
            131u8,
            109,                            // binary
            0, 0, 0, 3,                     // length
            97, 1,                          // 1
            97, 2,                          // 2
            97, 3                           // 3
        ]
    );
}

The basic signature for this function is described in serde here. After implementing special behaviour for this type of data, I'd written few tests, which checking correctness of this code. So, cargo test just note me, that those test are failing, because have a different headers. BERT specification for a binary type of data using tag with number 109. But in a result, I've taken a header with 108 number which is using for a list.

What can I do for that serializer will invoke serialize_bytes method instead of serialize_seq?

dtolnay commented 8 years ago

We don't yet support Rust's experimental impl specialization feature so right now &[u8] will get serialized the same as any other &[T], which is with serialize_seq instead of serialize_bytes. Support for specialization is tracked in #309.

For now your test will need to wrap the &[u8] in serde::bytes::Bytes which implements Serialize to go through serialize_bytes.

let bytes: serde::bytes::Bytes = b"testing"[..].into();
dtolnay commented 8 years ago

I filed #519 because there should be a better way to construct a Bytes :frowning:.

Relrin commented 8 years ago

Yeah, that helped me. When specialization support will have done, does serialize_bytes method of serde-rs support either of &[u8] and serde::bytes::Bytes?

Thanks for the detail answer!

dtolnay commented 8 years ago

When specialization support happens, there will be no reason to have serde::bytes::Bytes anymore.

Currently we have this impl:

impl<T> Serialize for [T] where T: Serialize

Specialization will allow us to add this impl, which would conflict with the previous one before specialization:

impl Serialize for [u8]

Adding this impl is a breaking change because it affects the representation of &[u8] in formats that handle serialize_bytes differently from serialize_seq, so it needs to happen in a breaking Serde release like 0.9.0 or 0.10.0. In the same breaking release we will remove Bytes and ByteBuf.

sffc commented 2 years ago

Note that since serde 1.0.0, serde::bytes::Bytes is now in its own crate:

https://github.com/serde-rs/bytes