1
Fork 0

Compare commits

...

2 commits

Author SHA1 Message Date
e037ef7659
version: v0.2.0 2022-11-25 16:09:53 +01:00
d4ea35d273
feat: Implement deserialization 2022-11-25 16:08:58 +01:00
7 changed files with 952 additions and 120 deletions

View file

@ -6,6 +6,12 @@
== [Unreleased] == [Unreleased]
== [v0.2.0] - 2022-11-25
=== Added
* parsing & deserialization
== [v0.1.0] - 2022-11-18 == [v0.1.0] - 2022-11-18
=== Added === Added

View file

@ -1,12 +1,14 @@
[package] [package]
name = "serde_sjson" name = "serde_sjson"
version = "0.1.0" version = "0.2.0"
edition = "2021" edition = "2021"
keywords = ["serde", "serialization", "sjson"] keywords = ["serde", "serialization", "sjson"]
description = "An SJSON serialization file format" description = "An SJSON serialization file format"
categories = ["encoding", "parser-implementations"] categories = ["encoding", "parser-implementations"]
[dependencies] [dependencies]
nom = "7.1.1"
nom_locate = "4.0.0"
serde = { version = "1.0.147", default-features = false } serde = { version = "1.0.147", default-features = false }
[dev-dependencies] [dev-dependencies]

709
src/de.rs
View file

@ -1,233 +1,734 @@
pub struct Deserializer {} use nom::IResult;
use serde::de::{EnumAccess, IntoDeserializer, VariantAccess};
use serde::Deserialize;
impl serde::Deserializer for Deserializer { use crate::error::{Error, ErrorCode, Result};
type Error; use crate::parser::*;
fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error> pub struct Deserializer<'de> {
where input: Span<'de>,
V: serde::de::Visitor<'de>, is_top_level: bool,
{
todo!()
} }
fn deserialize_bool<V>(self, visitor: V) -> Result<V::Value, Self::Error> impl<'de> Deserializer<'de> {
where #![allow(clippy::should_implement_trait)]
V: serde::de::Visitor<'de>, pub fn from_str(input: &'de str) -> Self {
{ Self {
todo!() input: Span::from(input),
is_top_level: true,
}
} }
fn deserialize_i8<V>(self, visitor: V) -> Result<V::Value, Self::Error> fn parse(&mut self, f: &dyn Fn(Span) -> IResult<Span, Token>) -> Result<Token> {
where f(self.input)
V: serde::de::Visitor<'de>, .map(|(span, token)| {
{ self.input = span;
todo!() token
})
.map_err(|err| self.error(ErrorCode::Message(err.to_string())))
} }
fn deserialize_i16<V>(self, visitor: V) -> Result<V::Value, Self::Error> fn next_token(&mut self) -> Result<Token> {
where match parse_next_token(self.input) {
V: serde::de::Visitor<'de>, Ok((span, token)) => {
{ self.input = span;
todo!() Ok(token)
}
Err(err) => Err(self.error(ErrorCode::Message(err.to_string()))),
}
} }
fn deserialize_i32<V>(self, visitor: V) -> Result<V::Value, Self::Error> fn peek_token(&mut self) -> Result<Token> {
where match parse_next_token(self.input) {
V: serde::de::Visitor<'de>, Ok((_, token)) => Ok(token),
{ Err(err) => Err(self.error(ErrorCode::Message(err.to_string()))),
todo!() }
} }
fn deserialize_i64<V>(self, visitor: V) -> Result<V::Value, Self::Error> fn error(&self, code: ErrorCode) -> Error {
where Error::new(
V: serde::de::Visitor<'de>, code,
{ self.input.location_line(),
todo!() self.input.get_utf8_column(),
Some(self.input.fragment().to_string()),
)
}
} }
fn deserialize_u8<V>(self, visitor: V) -> Result<V::Value, Self::Error> pub fn from_str<'a, T>(input: &'a str) -> Result<T>
where where
V: serde::de::Visitor<'de>, T: Deserialize<'a>,
{ {
todo!() let mut de = Deserializer::from_str(input);
let t = T::deserialize(&mut de)?;
if de.input.is_empty() || parse_trailing_characters(de.input).is_ok() {
Ok(t)
} else {
Err(de.error(ErrorCode::TrailingCharacters))
}
} }
fn deserialize_u16<V>(self, visitor: V) -> Result<V::Value, Self::Error> impl<'de, 'a> serde::de::Deserializer<'de> for &'a mut Deserializer<'de> {
type Error = Error;
fn deserialize_any<V>(self, visitor: V) -> Result<V::Value>
where where
V: serde::de::Visitor<'de>, V: serde::de::Visitor<'de>,
{ {
todo!() if self.is_top_level {
return Err(self.error(ErrorCode::ExpectedTopLevelObject));
} }
fn deserialize_u32<V>(self, visitor: V) -> Result<V::Value, Self::Error> match self.next_token()? {
where Token::Boolean(val) => visitor.visit_bool::<Self::Error>(val),
V: serde::de::Visitor<'de>, Token::Float(val) => visitor.visit_f64(val),
{ Token::Integer(val) => visitor.visit_i64(val),
todo!() Token::Null => visitor.visit_unit(),
Token::String(val) => visitor.visit_str(&val),
_ => Err(self.error(ErrorCode::ExpectedValue)),
}
} }
fn deserialize_u64<V>(self, visitor: V) -> Result<V::Value, Self::Error> fn deserialize_bool<V>(self, visitor: V) -> Result<V::Value>
where where
V: serde::de::Visitor<'de>, V: serde::de::Visitor<'de>,
{ {
todo!() if self.is_top_level {
return Err(self.error(ErrorCode::ExpectedTopLevelObject));
} }
fn deserialize_f32<V>(self, visitor: V) -> Result<V::Value, Self::Error> if let Ok(Token::Boolean(val)) = self.parse(&parse_bool) {
where visitor.visit_bool(val)
V: serde::de::Visitor<'de>, } else {
{ Err(self.error(ErrorCode::ExpectedBoolean))
todo!() }
} }
fn deserialize_f64<V>(self, visitor: V) -> Result<V::Value, Self::Error> fn deserialize_i8<V>(self, visitor: V) -> Result<V::Value>
where where
V: serde::de::Visitor<'de>, V: serde::de::Visitor<'de>,
{ {
todo!() self.deserialize_i64(visitor)
} }
fn deserialize_char<V>(self, visitor: V) -> Result<V::Value, Self::Error> fn deserialize_i16<V>(self, visitor: V) -> Result<V::Value>
where where
V: serde::de::Visitor<'de>, V: serde::de::Visitor<'de>,
{ {
todo!() self.deserialize_i64(visitor)
} }
fn deserialize_str<V>(self, visitor: V) -> Result<V::Value, Self::Error> fn deserialize_i32<V>(self, visitor: V) -> Result<V::Value>
where where
V: serde::de::Visitor<'de>, V: serde::de::Visitor<'de>,
{ {
todo!() self.deserialize_i64(visitor)
} }
fn deserialize_string<V>(self, visitor: V) -> Result<V::Value, Self::Error> fn deserialize_i64<V>(self, visitor: V) -> Result<V::Value>
where where
V: serde::de::Visitor<'de>, V: serde::de::Visitor<'de>,
{ {
todo!() if self.is_top_level {
return Err(self.error(ErrorCode::ExpectedTopLevelObject));
} }
fn deserialize_bytes<V>(self, visitor: V) -> Result<V::Value, Self::Error> if let Ok(Token::Integer(val)) = self.parse(&parse_integer) {
where visitor.visit_i64(val)
V: serde::de::Visitor<'de>, } else {
{ Err(self.error(ErrorCode::ExpectedInteger))
todo!() }
} }
fn deserialize_byte_buf<V>(self, visitor: V) -> Result<V::Value, Self::Error> fn deserialize_u8<V>(self, visitor: V) -> Result<V::Value>
where where
V: serde::de::Visitor<'de>, V: serde::de::Visitor<'de>,
{ {
todo!() self.deserialize_i64(visitor)
} }
fn deserialize_option<V>(self, visitor: V) -> Result<V::Value, Self::Error> fn deserialize_u16<V>(self, visitor: V) -> Result<V::Value>
where where
V: serde::de::Visitor<'de>, V: serde::de::Visitor<'de>,
{ {
todo!() self.deserialize_i64(visitor)
} }
fn deserialize_unit<V>(self, visitor: V) -> Result<V::Value, Self::Error> fn deserialize_u32<V>(self, visitor: V) -> Result<V::Value>
where where
V: serde::de::Visitor<'de>, V: serde::de::Visitor<'de>,
{ {
todo!() self.deserialize_i64(visitor)
} }
fn deserialize_unit_struct<V>( fn deserialize_u64<V>(self, visitor: V) -> Result<V::Value>
self,
name: &'static str,
visitor: V,
) -> Result<V::Value, Self::Error>
where where
V: serde::de::Visitor<'de>, V: serde::de::Visitor<'de>,
{ {
todo!() self.deserialize_i64(visitor)
} }
fn deserialize_newtype_struct<V>( fn deserialize_f32<V>(self, visitor: V) -> Result<V::Value>
self,
name: &'static str,
visitor: V,
) -> Result<V::Value, Self::Error>
where where
V: serde::de::Visitor<'de>, V: serde::de::Visitor<'de>,
{ {
todo!() self.deserialize_f64(visitor)
} }
fn deserialize_seq<V>(self, visitor: V) -> Result<V::Value, Self::Error> fn deserialize_f64<V>(self, visitor: V) -> Result<V::Value>
where where
V: serde::de::Visitor<'de>, V: serde::de::Visitor<'de>,
{ {
todo!() if self.is_top_level {
return Err(self.error(ErrorCode::ExpectedTopLevelObject));
} }
fn deserialize_tuple<V>(self, len: usize, visitor: V) -> Result<V::Value, Self::Error> if let Ok(Token::Float(val)) = self.parse(&parse_float) {
visitor.visit_f64(val)
} else {
Err(self.error(ErrorCode::ExpectedFloat))
}
}
fn deserialize_char<V>(self, visitor: V) -> Result<V::Value>
where where
V: serde::de::Visitor<'de>, V: serde::de::Visitor<'de>,
{ {
todo!() self.deserialize_str(visitor)
}
fn deserialize_str<V>(self, visitor: V) -> Result<V::Value>
where
V: serde::de::Visitor<'de>,
{
if self.is_top_level {
return Err(self.error(ErrorCode::ExpectedTopLevelObject));
}
if let Ok(Token::String(val)) = self.parse(&parse_string) {
visitor.visit_str(&val)
} else {
Err(self.error(ErrorCode::ExpectedString))
}
}
fn deserialize_string<V>(self, visitor: V) -> Result<V::Value>
where
V: serde::de::Visitor<'de>,
{
self.deserialize_str(visitor)
}
fn deserialize_bytes<V>(self, _visitor: V) -> Result<V::Value>
where
V: serde::de::Visitor<'de>,
{
unimplemented!()
}
fn deserialize_byte_buf<V>(self, _visitor: V) -> Result<V::Value>
where
V: serde::de::Visitor<'de>,
{
unimplemented!()
}
fn deserialize_option<V>(self, visitor: V) -> Result<V::Value>
where
V: serde::de::Visitor<'de>,
{
if self.is_top_level {
return Err(self.error(ErrorCode::ExpectedTopLevelObject));
}
if self.peek_token()? == Token::Null {
let _ = self.next_token()?;
visitor.visit_none()
} else {
visitor.visit_some(self)
}
}
fn deserialize_unit<V>(self, visitor: V) -> Result<V::Value>
where
V: serde::de::Visitor<'de>,
{
if self.is_top_level {
return Err(self.error(ErrorCode::ExpectedTopLevelObject));
}
if let Ok(Token::Null) = self.parse(&parse_null) {
visitor.visit_unit()
} else {
Err(self.error(ErrorCode::ExpectedNull))
}
}
fn deserialize_unit_struct<V>(self, _name: &'static str, visitor: V) -> Result<V::Value>
where
V: serde::de::Visitor<'de>,
{
self.deserialize_unit(visitor)
}
fn deserialize_newtype_struct<V>(self, _name: &'static str, visitor: V) -> Result<V::Value>
where
V: serde::de::Visitor<'de>,
{
visitor.visit_newtype_struct(self)
}
fn deserialize_seq<V>(self, visitor: V) -> Result<V::Value>
where
V: serde::de::Visitor<'de>,
{
if self.is_top_level {
return Err(self.error(ErrorCode::ExpectedTopLevelObject));
}
if self.next_token()? != Token::ArrayStart {
return Err(self.error(ErrorCode::ExpectedArray));
}
let value = visitor.visit_seq(Separated::new(self))?;
if self.next_token()? == Token::ArrayEnd {
Ok(value)
} else {
Err(self.error(ErrorCode::ExpectedArrayEnd))
}
}
fn deserialize_tuple<V>(self, _len: usize, visitor: V) -> Result<V::Value>
where
V: serde::de::Visitor<'de>,
{
self.deserialize_seq(visitor)
} }
fn deserialize_tuple_struct<V>( fn deserialize_tuple_struct<V>(
self, self,
name: &'static str, _name: &'static str,
len: usize, _len: usize,
visitor: V, visitor: V,
) -> Result<V::Value, Self::Error> ) -> Result<V::Value>
where where
V: serde::de::Visitor<'de>, V: serde::de::Visitor<'de>,
{ {
todo!() self.deserialize_seq(visitor)
} }
fn deserialize_map<V>(self, visitor: V) -> Result<V::Value, Self::Error> fn deserialize_map<V>(self, visitor: V) -> Result<V::Value>
where where
V: serde::de::Visitor<'de>, V: serde::de::Visitor<'de>,
{ {
todo!() if self.is_top_level {
self.is_top_level = false;
visitor.visit_map(Separated::new(self))
} else {
if self.next_token()? != Token::ObjectStart {
return Err(self.error(ErrorCode::ExpectedMap));
}
let value = visitor.visit_map(Separated::new(self))?;
if self.next_token()? == Token::ObjectEnd {
Ok(value)
} else {
Err(self.error(ErrorCode::ExpectedMapEnd))
}
}
} }
fn deserialize_struct<V>( fn deserialize_struct<V>(
self, self,
name: &'static str, _name: &'static str,
fields: &'static [&'static str], _fields: &'static [&'static str],
visitor: V, visitor: V,
) -> Result<V::Value, Self::Error> ) -> Result<V::Value>
where where
V: serde::de::Visitor<'de>, V: serde::de::Visitor<'de>,
{ {
todo!() self.deserialize_map(visitor)
} }
fn deserialize_enum<V>( fn deserialize_enum<V>(
self, self,
name: &'static str, _name: &'static str,
variants: &'static [&'static str], _variants: &'static [&'static str],
visitor: V, visitor: V,
) -> Result<V::Value, Self::Error> ) -> Result<V::Value>
where where
V: serde::de::Visitor<'de>, V: serde::de::Visitor<'de>,
{ {
todo!() match self.next_token()? {
Token::String(val) => visitor.visit_enum(val.into_deserializer()),
Token::ObjectStart => {
let value = visitor.visit_enum(Enum::new(self))?;
if self.next_token()? == Token::ObjectEnd {
Ok(value)
} else {
Err(self.error(ErrorCode::ExpectedMapEnd))
}
}
_ => Err(self.error(ErrorCode::ExpectedEnum)),
}
} }
fn deserialize_identifier<V>(self, visitor: V) -> Result<V::Value, Self::Error> fn deserialize_identifier<V>(self, visitor: V) -> Result<V::Value>
where where
V: serde::de::Visitor<'de>, V: serde::de::Visitor<'de>,
{ {
todo!() if let Ok(Token::String(val)) = self.parse(&parse_identifier) {
visitor.visit_str(&val)
} else {
Err(self.error(ErrorCode::ExpectedString))
}
} }
fn deserialize_ignored_any<V>(self, visitor: V) -> Result<V::Value, Self::Error> fn deserialize_ignored_any<V>(self, visitor: V) -> Result<V::Value>
where where
V: serde::de::Visitor<'de>, V: serde::de::Visitor<'de>,
{ {
todo!() self.deserialize_any(visitor)
} }
} }
pub fn from_str<T>() -> crate::Result<T> {} struct Separated<'a, 'de: 'a> {
de: &'a mut Deserializer<'de>,
first: bool,
}
impl<'a, 'de: 'a> Separated<'a, 'de> {
fn new(de: &'a mut Deserializer<'de>) -> Self {
Self { de, first: true }
}
}
impl<'de, 'a> serde::de::SeqAccess<'de> for Separated<'a, 'de> {
type Error = Error;
fn next_element_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>>
where
T: serde::de::DeserializeSeed<'de>,
{
if self.de.peek_token()? == Token::ArrayEnd {
return Ok(None);
}
if !self.first && self.de.parse(&parse_separator)? != Token::Separator {
return Err(self.de.error(ErrorCode::ExpectedArraySeparator));
}
self.first = false;
// TODO: Shouldn't I check that this is a valid value?
seed.deserialize(&mut *self.de).map(Some)
}
}
impl<'de, 'a> serde::de::MapAccess<'de> for Separated<'a, 'de> {
type Error = Error;
fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>>
where
K: serde::de::DeserializeSeed<'de>,
{
if matches!(self.de.peek_token()?, Token::ObjectEnd | Token::Eof) {
return Ok(None);
}
if !self.first && self.de.parse(&parse_separator)? != Token::Separator {
return Err(self.de.error(ErrorCode::ExpectedMapSeparator));
}
self.first = false;
// TODO: Shouldn't I check that this is a valid identifier?
seed.deserialize(&mut *self.de).map(Some)
}
fn next_value_seed<V>(&mut self, seed: V) -> Result<V::Value>
where
V: serde::de::DeserializeSeed<'de>,
{
if self.de.next_token()? != Token::Equals {
return Err(self.de.error(ErrorCode::ExpectedMapEquals));
}
// TODO: Shouldn't I check that this is a valid value?
seed.deserialize(&mut *self.de)
}
}
struct Enum<'a, 'de: 'a> {
de: &'a mut Deserializer<'de>,
}
impl<'a, 'de> Enum<'a, 'de> {
fn new(de: &'a mut Deserializer<'de>) -> Self {
Self { de }
}
}
impl<'de, 'a> EnumAccess<'de> for Enum<'a, 'de> {
type Error = Error;
type Variant = Self;
fn variant_seed<V>(self, seed: V) -> Result<(V::Value, Self::Variant)>
where
V: serde::de::DeserializeSeed<'de>,
{
let val = seed.deserialize(&mut *self.de)?;
if self.de.next_token()? == Token::Equals {
Ok((val, self))
} else {
Err(self.de.error(ErrorCode::ExpectedMapEquals))
}
}
}
impl<'de, 'a> VariantAccess<'de> for Enum<'a, 'de> {
type Error = Error;
fn unit_variant(self) -> Result<()> {
Err(self.de.error(ErrorCode::ExpectedString))
}
fn newtype_variant_seed<T>(self, seed: T) -> Result<T::Value>
where
T: serde::de::DeserializeSeed<'de>,
{
seed.deserialize(self.de)
}
fn tuple_variant<V>(self, _len: usize, visitor: V) -> Result<V::Value>
where
V: serde::de::Visitor<'de>,
{
serde::Deserializer::deserialize_seq(self.de, visitor)
}
fn struct_variant<V>(self, _fields: &'static [&'static str], visitor: V) -> Result<V::Value>
where
V: serde::de::Visitor<'de>,
{
serde::Deserializer::deserialize_map(self.de, visitor)
}
}
#[cfg(test)]
mod test {
use std::path::PathBuf;
use crate::error::{Error, ErrorCode};
use crate::from_str;
macro_rules! assert_value_ok {
($type:ty, $json:expr) => {
assert_value_ok!($type, Default::default(), $json)
};
($type:ty, $expected:expr, $json:expr) => {{
#[derive(Debug, serde::Deserialize, PartialEq)]
struct Value {
value: $type,
}
let expected = Value { value: $expected };
let json = format!("value = {}", $json);
let actual = from_str::<Value>(&json).unwrap();
assert_eq!(actual, expected);
}};
}
macro_rules! assert_ok {
($type:ty, $expected:expr, $json:expr) => {{
let actual = from_str::<$type>($json).unwrap();
assert_eq!(actual, $expected);
}};
}
macro_rules! assert_value_err {
($type:ty, $expected:expr, $json:expr) => {{
#[derive(Debug, serde::Deserialize, PartialEq)]
struct Value {
value: $type,
}
let json = format!("value = {}", $json);
let actual = from_str::<Value>(&json);
assert_eq!(actual, Err($expected));
}};
}
#[test]
fn deserialize_null() {
assert_value_ok!((), "null");
let err = Error::new(ErrorCode::ExpectedNull, 1, 8, Some(" foo".to_string()));
assert_value_err!((), err, "foo");
}
#[test]
fn deserialize_bool() {
assert_value_ok!(bool, true, "true");
assert_value_ok!(bool, false, "false");
let err = Error::new(ErrorCode::ExpectedBoolean, 1, 8, Some(" foo".to_string()));
assert_value_err!(bool, err, "foo");
}
#[test]
fn deserialize_integer() {
assert_value_ok!(i64, 0, "0");
assert_value_ok!(i64, -1, "-1");
assert_value_ok!(i64, i64::MAX, i64::MAX.to_string());
assert_value_ok!(i64, i64::MIN, i64::MIN.to_string());
assert_value_ok!(i8, 0, "0");
assert_value_ok!(i8, 102, "102");
assert_value_ok!(i8, -102, "-102");
assert_value_ok!(u8, 102, "102");
assert_value_ok!(i16, 256, "256");
let err = Error::new(ErrorCode::ExpectedInteger, 1, 8, Some(" foo".to_string()));
assert_value_err!(i64, err, "foo");
}
#[test]
fn deserialize_float() {
assert_value_ok!(f64, 0.0, "0");
assert_value_ok!(f64, 0.0, "0.0");
assert_value_ok!(f64, -1.0, "-1");
assert_value_ok!(f64, -1.0, "-1.0");
assert_value_ok!(f64, f64::MAX, f64::MAX.to_string());
assert_value_ok!(f64, f64::MIN, f64::MIN.to_string());
}
#[test]
fn deserialize_vec() {
assert_value_ok!(Vec<u64>, vec![1, 2, 3], "[1, 2, 3]");
assert_value_ok!(
Vec<u64>,
vec![1, 2, 3],
"\
[
1
2
3
]"
);
}
#[test]
fn deserialize_enum() {
#[derive(Debug, serde::Deserialize, PartialEq)]
enum Animal {
Mouse,
Dog { name: String },
Cat(u64),
}
assert_value_ok!(Animal, Animal::Mouse, "Mouse");
assert_value_ok!(Animal, Animal::Cat(9), "{ Cat = 9 }");
assert_value_ok!(
Animal,
Animal::Dog {
name: String::from("Buddy")
},
"{ Dog = { name = Buddy }}"
);
}
// Checks the example from
// https://help.autodesk.com/view/Stingray/ENU/?guid=__stingray_help_managing_content_sjson_html
#[test]
fn deserialize_stingray_example() {
#[derive(Debug, serde::Deserialize, PartialEq)]
struct Win32Settings {
query_performance_counter_affinity_mask: u64,
}
#[derive(Debug, serde::Deserialize, PartialEq)]
struct Settings {
boot_script: String,
console_port: u16,
win32: Win32Settings,
render_config: PathBuf,
}
let expected = Settings {
boot_script: String::from("boot"),
console_port: 14030,
win32: Win32Settings {
query_performance_counter_affinity_mask: 0,
},
render_config: PathBuf::from("core/rendering/renderer"),
};
let json = r#"
// The script that should be started when the application runs.
boot_script = "boot"
// The port on which the console server runs.
console_port = 14030
// Settings for the win32 platform
win32 = {
/* Sets the affinity mask for
QueryPerformanceCounter() */
query_performance_counter_affinity_mask = 0
}
render_config = "core/rendering/renderer"
"#;
assert_ok!(Settings, expected, json);
}
#[test]
fn deserialize_missing_top_level_struct() {
let json = "0";
let err = Error::new(
ErrorCode::ExpectedTopLevelObject,
1,
1,
Some(json.to_string()),
);
let actual = from_str::<i64>(json);
assert_eq!(actual, Err(err));
let json = "1.23";
let err = Error::new(
ErrorCode::ExpectedTopLevelObject,
1,
1,
Some(json.to_string()),
);
let actual = from_str::<f64>(json);
assert_eq!(actual, Err(err));
let json = "true";
let err = Error::new(
ErrorCode::ExpectedTopLevelObject,
1,
1,
Some(json.to_string()),
);
let actual = from_str::<bool>(json);
assert_eq!(actual, Err(err));
let json = "null";
let err = Error::new(
ErrorCode::ExpectedTopLevelObject,
1,
1,
Some(json.to_string()),
);
let actual = from_str::<()>(json);
assert_eq!(actual, Err(err));
}
}

View file

@ -1,36 +1,39 @@
use std::{fmt, io}; use std::fmt;
pub type Result<T> = std::result::Result<T, Error>; pub type Result<T> = std::result::Result<T, Error>;
#[derive(PartialEq)]
pub struct Error { pub struct Error {
inner: Box<ErrorImpl>, inner: Box<ErrorImpl>,
} }
#[derive(PartialEq)]
struct ErrorImpl { struct ErrorImpl {
code: ErrorCode, code: ErrorCode,
line: usize, line: u32,
column: usize, column: usize,
fragment: Option<String>,
} }
// TODO: Remove once they are constructed #[derive(PartialEq)]
#[allow(dead_code)]
pub(crate) enum ErrorCode { pub(crate) enum ErrorCode {
// Generic error built from a message or different error // Generic error built from a message or different error
Message(String), Message(String),
// Wrap inner I/O errors
Io(io::Error),
Eof,
Syntax,
ExpectedTopLevelObject,
ExpectedBoolean,
ExpectedInteger,
ExpectedString,
ExpectedNull,
ExpectedArray, ExpectedArray,
ExpectedArrayEnd, ExpectedArrayEnd,
ExpectedArraySeparator,
ExpectedBoolean,
ExpectedEnum,
ExpectedFloat,
ExpectedInteger,
ExpectedMap, ExpectedMap,
ExpectedMapEquals,
ExpectedMapEnd, ExpectedMapEnd,
ExpectedMapEquals,
ExpectedMapSeparator,
ExpectedNull,
ExpectedString,
ExpectedTopLevelObject,
ExpectedValue,
TrailingCharacters, TrailingCharacters,
} }
@ -38,19 +41,25 @@ impl fmt::Display for ErrorCode {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self { match self {
ErrorCode::Message(msg) => f.write_str(msg), ErrorCode::Message(msg) => f.write_str(msg),
ErrorCode::Io(err) => fmt::Display::fmt(err, f),
ErrorCode::Eof => f.write_str("unexpected end of input"),
ErrorCode::Syntax => f.write_str("syntax error"),
ErrorCode::ExpectedTopLevelObject => f.write_str("expected object at the top level"),
ErrorCode::ExpectedBoolean => f.write_str("expected a boolean value"),
ErrorCode::ExpectedInteger => f.write_str("expected an integer value"),
ErrorCode::ExpectedString => f.write_str("expected a string value"),
ErrorCode::ExpectedNull => f.write_str("expected null"),
ErrorCode::ExpectedArray => f.write_str("expected an array value"), ErrorCode::ExpectedArray => f.write_str("expected an array value"),
ErrorCode::ExpectedArrayEnd => f.write_str("expected an array end delimiter"), ErrorCode::ExpectedArrayEnd => f.write_str("expected an array end delimiter"),
ErrorCode::ExpectedMap => f.write_str("expected an object value"), ErrorCode::ExpectedArraySeparator => {
ErrorCode::ExpectedMapEquals => f.write_str("expected a '=' between key and value"), f.write_str("expected comma or newline between array entries")
}
ErrorCode::ExpectedBoolean => f.write_str("expected a boolean value"),
ErrorCode::ExpectedEnum => f.write_str("expected string or object"),
ErrorCode::ExpectedFloat => f.write_str("expected floating point number"),
ErrorCode::ExpectedInteger => f.write_str("expected an integer value"),
ErrorCode::ExpectedMap => f.write_str("expected an object"),
ErrorCode::ExpectedMapEnd => f.write_str("expected an object end delimiter"), ErrorCode::ExpectedMapEnd => f.write_str("expected an object end delimiter"),
ErrorCode::ExpectedMapEquals => f.write_str("expected a '=' between key and value"),
ErrorCode::ExpectedMapSeparator => {
f.write_str("expected comma or newline between object entries")
}
ErrorCode::ExpectedNull => f.write_str("expected null"),
ErrorCode::ExpectedString => f.write_str("expected a string value"),
ErrorCode::ExpectedTopLevelObject => f.write_str("expected object at the top level"),
ErrorCode::ExpectedValue => f.write_str("expected a value"),
ErrorCode::TrailingCharacters => f.write_str("unexpected trailing characters"), ErrorCode::TrailingCharacters => f.write_str("unexpected trailing characters"),
} }
} }
@ -80,10 +89,11 @@ impl fmt::Debug for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!( write!(
f, f,
"Error({:?}, line: {}, column: {})", "Error({:?}, line: {}, column: {}, fragment: {:?})",
self.inner.code.to_string(), self.inner.code.to_string(),
self.inner.line, self.inner.line,
self.inner.column self.inner.column,
self.inner.fragment,
) )
} }
} }
@ -97,6 +107,7 @@ impl serde::de::Error for Error {
code: ErrorCode::Message(msg.to_string()), code: ErrorCode::Message(msg.to_string()),
line: 0, line: 0,
column: 0, column: 0,
fragment: None,
}); });
Self { inner } Self { inner }
} }
@ -111,6 +122,7 @@ impl serde::ser::Error for Error {
code: ErrorCode::Message(msg.to_string()), code: ErrorCode::Message(msg.to_string()),
line: 0, line: 0,
column: 0, column: 0,
fragment: None,
}); });
Self { inner } Self { inner }
} }
@ -119,9 +131,14 @@ impl serde::ser::Error for Error {
impl std::error::Error for Error {} impl std::error::Error for Error {}
impl Error { impl Error {
pub(crate) fn new(code: ErrorCode, line: usize, column: usize) -> Self { pub(crate) fn new(code: ErrorCode, line: u32, column: usize, fragment: Option<String>) -> Self {
Self { Self {
inner: Box::new(ErrorImpl { code, line, column }), inner: Box::new(ErrorImpl {
code,
line,
column,
fragment,
}),
} }
} }
} }

View file

@ -1,7 +1,8 @@
// mod de; mod de;
mod error; mod error;
mod parser;
mod ser; mod ser;
// pub use de::{from_str, Deserializer}; pub use de::{from_str, Deserializer};
pub use error::{Error, Result}; pub use error::{Error, Result};
pub use ser::{to_string, Serializer}; pub use ser::{to_string, Serializer};

305
src/parser.rs Normal file
View file

@ -0,0 +1,305 @@
use nom::branch::alt;
use nom::bytes::complete::{escaped, tag, take_until};
use nom::character::complete::{
alpha1, alphanumeric1, char, digit1, none_of, not_line_ending, one_of,
};
use nom::combinator::{cut, eof, map, map_res, opt, recognize, value};
use nom::multi::{many0_count, many1_count};
use nom::number::complete::double;
use nom::sequence::{delimited, pair, preceded, terminated, tuple};
use nom::IResult;
use nom_locate::LocatedSpan;
pub(crate) type Span<'a> = LocatedSpan<&'a str>;
#[derive(Clone, Debug, PartialEq)]
pub(crate) enum Token {
ArrayEnd,
ArrayStart,
Boolean(bool),
Eof,
Equals,
Float(f64),
Integer(i64),
Null,
ObjectEnd,
ObjectStart,
Separator,
String(String),
}
fn horizontal_whitespace(input: Span) -> IResult<Span, char> {
one_of(" \t")(input)
}
fn whitespace(input: Span) -> IResult<Span, char> {
one_of(" \n\r\t")(input)
}
fn null(input: Span) -> IResult<Span, ()> {
value((), tag("null"))(input)
}
fn separator(input: Span) -> IResult<Span, &str> {
map(alt((tag(","), tag("\n"))), |val: Span| *val.fragment())(input)
}
fn bool(input: Span) -> IResult<Span, bool> {
alt((value(true, tag("true")), value(false, tag("false"))))(input)
}
fn integer(input: Span) -> IResult<Span, i64> {
map_res(recognize(tuple((opt(char('-')), digit1))), |val: Span| {
val.fragment().parse::<i64>()
})(input)
}
fn float(input: Span) -> IResult<Span, f64> {
double(input)
}
fn identifier(input: Span) -> IResult<Span, &str> {
let leading = alt((alpha1, tag("_")));
let trailing = many0_count(alt((alphanumeric1, tag("_"))));
let ident = pair(leading, trailing);
map(recognize(ident), |val: Span| *val.fragment())(input)
}
fn string_content(input: Span) -> IResult<Span, &str> {
// TODO: Handle Unicode escapes
map(
alt((
escaped(none_of("\n\\\""), '\\', one_of(r#""rtn\"#)),
tag(""),
)),
|val: Span| *val.fragment(),
)(input)
}
fn delimited_string(input: Span) -> IResult<Span, &str> {
preceded(char('"'), cut(terminated(string_content, char('"'))))(input)
}
fn string(input: Span) -> IResult<Span, &str> {
alt((identifier, delimited_string))(input)
}
fn line_comment(input: Span) -> IResult<Span, &str> {
map(
preceded(tag("//"), alt((not_line_ending, eof))),
|val: Span| *val.fragment(),
)(input)
}
fn block_comment(input: Span) -> IResult<Span, &str> {
map(
delimited(tag("/*"), take_until("*/"), tag("*/")),
|val: Span| *val.fragment(),
)(input)
}
fn comment(input: Span) -> IResult<Span, &str> {
alt((line_comment, block_comment))(input)
}
fn optional(input: Span) -> IResult<Span, ()> {
let whitespace = value((), whitespace);
let comment = value((), comment);
let empty = value((), tag(""));
let content = value((), many1_count(alt((whitespace, comment))));
alt((content, empty))(input)
}
pub(crate) fn parse_next_token(input: Span) -> IResult<Span, Token> {
preceded(
opt(optional),
alt((
// Order is important here.
// Certain valid strings like "null", "true" or "false" need to be
// matched to their special value.
// Integer-like numbers need to be matched to that, but are valid floats, too.
value(Token::Eof, eof),
value(Token::Separator, separator),
value(Token::ObjectStart, tag("{")),
value(Token::ObjectEnd, tag("}")),
value(Token::ArrayStart, tag("[")),
value(Token::ArrayEnd, tag("]")),
value(Token::Equals, tag("=")),
value(Token::Null, null),
map(bool, Token::Boolean),
map(integer, Token::Integer),
map(float, Token::Float),
map(string, |val| Token::String(val.to_string())),
)),
)(input)
}
pub(crate) fn parse_trailing_characters(input: Span) -> IResult<Span, ()> {
value((), optional)(input)
}
pub(crate) fn parse_null(input: Span) -> IResult<Span, Token> {
preceded(optional, value(Token::Null, null))(input)
}
pub(crate) fn parse_separator(input: Span) -> IResult<Span, Token> {
preceded(
opt(horizontal_whitespace),
value(Token::Separator, separator),
)(input)
}
pub(crate) fn parse_bool(input: Span) -> IResult<Span, Token> {
preceded(optional, map(bool, Token::Boolean))(input)
}
pub(crate) fn parse_integer(input: Span) -> IResult<Span, Token> {
preceded(optional, map(integer, Token::Integer))(input)
}
pub(crate) fn parse_float(input: Span) -> IResult<Span, Token> {
preceded(optional, map(float, Token::Float))(input)
}
pub(crate) fn parse_identifier(input: Span) -> IResult<Span, Token> {
preceded(
optional,
map(identifier, |val| Token::String(val.to_string())),
)(input)
}
pub(crate) fn parse_string(input: Span) -> IResult<Span, Token> {
preceded(optional, map(string, |val| Token::String(val.to_string())))(input)
}
#[cfg(test)]
mod test {
use nom::error::{Error, ErrorKind};
use nom::Err;
use super::*;
macro_rules! assert_ok {
($input:expr, $parser:ident, $remain:expr, $output:expr) => {{
let res = super::$parser(Span::from($input));
assert_eq!(
res.map(|(span, res)| { (*span, res) }),
Ok(($remain, $output))
);
}};
}
macro_rules! assert_err {
($input:expr, $parser:ident, $kind:expr) => {{
{
let input = Span::from($input);
assert_eq!(
super::$parser(input),
Err(Err::Error(Error::new(input, $kind)))
);
}
}};
}
#[test]
fn parse_optional() {
assert_ok!("\n", whitespace, "", '\n');
assert_ok!("\t", whitespace, "", '\t');
assert_ok!(" ", whitespace, " ", ' ');
assert_ok!("/* foo bar */", comment, "", " foo bar ");
assert_ok!("// foo", comment, "", " foo");
assert_ok!("// foo\n", comment, "\n", " foo");
assert_ok!("", optional, "", ());
assert_ok!("\t\n", optional, "", ());
assert_ok!("\n\t", optional, "", ());
assert_ok!("// foo", optional, "", ());
assert_ok!("\n\t// foo\n\t/* foo\n\tbar */\n", optional, "", ());
}
#[test]
fn parse_integer() {
assert_ok!("3", integer, "", 3);
assert_ok!("12345", integer, "", 12345);
assert_ok!("-12345", integer, "", -12345);
assert_ok!("12345 ", integer, " ", 12345);
assert_err!(" 12345", integer, ErrorKind::Digit);
assert_ok!(" 12345", parse_integer, "", Token::Integer(12345));
assert_ok!("\n12345", parse_integer, "", Token::Integer(12345));
assert_ok!("\t12345", parse_integer, "", Token::Integer(12345));
}
#[test]
fn parse_float() {
assert_ok!("3", float, "", 3.0);
assert_ok!("3.0", float, "", 3.0);
assert_ok!("3.1415", float, "", 3.1415);
assert_ok!("-123.456789", float, "", -123.456789);
assert_err!(" 1.23", float, ErrorKind::Float);
assert_ok!("1.23 ", float, " ", 1.23);
}
#[test]
fn parse_raw_string() {
assert_ok!("foo", identifier, "", "foo");
assert_ok!("foo123", identifier, "", "foo123");
assert_ok!("foo_bar", identifier, "", "foo_bar");
assert_ok!("_foo", identifier, "", "_foo");
assert_ok!("foo bar", identifier, " bar", "foo");
assert_err!("123", identifier, ErrorKind::Tag);
assert_err!("1foo", identifier, ErrorKind::Tag);
assert_err!("\"foo\"", identifier, ErrorKind::Tag);
}
#[test]
fn parse_delimited_string() {
assert_ok!(r#""""#, delimited_string, "", "");
assert_ok!(r#""foo""#, delimited_string, "", "foo");
assert_ok!(r#""\"foo""#, delimited_string, "", r#"\"foo"#);
assert_ok!(r#""foo bar""#, delimited_string, "", "foo bar");
assert_ok!(r#""foo123""#, delimited_string, "", "foo123");
assert_ok!(r#""123foo""#, delimited_string, "", "123foo");
assert_ok!(r#""foo\"bar""#, delimited_string, "", "foo\\\"bar");
assert_err!("foo\"", delimited_string, ErrorKind::Char);
{
let input = Span::from("\"foo");
assert_eq!(
delimited_string(input),
Err(Err::Failure(Error::new(
unsafe { Span::new_from_raw_offset(4, 1, "", ()) },
ErrorKind::Char
)))
);
}
{
let input = Span::from("\"foo\nbar\"");
assert_eq!(
delimited_string(input),
Err(Err::Failure(Error::new(
unsafe { Span::new_from_raw_offset(4, 1, "\nbar\"", ()) },
ErrorKind::Char
)))
);
}
}
#[test]
fn parse_line_comment() {
assert_ok!("// foo", line_comment, "", " foo");
assert_ok!("// foo\n", line_comment, "\n", " foo");
}
#[test]
fn parse_block_comment() {
assert_ok!("/* foo */", block_comment, "", " foo ");
assert_ok!("/*\n\tfoo\nbar\n*/", block_comment, "", "\n\tfoo\nbar\n");
}
}

View file

@ -33,7 +33,7 @@ impl Serializer {
fn ensure_top_level_struct(&self) -> Result<()> { fn ensure_top_level_struct(&self) -> Result<()> {
if self.level == 0 { if self.level == 0 {
return Err(Error::new(ErrorCode::ExpectedTopLevelObject, 0, 0)); return Err(Error::new(ErrorCode::ExpectedTopLevelObject, 0, 0, None));
} }
Ok(()) Ok(())