Home > database >  Parsing Yaml file
Parsing Yaml file

Time:05-13

For the last 3 days now, I tried to figure out how to parse my yaml in Rust. And I can't figure out why it doesn't work.

My Yaml:

default_verbosity: 0
logging:
  use_color: True,
  log_color: 
    fatal: Red,
    error: Red,
    warn: Red,
    info: Green,
    debug: Blue,
    trace: Yellow
  log_output: file,
  file_location: "example.log"
rocket: 
  mount_location: "/",
  port: 8000

But my programm failes at the unwrap line: let myYaml: Config = serde_yaml::from_reader(yamlFile).unwrap(); with this error message:

thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: 
Scan(ScanError { mark: Marker { index: 284, line: 14, col: 21 }, info: "while parsing 
a block mapping, did not find expected key" })', src/main.rs:41:60

My program:

use std::fs::File;

extern crate serde_yaml;

#[macro_use]
extern crate serde_derive;

#[derive(Debug, Serialize, Deserialize)]
struct ColorStruct {
    fatal: String,
    error: String,
    warn:  String,
    info:  String,
    debug: String,
    trace: String   
}

#[derive(Debug, Serialize, Deserialize)]
struct LoggingStruct {
    use_color:     bool,
    log_color:     Vec<ColorStruct>,
    log_output:    String,
    file_location: String 
}

#[derive(Debug, Serialize, Deserialize)]
struct RocketStruct {
    mount_location: String,
    port:          String
}

#[derive(Debug, Serialize, Deserialize)]
struct Config {
    default_verbosity: i32,
    logging:           Vec<LoggingStruct>,
    rocket:            Vec<RocketStruct>
}

fn main(){
    let yamlFile = File::open("config.yaml").unwrap();
    let myYaml: Config = serde_yaml::from_reader(yamlFile).unwrap();
}

I am really frustrated by this. What am I doing wrong? Am I missing something in my structs?

CodePudding user response:

Both your schema and your yaml were wrong. Main reasons:

  • You should have nested structs, not Vec.
  • Your yaml types were not accurate, for example True is string, true is bool. 8000 is not String, "8000" is.
use std::fs::File;
use serde_yaml; // 0.8.23
use serde::{Serialize, Deserialize};

#[derive(Debug, Serialize, Deserialize)]
struct ColorStruct {
    fatal: String,
    error: String,
    warn:  String,
    info:  String,
    debug: String,
    trace: String   
}

#[derive(Debug, Serialize, Deserialize)]
struct LoggingStruct {
    use_color:     bool,
    log_color:     ColorStruct,
    log_output:    String,
    file_location: String 
}

#[derive(Debug, Serialize, Deserialize)]
struct RocketStruct {
    mount_location: String,
    port:          String
}

#[derive(Debug, Serialize, Deserialize)]
struct Config {
    default_verbosity: i32,
    logging:           LoggingStruct,
    rocket:            RocketStruct
}

fn main(){
    let yamlFile = r#"default_verbosity: 0
logging:
  use_color: true
  log_color: 
    fatal: "Red"
    error: "Red"
    warn: "Red"
    info: "Green"
    debug: "Blue"
    trace: "Yellow"
  log_output: "file"
  file_location: "example.log"
rocket: 
  mount_location: "/"
  port: "8000""#;
    let myYaml: Config = serde_yaml::from_str(yamlFile).unwrap();
}

Playground

If you really want to use Vec as part of your original schema, you would need some changes:

  • Probably ColorStruct should be an enum, but if not you just need to keep as the remaining examples.
  • Your yaml need to provide the data correcly too to match those types.

#[derive(Debug, Serialize, Deserialize)]
enum ColorStruct {
    fatal(String),
    error(String),
    warn(String),
    info(String),
    debug(String),
    trace(String),
}

...

let yamlFile = r#"default_verbosity: 0
logging: [
    {
        log_output: "file",
        file_location: "example.log",
        use_color: true,
        log_color: [
            { fatal: "Red" },
            { error: "Red" },
            { warn: "Red" },
            { info: "Green" },
            { debug: "Blue" },
            { trace: "Yellow" }
        ]
    }
]

rocket:  [
    {
        mount_location: "/",
        port: "8000"
    }
]"#;

...

Playground

  • Related