I have a type like this, although my actual type is bigger and more complex:
struct MyType {
i: u32,
}
If I implement Deserialize
for this type, serde looks for something like this (I'm interested in JSON):
{"i":100}
I want to customize it so that I can deserialize from a byte array as well:
[1, 2, 3, 4]
I can write an impl to handle the array, but I want serde to auto generate the rest (which will be visit_map
):
impl<'de> Deserialize<'de> for MyType {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
struct MyTypeVisitor;
impl<'de> Visitor<'de> for MyTypeVisitor {
type Value = MyType;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
write!(formatter, "struct or array of 4 integers")
}
fn visit_seq<A: SeqAccess<'de>>(self, seq: A) -> Result<Self::Value, A::Error> {
// ...
}
}
// deserializer.deserialize_any(MyTypeVisitor)
}
}
Is that possible? In this example, it's not difficult, but when the struct is large, hand writing deserialization can be painful.
This is not a duplicate of How to transform fields during deserialization using Serde? because deserialize_with
works only for 1 field. I can't understand how I would make it work for my real type:
pub enum Component {
String(StringComponent),
Translation(TranslationComponent),
Score(ScoreComponent),
Selector(SelectorComponent),
}
pub struct StringComponent {
#[serde(flatten)] pub base: Base,
pub text: String,
}
pub struct Base {
// ...
extra: Option<Vec<Component>>,
// ...
}
What I want to do is:
- While deserializing, if the input is a number, return a
Component::String
. This can be done withvisit_i
/u
/f64
and friends. - If the input is a string, return a
Component::String
again. This can be done withvisit_str
/string
. - If input is an array
[..]
, deserialize it as usual, but make assign elements in array[1..] to extra of array[0]. This can be done byvisit_seq
. - If input is a map, let serde derive handle it.