How to implement serde's Deserialize & Serialize for an external type?

Viewed 1782

I'm trying to implement Serialize & Deserialize for an external enum and I have no idea how. It has From<u64> so all I want to do is just have that object serialize with that.

#[derive(Serialize, Deserialize)]
pub struct ImageBinds {
    binds: HashMap<KeybdKey, Vec<u8>>, // KeybdKey doesn't implement serialize
}

// won't compile with this:
// only traits defined in the current crate can be implemented for arbitrary types
// impl doesn't use only types from inside the current crate
// I understand the orphan rule and all that but I have no idea how else I'd implement it
// I've looked at serde remote stuff and I cannot work out how to do it with an enum without
// literally just copying the whole crate into my scope which is stupid
impl Serialize for KeybdKey {
    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
        serializer.serialize_u64(u64::from(*self))
    }
}

KeybdKey is from the inputbot crate.

1 Answers

The correct way to do this is with the Newtype pattern. By wrapping the external type in a Newtype, you can implement a trait for it.

Your example will work with the following:

#[derive(Serialize, Deserialize)]
pub struct ImageBinds {
    binds: HashMap<MyKeybdKey, Vec<u8>>,
}

// This is a Newtype containing the external type .
struct MyKeybdKey(KeybdKey);

impl Serialize for MyKeybdKey {
    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
        serializer.serialize_u64(u64::from(self.0))
    }
}

impl<'de> Deserialize<'de> for MyKeybdKey {
    fn deserialize<D: Deserializer>(deserializer: D) -> Result<Self, D::Error> {
        // ...deserialize implementation.
    }
}

I didn't fill in the Deserialize implementation, because it will be rather long, but the basic concept is to just reverse the From implementation you relied on in the Serialize implementation.

Related