Compare commits
2 commits
39486e8503
...
fc5d8b25fb
Author | SHA1 | Date | |
---|---|---|---|
fc5d8b25fb | |||
5a367bc478 |
5 changed files with 162 additions and 9 deletions
|
@ -6,6 +6,12 @@
|
|||
|
||||
== [Unreleased]
|
||||
|
||||
== [v0.2.2] - 2023-02-18
|
||||
|
||||
=== Fixed
|
||||
|
||||
- fix deserialization failing on arrays and objects in some cases
|
||||
|
||||
== [v0.2.1] - 2022-12-28
|
||||
|
||||
=== Fixed
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "serde_sjson"
|
||||
version = "0.2.1"
|
||||
version = "0.2.2"
|
||||
edition = "2021"
|
||||
keywords = ["serde", "serialization", "sjson"]
|
||||
description = "An SJSON serialization file format"
|
||||
|
|
75
src/de.rs
75
src/de.rs
|
@ -53,6 +53,16 @@ impl<'de> Deserializer<'de> {
|
|||
Some(self.input.fragment().to_string()),
|
||||
)
|
||||
}
|
||||
|
||||
fn error_with_token(&self, code: ErrorCode, token: Token) -> Error {
|
||||
Error::with_token(
|
||||
code,
|
||||
self.input.location_line(),
|
||||
self.input.get_utf8_column(),
|
||||
Some(self.input.fragment().to_string()),
|
||||
token,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_str<'a, T>(input: &'a str) -> Result<T>
|
||||
|
@ -79,13 +89,15 @@ impl<'de, 'a> serde::de::Deserializer<'de> for &'a mut Deserializer<'de> {
|
|||
return Err(self.error(ErrorCode::ExpectedTopLevelObject));
|
||||
}
|
||||
|
||||
match self.next_token()? {
|
||||
Token::Boolean(val) => visitor.visit_bool::<Self::Error>(val),
|
||||
Token::Float(val) => visitor.visit_f64(val),
|
||||
Token::Integer(val) => visitor.visit_i64(val),
|
||||
Token::Null => visitor.visit_unit(),
|
||||
Token::String(val) => visitor.visit_str(&val),
|
||||
_ => Err(self.error(ErrorCode::ExpectedValue)),
|
||||
match self.peek_token()? {
|
||||
Token::Boolean(_) => self.deserialize_bool(visitor),
|
||||
Token::Float(_) => self.deserialize_f64(visitor),
|
||||
Token::Integer(_) => self.deserialize_i64(visitor),
|
||||
Token::Null => self.deserialize_unit(visitor),
|
||||
Token::String(_) => self.deserialize_str(visitor),
|
||||
Token::ArrayStart => self.deserialize_seq(visitor),
|
||||
Token::ObjectStart => self.deserialize_map(visitor),
|
||||
token => Err(self.error_with_token(ErrorCode::ExpectedValue, token)),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -731,4 +743,53 @@ render_config = "core/rendering/renderer"
|
|||
let actual = from_str::<()>(json);
|
||||
assert_eq!(actual, Err(err));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn deserialize_array() {
|
||||
#[derive(Debug, Default, serde::Deserialize, PartialEq)]
|
||||
struct Data {
|
||||
array: Vec<String>,
|
||||
}
|
||||
|
||||
let expected = Data {
|
||||
array: vec![String::from("foo")],
|
||||
};
|
||||
|
||||
let sjson = r#"
|
||||
array = [
|
||||
"foo"
|
||||
]
|
||||
"#;
|
||||
assert_ok!(Data, expected, sjson);
|
||||
}
|
||||
|
||||
// Regression test for #1 (https://git.sclu1034.dev/lucas/serde_sjson/issues/1)
|
||||
#[test]
|
||||
fn deserialize_dtmt_config() {
|
||||
#[derive(Debug, Default, serde::Deserialize, PartialEq)]
|
||||
struct DtmtConfig {
|
||||
name: String,
|
||||
#[serde(default)]
|
||||
description: String,
|
||||
version: Option<String>,
|
||||
}
|
||||
|
||||
let sjson = r#"
|
||||
name = "test-mod"
|
||||
description = "A dummy project to test things with"
|
||||
version = "0.1.0"
|
||||
|
||||
packages = [
|
||||
"packages/test-mod"
|
||||
]
|
||||
"#;
|
||||
|
||||
let expected = DtmtConfig {
|
||||
name: String::from("test-mod"),
|
||||
description: String::from("A dummy project to test things with"),
|
||||
version: Some(String::from("0.1.0")),
|
||||
};
|
||||
|
||||
assert_ok!(DtmtConfig, expected, sjson);
|
||||
}
|
||||
}
|
||||
|
|
26
src/error.rs
26
src/error.rs
|
@ -1,5 +1,7 @@
|
|||
use std::fmt;
|
||||
|
||||
use crate::parser::Token;
|
||||
|
||||
pub type Result<T> = std::result::Result<T, Error>;
|
||||
|
||||
#[derive(PartialEq)]
|
||||
|
@ -13,6 +15,7 @@ struct ErrorImpl {
|
|||
line: u32,
|
||||
column: usize,
|
||||
fragment: Option<String>,
|
||||
token: Option<Token>,
|
||||
}
|
||||
|
||||
#[derive(PartialEq)]
|
||||
|
@ -89,11 +92,12 @@ impl fmt::Debug for Error {
|
|||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"Error({:?}, line: {}, column: {}, fragment: {:?})",
|
||||
"Error({:?}, line: {}, column: {}, fragment: {:?}, token: {:?})",
|
||||
self.inner.code.to_string(),
|
||||
self.inner.line,
|
||||
self.inner.column,
|
||||
self.inner.fragment,
|
||||
self.inner.token,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -108,6 +112,7 @@ impl serde::de::Error for Error {
|
|||
line: 0,
|
||||
column: 0,
|
||||
fragment: None,
|
||||
token: None,
|
||||
});
|
||||
Self { inner }
|
||||
}
|
||||
|
@ -123,6 +128,7 @@ impl serde::ser::Error for Error {
|
|||
line: 0,
|
||||
column: 0,
|
||||
fragment: None,
|
||||
token: None,
|
||||
});
|
||||
Self { inner }
|
||||
}
|
||||
|
@ -138,6 +144,24 @@ impl Error {
|
|||
line,
|
||||
column,
|
||||
fragment,
|
||||
token: None,
|
||||
}),
|
||||
}
|
||||
}
|
||||
pub(crate) fn with_token(
|
||||
code: ErrorCode,
|
||||
line: u32,
|
||||
column: usize,
|
||||
fragment: Option<String>,
|
||||
token: Token,
|
||||
) -> Self {
|
||||
Self {
|
||||
inner: Box::new(ErrorImpl {
|
||||
code,
|
||||
line,
|
||||
column,
|
||||
fragment,
|
||||
token: Some(token),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -203,6 +203,32 @@ mod test {
|
|||
}};
|
||||
}
|
||||
|
||||
fn check_parse_result<S: AsRef<str>, T: AsRef<[Token]>>(input: S, tokens: T) {
|
||||
let tokens = tokens.as_ref();
|
||||
let mut remaining = Span::from(input.as_ref());
|
||||
let mut i = 0;
|
||||
|
||||
loop {
|
||||
if remaining.fragment().is_empty() {
|
||||
break;
|
||||
}
|
||||
|
||||
let (span, token) =
|
||||
super::parse_next_token(remaining).expect("failed to parse next token");
|
||||
|
||||
assert_eq!(Some(&token), tokens.get(i));
|
||||
|
||||
remaining = span;
|
||||
i = i + 1;
|
||||
}
|
||||
|
||||
assert_eq!(
|
||||
tokens.len(),
|
||||
i,
|
||||
"tokens to check against were not exhausted"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_optional() {
|
||||
assert_ok!("\n", whitespace, "", '\n');
|
||||
|
@ -265,6 +291,7 @@ mod test {
|
|||
assert_ok!(r#""foo123""#, delimited_string, "", "foo123");
|
||||
assert_ok!(r#""123foo""#, delimited_string, "", "123foo");
|
||||
assert_ok!(r#""foo\"bar""#, delimited_string, "", "foo\\\"bar");
|
||||
assert_ok!(r#""foo/bar""#, delimited_string, "", "foo/bar");
|
||||
|
||||
assert_err!("foo\"", delimited_string, ErrorKind::Char);
|
||||
|
||||
|
@ -302,4 +329,39 @@ mod test {
|
|||
assert_ok!("/* foo */", block_comment, "", " foo ");
|
||||
assert_ok!("/*\n\tfoo\nbar\n*/", block_comment, "", "\n\tfoo\nbar\n");
|
||||
}
|
||||
|
||||
// Regression test for #1 (https://git.sclu1034.dev/lucas/serde_sjson/issues/1)
|
||||
#[test]
|
||||
fn parse_dtmt_config() {
|
||||
let sjson = r#"
|
||||
name = "test-mod"
|
||||
description = "A dummy project to test things with"
|
||||
version = "0.1.0"
|
||||
|
||||
packages = [
|
||||
"packages/test-mod"
|
||||
]
|
||||
"#;
|
||||
|
||||
check_parse_result(
|
||||
sjson,
|
||||
[
|
||||
Token::String(String::from("name")),
|
||||
Token::Equals,
|
||||
Token::String(String::from("test-mod")),
|
||||
Token::String(String::from("description")),
|
||||
Token::Equals,
|
||||
Token::String(String::from("A dummy project to test things with")),
|
||||
Token::String(String::from("version")),
|
||||
Token::Equals,
|
||||
Token::String(String::from("0.1.0")),
|
||||
Token::String(String::from("packages")),
|
||||
Token::Equals,
|
||||
Token::ArrayStart,
|
||||
Token::String(String::from("packages/test-mod")),
|
||||
Token::ArrayEnd,
|
||||
Token::Eof,
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue