Converting Ruby to Rust JSON Parsing

Hi,
I am new to rust and I am trying to convert this ruby script into rust:
file = File.open("aws_reserved", "rb")
reserved = file.read
res = JSON.parse(reserved)
reservations = {}
res["ReservedInstances"].each do |reservation|
key = reservation["InstanceType"] # + "/" + reservation["AvailabilityZone"]
reservations[key] = 0 if reservations.has_key?(key) == false
reservations[key] += reservation["InstanceCount"] if reservation["State"] == "active"
end
Essentially this section of the script opens a file and JSON parses it. Afterwards it uses a for each loop, putting "ReservedInstances" from res into reservation. Then depending on the conditions it adds values into reservations. My attempt for tackling this in rust:

let mut file = File::open("aws_reserved").expect("File can't be opened.");
let mut reserved = String::new();
file.read_to_string(&mut reserved).expect("File can't be read");
let res: serde_json::Value =
serde_json::from_str(&reserved).expect("Json was not well formatted.");
let mut reservations:Vec = Vec::new();
for reservation in res.get("ReservedInstances").iter(){
let key = reservation["InstanceType"];
if reservations.contains(&key){
reservations[key] = 0;
}
if reservation["State"] == "active"{
reservations[key].push(reservation["InstanceCount"]);
}
}
The JSON part seems to be working fine, but I'm having trouble with the loop. The issue is creating an equivalent for each loop. The iter statement works fine, but if I under stand the for each in ruby, it puts the value in reservation. I've tried reservation.push(res.get("InstanceType")), but I reach an error. I believe I'm not understanding the code properly. Because of this, reservations.contains(&key) gives me a mismatched type error as it expects a string instead of the enum 'Option'. Likewise that causes reservations[key] = 0 along with reservations[key].push... I would appreciate some insight clarifying my misunderstandings of the code.
Thanks.

Welcome! Please read the pinned code formatting post so that it is easier to help you.

I haven't used Ruby much, and thus may have gotten something wrong, but here's my take.

use std::collections::HashMap;
use std::fs::File;
use std::io::Read;

fn main() {
    // Open the file: `file = File.open("aws_reserved", "rb")`
    let mut file = File::open("aws_reserved").expect("File can't be opened.");

    // Read the file: `reserved = file.read`
    let mut reserved = String::new();
    file.read_to_string(&mut reserved)
        .expect("File can't be read");

    // Parse it as JSON: `res = JSON.parse(reserved)`
    let res: serde_json::Value =
        serde_json::from_str(&reserved).expect("Json was not well formatted.");

    // Create a new `HashMap`: `reservations = {}`
    let mut reservations = HashMap::new();

    // Iterate over reserved instances: `res["ReservedInstances"].each do |reservation|`
    for reservation in res.get("ReservedInstances").iter() {
        // If the key is a string type... ~: `key = reservation["InstanceType"]`
        if let Some(key) = reservation["InstanceType"].as_str() {
            // Initialize the value to 0 if it's not in the `HashMap`:
            //   `reservations[key] = 0 if reservations.has_key?(key) == false`
            let value = reservations.entry(key).or_insert(0);
            // If the state is active, add value:
            //   `reservations[key] += reservation["InstanceCount"] if reservation["State"] == "active"`
            if reservation["State"] == "active" {
                *value += reservation["InstanceCount"].as_u64().unwrap_or(0);
            }
        }
    }
}
1 Like

Thanks, the solution worked for me. I completely forgot about hashmaps! I'll have to look at some videos/tutorials on how to use them in rust. Thanks again for your help.

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.