Print data from Struct which contains HashMap which in turn contains String and Struct

Hi all
I am writing a little application ( purely for learning purposes ) that queries an API ,parses the JSON response and then will write some of the data to file. As someone has already created a crate for more or less this functionality i have 'borrowed' a couple of Structs that match the JSON output so i don't have to re-write them myself .
I have removed a lot of the lines from the Structs just to keep this post more readable:

#[derive(Debug , Deserialize)]
pub struct FileReportResponse {
    pub response_code: i32,
    pub total: Option<u32>,
    pub scans: Option<HashMap<String, FileScan>>,
}

#[derive(Debug , Deserialize)]
pub struct FileScan {
    pub detected: Option<bool>,
    pub version: Option<String>,
    pub result: Option<String>,
}

This is most of the code so far :

let request_url = format!("https[:]//www[.]virustotal[.]com/vtapi/v2/file/report?apikey={}&resource={}",
		api_key , hash);    // Sanitised the code so you cannot click on it by accident 
let mut response = reqwest::get(&request_url)?;
let returned : FileReportResponse = response.json()?;

for scan in returned.scans.iter(){
		println!("{:#?}  ", scan )
	}

Here is a sample of the output when run :
"TotalDefense": FileScan {
detected: Some(
false,
),
version: Some(
"37.1.62.1",
),
result: None,
update: Some(
"20190902",
),
detail: None,
},
"K7GW": FileScan {
detected: Some(
false,
),
version: Some(
"11.64.31878",
),
result: None,
update: Some(
"20190902",
),
detail: None,

What i cannot figure out is how to specify/reference the above data in my code?
So for example how could i only show the relevant data for TotalDefense ? I am getting very confused and i haven't had success in finding any similar examples on the internet ( i find plenty of examples on how to reference data inside a hash_map but not when this hashmap is 'inside' a struct' and also contains its own 'struct .
Any help would be great.

Hi, here is a (verbose) way to go access deeper and deeper elements in your struct:

let opt_scans: &Option<HashMap<String, FileScan>> = &returned.scans;
if let Some(scans) = opt_scans { // this `if let` handles the outer `Option`
    let _: &HashMap<String, FileScan> = scans; // type checks
    if let Some(total_defense) = scans.get("TotalDefense") {
        let _: &FileScan = total_defense; // type_checks
        let _: &Option<bool> = &total_defense.detected;
        let _: &Option<String> = &total_defense.version;
        let _: &Option<String> = &total_defense.result;
        match total_defense.detected {
            | Some(true) => { /* handle detected present and `true` */ },
            | Some(false) => { /* handle detected present and `false` */ },
            | None => { /* handle detected missing */ },
        }
        // etc.
    } else {
        // handle no entry at key "TotalDefense"
    }
} else {
    // handle opt_scans = None
}
1 Like

Thanks s much for the information , way more in depth than i ever hoped for ( and given me new things to go learn about :smile: ) so again thanks a lot!

1 Like