The overarching issue I'm having stems from the fact that the serde::Serializer
trait is modeled around the data model of 19 types, and I'm trying to define a type that has Serializer
-specific behaviour and can be shared across crates.
I've gotten pretty far by doing two things:
- define a "subclass" trait (or maybe this is like prototypal inheritance?) of a
serde::Serializer
calledEncoder
to use in place of aSerializer
that defines an additional methodencode_link
and its default impl by:- requiring impls of
Encoder
to also implSerializer
- blanket impl of
Encoder
for allSerializer
s, including adefault
impl forencode_link
-
#[feature(specialization)]
to annotate the additional method as overridable
- requiring impls of
- define a public type whose
serialize
method treats the passedSerializer
as anEncoder
and callsencode_link
, which if not defined by the inputSerializer
will be just the default method impl- this (ideally) would let the type's
serialize
behaviour be configured by theSerializer
/Encoder
, rather than require that external crates define their own equivalentLink
types with customserialize
impls
- this (ideally) would let the type's
In code, this is what it looks like - in crate A:
#![feature(specialization)]
// struct to use in other crates that want to implement an `Encoder` for custom types that include `Link`
struct Link(u8);
impl Serialize for Link {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok>
where
S: serde::Serializer
{
// allowed due to the blanket impl provided above
<S as Encoder>::encode_link(serializer, self)
}
}
trait Encoder: serde::Serializer {
fn encode_link(self, link: &Link) -> Result<Self::Ok>;
}
impl<T> Encoder for T where T: serde::Serializer {
// the default keyword below lets me override this method impl in more specific impls elsewhere
default fn encode_link(self, link: &Link) -> Result<Self::Ok> {
self.serialize_u8(link.0)
}
}
In crate B:
#![feature(specialization)]
use crateA::{Encoder, Link};
struct MyJsonEncoder(serde_json::Serializer);
// &'a mut b/c of `serde_json::Serializer`, otherwise the lifetime changes nothing
impl<'a> Serializer for &'a mut MyJsonEncoder {
// ... delegates all `Serializer` methods to the wrapped `serde_json::Serializer`
}
impl<'a> Encoder for &'a mut MyJsonEncoder {
// ... serialization behaviour for `Link`s specific to this crate's `Encoder`/`Serializer`
// ... allowed b/c of #[feature(specialization)] and the `default` keyword on the blanket method impl`
fn encode_link(self, link: &Link) -> Result<S::Ok> {
self.serialize_none()
}
}
fn main() {
let link = Link(1);
let mut writer = Vec::new();
let mut ser = Encoder(serde_json::Serializer::new(writer));
link.serialize(&mut ser)?;
let string = String::from_utf8(writer).unwrap();
println!("result: {}", string) // prints "1", expected "null"
}
In essence, the issue is that crateA::Link::serialize
only ever calls the default crateA::Encoder::encode_link
, despite me passing in a crateB::MyJsonEncoder
which overrides the default impl.
How do I get Link::serialize
to call any given Serializer
's encode_link
method impl, or the default if not overridden?
UPDATE: I fixed it, and the bug was due to not recursing with my Encoder
but instead recursing with the original Serializer
.