Serde's documentation says that it supports deserializing to OsString
, albeit in some sort of indirect way that I'm not clear how to use. Trying to deserialize to OsString
naïvely with:
use serde::{Serialize, Deserialize};
use std::error::Error;
use std::ffi::OsString;
use std::path::PathBuf;
#[derive(Serialize, Deserialize, Debug)]
struct Config {
#[serde(default)]
dirpaths: Vec<PathBuf>,
#[serde(default)]
filenames: Vec<OsString>,
}
fn main() -> Result<(), Box<dyn Error>> {
let input = r#"{
"dirpaths": ["/usr/src", "/home/me"],
"filenames": ["foo", "bar"],
}"#;
let cfg: Config = serde_json::from_str(input)?;
println!("{cfg:#?}");
Ok(())
}
fails with:
Error: Error("unknown variant `foo`, expected `Unix` or `Windows`", line: 3, column: 23)
What exactly do I need to do to be able to deserialize to an OsString
?
First a clarification: the docs you linked to are just an import of std
docs/types.
OsString
is an enum in the model, and this works:
let input = r#"{
"dirpaths": ["/usr/src", "/home/me"],
"filenames": [{ "Unix": [102, 111, 111] }, { "Unix": [98, 97, 114] }]
}"#;
PathBuf
will only actually work with paths that could be String
s, which is quite dishonest IMO. (Supporting non-UTF8 paths is a main motivator for supporting OsString
s.)
n.b. I'm not a serde
expert and there may be a better way.
I'm not about to change the input format for my program to look like {"Unix": [102, 111, 111]}
. So far, the only way I can see to get strings in JSON or TOML to deserialize to OsString
s is to use an intermediate struct with String
fields and an impl From<IntermediateConfig> for Config
implementation plus serde's #[serde(from = "IntermediateConfig")]
. Does anyone know of a better way?
1 Like
That's what I would do. Almost all JSON strings are encoded as UTF-8 anyway, so it's not really possible for your end users to put a non-UTF-8 string in the file unless they want to write the bytes out as an array of numbers. If you want to support both, then I would probably create my own serialize()
and deserialize()
implementations using the #[serde(with = ...)]
attribute that fits what you want.
1 Like