-
-
Notifications
You must be signed in to change notification settings - Fork 221
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: please add invalid_result
deserializer
#345
Comments
If this is possible to do in a small patch, like adding a new |
I could create a PR when I have some time... do you see any other need apart from adding the |
@BurntSushi, for now I implemented the following function: pub fn invalid_result<'de, D, T>(
de: D,
) -> result::Result<std::result::Result<T, String>, D::Error>
where
D: Deserializer<'de>,
T: Deserialize<'de>,
{
Ok(T::deserialize(de).or_else(|err| Err(err.to_string())))
} This works but reports the error message, not the original invalid string value as it should be. So for instance for good values, empty strings, or invalid strings, I am getting respectively:
Do you know how to get the original invalid string value from within the function? |
@BurntSushi, sorry to bother you but I've been trying to implement this for a while without success, and I can't really figure out how to solve this. I'm now wondering if it is feasible at all... should the |
@BurntSushi I finally got two working functions. The first one is simpler and relies on pub fn invalid_result<'de, D, T>(
de: D,
) -> result::Result<result::Result<T, String>, D::Error>
where
D: Deserializer<'de>,
T: Deserialize<'de>,
{
// Need to use `Content` and `ContentRefDeserializer`, which currently are in
// Serde private API but may become public in the future, see:
// https://github.com/serde-rs/serde/issues/741
// https://github.com/arcnmx/serde-value/issues/16
let content = serde::__private::de::Content::deserialize(de)?;
let de = serde::__private::de::ContentRefDeserializer::<D::Error>::new(
&content,
);
if let Ok(t) = T::deserialize(de) {
Ok(Ok(t))
} else if let Some(s) = content.as_str() {
Ok(Err(s.to_owned()))
} else {
Err(serde::de::Error::custom("input data is not a valid UTF-8 string"))
}
} pub fn invalid_result<'de, D, T>(
de: D,
) -> result::Result<result::Result<T, String>, D::Error>
where
D: Deserializer<'de>,
T: Deserialize<'de>,
{
// Need to use `Content` and `ContentRefDeserializer`, which currently are in
// Serde private API but may become public in the future, see:
// https://github.com/serde-rs/serde/issues/741
// https://github.com/arcnmx/serde-value/issues/16
let content = serde::__private::de::Content::deserialize(de)?;
let de = serde::__private::de::ContentRefDeserializer::<D::Error>::new(
&content,
);
let result = if let Ok(t) = T::deserialize(de) {
Ok(t)
} else {
Err(match content {
serde::__private::de::Content::Bool(b) => b.to_string(),
serde::__private::de::Content::U8(u) => u.to_string(),
serde::__private::de::Content::U16(u) => u.to_string(),
serde::__private::de::Content::U32(u) => u.to_string(),
serde::__private::de::Content::U64(u) => u.to_string(),
serde::__private::de::Content::I8(i) => i.to_string(),
serde::__private::de::Content::I16(i) => i.to_string(),
serde::__private::de::Content::I32(i) => i.to_string(),
serde::__private::de::Content::I64(i) => i.to_string(),
serde::__private::de::Content::F32(f) => f.to_string(),
serde::__private::de::Content::F64(f) => f.to_string(),
serde::__private::de::Content::Char(c) => c.to_string(),
serde::__private::de::Content::String(s) => s,
serde::__private::de::Content::Str(s) => s.to_owned(),
serde::__private::de::Content::ByteBuf(buf) => {
String::from_utf8_lossy(&buf).into_owned()
}
serde::__private::de::Content::Bytes(bytes) => {
String::from_utf8_lossy(bytes).into_owned()
}
serde::__private::de::Content::None => String::new(),
serde::__private::de::Content::Some(some) => {
format!("{:?}", some)
}
serde::__private::de::Content::Unit => String::new(),
serde::__private::de::Content::Newtype(newtype) => {
format!("{:?}", newtype)
}
serde::__private::de::Content::Seq(seq) => format!("{:?}", seq),
serde::__private::de::Content::Map(m) => format!("{:?}", m),
})
};
Ok(result)
} I prefer the second function, but please let me know your preference and advice, or otherwise if I should use /// Used from generated code to buffer the contents of the Deserializer when
/// deserializing untagged enums and internally tagged enums.
///
/// Not public API. Use serde-value instead.
#[derive(Debug, Clone)]
pub enum Content<'de> { |
@BurntSushi, I think I found a better implementation. I hope you like it, the only drawback is that it requires Serde's pub fn invalid_result<'de, D, T, F>(
de: D,
) -> result::Result<result::Result<T, F>, D::Error>
where
D: Deserializer<'de>,
T: Deserialize<'de>,
F: Deserialize<'de>,
{
#[derive(Deserialize)]
#[serde(untagged)]
enum DeFallback<T, F> {
Expected(T),
Fallback(F),
}
DeFallback::<T, F>::deserialize(de).map(|d| match d {
DeFallback::Expected(t) => Ok(t),
DeFallback::Fallback(f) => Err(f),
})
} |
Never mind, the above code using Serde's So at the moment the only two options that I could find are either relying on Serde's private API or on pub fn invalid_result_private<'de, D, T>(
de: D,
) -> result::Result<result::Result<T, String>, D::Error>
where
D: Deserializer<'de>,
T: Deserialize<'de>,
{
let content = serde::__private::de::Content::deserialize(de)?;
let de = serde::__private::de::ContentRefDeserializer::<D::Error>::new(
&content,
);
let result = T::deserialize(de).map_err(|_| match content {
serde::__private::de::Content::Bool(b) => b.to_string(),
serde::__private::de::Content::U8(u) => u.to_string(),
serde::__private::de::Content::U16(u) => u.to_string(),
serde::__private::de::Content::U32(u) => u.to_string(),
serde::__private::de::Content::U64(u) => u.to_string(),
serde::__private::de::Content::I8(i) => i.to_string(),
serde::__private::de::Content::I16(i) => i.to_string(),
serde::__private::de::Content::I32(i) => i.to_string(),
serde::__private::de::Content::I64(i) => i.to_string(),
serde::__private::de::Content::F32(f) => f.to_string(),
serde::__private::de::Content::F64(f) => f.to_string(),
serde::__private::de::Content::Char(c) => c.to_string(),
serde::__private::de::Content::String(s) => s,
serde::__private::de::Content::Str(s) => s.to_owned(),
serde::__private::de::Content::ByteBuf(buf) => {
String::from_utf8_lossy(&buf).into_owned()
}
serde::__private::de::Content::Bytes(bytes) => {
String::from_utf8_lossy(bytes).into_owned()
}
serde::__private::de::Content::None => String::new(),
serde::__private::de::Content::Some(some) => {
format!("{:?}", some)
}
serde::__private::de::Content::Unit => String::new(),
serde::__private::de::Content::Newtype(newtype) => {
format!("{:?}", newtype)
}
serde::__private::de::Content::Seq(seq) => format!("{:?}", seq),
serde::__private::de::Content::Map(map) => format!("{:?}", map),
});
Ok(result)
} pub fn invalid_result_serdevalue<'de, D, T>(
de: D,
) -> result::Result<result::Result<T, String>, D::Error>
where
D: Deserializer<'de>,
T: Deserialize<'de>,
{
let value = serde_value::Value::deserialize(de)?;
let result = T::deserialize(value.clone()).map_err(|_| match value {
serde_value::Value::Bool(b) => b.to_string(),
serde_value::Value::U8(u) => u.to_string(),
serde_value::Value::U16(u) => u.to_string(),
serde_value::Value::U32(u) => u.to_string(),
serde_value::Value::U64(u) => u.to_string(),
serde_value::Value::I8(i) => i.to_string(),
serde_value::Value::I16(i) => i.to_string(),
serde_value::Value::I32(i) => i.to_string(),
serde_value::Value::I64(i) => i.to_string(),
serde_value::Value::F32(f) => f.to_string(),
serde_value::Value::F64(f) => f.to_string(),
serde_value::Value::Char(c) => c.to_string(),
serde_value::Value::String(s) => s,
serde_value::Value::Unit => String::new(),
serde_value::Value::Option(option) => {
format!("{:?}", option)
}
serde_value::Value::Newtype(newtype) => {
format!("{:?}", newtype)
}
serde_value::Value::Seq(seq) => format!("{:?}", seq),
serde_value::Value::Map(map) => format!("{:?}", map),
serde_value::Value::Bytes(bytes) => {
String::from_utf8_lossy(&bytes).into_owned()
}
});
Ok(result)
} |
When dealing with invalid data with serde, sometimes it is useful to get also invalid fields when present. The current
invalid_option
deserializer discards all invalid fields. It would be convenient to have a similarinvalid_result
deserializer, which returnsOk(value)
for all valid fields, andErr(string_field)
for all invalid fields.The text was updated successfully, but these errors were encountered: