Deserializer seems to work a bit

This commit is contained in:
Alex 2022-11-18 16:26:44 +01:00
parent 4b8555711e
commit 1bcefaa1ae
Signed by: lx
GPG Key ID: 0E496D15096376BE
8 changed files with 595 additions and 57 deletions

View File

@ -8,43 +8,11 @@ use nom::{
IResult, InputLength,
};
use crate::dec::{debug, AnyTerm, NonListTerm, Term};
use crate::dec::{AnyTerm, DecodeError, NonListTerm, Term};
use crate::{is_string_char, is_whitespace, DICT_ASSIGN, DICT_CLOSE, DICT_DELIM, DICT_OPEN};
// ----
/// The error kind returned by the `decode` function.
#[derive(Eq, PartialEq)]
pub enum DecodeError<'a> {
/// Indicates that there is trailing garbage at the end of the decoded string
Garbage(&'a [u8]),
/// Indicates that the entered string does not represent a complete nettext term
IncompleteInput,
/// Indicates a syntax error in the decoded term
NomError(&'a [u8], nom::error::ErrorKind),
}
impl<'a> std::fmt::Debug for DecodeError<'a> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
match self {
DecodeError::Garbage(g) => write!(f, "Garbage: `{}`", debug(g)),
DecodeError::IncompleteInput => write!(f, "Incomplete input"),
DecodeError::NomError(s, e) => write!(f, "Nom: {:?}, at: `{}`", e, debug(s)),
}
}
}
impl<'a> From<nom::Err<nom::error::Error<&'a [u8]>>> for DecodeError<'a> {
fn from(e: nom::Err<nom::error::Error<&'a [u8]>>) -> DecodeError<'a> {
match e {
nom::Err::Incomplete(_) => DecodeError::IncompleteInput,
nom::Err::Error(e) | nom::Err::Failure(e) => DecodeError::NomError(e.input, e.code),
}
}
}
// ----
/// Decodes a nettext string into the term it represents.
pub fn decode(input: &[u8]) -> std::result::Result<Term<'_, '_>, DecodeError<'_>> {
let (rest, term) = decode_term(input)?;

View File

@ -1,5 +1,7 @@
use std::fmt;
use crate::dec::debug;
/// The type of errors returned by helper functions on `Term`
#[derive(Debug, Clone)]
pub enum TypeError {
@ -32,3 +34,41 @@ impl std::fmt::Display for TypeError {
}
}
}
// ----
/// The error kind returned by the `decode` function.
#[derive(Eq, PartialEq)]
pub enum DecodeError<'a> {
/// Indicates that there is trailing garbage at the end of the decoded string
Garbage(&'a [u8]),
/// Indicates that the entered string does not represent a complete nettext term
IncompleteInput,
/// Indicates a syntax error in the decoded term
NomError(&'a [u8], nom::error::ErrorKind),
}
impl<'a> std::fmt::Display for DecodeError<'a> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
match self {
DecodeError::Garbage(g) => write!(f, "Garbage: `{}`", debug(g)),
DecodeError::IncompleteInput => write!(f, "Incomplete input"),
DecodeError::NomError(s, e) => write!(f, "Nom: {:?}, at: `{}`", e, debug(s)),
}
}
}
impl<'a> std::fmt::Debug for DecodeError<'a> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
std::fmt::Display::fmt(self, f)
}
}
impl<'a> From<nom::Err<nom::error::Error<&'a [u8]>>> for DecodeError<'a> {
fn from(e: nom::Err<nom::error::Error<&'a [u8]>>) -> DecodeError<'a> {
match e {
nom::Err::Incomplete(_) => DecodeError::IncompleteInput,
nom::Err::Error(e) | nom::Err::Failure(e) => DecodeError::NomError(e.input, e.code),
}
}
}

View File

@ -7,7 +7,7 @@ use std::collections::HashMap;
use crate::crypto;
pub use decode::*;
pub use error::TypeError;
pub use error::*;
/// A parsed nettext term, with many helpers for destructuring
///
@ -17,7 +17,7 @@ pub use error::TypeError;
/// is returned by one of the helper functions, or 'static when first returned from
/// `decode()`
#[derive(Eq, PartialEq, Debug)]
pub struct Term<'a, 'b>(AnyTerm<'a, 'b>);
pub struct Term<'a, 'b>(pub(crate) AnyTerm<'a, 'b>);
#[derive(Eq, PartialEq, Clone)]
pub(crate) enum AnyTerm<'a, 'b> {
@ -501,7 +501,7 @@ impl<'a, 'b> AnyTerm<'a, 'b> {
}
}
fn mkref(&self) -> AnyTerm<'a, '_> {
pub(crate) fn mkref(&self) -> AnyTerm<'a, '_> {
match &self {
AnyTerm::Str(s) => AnyTerm::Str(s),
AnyTerm::Dict(r, d) => AnyTerm::DictRef(r, d),

View File

@ -19,8 +19,8 @@
mod error;
use std::borrow::{Borrow, Cow};
use std::collections::HashMap;
use std::borrow::{Cow, Borrow};
use crate::dec::{self, decode};
use crate::{is_string_char, is_whitespace};

493
src/serde/de.rs Normal file
View File

@ -0,0 +1,493 @@
use std::collections::{hash_map, HashMap};
use serde::de::{
self, DeserializeSeed, EnumAccess, Error as DeError, MapAccess, SeqAccess, VariantAccess,
Visitor,
};
use serde::Deserialize;
use crate::dec::debug as fmtdebug;
use crate::dec::*;
use crate::serde::error::{Error, Result};
pub struct Deserializer<'de, 'a>(Term<'de, 'a>);
impl<'de, 'a> Deserializer<'de, 'a> {
pub fn from_term(input: &'a Term<'de, 'a>) -> Deserializer<'de, 'a> {
if let Ok(nested) = input.nested() {
Deserializer(nested)
} else {
Deserializer(Term(input.0.mkref()))
}
}
}
pub fn from_bytes<'a, T>(s: &'a [u8]) -> Result<T>
where
T: Deserialize<'a>,
{
let term = decode(s)?;
let mut deserializer = Deserializer::from_term(&term);
Ok(T::deserialize(&mut deserializer)?)
}
// ----
impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de, 'a> {
type Error = Error;
fn deserialize_any<V>(self, _visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
Err(Error::custom("derialize_any not supported"))
}
fn deserialize_bool<V>(self, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
let value = match self.0.string()? {
"true" => true,
"false" => false,
_ => return Err(Error::custom("Invalid boolean litteral")),
};
visitor.visit_bool(value)
}
fn deserialize_i8<V>(self, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
visitor.visit_i8(self.0.string()?.parse()?)
}
fn deserialize_i16<V>(self, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
visitor.visit_i16(self.0.string()?.parse()?)
}
fn deserialize_i32<V>(self, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
visitor.visit_i32(self.0.string()?.parse()?)
}
fn deserialize_i64<V>(self, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
visitor.visit_i64(self.0.string()?.parse()?)
}
fn deserialize_u8<V>(self, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
visitor.visit_u8(self.0.string()?.parse()?)
}
fn deserialize_u16<V>(self, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
visitor.visit_u16(self.0.string()?.parse()?)
}
fn deserialize_u32<V>(self, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
visitor.visit_u32(self.0.string()?.parse()?)
}
fn deserialize_u64<V>(self, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
visitor.visit_u64(self.0.string()?.parse()?)
}
fn deserialize_f32<V>(self, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
visitor.visit_f32(self.0.string()?.parse()?)
}
fn deserialize_f64<V>(self, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
visitor.visit_f64(self.0.string()?.parse()?)
}
fn deserialize_char<V>(self, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
let s = String::from_utf8(self.0.bytes()?)?;
let mut chars = s.chars();
let c = chars
.next()
.ok_or(Error::custom("invalid char: empty string"))?;
if chars.next().is_some() {
Err(Error::custom("invalid char: too many chars"))
} else {
visitor.visit_char(c)
}
}
fn deserialize_str<V>(self, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
let s = String::from_utf8(self.0.bytes()?)?;
visitor.visit_string(s)
}
fn deserialize_string<V>(self, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
self.deserialize_str(visitor)
}
fn deserialize_bytes<V>(self, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
visitor.visit_byte_buf(self.0.bytes()?)
}
fn deserialize_byte_buf<V>(self, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
visitor.visit_byte_buf(self.0.bytes()?)
}
fn deserialize_option<V>(self, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
if self.0.dict_of::<0, &[u8]>([], false).is_ok() {
visitor.visit_none()
} else {
visitor.visit_some(self)
}
}
fn deserialize_unit<V>(self, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
if self.0.dict_of::<0, &[u8]>([], false).is_ok() {
visitor.visit_unit()
} else {
Err(Error::custom(format!(
"Expected unit, got: `{}`",
fmtdebug(self.0.raw())
)))
}
}
fn deserialize_unit_struct<V>(self, name: &'static str, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
if self.0.string()? == name {
visitor.visit_unit()
} else {
Err(Error::custom(format!(
"Expected {}, got: `{}`",
name,
fmtdebug(self.0.raw())
)))
}
}
fn deserialize_newtype_struct<V>(self, name: &'static str, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
let [variant, args] = self.0.list_of_first()?;
if variant.string()? == name {
visitor.visit_newtype_struct(&mut Deserializer(args))
} else {
Err(Error::custom(format!(
"Expected {}, got: `{}`",
name,
fmtdebug(variant.raw())
)))
}
}
fn deserialize_seq<V>(self, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
visitor.visit_seq(&mut Seq(&self.0.list()))
}
fn deserialize_tuple<V>(self, _len: usize, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
visitor.visit_seq(&mut Seq(&self.0.list()))
}
fn deserialize_tuple_struct<V>(
self,
name: &'static str,
_len: usize,
visitor: V,
) -> Result<V::Value>
where
V: Visitor<'de>,
{
let [variant, args] = self.0.list_of_first()?;
if variant.string()? == name {
visitor.visit_seq(&mut Seq(&args.list()))
} else {
Err(Error::custom(format!(
"Expected {}, got: `{}`",
name,
fmtdebug(variant.raw())
)))
}
}
fn deserialize_map<V>(self, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
visitor.visit_map(&mut Dict::from_term(&self.0)?)
}
fn deserialize_struct<V>(
self,
name: &'static str,
_fields: &'static [&'static str],
visitor: V,
) -> Result<V::Value>
where
V: Visitor<'de>,
{
let [variant, data] = self.0.list_of()?;
if variant.string()? != name {
return Err(Error::custom(format!(
"Expected {}, got: `{}`",
name,
fmtdebug(variant.raw())
)));
}
Deserializer(data).deserialize_map(visitor)
}
fn deserialize_enum<V>(
self,
_name: &'static str,
_variants: &'static [&'static str],
visitor: V,
) -> Result<V::Value>
where
V: Visitor<'de>,
{
visitor.visit_enum(Enum(&self.0))
}
fn deserialize_identifier<V>(self, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
let s = self.0.string()?;
match s.split_once('.') {
Some((_a, b)) => visitor.visit_borrowed_str(b),
None => visitor.visit_borrowed_str(s),
}
}
fn deserialize_ignored_any<V>(self, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
self.deserialize_any(visitor)
}
}
pub struct Seq<'de, 'a>(&'a [Term<'de, 'a>]);
impl<'de, 'a> SeqAccess<'de> for &'a mut Seq<'de, 'a> {
type Error = Error;
fn next_element_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>>
where
T: DeserializeSeed<'de>,
{
// Check if there are no more elements.
if self.0.is_empty() {
return Ok(None);
}
let first = Term(self.0[0].0.mkref());
self.0 = &self.0[1..];
seed.deserialize(&mut Deserializer(first)).map(Some)
}
}
pub struct Dict<'de, 'a>(
&'a HashMap<&'de [u8], AnyTerm<'de, 'a>>,
Option<&'de [u8]>,
hash_map::Keys<'a, &'de [u8], AnyTerm<'de, 'a>>,
);
impl<'de, 'a> Dict<'de, 'a> {
fn from_term(t: &'a Term<'de, 'a>) -> Result<Dict<'de, 'a>> {
match t.0.mkref() {
AnyTerm::DictRef(_, d) => Ok(Dict(d, None, d.keys())),
_ => Err(Error::custom("expected a DICT")),
}
}
}
impl<'de, 'a> MapAccess<'de> for &'a mut Dict<'de, 'a> {
type Error = Error;
fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>>
where
K: DeserializeSeed<'de>,
{
match self.2.next() {
None => Ok(None),
Some(k) => {
self.1 = Some(k);
seed.deserialize(&mut Deserializer(Term(AnyTerm::Str(k))))
.map(Some)
}
}
}
fn next_value_seed<V>(&mut self, seed: V) -> Result<V::Value>
where
V: DeserializeSeed<'de>,
{
let k = self.1.ok_or(Error::custom("invald mapaccess order"))?;
let v = self
.0
.get(k)
.ok_or(Error::custom("invald mapaccess order"))?;
seed.deserialize(&mut Deserializer(Term(v.mkref())))
}
}
// ----
struct Enum<'de, 'a>(&'a Term<'de, 'a>);
impl<'de, 'a> EnumAccess<'de> for Enum<'de, 'a> {
type Error = Error;
type Variant = Self;
fn variant_seed<V>(self, seed: V) -> Result<(V::Value, Self::Variant)>
where
V: DeserializeSeed<'de>,
{
let value = seed.deserialize(&mut Deserializer::from_term(&self.0.list()[0]))?;
Ok((value, self))
}
}
impl<'de, 'a> VariantAccess<'de> for Enum<'de, 'a> {
type Error = Error;
fn unit_variant(self) -> Result<()> {
if self.0.list().len() > 1 {
Err(Error::custom("Spurrious data in unit variant"))
} else {
Ok(())
}
}
fn newtype_variant_seed<T>(self, seed: T) -> Result<T::Value>
where
T: DeserializeSeed<'de>,
{
let [_, rest] = self.0.list_of_first()?;
seed.deserialize(&mut Deserializer::from_term(&rest))
}
fn tuple_variant<V>(self, _len: usize, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
let [_, rest] = self.0.list_of_first()?;
visitor.visit_seq(&mut Seq(&rest.list()))
}
fn struct_variant<V>(self, _fields: &'static [&'static str], visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
let [_, rest] = self.0.list_of_first()?;
visitor.visit_map(&mut Dict::from_term(&rest)?)
}
}
////////////////////////////////////////////////////////////////////////////////
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_struct() {
#[derive(Deserialize, PartialEq, Debug)]
struct Test {
int: u32,
seq: Vec<String>,
}
let nt = br#"Test { int = 1, seq = YQ Yg }"#;
let expected = Test {
int: 1,
seq: vec!["a".to_owned(), "b".to_owned()],
};
assert_eq!(expected, from_bytes(nt).unwrap());
}
#[test]
fn test_enum() {
#[derive(Deserialize, PartialEq, Debug)]
enum E {
Unit,
Newtype(u32),
Tuple(u32, u32),
Struct { a: u32 },
}
let nt = br#"E.Unit"#;
let expected = E::Unit;
assert_eq!(expected, from_bytes(nt).unwrap());
eprintln!("UNIT OK");
let nt = br#"E.Newtype 1"#;
let expected = E::Newtype(1);
assert_eq!(expected, from_bytes(nt).unwrap());
eprintln!("NEWTYPE OK");
let nt = br#"E.Tuple 1 2"#;
let expected = E::Tuple(1, 2);
assert_eq!(expected, from_bytes(nt).unwrap());
eprintln!("TUPLE OK");
let nt = br#"E.Struct { a = 1 }"#;
let expected = E::Struct { a: 1 };
assert_eq!(expected, from_bytes(nt).unwrap());
eprintln!("STRUCT OK");
}
}

View File

@ -11,7 +11,11 @@ pub type Result<T> = std::result::Result<T, Error>;
pub enum Error {
Message(String),
Encode(enc::Error),
Decode(String),
Type(dec::TypeError),
ParseInt(std::num::ParseIntError),
ParseFloat(std::num::ParseFloatError),
Utf8(std::string::FromUtf8Error),
}
impl From<enc::Error> for Error {
@ -20,6 +24,12 @@ impl From<enc::Error> for Error {
}
}
impl<'a> From<dec::DecodeError<'a>> for Error {
fn from(e: dec::DecodeError) -> Self {
Error::Decode(e.to_string())
}
}
impl From<dec::TypeError> for Error {
fn from(e: dec::TypeError) -> Self {
Error::Type(e)
@ -32,6 +42,24 @@ impl ser::Error for Error {
}
}
impl From<std::num::ParseIntError> for Error {
fn from(x: std::num::ParseIntError) -> Error {
Error::ParseInt(x)
}
}
impl From<std::num::ParseFloatError> for Error {
fn from(x: std::num::ParseFloatError) -> Error {
Error::ParseFloat(x)
}
}
impl From<std::string::FromUtf8Error> for Error {
fn from(x: std::string::FromUtf8Error) -> Error {
Error::Utf8(x)
}
}
impl de::Error for Error {
fn custom<T: Display>(msg: T) -> Self {
Error::Message(msg.to_string())
@ -43,7 +71,11 @@ impl Display for Error {
match self {
Error::Message(msg) => formatter.write_str(msg),
Error::Encode(err) => write!(formatter, "Encode: {}", err),
Error::Decode(err) => write!(formatter, "Decode: {}", err),
Error::Type(err) => write!(formatter, "Type: {}", err),
Error::ParseInt(err) => write!(formatter, "Parse (int): {}", err),
Error::ParseFloat(err) => write!(formatter, "Parse (float): {}", err),
Error::Utf8(err) => write!(formatter, "Invalid UTF-8 byte sequnence: {}", err),
}
}
}

View File

@ -1,7 +1,7 @@
//mod de;
mod de;
mod error;
mod ser;
//pub use de::{from_str, Deserializer};
pub use de::{from_bytes, Deserializer};
pub use error::{Error, Result};
pub use ser::{to_bytes, Serializer};
pub use ser::{to_bytes, to_term, Serializer};

View File

@ -6,6 +6,13 @@ use serde::ser::Error as SerError;
pub struct Serializer;
pub fn to_term<T>(value: &T) -> Result<Term<'static>>
where
T: Serialize,
{
Ok(value.serialize(&mut Serializer)?)
}
pub fn to_bytes<T>(value: &T) -> Result<Vec<u8>>
where
T: Serialize,
@ -94,7 +101,7 @@ impl<'a> ser::Serializer for &'a mut Serializer {
where
T: ?Sized + Serialize,
{
value.serialize(self)
Ok(value.serialize(self)?.nested())
}
fn serialize_unit(self) -> Result<Self::Ok> {
@ -142,7 +149,9 @@ impl<'a> ser::Serializer for &'a mut Serializer {
}
fn serialize_tuple(self, len: usize) -> Result<Self::SerializeTuple> {
Ok(SeqSerializer { items: Vec::with_capacity(len) })
Ok(SeqSerializer {
items: Vec::with_capacity(len),
})
}
fn serialize_tuple_struct(
@ -150,11 +159,9 @@ impl<'a> ser::Serializer for &'a mut Serializer {
name: &'static str,
len: usize,
) -> Result<Self::SerializeTupleStruct> {
let mut items = Vec::with_capacity(len + 1);
items.push(string(name)?);
Ok(SeqSerializer {
items,
})
let mut items = Vec::with_capacity(len + 1);
items.push(string(name)?);
Ok(SeqSerializer { items })
}
fn serialize_tuple_variant(
@ -164,11 +171,9 @@ impl<'a> ser::Serializer for &'a mut Serializer {
variant: &'static str,
len: usize,
) -> Result<Self::SerializeTupleVariant> {
let mut items = Vec::with_capacity(len + 1);
items.push(string_owned(format!("{}.{}", name, variant))?);
Ok(SeqSerializer {
items,
})
let mut items = Vec::with_capacity(len + 1);
items.push(string_owned(format!("{}.{}", name, variant))?);
Ok(SeqSerializer { items })
}
fn serialize_map(self, _len: Option<usize>) -> Result<Self::SerializeMap> {
@ -360,7 +365,7 @@ impl<'a> ser::SerializeStructVariant for StructVariantSerializer {
mod tests {
use super::*;
use serde::Serialize;
use std::collections::HashMap;
use std::collections::HashMap;
#[test]
fn test_struct() {
@ -430,8 +435,8 @@ mod tests {
#[test]
fn test_dict() {
let mut d = HashMap::new();
d.insert("hello", "world");
d.insert("dont", "panic");
d.insert("hello", "world");
d.insert("dont", "panic");
let expected = br#"{
ZG9udA = cGFuaWM,
aGVsbG8 = d29ybGQ,
@ -439,8 +444,8 @@ mod tests {
assert_eq!(&to_bytes(&d).unwrap(), expected);
let mut d = HashMap::new();
d.insert(12, vec![42, 125]);
d.insert(33, vec![19, 22, 21]);
d.insert(12, vec![42, 125]);
d.insert(33, vec![19, 22, 21]);
let expected = br#"{
12 = 42 125,
33 = 19 22 21,