Rust Serde Json Struct

Here's the context for the code:

#[derive(serde::Deserialize)]
#[serde(rename_all = "PascalCase")]
struct Instance {
 //instance_lifecycle: String,
placement: Placement,
r#type: String,
tags: Vec<InstanceTag>,
instance_id: String,
}
let instances_list: InstancesList = 
        serde_json::from_str(&instances).expect("Json was not well formatted.");

for reservation in &instances_list.reservations{
        for instance in &reservation.instances{
            //if instance.life_cycle == "spot"
            if instance["Lifecycle"] == "spot"{
                continue; 
            }

Originally, I had "Lifecycle" as part of the Instance struct, but the file I'm parsing essentially looks like:

Reservations: {
       Instances: {
        a: .......
        b:.......
        c:........
        d:........
       }
       Instances:{
        a: .......
        b:.......
        c:........
        d:........
        Lifecycle:.....
       }
}

And only one of the Instances has a "Lifecycle", and the other doesn't. So originally I had Lifecycle as part of the Instance struct, but that leads to a JSON parsing error since it doesn't appear in one of the Instances in the file(shown through comments in the code). As a result, I need to check if Lifecycle is in Instances so I tried:

if instance["Lifecycle"] == "spot"{

However, I get the following error:
error[E0608]: cannot index into a value of type &Instance

   --> src/main.rs:116:16
    |
116 |             if instance["Lifecycle"] == "spot"{
    |                ^^^^^^^^^^^^^^^^^^^^^

Would appreciate any input. Thanks for your time and help.

If your struct doesn't have a field corresponding to Lifecycle then it will simply be ignored when the JSON is parsed. In your example code an Instance will never contain a Lifecycle.

For a field that is sometimes there and sometimes not, make it optional with Option.

#[derive(serde::Deserialize)]
#[serde(rename_all = "PascalCase")]
struct Instance {
    lifecycle: Option<String>,
    placement: Placement,
    r#type: String,
    tags: Vec<InstanceTag>,
    instance_id: String,
}

You can then check for its contents with

if instance.lifecycle.as_ref().map(|lc| lc == "spot").unwrap_or_default() {
    continue;
}

In this case, Option::unwrap_or_default will either return the result of the comparison or false if lifecycle is None and there's nothing to compare.

edit: fixed the second example, thanks @steffahn

2 Likes

maybe something like instance.lifecycle.as_deref() == Some("spot") is more readable.

(Also your version tries to consume the lifecycle which doesn't work behind a reference, so you might be missing an as_ref() call.)

2 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.