Deserialize an array?

I'm using serde_json to deserialize data that comes in fixed-sized lists in the file, that gets reformatted into a structure. I'm currently successfully reading in the raw data, but I have to do it as a Vec, and manually check that the size is right.

Is there a way to read this in as an array? I.e., below I'm reading a Vec::, then checking that its length is 5 -- I'd rather read an [f64; 5] directly.

https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=8930aa55832a862bfddc3f7c41f3aefb

#![allow(unused)]

use ndarray::{Array1, Array2, Array3, Axis, array};
use serde::{Deserialize, Deserializer};

#[derive(Debug, PartialEq)]
struct Bob {
    a: f64, b: f64, c: f64, d: f64, e: f64, 
}

impl<'de> Deserialize<'de> for Bob {
    /// Deserialize a JSON file
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where D: Deserializer<'de>
    {
        // Gee, it would be nice to read an array here
        let coef = Vec::<f64>::deserialize(deserializer)?;
        if coef.len() != 5 {
            return Err(serde::de::Error::invalid_length(
                coef.len(), 
                &"5")
            )
        }
        let r = Self {
            a: coef[0],
            b: coef[1],
            c: coef[2],
            d: coef[3],
            e: coef[4],
        };

        Ok(r)
    }
}

fn main () {
    let bob: Bob = serde_json::from_str(r#"[1.0, 2.0, 3.0, 4.0, 5.0]"#).unwrap();
    println!("{:?}", bob);
}

Sure, you can use <[f64; 5]>::deserialize.

2 Likes

I'm not sure how close your Bob struct is to your actual data, but at least for the provided example, you can reduce the code to this:

#[derive(Debug, PartialEq, serde::Deserialize)]
struct Bob {
    a: f64, b: f64, c: f64, d: f64, e: f64, 
}

fn main () {
    let bob: Bob = serde_json::from_str(r#"[1.0, 2.0, 3.0, 4.0, 5.0]"#).unwrap();
    println!("{:?}", bob);
}

You can simply derive the Deserialize trait, and it will do the correct thing. The derived Deserialize implementation is quite clever and can also deserialize from a sequence. The fields of the struct are simply filled in declaration order.

If you want the same behavior also for the Serialize implementation you need a crate. With serde_tuple you can derive matching implementations. The Deserialize implementation provided by serde_tuple only supports sequences and will fail otherwise.

1 Like

Thank you both. I wish I could mark both answers as solutions.

Somehow, Captain Obvious did not visit me this morning, so I didn't try the obvious with the simple structure.

And it wasn't apparent to me how to make the array work: I was trying [f64; 5]::deserialize, which the compiler did not like at all.

@jonasbb : It'll work. The stuff in the file is in a nonintuitive ordering, but I can deal with non-intuitive ordering in the structure.