Code review for implementing custom trait

I'm implementing a custom trait for several of my structs, but I think writing out impl MySerialize for StructX {} for every struct doesn't seem very efficient. I know I can derive it as a custom trait, but writing a proc macro requires a new crate, which I don't want to use. Is there a way I can put it into the struct's method implementation block i.e., the impl StructX block?

Also just looking for general suggestions on this topic since I'm pretty new to custom trait implementations.

use bincode2;
use serde::{Serialize as SerdeSerialize, Deserialize as SerdeDeserialize};

pub trait MySerialize {
    fn to_bytes(&self) -> Result<Vec<u8>, String> 
    where 
        Self: SerdeSerialize 
    {
        let serialized = bincode2::config().
            serialize(&self).
            unwrap();
        Ok(serialized)
    }
}

pub trait MyDeserialize<'de> {
    fn from_bytes(buf: &'de [u8]) -> Result<Self, String> 
    where 
        Self: Sized,
        Self: SerdeDeserialize<'de>
    {
        let deserialized: Self = bincode2::config().
            deserialize(buf).
            unwrap();
        Ok(deserialized)
    }
}

#[derive(SerdeSerialize, SerdeDeserialize, Clone, Debug, PartialEq, Eq)]
pub struct Snake {
    pub route: Vec<u8>,
    pub foods: [u8; 32],
}

// I don't like writing these out for every struct...
impl MySerialize for Snake {}
impl<'de> MyDeserialize<'de> for Snake {}

#[derive(SerdeSerialize, SerdeDeserialize, Clone, Debug, PartialEq, Eq)]
pub struct Ocean {
    pub fishes: Vec<u8>,
    pub boats: Vec<u8>,
}

// Would be nice to put this into the impl Ocean block below to clean up code
impl MySerialize for Ocean {}
impl<'de> MyDeserialize<'de> for Ocean {}

impl Ocean {
    pub fn new(fishes: Vec<u8>, boats: Vec<u8>) -> Self {
        Ocean {
            fishes,
            boats,
        }
    }
}

fn main() {
    let ocean = Ocean::new(vec![1, 2], vec![3, 4]);
    let bytes = ocean.to_bytes().unwrap();
    let back_to_ocean = Ocean::from_bytes(&bytes).unwrap();
    assert_eq!(ocean, back_to_ocean);
}

You could use a regular macro, which is especially easy if your output is easily pattern-able based on some parameters.

Since it seems your implementation is empty, you could do something like this:

macro_rules! impl_custom_serde {
    ($name:ident) => {
        impl MySerialize for $name {}
        impl<'de> MyDeserialize<'de> for $name {}
    };
}

struct Foo;
impl_custom_serde!(Foo);
1 Like