Как я могу десериализовать тип, в котором все поля имеют значения по умолчанию, вместо этого?

Мне нужно десериализовать капли JSON, где в некоторых местах отсутствие всего объекта кодируется как объект с той же структурой, но для всех его полей установлены значения по умолчанию (пустые строки и нули).

extern crate serde_json; // 1.0.27
#[macro_use] extern crate serde_derive; // 1.0.78
extern crate serde; // 1.0.78

#[derive(Debug, Deserialize)]
struct Test<T> {
    text: T,
    number: i32,
}

#[derive(Debug, Deserialize)]
struct Outer {
    test: Option<Test<String>>,
}

#[derive(Debug, Deserialize)]
enum Foo { Bar, Baz }
#[derive(Debug, Deserialize)]
struct Outer2 {
    test: Option<Test<Foo>>,
}

fn main() {
    println!("{:?}", serde_json::from_str::<Outer>(r#"{ "test": { "text": "abc", "number": 42 } }"#).unwrap());
    // good: Outer { test: Some(Test { text: "abc", number: 42 }) }

    println!("{:?}", serde_json::from_str::<Outer>(r#"{ "test": null }"#).unwrap());
    // good: Outer { test: None }

    println!("{:?}", serde_json::from_str::<Outer>(r#"{ "test": { "text": "", "number": 0 } }"#).unwrap());
    // bad: Outer { test: Some(Test { text: "", number: 0 }) }
    // should be: Outer { test: None }

    println!("{:?}", serde_json::from_str::<Outer2>(r#"{ "test": { "text": "Bar", "number": 42 } }"#).unwrap());
    // good: Outer2 { test: Some(Test { text: Bar, number: 42 }) }

    println!("{:?}", serde_json::from_str::<Outer2>(r#"{ "test": { "text": "", "number": 0 } }"#).unwrap());
    // bad: error
    // should be: Outer { test: None }
}

Я бы справился с этим после десериализации, но, как вы можете видеть, этот подход невозможен для значений перечисления: ни один вариант не соответствует пустой строке, поэтому десериализация полностью не выполняется.

Как я могу научить этому серде?


person main--    schedule 02.10.2018    source источник


Ответы (1)


Вы можете посмотреть пример десериализации настраиваемого поля.

В частности, вы можете определить что-то вроде

extern crate serde; // 1.0.78
#[macro_use]
extern crate serde_derive; // 1.0.78

use serde::{Deserialize, Deserializer, de::Visitor};

fn none_if_all_default<'de, T, D>(deserializer: D) -> Result<Option<T>, D::Error>
where
    T: Deserialize<'de>,
    D: Deserializer<'de> + Clone,
{
    struct AllDefault;

    impl<'de> Visitor<'de> for AllDefault {
        type Value = bool;

        // Implement the visitor functions here -
        // You can recurse over all values to check if they're
        // the empty string or 0, and return true
        //...
    }

    let all_default = deserializer.clone().deserialize_any(AllDefault)?;

    if all_default {
        Ok(None)
    } else {
        Ok(Some(T::deserialize(deserializer)?))
    }
}

А потом сделай

#[derive(Deserialize)]
struct Outer2 {
    #[serde(deserialize_with = "none_if_all_default")]
    test: Option<Test<Foo>>,
}
person Isaac van Bakel    schedule 14.10.2018
comment
Пожалуйста, улучшите свой пример, чтобы показать, как это можно использовать для перечисления по запросу OP. Мне не удалось заставить свои собственные примеры работать с перечислением. Это также не может быть скомпилировано из-за not all trait items implemented, missing: `expecting`. - person Shepmaster; 14.10.2018
comment
Он не может быть скомпилирован, потому что он не предназначен для компиляции - это скелетный ответ, а реализация трейта - это ручная работа, которую можно выполнить, обратившись к документации. Дело в том, чтобы продемонстрировать высокоуровневую идею, решающую проблему ОП. Это работает для поля enum, потому что это работает для любого поля, которое является Option<T>. - person Isaac van Bakel; 14.10.2018
comment
deserialize_any потребляет self. Как вы позвоните T::deserialize, когда он исчезнет? Тип возврата вашей функции несовместим (Result::Ok против Option::Some). Этот ответ не работает. - person Shepmaster; 14.10.2018
comment
Десериализаторы не могут быть клонированы. Обратите внимание, что именно из-за этого разговора вам настоятельно рекомендуется создать рабочее решение перед ответом. - person Shepmaster; 14.10.2018