Last active
May 18, 2019 13:36
-
-
Save peterjoel/a41363fea48c4cb529e4a4bf8421ec20 to your computer and use it in GitHub Desktop.
Format deserializes for manually flattened struct but requires deserialize_any when the fields are flattened using serde attributes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[package] | |
name = "serde_fix_s" | |
version = "0.1.0" | |
edition = "2018" | |
[dependencies] | |
serde = { version = "1.0.91", features = ["derive"] } | |
[dev-dependencies] | |
serde_test = "1" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use crate::error::{Error, Result}; | |
use serde::de::{self, DeserializeSeed, MapAccess, Visitor}; | |
use serde::Deserialize; | |
pub struct Deserializer<'de> { | |
input: &'de [u8], | |
} | |
impl<'de> Deserializer<'de> { | |
pub fn from_bytes(input: &'de [u8]) -> Self { | |
Deserializer { input } | |
} | |
fn peek_byte(&mut self) -> Result<u8> { | |
if self.input.is_empty() { | |
Err(Error::new("EOF")) | |
} else { | |
Ok(self.input[0]) | |
} | |
} | |
fn next_byte(&mut self) -> Result<u8> { | |
let byte = self.peek_byte()?; | |
self.input = &self.input[1..]; | |
Ok(byte) | |
} | |
fn parse_string(&mut self) -> Result<String> { | |
if let Ok(b'=') = self.peek_byte() { | |
Err(Error::new("Expected string")) | |
} else if let Some(index) = self.input.iter().position(|ch| *ch == b'|' || *ch == b'=') { | |
let s = unsafe { std::str::from_utf8_unchecked(&self.input[0..index]) }; | |
self.input = &self.input[index..]; | |
Ok(s.to_string()) | |
} else { | |
Err(Error::new("EOF")) | |
} | |
} | |
} | |
pub fn from_bytes<'a, T>(input: &'a [u8]) -> Result<T> | |
where | |
T: Deserialize<'a>, | |
{ | |
let mut deserializer = Deserializer::from_bytes(input); | |
T::deserialize(&mut deserializer) | |
} | |
macro_rules! omit_unimplemented { | |
($($name: ident $(($($type: ty),+))?)*) => { | |
$( | |
fn $name<V>(self $($(, _: $type)+)?, _visitor: V) -> Result<V::Value> | |
where V: Visitor<'de> | |
{ | |
unimplemented!(stringify!($name)); | |
} | |
)* | |
} | |
} | |
impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> { | |
type Error = Error; | |
omit_unimplemented! { | |
deserialize_any deserialize_bool deserialize_i8 deserialize_i16 | |
deserialize_i32 deserialize_i64 deserialize_u8 deserialize_u16 | |
deserialize_u32 deserialize_u64 deserialize_f32 deserialize_f64 | |
deserialize_char deserialize_str deserialize_bytes deserialize_byte_buf | |
deserialize_option deserialize_unit deserialize_seq deserialize_map | |
deserialize_ignored_any | |
deserialize_unit_struct(&'static str) | |
deserialize_newtype_struct(&'static str) | |
deserialize_tuple(usize) | |
deserialize_tuple_struct(&'static str, usize) | |
deserialize_enum(&'static str, &'static [&'static str]) | |
} | |
fn deserialize_string<V>(self, visitor: V) -> Result<V::Value> | |
where | |
V: Visitor<'de>, | |
{ | |
let s = self.parse_string()?; | |
visitor.visit_string(s) | |
} | |
fn deserialize_struct<V>( | |
mut self, | |
_name: &'static str, | |
_fields: &'static [&'static str], | |
visitor: V, | |
) -> Result<V::Value> | |
where | |
V: Visitor<'de>, | |
{ | |
visitor.visit_map(Fields::new(&mut self)) | |
} | |
fn deserialize_identifier<V>(self, visitor: V) -> Result<V::Value> | |
where | |
V: Visitor<'de>, | |
{ | |
visitor.visit_string(self.parse_string()?) | |
} | |
} | |
struct Fields<'a, 'de: 'a> { | |
de: &'a mut Deserializer<'de>, | |
} | |
impl<'a, 'de> Fields<'a, 'de> { | |
fn new(de: &'a mut Deserializer<'de>) -> Self { | |
Fields { de } | |
} | |
} | |
impl<'de, 'a> MapAccess<'de> for Fields<'a, 'de> { | |
type Error = Error; | |
fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>> | |
where | |
K: DeserializeSeed<'de>, | |
{ | |
if self.de.input.is_empty() { | |
return Ok(None); | |
} | |
let key = seed.deserialize(&mut *self.de).map(Some)?; | |
if self.de.next_byte()? != b'=' { | |
return Err(Error::new("Expected `=`")); | |
} | |
Ok(key) | |
} | |
fn next_value_seed<V>(&mut self, seed: V) -> Result<V::Value> | |
where | |
V: DeserializeSeed<'de>, | |
{ | |
let value = seed.deserialize(&mut *self.de)?; | |
if self.de.next_byte()? != b'|' { | |
return Err(Error::new("Expected `|`")); | |
} | |
Ok(value) | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use serde::de; | |
use std::error::Error as _; | |
use std::{error, fmt, result}; | |
pub type Result<T> = result::Result<T, Error>; | |
#[derive(Debug)] | |
pub struct Error(String); | |
impl Error { | |
pub fn new(reason: &str) -> Error { | |
Error(reason.to_string()) | |
} | |
} | |
impl error::Error for Error { | |
fn description(&self) -> &str { | |
&self.0 | |
} | |
} | |
impl fmt::Display for Error { | |
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
f.write_str(self.description()) | |
} | |
} | |
impl de::Error for Error { | |
fn custom<T: fmt::Display>(msg: T) -> Self { | |
Error::new(&msg.to_string()) | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
mod de; | |
mod error; | |
#[cfg(test)] | |
mod tests; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use crate::de::*; | |
use crate::error::*; | |
use serde::Deserialize; | |
use serde_test::{assert_de_tokens, Token}; | |
#[derive(Debug, PartialEq, Deserialize)] | |
#[serde(rename = "Message")] | |
struct Nested { | |
a: String, | |
#[serde(flatten)] | |
inner: NestedInner, | |
} | |
#[derive(Debug, PartialEq, Deserialize)] | |
struct NestedInner { | |
b: String, | |
} | |
impl Nested { | |
fn new(a: &str, b: &str) -> Nested { | |
Nested { | |
a: a.to_string(), | |
inner: NestedInner { b: b.to_string() }, | |
} | |
} | |
} | |
#[derive(Debug, PartialEq, Deserialize)] | |
#[serde(rename = "Message")] | |
struct Flattened { | |
a: String, | |
b: String, | |
} | |
impl Flattened { | |
fn new(a: &str, b: &str) -> Flattened { | |
Flattened { | |
a: a.to_string(), | |
b: b.to_string(), | |
} | |
} | |
} | |
#[test] | |
fn deser_flat_struct() { | |
let input = b"a=v1|b=99|"; | |
let actual: Result<Flattened> = from_bytes(input); | |
let expected = Flattened::new("v1", "99"); | |
assert_eq!(expected, actual.unwrap()); | |
} | |
#[test] | |
fn deser_nested_and_flattened_struct() { | |
let input = b"a=v1|b=99|"; | |
let actual: Result<Nested> = from_bytes(input); | |
let expected = Nested::new("v1", "99"); | |
// FAILS: panicked at 'not yet implemented: deserialize_map' | |
assert_eq!(expected, actual.unwrap()); | |
} | |
#[test] | |
fn both_deserialize_as_flat_struct_tokens() { | |
let expected_tokens = &[ | |
Token::Struct { | |
name: "Message", | |
len: 5, | |
}, | |
Token::Str("a"), | |
Token::Str("v1"), | |
Token::Str("b"), | |
Token::Str("99"), | |
Token::StructEnd, | |
]; | |
let nested = Nested::new("v1", "99"); | |
assert_de_tokens(&nested, expected_tokens); | |
let flattened = Flattened::new("v1", "99"); | |
assert_de_tokens(&flattened, expected_tokens); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment