2016-12-14 9 views
2

JSON 웹 API와 인터페이스하는 상자를 작성하고 있습니다. 하나의 엔드 포인트는 일반적 형태 { "key": ["value1", "value2"] }의 응답을 반환하지만 때로는 키에 대해 하나의 값이, 그리고 엔드 포인트는 내가 너무 좋아 #[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을 newtypes의 역 직렬화를 호출해야하는 사람이 필요했기 때문에 내가 찾은 방식으로 사용자 지정 deserializer를 작성해야했지만, 그렇게하는 것은 serde에 내장되어있는 것처럼 보이지 않습니다. (나는 ValueDeserializer 계열과 같은 것을 기대하고 있었다.)

독립된 예가 아래에있다. SomeStruct은 두 입력에 대해 올바르게 직렬화 해제됩니다. 하나는 값이 JSON 문자열 배열이고 다른 하나는 문자열입니다.

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)) 
} 

이 : 경우

#[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

단일 문자열이나 대신 사용자 정의 유형의 더 일반적인 Vec<String>에 문자열 목록을 직렬화하는 다음은 Serde 1.0에 대한 간단한 해결책이다 솔루션은 다음과 같은 변화 Serde의 0.9 버전에서 작동합니다

  • 라이프 타임을 제거
  • >SeqVisitorDeserializer
  • MapAccess - - 15,336,->SeqVisitor
  • SeqAccessDeserializer>MapVisitor
  • MapAccessDeserializer ->MapVisitorDeserializer
+0

이 질문으로'SomeStringNewType (문자열)'또는'SomeTypeWithCustomDeserializeFromStr (String)를'역 직렬화하지 않습니다 필요합니다. – Arnavion

+1

죄송합니다.'SomeStringNewType'은'String'으로 작업 할 수 없기 때문에 해결 방법의 일부였습니다. 네가 괜찮 으면, 나는 적어도이 제목을 찾았 기 때문에이 질문을 접하게 되었기 때문에 나는 여전히이 해답을 가지고있다. 나는 이것이 단순한'String'을 원한다는 일반적인 형식을위한 답을 업데이트했다. – Pit

+1

예, 사용자가 String을 직접 deserialize하려는 경우에 대한 대답이 좋습니다. 삭제할 이유가 없습니다. – Arnavion