Ok value of a serde Serializer


I'm trying to implement a custom serde serialization for a field of a struct using the with attribute. I'm stuck while trying to write a no-op function to start with because I can't find how to return a Result containing the Ok value of the generic Serializer.

mod custom_serializer {
    use serde::{Deserializer, Serializer};

    fn serialize<S>(x: &Vec<u8>, s: S) -> Result::<S::Ok, S::Error>
        where S: Serializer
        Ok(()) // << here is the faulty part

    fn deserialize<'de, D>(d: D) -> Result::<Vec<u8>, D::Error>
        where D: Deserializer<'de>

I think I've tried almost everything I could come up with... Ok(()), Ok(S::Ok) (which doesn't make sense since S::Ok is a type, Ok(S::Ok::default()) but there's no Default bound on the Ok parameter of Serializer so...

What am I supposed to return when everything goes well then? Looking for some examples I found that most people just call the underlying methods and don't care about the return type, which is fine but still I'd like to understand how these work.

Not directly related to the question but I'm playing with Rust for a bit more than a month now, and it stills feel like fighting with the type system. The interfaces are really hard to read, it's not as bad as for Haskell, but I really don't know where to start if no examples are provided in the documentation. Is it supposed to fade at some point up in the learning curve? Or is that just part of Rust programming?

Hi, I never used serde but based on the api, I don't think you're supposed to know (or care) what S::Ok is. serde will return Result<S::Ok, S::Error> from the serialization methods and you just bubble up errors and return the output of the serialization if success.

Regarding your two questions I'd say it depends, do you have issue understanding what a trait does when it's "alone", like std::iter::Iterator? or when it's multiple traits interacting with each other?

So as you can observe, that's not going to work because without a way to generically construct the Ok value, you simply can't make an instance of it. If you are trying to stub out the method until you actually get to implementing it, then consider using the unimplemented!() macro, which simply panics.

Other than that, you can actually serialize something that doesn't require much thought, e.g. s.serialize_unit(), because these methods also return Result<S::Ok, S::Error>. (In fact, the point of the signature of serialize is to serve as a proxy for the various serialize_ methods of the serializer with which you can translate your custom data structure into a set of primitives.)

I come from C++ so understanding what a specific interface expects isn't really the issue (even though it might be sometimes when too many bounds are involved...), it was more of a general remark: getting into a new package feels like picking up the pieces. And because we rely on a lot of small packages instead of a few monolithic ones (Python style), the common ground between the various parts of a program is rather thin.

I had forgotten about being able to panic in order to avoid return type issues. It'll do! Thanks for these two tricks.

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.