4

I am completely new to Rust coming from JS/TS

I have already seen other questions like: How do I iterate over elements of a struct in Rust? but they didn't get me to a real answer.

I am trying to iterate over the keys and values of a struct in rust

In JS/TS this would work like this:

const o = {
    a: "hello",
    b: "world"
};

const keys = Object.keys(o);
const values = Object.values(o);

// now loop over them 

How would something like this work in Rust?

I am using Serde to parse a config yaml file to a struct.


#[derive(Deserialize, Debug, Clone)]
pub struct Config {
    pub headers: Headers,
}

#[derive(Deserialize, Debug, Clone)]
pub struct Headers {
    #[serde(rename = "Content-Security-Policy")]
    pub content_security_policy: String,
    #[serde(rename = "x-frame-options")]
    pub x_frame_options: String,
    #[serde(rename = "x-content-type-options")]
    pub x_content_type_options: String,
    #[serde(rename = "x-permitted-cross-domain-policies")]
    pub x_permitted_cross_domain_policies: String,
    #[serde(rename = "x-download-options")]
    pub x_download_options: String,
    #[serde(rename = "x-xss-protection")]
    pub x_xss_protection: String,
    #[serde(rename = "referrer-policy")]
    pub referrer_policy: String,
    #[serde(rename = "Strict-Transport-Security")]
    pub strict_transport_security: String,
    #[serde(rename = "feature-policy")]
    pub feature_policy: String,
    #[serde(rename = "Cache-Control")]
    pub cache_control: String,
}

But this does not implement the .iter() function and i haven't found a solution searching for this.

firstdorsal
  • 401
  • 5
  • 17
  • 1
    Does this answer your question? [How do I iterate over elements of a struct in Rust?](https://stackoverflow.com/questions/38111486/how-do-i-iterate-over-elements-of-a-struct-in-rust) – Chayim Friedman Mar 30 '22 at 11:33
  • No this just leads down to another question that is even further away from an answer – firstdorsal Mar 30 '22 at 11:37
  • 3
    You cant iterate over structs in rust. But since you're already using serde, you could use that to convert your struct to something that can be iterated, e.g. a `HashMap`. See [here](https://stackoverflow.com/questions/57477967/how-can-i-use-serde-to-serialize-a-struct-to-another-rust-data-structure). – Caesar Mar 30 '22 at 11:38
  • It says pretty explicitly: "No. You have to implement it yourself, or find a macro / compiler plugin that will do it for you.". – Chayim Friedman Mar 30 '22 at 11:47

2 Answers2

4

Thanks to Caesar

I tried this:


use serde::{Deserialize, Serialize};

#[derive(Deserialize, Debug, Clone, Serialize)]
pub struct Config {
    pub headers: Headers,
}

#[derive(Deserialize, Debug, Clone, Serialize)]
pub struct Headers {
    #[serde(rename = "Content-Security-Policy")]
    pub content_security_policy: String,
    #[serde(rename = "x-frame-options")]
    pub x_frame_options: String,
    #[serde(rename = "x-content-type-options")]
    pub x_content_type_options: String,
    #[serde(rename = "x-permitted-cross-domain-policies")]
    pub x_permitted_cross_domain_policies: String,
    #[serde(rename = "x-download-options")]
    pub x_download_options: String,
    #[serde(rename = "x-xss-protection")]
    pub x_xss_protection: String,
    #[serde(rename = "referrer-policy")]
    pub referrer_policy: String,
    #[serde(rename = "Strict-Transport-Security")]
    pub strict_transport_security: String,
    #[serde(rename = "feature-policy")]
    pub feature_policy: String,
    #[serde(rename = "Cache-Control")]
    pub cache_control: String,
}

let iterable_headers: HashMap<String, String> =
 serde_yaml::from_value(serde_yaml::to_value(&config.headers).unwrap()).unwrap();

for header in &iterable_headers {
    res = res.header(header.0, header.1);
}

firstdorsal
  • 401
  • 5
  • 17
2

You can use struct_iterable crate.

use struct_iterable::Iterable;
            
#[derive(Iterable)]
struct MyStruct {
    field1: u32,
    field2: String,
    field3: Option<String>,
    // etc.
}
    
let my_instance = MyStruct {
    field1: 42,
    field2: "Hello, world!".to_string(),
    field3: Some("Hello, world!".to_string()),
};
    
for (field_name, field_value) in my_instance.iter() {
    if let Some(string_opt) = field_value.downcast_ref::<Option<String>>() {
        if let Some(string) = string_opt.as_deref() {
            println!("{} optional String: {:?}", field_name, field_value);
        }
    }
    println!("{}: {:?}", field_name, field_value);
}