Tengo un tipo como este, aunque mi tipo real es más grande y más complejo:
struct MyType {
i: u32,
}
Si implemento Deserialize
para este tipo, serde busca algo como esto (estoy interesado en JSON):
{"i":100}
Quiero personalizarlo para poder deserializar desde una matriz de bytes también:
[1, 2, 3, 4]
Puedo escribir un impl para manejar la matriz, pero quiero que serde genere automáticamente el resto (que será 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)
}
}
¿Es eso posible? En este ejemplo, no es difícil, pero cuando la estructura es grande, la deserialización a mano puede ser dolorosa.
Esto no es un duplicado de ¿Cómo transformar campos durante la deserialización utilizando Serde? porque deserialize_with
Funciona solo para 1 campo. No puedo entender cómo lo haría funcionar para mi tipo real:
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>>,
// ...
}
Lo que quiero hacer es:
- Durante la deserialización, si la entrada es un número, devuelva un
Component::String
. Esto se puede hacer convisit_i
/u
/f64
y amigos. - Si la entrada es una cadena, devuelve un
Component::String
otra vez. Esto se puede hacer convisit_str
/string
. - Si la entrada es una matriz
[..]
, deserialícelo como de costumbre, pero asigne elementos en la matriz [1 ..] a extra de la matriz [0]. Esto se puede hacer porvisit_seq
. - Si la entrada es un mapa, deje que serde derive lo maneje.
Respuestas
1 para la respuesta № 1los Serde documentacion tiene un ejemplo que muestra cómo implementar deserialización desde ya sea una cadena o una estructura. Esto es equivalente a tu caso, solo que más pequeño.
La parte importante es esta:
fn visit_map<M>(self, visitor: M) -> Result<T, M::Error>
where
M: MapAccess<"de>,
{
Deserialize::deserialize(de::value::MapAccessDeserializer::new(visitor))
}
Esto delega a la implementación de deserialización incorporada. Ya que todos sus otros casos son personalizados, esto debería ser adecuado.