Skip to content

Instantly share code, notes, and snippets.

@peterjoel
Last active May 18, 2019 13:36
Show Gist options
  • Save peterjoel/a41363fea48c4cb529e4a4bf8421ec20 to your computer and use it in GitHub Desktop.
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.
[package]
name = "serde_fix_s"
version = "0.1.0"
edition = "2018"
[dependencies]
serde = { version = "1.0.91", features = ["derive"] }
[dev-dependencies]
serde_test = "1"
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)
}
}
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())
}
}
mod de;
mod error;
#[cfg(test)]
mod tests;
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