0

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.

1
  • I think you'd probably need to deserialize the third next_element into some sort of intermediate representation - e.g. a StructOrString enum. Then you could match on that to determine what to expect for the remaining elements. Commented Nov 23, 2022 at 11:47

1 Answer 1

2

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

Previous struct version in playground

@cafce25's example in the playground

Sign up to request clarification or add additional context in comments.

3 Comments

Yea that's about what I came up with too.
The tuple variant is probably cleaner, I will update my answer
This works wonderfully, thanks! It's very close to what I initially attempted, using struct syntax instead of tuples, which doesn't work.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.