Deserialize JSON array into tuple and give it type tags

1.2k Views Asked by At

I have JSON that looks like:

[{"range": [1, 2]}, {"range": [2, 5]}]

The objects in array have fields other than range of course, but it doesn't matter.

Would it be possible to deserialize them into tuples that have two phantom types to indicate whether the start and end are inclusive or exclusive automatically?

This could also be solved with deserialzing numbers into some kind of tuples with phantom types.

#[macro_use]
extern crate serde_derive;
extern crate serde_json;

use std::marker::PhantomData;

#[derive(Debug)]
struct Inclusive;
#[derive(Debug)]
struct Exclusive;

#[derive(Deserialize)]
struct Range<S, E, V: Ord>(Option<V>, Option<V>, PhantomData<S>, PhantomData<E>);

fn main() {
    let data = "[1, 2]";
    let r: Range<Inclusive, Exclusive, i32> = serde_json::from_str(data).expect("Error");
    println!("Range from {:?} to {:?}", r.0, r.1);
}

This doesn't work because serde_json seems to be ignorant about PhantomData and expects arrays of size 4, which can be solved by implementing Deserializer manually, which is exactly the thing I'd like to avoid.

I don't have high hopes, but maybe this can be done and I don't know something.

1

There are 1 best solutions below

2
On

You seem to want serde to ignore certain fields entirely. That can be done with #[serde(skip)]. Serde will fetch a default value from Default::default(), which is available for PhantomData.

#[derive(Debug, Deserialize)]
struct Range<S, E, V: Ord>(
    Option<V>,
    Option<V>,
    #[serde(skip)] PhantomData<S>,
    #[serde(skip)] PhantomData<E>,
);

Playground

On (possibly) a side note, if your types Inclusive and Exclusive are always unit-like and not singletons, you might consider holding them directly instead of PhantomData, since they will also be zero-sized.

#[derive(Debug, Default)]
struct Inclusive;
#[derive(Debug, Default)]
struct Exclusive;

#[derive(Deserialize)]
struct Range<S, E, V: Ord>(
    Option<V>,
    Option<V>,
    #[serde(skip)] S,
    #[serde(skip)] E,
);