Overriding default implementation for usize in Serde

When serializing vectors, serde prepends the size of the vector to the serialized bytes. For instance,

use serde::{Serialize, Deserialize};
use bincode;

#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct SneksStruct {
    id: u16,
    note: Vec<u8>,
}

fn main() {
    let snek = SneksStruct {
        id: 0x0001,
        note: vec![119,120,114],
    };

    let serialized = bincode::serialize(&snek).unwrap();
    println!("{:?}", serialized);
}

outputs [1, 0, 3, 0, 0, 0, 0, 0, 0, 0, 119, 120, 114].

I don't want to have the length prepended as a usize. Instead I want it to be prepended as a u16, i.e., I want the output to be [1, 0, 3, 0, 119, 120, 114].

I tried to override the implementation of usize as follows:

impl Serialize for usize {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        serializer.serialize_u16(*self)
    }
}

but I get the following errors:

error[E0119]: conflicting implementations of trait `_::_serde::Serialize` for type `usize`:
  --> src/main.rs:24:1
   |
24 | impl Serialize for usize {
   | ^^^^^^^^^^^^^^^^^^^^^^^^
   |
   = note: conflicting implementation in crate `serde`:
           - impl _::_serde::Serialize for usize;

error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
  --> src/main.rs:24:1
   |
24 | impl Serialize for usize {
   | ^^^^^^^^^^^^^^^^^^^-----
   | |                  |
   | |                  `usize` is not defined in the current crate
   | impl doesn't use only types from inside the current crate
   |
   = note: define and implement a trait or new type instead

error: aborting due to 2 previous errors

What would be a good way to do this that wouldn't involve vendoring and patching serde?

This is not serialization for usize. This is the way bincode does to serialize sequences. If you want to tweak this, you have to roll out your own bincode-like serialization and deserialization.

5 Likes

If it’s just to save space and not necessarily for compatibility reasons, there’s the VarintEncoding option

2 Likes

Sadly it is for compatibility reasons.

There’s also bincode2 which is a fork that supports configuring the type used for lengths. I’ve never used it so I can’t exactly vouch for it in any way.

1 Like

Thank you! That worked perfectly. For anyone else reading this:

let serialized = bincode2::config().
    array_length(bincode2::LengthOption::U16).
    serialize(&snek).
    unwrap();

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.