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 notString
,"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();
}
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"
}
]"#;
...