Как изменить вывод JSON для результатасериализовано с серде? - PullRequest
0 голосов
/ 26 сентября 2019

Простой код:

use serde::Serialize;

#[derive(Serialize)]
struct MyStruct {
    foo: Result<u32, String>
}

fn main() {
    let m = MyStruct {
        foo: Ok(43)
    };
    let n = MyStruct {
        foo: Err("oh no!".into())
    };

    println!("{}", serde_json::to_string_pretty(&m).unwrap());
    println!("{}", serde_json::to_string_pretty(&n).unwrap());
}

Это выводит ( детская площадка ):

{
  "foo": {
    "Ok": 43
  }
}
{
  "foo": {
    "Err": "oh no!"
  }
}

Могу ли я изменить сериализатор, чтобы иметь собственный вывод для Result<T,E>?Я хотел бы что-то вроде:

// No "Ok" field in case of Ok(T)
{
  "foo": 43
}
// Rename "Err" to "error" in case of Err(E)
{
  "foo": {
    "error": "oh no!"
  }
}

1 Ответ

3 голосов
/ 26 сентября 2019

Serde атрибуты недостаточно мощны, чтобы выполнить преобразование из сериализации Result по умолчанию в то, что вам нужно, поэтому вам нужно написать собственную сериализацию.К счастью, все довольно просто:

use serde::{Serialize, Serializer, ser::SerializeMap};

struct MyStruct {
    foo: Result<u32, String>
}

impl Serialize for MyStruct {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        let mut map = serializer.serialize_map(Some(1))?;
        match &self.foo {
            Ok(value) => map.serialize_entry("foo", &value)?,
            Err(error) => map.serialize_entry("foo", &MyError { error } )?,
        }
        map.end()
    }
}

// This is just used internally to get the nested error field
#[derive(Serialize)]
struct MyError<E> {
    error: E,
}
...