How to implement serde's Serialize and Deserialize traits for an external type?
Asked Answered
M

1

14

I'm trying to implement Serialize and 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.

Mixedup answered 17/4, 2021 at 20:28 Comment(3)
Does this tutorial help?Strident
I would be helpful to include the exact error and, even better, a reproducible case in a Rust Playground: play.rust-lang.orgDuthie
The remote derive feature will not help you if your type is nested inside a HashMap. You either need a custom deserialize for the HashMap (i.e., with attribute), a wrapper type, or you try the serde_with crate. The documentation only mentions From<KeybdKey> for u64 but not a From<u64>. So this will only allow you to write the serialization code, but not the deserialization.Uta
R
7

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.

Rubetta answered 12/8, 2022 at 5:13 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.