#251 landed the buffa-remote-derive crate (ProtoString/ProtoBytes/ProtoList/ProtoBox/MapStorage derives for newtypes over remote types), scoped to the binary codec only. This issue tracks the remaining piece of #212's design sketch: optionally generating the feature-gated forwarders so a derived newtype is usable in JSON, fuzzing, and reflection builds without hand-written impls.
What the derives currently do not generate, and where the gap bites:
- serde forwarders — a string newtype used as a repeated element, an
optional field, or a map value serializes through its own Serialize/Deserialize; without them a generate_json(true) build fails with a trait-bound error deep in generated message code. (Bytes newtypes are exempt: all bytes positions route through the base64 with-modules.) The crate docs' "Scope: the binary codec only" section documents the current hand-written workaround (#[derive(serde::Serialize, serde::Deserialize)] + #[serde(transparent)]).
arbitrary::Arbitrary — needed for fuzz targets that construct messages containing the newtype.
- reflection (
ReflectList/ReflectMap) — needed for vtable-reflection builds where the newtype backs a repeated or map field.
Design questions to settle before implementing:
- Feature flags on the derive crate (
json/arbitrary/reflect) versus derive-attribute opt-ins (#[buffa(serde)]); a proc-macro crate's features are unified across the dependency graph, which argues for per-derive attributes.
- Whether the serde forwarder should be
#[serde(transparent)]-equivalent (delegate to the remote type's serde) or route through AsRef/From like buffa's own with-modules, which would drop the remote-type-must-support-serde requirement.
Until then, the hand-written pattern in examples/custom-types/src/types/ is the reference, and the per-position serde matrix lives in that example's README.
#251 landed the
buffa-remote-derivecrate (ProtoString/ProtoBytes/ProtoList/ProtoBox/MapStoragederives for newtypes over remote types), scoped to the binary codec only. This issue tracks the remaining piece of #212's design sketch: optionally generating the feature-gated forwarders so a derived newtype is usable in JSON, fuzzing, and reflection builds without hand-written impls.What the derives currently do not generate, and where the gap bites:
optionalfield, or a map value serializes through its ownSerialize/Deserialize; without them agenerate_json(true)build fails with a trait-bound error deep in generated message code. (Bytes newtypes are exempt: all bytes positions route through the base64with-modules.) The crate docs' "Scope: the binary codec only" section documents the current hand-written workaround (#[derive(serde::Serialize, serde::Deserialize)]+#[serde(transparent)]).arbitrary::Arbitrary— needed for fuzz targets that construct messages containing the newtype.ReflectList/ReflectMap) — needed for vtable-reflection builds where the newtype backs arepeatedormapfield.Design questions to settle before implementing:
json/arbitrary/reflect) versus derive-attribute opt-ins (#[buffa(serde)]); a proc-macro crate's features are unified across the dependency graph, which argues for per-derive attributes.#[serde(transparent)]-equivalent (delegate to the remote type's serde) or route throughAsRef/Fromlike buffa's own with-modules, which would drop the remote-type-must-support-serde requirement.Until then, the hand-written pattern in
examples/custom-types/src/types/is the reference, and the per-position serde matrix lives in that example's README.