How to create a struct from key value pair?

I need to know how to desterilize some key value pairs into a struct in rust.

I have some key=value like this:

key = value
key = value2
num = 255
struct Data {
    key: Vec<String>,
    num: u8
}

let data: Data = parse(input)?;
fn parse(input: Input) -> Result<...> {
    // how to parse key, value into struct?
    for (key, value) in input {
        // ...
    }
}

Also see in stackoverflow

Hello @Rohan

Not really sure I understood your intended solution. Do you mean something like this?

use std::collections::HashMap;
use url::Url; // 2.2.2
type GenericError = Box<dyn std::error::Error + Send + Sync>;
type Result<T> = std::result::Result<T, GenericError>;

fn main() -> Result<()> {
    parse()?;
    Ok(())
}

#[derive(Debug)]
struct Data {
    key: HashMap<String, Vec<String>>,
}

fn parse() -> Result<()> {
    let input = Url::parse("http://www.example.com/path?key=value&key=value2&num=255")?;
    let mut data = Data {
        key: HashMap::new(),
    };
    for (key, value) in input.query_pairs() {
        let key_str = key.to_string();
        if !data.key.contains_key(&key_str) {
            data.key.insert(key.to_string(), Vec::new());
        }
        data.key
            .get_mut(&key.to_string())
            .unwrap()
            .push(value.to_string());
    }
    println!("{:?}", data);
    Ok(())
}

which then prints

Data { key: {"key": ["value", "value2"], "num": ["255"]} }

Stefan

result should look like this, Data { key: ["value", "value2"], num: 255 }, also Data struct could be anything.

The data struct cannot be anything. It must be determined at compile time.

1 Like

Hello @Rohan

You could have something like this - although I don't consider this as a good solution. Since your query string can change.

use url::Url; // 2.2.2
type GenericError = Box<dyn std::error::Error + Send + Sync>;
type Result<T> = std::result::Result<T, GenericError>;

fn main() -> Result<()> {
    parse()?;
    Ok(())
}

#[derive(Debug)]
struct Data {
    key: Vec<String>,
    num: u8,
}

fn parse() -> Result<()> {
    let input = Url::parse("http://www.example.com/path?key=value&key=value2&num=255")?;
    let mut keys: Vec<String> = Vec::new();
    let mut num: u8 = 0;
    for (key, value) in input.query_pairs() {
        if key.eq("key") {
            keys.push(value.to_string())
        } else if key.eq("num") {
            num = value.to_string().parse()?;
        }
    }
    println!("{:?}", Data { key: keys, num });
    Ok(())
}

prints

Data { key: ["value", "value2"], num: 255 }

Now the struct is bound to the query string, which I would consider a bad solution, since new query string, new implementation.

Stefan

This answer was already rejected in the StackOverflow thread:

@Netwave , Data struct could be anything... not only { key, num }Stone 2 hours ago

Rohan, Rust is a compiled language, and structs are not simple key-value stores. A Rust struct doesn't have a definition that can be created at runtime, and their fields cannot be accesses based on string values.

You can parse it into an open struct, as sdoerig describes, or you can parse it into a known struct using serde or some other manual parsing function. You cannot create a value for struct that you have not previously defined in source code.