How to insert the contents of a json object into a struct containing vectors?


#1

How to insert the below json string into the Data struct?
That is how to push each of the json fields onto the vectors of strings for each json entry?

From reading the book it seems like Option should be used when the values of rgb_value or hex_value are missing and I am confused about this.

    [
    	{
    		type: "red",
    		rgb_value: "(255,0,0)"
    	},
    	{
    		type: "green",
    		hex_value: "#0f0"
    	},
    	{
    		type: "blue",
    		hex_value: "#00f"
    	},
    	{
    		type: "cyan",
    		hex_value: "#0ff"
    	},
    	{
    		type: "magenta",
    		hex_value: "#f0f"
    	},
    	{
    		type: "yellow",
    		rgb_value: "(255,255,0)"
    	},
    	{
    		type: "black",
    		rgb_value: "(0,0,0)"
    	}
    ]

How to iterate over the above json object and push the contents of each json observation onto the vectors?

    struct Data {
    	pub color: Vec<String>,
    	pub hex_value: Vec<String>,
    	pub rgb_value: Vec<String>,
    }

From reading the book it looks like Enums could be used to encode the color values however I’d prefer them to be kept in a struct directly.


#2

You may want to use an enum instead. For example, that blob of JSON could be turned into a Vec<Colour>, where Colour is defined as:

pub struct Colour {
  /// The colour's name (`type` is a Rust keyword).
  name: String,
  /// How the colour was defined (e.g. `rgb(1, 2, 3)` or `#123`).
  colour_value: ColourValue,
}

pub enum ColourValue {
  RGB(u8, u8, u8),
  Hex(String),
}

Note that I’m using an array-of-struct way of representing things (which is the JSON’s direct equivalent), whereas the Data struct you defined is a struct-of-arrays.


#3

This was cross-posted to Stack Overflow.


#4

A type to deserialize this directly using serde (into its unfortunately stringly-typed parts) would be

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

#[derive(Debug, Clone)]
#[derive(Serialize, Deserialize)]
pub struct RawRgb {
    #[serde(rename = "type")]
    name: String,
    rgb_value: String,
}

#[derive(Debug, Clone)]
#[derive(Serialize, Deserialize)]
pub struct RawHex {
    #[serde(rename = "type")]
    name: String,
    hex_value: String,
}

#[derive(Debug, Clone)]
#[derive(Serialize, Deserialize)]
#[serde(untagged)]
pub enum RawColor {
    Rgb(RawRgb),
    Hex(RawHex),
}

fn main() {
    let stringly_colors: Vec<RawColor> = ::serde_json::from_value(json!([
        {"type": "red", "rgb_value": "(255,0,0)"},
        {"type": "green", "hex_value": "#0f0"},
        {"type": "blue", "hex_value": "#00f"},
        {"type": "cyan","hex_value": "#0ff"},
        {"type": "magenta", "hex_value": "#f0f"},
        {"type": "yellow", "rgb_value": "(255,255,0)"},
        {"type": "black", "rgb_value": "(0,0,0)"}
    ])).unwrap();
    
    for x in stringly_colors {
        println!("{:?}", x);
    }
}
Rgb(RawRgb { name: "red", rgb_value: "(255,0,0)" })
Hex(RawHex { name: "green", hex_value: "#0f0" })
Hex(RawHex { name: "blue", hex_value: "#00f" })
Hex(RawHex { name: "cyan", hex_value: "#0ff" })
Hex(RawHex { name: "magenta", hex_value: "#f0f" })
Rgb(RawRgb { name: "yellow", rgb_value: "(255,255,0)" })
Rgb(RawRgb { name: "black", rgb_value: "(0,0,0)" })

Post-processing data in this form could be easier.