Often a type implements Display and FromStr but not Serialize and Deserialize.
The module from https://github.com/serde-rs/json/issues/329#issuecomment-305608405 should work.
#[macro_use]
extern crate serde_derive;
extern crate serde;
extern crate serde_json;
use std::fmt::{self, Display};
use std::str::FromStr;
#[derive(Debug)]
struct X;
impl Display for X {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("X")
}
}
impl FromStr for X {
type Err = &'static str;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"X" => Ok(X),
_ => Err("was not X"),
}
}
}
#[derive(Serialize, Deserialize, Debug)]
struct S {
#[serde(with = "string")]
x: X
}
mod string {
use std::fmt::Display;
use std::str::FromStr;
use serde::{de, Serializer, Deserialize, Deserializer};
pub fn serialize<T, S>(value: &T, serializer: S) -> Result<S::Ok, S::Error>
where
T: Display,
S: Serializer
{
serializer.collect_str(value)
}
pub fn deserialize<'de, T, D>(deserializer: D) -> Result<T, D::Error>
where
T: FromStr,
T::Err: Display,
D: Deserializer<'de>
{
String::deserialize(deserializer)?.parse().map_err(de::Error::custom)
}
}
fn main() {
let j = r#" { "x": "X" } "#;
let s: S = serde_json::from_str(j).unwrap();
println!("{:#?}", s);
println!("{}", serde_json::to_string_pretty(&s).unwrap());
}
I came here to suggest a simple way to do exactly this. I think it would be great if serde would provide a way to do that with some kind of derive-like thing.
However, in the case of deserialization, we should try avoid the unnecessary allocation of String
. Since FromStr
takes a &str
, it should be possible to use a str directly using a visitor implementation.
An alternative I cooked up from the original description: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=2b642a9a0b8747fe59e9190cc273810c or with some fixed typos and added deref and derefmut in rs-ipfs/rust-ipfs/.../http/src/v0/support/serdesupport.rs which might be of interest to someone. Apologies if this wrapper is already in serde, but let me know please? :)
Wouldn't it be possible to do something like this:
#[derive(Serialize, Deserialize)]
#[serde(stringify)]
pub MyType { ... }
impl fmt::Display for MyType { ... }
impl str::FromStr for MyType { ... }
Most helpful comment
I came here to suggest a simple way to do exactly this. I think it would be great if serde would provide a way to do that with some kind of derive-like thing.
However, in the case of deserialization, we should try avoid the unnecessary allocation of
String
. SinceFromStr
takes a&str
, it should be possible to use a str directly using a visitor implementation.