Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- use serde::{Deserialize, Deserializer};
- fn from_string<'de, D, T>(deserializer: D) -> Result<T, D::Error>
- where
- T: Default + std::str::FromStr + Deserialize<'de>,
- D: Deserializer<'de>,
- <T as std::str::FromStr>::Err: std::fmt::Display,
- {
- #[derive(Debug, Deserialize)]
- #[serde(untagged)]
- enum Value<T> {
- From(String),
- Into(T),
- }
- let result: Result<Value<T>, D::Error> = Deserialize::deserialize(deserializer);
- if let Ok(s) = result {
- match s {
- Value::From(v) => v.parse::<T>().map_err(serde::de::Error::custom),
- Value::Into(v) => Ok(v),
- }
- } else {
- Ok(T::default())
- }
- }
- fn into_string<'de, D>(deserializer: D) -> Result<String, D::Error>
- where
- D: Deserializer<'de>,
- {
- #[derive(Debug, Deserialize)]
- #[serde(untagged)]
- enum Value {
- String(String),
- Int(i64),
- Uint(u64),
- Float(f64),
- Bool(bool),
- Char(char),
- }
- let result: Result<Value, D::Error> = Deserialize::deserialize(deserializer);
- if let Ok(value) = result {
- match value {
- Value::String(v) => Ok(v),
- Value::Int(v) => Ok(v.to_string()),
- Value::Uint(v) => Ok(v.to_string()),
- Value::Float(v) => Ok(v.to_string()),
- Value::Bool(v) => Ok(v.to_string()),
- Value::Char(v) => Ok(v.to_string()),
- }
- } else {
- Ok(String::new())
- }
- }
- pub fn into_vec<'de, T, D>(deserializer: D) -> Result<Vec<T>, D::Error>
- where
- T: Deserialize<'de>,
- D: Deserializer<'de>,
- {
- #[derive(Debug, Deserialize)]
- #[serde(untagged)]
- enum Value<T> {
- Into(Vec<T>),
- From(T),
- }
- let result: Result<Value<T>, D::Error> = Deserialize::deserialize(deserializer);
- if let Ok(value) = result {
- match value {
- Value::Into(v) => Ok(v),
- Value::From(v) => Ok(vec![v]),
- }
- } else {
- Ok(vec![])
- }
- }
- fn extract_attr<'de, T, D>(deserializer: D, attr: &str) -> Result<T, D::Error>
- where
- T: Deserialize<'de> + Default + std::fmt::Debug + Clone,
- D: Deserializer<'de>,
- {
- use std::collections::HashMap;
- #[derive(Debug, Deserialize)]
- #[serde(untagged)]
- enum Value<T> {
- From(HashMap<String, T>),
- Into(T),
- }
- let result: Result<Value<T>, D::Error> = serde::Deserialize::deserialize(deserializer);
- if let Ok(value) = result {
- match value {
- Value::From(map) => {
- if let Some(value) = map.get(attr) {
- Ok(value.clone())
- } else {
- Ok(T::default())
- }
- }
- Value::Into(v) => Ok(v),
- }
- } else {
- Ok(T::default())
- }
- }
- #[macro_export]
- macro_rules! make_extract {
- ($name:ident, $attr:expr) => {
- pub fn $name<'de, T, D>(deserializer: D) -> Result<T, D::Error>
- where
- T: serde::Deserialize<'de> + Default + std::fmt::Debug + Clone,
- D: serde::Deserializer<'de>,
- {
- extract_attr(deserializer, $attr)
- }
- };
- }
- make_extract!(extract_text, "#text");
- make_extract!(extract_value, "$value");
- #[derive(Debug, Deserialize)]
- struct Address {
- #[serde(deserialize_with = "into_string")]
- plz: String,
- #[serde(deserialize_with = "extract_value")]
- id: u32
- }
- #[derive(Debug, Deserialize)]
- struct Person {
- #[serde(deserialize_with = "from_string")]
- age: u32,
- #[serde(deserialize_with = "into_vec")]
- address: Vec<Address>
- }
- fn main() {
- let json = r#"{ "age": "42", "address": { "plz": 99999, "id": { "$value": 23 } } }"#;
- let result: serde_json::Result<Person> = serde_json::from_str(json);
- dbg!(result);
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement