2016-12-14 5 views
2

JSON Web APIとインターフェイスするクレートを作成しています。一方のエンドポイントは、通常はフォーム{ "key": ["value1", "value2"] }の応答を返しますが、時には重要な1つの値だけがあります、およびエンドポイントは、私はそうのような#[serde(deserialize_with)]で使用することができ、このための一般的な何かを書きたい{ "key": "value" }代わりJSON文字列または文字列をVecに逆シリアル化する

{ "key": ["value"] }で返します。

#[derive(Deserialize)] 
struct SomeStruct { 
    #[serde(deserialize_with = "deserialize_string_or_seq_string")] 
    field1: Vec<SomeStringNewType>, 

    #[serde(deserialize_with = "deserialize_string_or_seq_string")] 
    field2: Vec<SomeTypeWithCustomDeserializeFromStr>, 
} 

#[derive(Deserialize)] 
struct SomeStringNewType(String); 

struct SomeTypeWithCustomDeserializeFromStr(String); 
impl ::serde::de::Deserialize for SomeTypeWithCustomDeserializeFromStr { 
    // Some custom implementation here 
} 

これを行うには、どうすればdeserialize_string_or_seq_stringを書くことができますか?

答えて

0

このソリューションはSerde 1.0で機能します。

visitor.visit_newtype_structという新しいタイプのデシリアライズを試みる必要があったため、カスタムデシリアライザを作成する必要がありました。また、そうすることはできません。 (私は、ValueDeserializerシリーズのようなものを期待していました)

以下は自己完結型の例です。 SomeStructは両方の入力に対して正しくデシリアライズされます。値はJSON配列の文字列で、もう1つは文字列です。あなたが代わりにカスタムタイプのより一般的なVec<String>に単一の文字列または文字列のリストをデシリアライズしたい場合には

#[macro_use] 
extern crate serde; 
#[macro_use] 
extern crate serde_derive; 
extern crate serde_json; 

fn main() { 
    #[derive(Debug, Deserialize)] 
    struct SomeStringNewType(String); 

    #[derive(Debug)] 
    struct SomeTypeWithCustomDeserializeFromStr(String); 
    impl<'de> ::serde::Deserialize<'de> for SomeTypeWithCustomDeserializeFromStr { 
     fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: ::serde::Deserializer<'de> { 
      struct Visitor; 

      impl<'de> ::serde::de::Visitor<'de> for Visitor { 
       type Value = SomeTypeWithCustomDeserializeFromStr; 

       fn expecting(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { 
        write!(f, "a string") 
       } 

       fn visit_str<E>(self, v: &str) -> Result<Self::Value, E> where E: ::serde::de::Error { 
        Ok(SomeTypeWithCustomDeserializeFromStr(v.to_string() + " custom")) 
       } 
      } 

      deserializer.deserialize_any(Visitor) 
     } 
    } 

    #[derive(Debug, Deserialize)] 
    struct SomeStruct { 
     #[serde(deserialize_with = "deserialize_string_or_seq_string")] 
     field1: Vec<SomeStringNewType>, 

     #[serde(deserialize_with = "deserialize_string_or_seq_string")] 
     field2: Vec<SomeTypeWithCustomDeserializeFromStr>, 
    } 

    let x: SomeStruct = ::serde_json::from_str(r#"{ "field1": ["a"], "field2": ["b"] }"#).unwrap(); 
    println!("{:?}", x); 
    assert_eq!(x.field1[0].0, "a"); 
    assert_eq!(x.field2[0].0, "b custom"); 

    let x: SomeStruct = ::serde_json::from_str(r#"{ "field1": "c", "field2": "d" }"#).unwrap(); 
    println!("{:?}", x); 
    assert_eq!(x.field1[0].0, "c"); 
    assert_eq!(x.field2[0].0, "d custom"); 
} 

/// Deserializes a string or a sequence of strings into a vector of the target type. 
pub fn deserialize_string_or_seq_string<'de, T, D>(deserializer: D) -> Result<Vec<T>, D::Error> 
    where T: ::serde::Deserialize<'de>, D: ::serde::Deserializer<'de> { 

    struct Visitor<T>(::std::marker::PhantomData<T>); 

    impl<'de, T> ::serde::de::Visitor<'de> for Visitor<T> 
     where T: ::serde::Deserialize<'de> { 

     type Value = Vec<T>; 

     fn expecting(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { 
      write!(f, "a string or sequence of strings") 
     } 

     fn visit_str<E>(self, v: &str) -> Result<Self::Value, E> 
      where E: ::serde::de::Error { 

      let value = { 
       // Try parsing as a newtype 
       let deserializer = StringNewTypeStructDeserializer(v, ::std::marker::PhantomData); 
       ::serde::Deserialize::deserialize(deserializer) 
      }.or_else(|_: E| { 
       // Try parsing as a str 
       let deserializer = ::serde::de::IntoDeserializer::into_deserializer(v); 
       ::serde::Deserialize::deserialize(deserializer) 
      })?; 
      Ok(vec![value]) 
     } 

     fn visit_seq<A>(self, visitor: A) -> Result<Self::Value, A::Error> 
      where A: ::serde::de::SeqAccess<'de> { 

      ::serde::Deserialize::deserialize(::serde::de::value::SeqAccessDeserializer::new(visitor)) 
     } 
    } 

    deserializer.deserialize_any(Visitor(::std::marker::PhantomData)) 
} 

// Tries to deserialize the given string as a newtype 
struct StringNewTypeStructDeserializer<'a, E>(&'a str, ::std::marker::PhantomData<E>); 

impl<'de, 'a, E> ::serde::Deserializer<'de> for StringNewTypeStructDeserializer<'a, E> where E: ::serde::de::Error { 
    type Error = E; 

    fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error> where V: ::serde::de::Visitor<'de> { 
     visitor.visit_newtype_struct(self) 
    } 

    fn deserialize_string<V>(self, visitor: V) -> Result<V::Value, Self::Error> where V: ::serde::de::Visitor<'de> { 
     // Called by newtype visitor 
     visitor.visit_str(self.0) 
    } 

    forward_to_deserialize_any! { 
     bool i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 char str bytes 
     byte_buf option unit unit_struct newtype_struct seq tuple tuple_struct map 
     struct enum identifier ignored_any 
    } 
} 
2

、次はSerde 1.0のための簡単なソリューションです:

extern crate serde; 
#[macro_use] extern crate serde_derive; 
extern crate serde_json; 

use std::fmt; 
use std::marker::PhantomData; 

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

#[derive(Deserialize, Debug, Clone)] 
pub struct Parent { 
    #[serde(deserialize_with = "string_or_seq_string")] 
    pub strings: Vec<String>, 
} 

fn main() { 
    let list_of_strings: Parent = serde_json::from_str(r#"{ "strings": ["value1", "value2"] }"#).unwrap(); 
    println!("list of strings: {:?}", list_of_strings); 
    // Prints: 
    // list of strings: Parent { strings: ["value1", "value2"] } 

    let single_string: Parent = serde_json::from_str(r#"{ "strings": "value" }"#).unwrap(); 
    println!("single string: {:?}", single_string); 
    // Prints: 
    // single string: Parent { strings: ["value"] } 
} 

fn string_or_seq_string<'de, D>(deserializer: D) -> Result<Vec<String>, D::Error> 
    where D: Deserializer<'de> 
{ 
    struct StringOrVec(PhantomData<Vec<String>>); 

    impl<'de> de::Visitor<'de> for StringOrVec { 
     type Value = Vec<String>; 

     fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { 
      formatter.write_str("string or list of strings") 
     } 

     fn visit_str<E>(self, value: &str) -> Result<Self::Value, E> 
      where E: de::Error 
     { 
      Ok(vec![value.to_owned()]) 
     } 

     fn visit_seq<S>(self, visitor: S) -> Result<Self::Value, S::Error> 
      where S: de::SeqAccess<'de> 
     { 
      Deserialize::deserialize(de::value::SeqAccessDeserializer::new(visitor)) 
     } 
    } 

    deserializer.deserialize_any(StringOrVec(PhantomData)) 
} 

このソリューションは、以下の変更をSerdeの0.9リリースで動作します:

  • 寿命に削除
  • SeqAccess - >SeqVisitor
  • SeqAccessDeserializer - >SeqVisitorDeserializer
  • MapAccess - >MapVisitor
  • MapAccessDeserializer - >MapVisitorDeserializer
+0

これが問題として '' SomeStringNewType(文字列) 'や' SomeTypeWithCustomDeserializeFromStr(String)をデシリアライズしません。必要です。 – Arnavion

+1

申し訳ありません - 私は 'SomeStringNewType'は' String'で動作するようにできなかったため、回避策の一種であると理解しました。あなたが気にしないなら、私はまだその答えを保持しています。なぜなら、少なくとも私はそのタイトルを捜したのでこの質問に出くわしたからです。私は単純な 'String'を必要とする一般的な形式のための答えを更新しました。 – Pit

+1

はい、ユーザーがストリングを直接デシリアライズしたい場合は、あなたの答えが良いです。それを削除する理由はありません。 – Arnavion

関連する問題