-
Notifications
You must be signed in to change notification settings - Fork 72
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Feature request] Deserialization that only uses FromStr
as a fallback
#702
Comments
It is possible to write code that does what you want. From a code perspective, the best place to add it would be the With a small modification, it should be possible to have that as a derive macro. Generate a However, I am not sure if this /*
[dependencies]
serde.version = "*"
serde.features = ["derive"]
serde_json = "*"
*/
use serde::Deserialize;
use serde::Deserializer;
use std::str::FromStr;
#[derive(Debug, Deserialize)]
#[serde(remote = "Self")]
struct RegexWrapper {
pattern: String,
}
impl FromStr for RegexWrapper {
type Err = String;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(Self {
pattern: s.to_string(),
})
}
}
impl<'de> Deserialize<'de> for RegexWrapper {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
struct V;
impl<'de> serde::de::Visitor<'de> for V {
type Value = RegexWrapper;
fn expecting(&self, _f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
todo!()
}
fn visit_str<E: serde::de::Error>(self, s: &str) -> Result<Self::Value, E> {
FromStr::from_str(s).map_err(|e| E::custom(e))
}
fn visit_map<M: serde::de::MapAccess<'de>>(
self,
map: M,
) -> Result<Self::Value, M::Error> {
RegexWrapper::deserialize(serde::de::value::MapAccessDeserializer::new(map))
}
}
deserializer.deserialize_any(V)
}
}
#[derive(Debug, Deserialize)]
struct ThingThatContainsRegex {
blah: RegexWrapper,
}
fn main() {
let _ = dbg!(serde_json::from_str::<ThingThatContainsRegex>(
r#"{"blah": "foobar"}"#
));
let _ = dbg!(serde_json::from_str::<ThingThatContainsRegex>(
r#"{"blah": {
"pattern": "foobar"
}}"#
));
} |
Finally got around to trying this and, uh, what? How does this not cause a "trait implemented twice" error, or any error for that matter. How does And perhaps most importantly and answerably, is there a way to make the serialize derive macro not break with this? I do also need it to work with enums if that matters. Oh, by the way, thank you so much. I was not ready to handle writing a deserializer for |
The remote implementation does not create an The This |
(Putting this here instead of the official
serde
repo because that one has an issue from 2018 that still hasn't been resolved.)The serde documentation provides a way to tell a struct to deserialize a field from either
FromStr::from_str
orDeserialize::deserialize
, but as far as I can tell the only ways to have the type in the field always have this behaviour is to manually implement deserialize or have a dummy type.DeserializeFromStr
almost handles this, but trying to derive both this and serde's normalDeserialize
doesn't work.For my particular use case, I have a struct that does lazy regex stuff and I would quite like to deserialize it from both
{"pattern": "...", ...}
and"..."
without having to put#[serde(deserialize_with = "string_or_struct")]
every time my wrapper appears in a field.Effectively I want something like this:
The text was updated successfully, but these errors were encountered: