I have some JSON of this format:
[
123,
{“some struct”: “is always here”},
{“optional struct”: ”is not always here”},
“String1”,
“String2”
]
Note that the second struct is sometimes not present - the array will sometimes contain 4 elements, other times 5. This means that seq[1]
is always the struct, but seq[2]
may either be the struct or String1.
I’ve written a custom Deserialize
using the SeqAccess
visitor, looking something like this:
let number: usize = v.next_element()?;
let struct: SomeStruct = v.next_element()?;
let maybe_struct: OtherStruct = v.next_element()?;
// …
The problem is that calling v.next_element()
where the struct is NOT present, it wants to deserialise immediately into OtherStruct
, which fails because the next element is String1
. If I call v.next_element()
again, the visitor has already moved onto the next element, and I’ll get String2
.
I think I’m looking at this wrong and probably need to write a visitor which receives a method call for each element in the sequence, I’ve not been able to locate any examples or documentation that explains how to do this.
You should be able to do this without using a custom deserializer if you wrap the combinations in an enum and use serde's untagged attribute.
Something like this should work
use serde::Deserialize;
use serde_json::from_str;
#[derive(Debug, Deserialize)]
#[serde(untagged)]
enum Either {
Four(i32, SomeStruct, String, String),
Five(i32, SomeStruct, OtherStruct, String, String),
}
pub fn main() {
let src_with_four = todo!();
let src_with_five = todo!();
let f1 = from_str::<Either>(src_with_four);
let f2 = from_str::<Either>(src_with_five);
println!("{f1:?}");
println!("{f2:?}");
}
Updated to use tuple variants directly based on @cafce23's comment