【ylong_json】修复 serde adapt 反序列解析 objcect 逻辑问题 & 补充 serde adapt 反序列化的 sdv 测试

Signed-off-by: 王柄涵 <wangbinghan1@huawei.com>
This commit is contained in:
王柄涵 2023-07-28 15:53:15 +08:00
parent 769ae53a36
commit 1380c12ac9
5 changed files with 585 additions and 38 deletions

View File

@ -108,8 +108,8 @@ where
{
let mut deserializer = Deserializer::new_from_io(reader);
let t = T::deserialize(&mut deserializer)?;
match deserializer.reader.peek() {
Ok(None) => Ok(t),
match eat_whitespace_until_not!(deserializer) {
None => Ok(t),
_ => Err(Error::Parsing(ParsingUnfinished)),
}
}
@ -141,9 +141,11 @@ where
{
let mut deserializer = Deserializer::new_from_slice(slice);
let t = T::deserialize(&mut deserializer)?;
match deserializer.reader.peek() {
Ok(None) => Ok(t),
_ => Err(Error::Parsing(ParsingUnfinished)),
match eat_whitespace_until_not!(deserializer) {
None => Ok(t),
_ => {
unexpected_character!(&mut deserializer)
}
}
}
@ -415,7 +417,6 @@ where
let peek_ch = match eat_whitespace_until_not!(self) {
Some(ch) => ch,
None => {
println!("arrive optin None branch");
return Err(Error::Parsing(ParsingUnfinished));
}
};
@ -601,7 +602,9 @@ where
}
_ => {
if self.next_char()? == Some(b'{') {
eat_whitespace_until_not!(self);
let value = visitor.visit_enum(EnumAssistant::new(self))?;
eat_whitespace_until_not!(self);
if self.next_char()? == Some(b'}') {
Ok(value)
@ -661,25 +664,36 @@ where
T: DeserializeSeed<'de>,
{
let peek_ch = match eat_whitespace_until_not!(self.deserializer) {
Some(ch) => ch,
None => {
return Err(Error::Parsing(ParsingUnfinished));
Some(b']') => return Ok(None),
Some(b',') if !self.is_first => {
self.deserializer.discard_char();
eat_whitespace_until_not!(self.deserializer)
}
Some(ch) => {
if self.is_first {
self.is_first = false;
Some(ch)
} else {
let position = self.deserializer.reader.position();
return Err(Error::Parsing(MissingComma(
position.line(),
position.column(),
)));
}
}
None => return Err(Error::Parsing(ParsingUnfinished)),
};
match peek_ch {
b']' => Ok(None),
b',' if self.is_first => {
unexpected_character!(self.deserializer)
}
b',' => {
self.deserializer.discard_char();
Ok(Some(seed.deserialize(&mut *self.deserializer)?))
}
_ => {
self.is_first = false;
Ok(Some(seed.deserialize(&mut *self.deserializer)?))
Some(b']') => {
let position = self.deserializer.reader.position();
Err(Error::Parsing(TrailingComma(
position.line(),
position.column(),
)))
}
Some(_) => Ok(Some(seed.deserialize(&mut *self.deserializer)?)),
None => Err(Error::Parsing(ParsingUnfinished)),
}
}
}
@ -689,30 +703,45 @@ where
R: BytesReader + Cacheable,
{
type Error = Error;
fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>, Error>
where
K: DeserializeSeed<'de>,
{
let peek_ch = match eat_whitespace_until_not!(self.deserializer) {
Some(ch) => ch,
Some(b'}') => return Ok(None),
Some(b',') if !self.is_first => {
self.deserializer.discard_char();
eat_whitespace_until_not!(self.deserializer)
}
Some(ch) => {
if self.is_first {
self.is_first = false;
Some(ch)
} else {
let position = self.deserializer.reader.position();
return Err(Error::Parsing(MissingComma(
position.line(),
position.column(),
)));
}
}
None => {
return Err(Error::Parsing(ParsingUnfinished));
}
};
match peek_ch {
b'}' => Ok(None),
b',' if self.is_first => {
unexpected_character!(self.deserializer)
}
b',' => {
self.deserializer.discard_char();
Ok(Some(seed.deserialize(&mut *self.deserializer)?))
}
_ => {
self.is_first = false;
Ok(Some(seed.deserialize(&mut *self.deserializer)?))
Some(b'"') => Ok(Some(seed.deserialize(&mut *self.deserializer)?)),
Some(b'}') => {
let position = self.deserializer.reader.position();
Err(Error::Parsing(TrailingComma(
position.line(),
position.column(),
)))
}
// Object key must be String.
_ => unexpected_character!(self.deserializer),
}
}
@ -723,9 +752,16 @@ where
match eat_whitespace_until_not!(self.deserializer) {
Some(b':') => {
self.deserializer.discard_char();
eat_whitespace_until_not!(self.deserializer);
seed.deserialize(&mut *self.deserializer)
}
Some(_ch) => unexpected_character!(self.deserializer),
Some(_ch) => {
let position = self.deserializer.reader.position();
Err(Error::Parsing(MissingColon(
position.line(),
position.column(),
)))
}
None => Err(Error::Parsing(ParsingUnfinished)),
}
}
@ -884,12 +920,24 @@ mod ut_test_for_deserializer {
let expected: Vec<u8> = vec![1, 2, 3];
assert_eq!(expected, from_slice::<Vec<u8>>(slice_seq).unwrap());
let slice_map = r#"{ true : 1 }"#.as_bytes();
let slice_map = r#"{ "apple" : 3 }"#.as_bytes();
let mut expected = HashMap::new();
expected.insert(true, 1);
expected.insert("appple", 3);
assert_eq!(
expected,
from_slice::<HashMap<bool, i32>>(slice_map).unwrap()
crate::from_slice::<HashMap<&str, i32>>(slice_map).unwrap()
);
}
#[test]
fn de_map() {
use std::collections::HashMap;
let slice_map = r#"{ "apple" : 3 }"#.as_bytes();
let mut expected = HashMap::new();
expected.insert(String::from("apple"), 3);
assert_eq!(
expected,
from_slice::<HashMap<String, i32>>(slice_map).unwrap()
);
}
@ -1024,10 +1072,43 @@ mod ut_test_for_deserializer {
};
assert_eq!(expected, from_str(str).unwrap());
let str = r#"{
"int" : 1 ,
"seq" : ["abcd" , "efgh" ],
"tup" : [1, 2 ,3 ]
}"#;
let expected = Test {
int: 1,
seq: vec![String::from("abcd"), String::from("efgh")],
tup: (1, 2, 3),
};
assert_eq!(expected, from_str(str).unwrap());
// The following is the test for abnormal input of JSON.
// Missing '}' at the end.
let str_abnormal = r#"{"int":1,"seq":["abcd","efgh"],"tup":[1,2,3]"#;
let res = from_str::<Test>(str_abnormal);
assert!(res.is_err());
// Missing ','.
let str_abnormal = r#"{"int":1 "seq":["abcd","efgh"],"tup":[1,2,3]"#;
let res = from_str::<Test>(str_abnormal);
assert!(res.is_err());
// Trailing ','.
let str_abnormal = r#"{"int":1, "seq":["abcd","efgh",],"tup":[1,2,3]"#;
let res = from_str::<Test>(str_abnormal);
assert!(res.is_err());
// Missing ':'.
let str_abnormal = r#"{"int":1, "seq":["abcd","efgh"],"tup" [1,2,3]"#;
let res = from_str::<Test>(str_abnormal);
assert!(res.is_err());
// Incorrect field name.
let str_abnormal = r#"{"it":1, "sq" : ["abcd","efgh"],"tp": [1,2,3]"#;
let res = from_str::<Test>(str_abnormal);
assert!(res.is_err());
}
/// UT test to deserialize enum

View File

@ -61,6 +61,15 @@ pub enum ParseError {
/// The input sequence has not yet been parsed.
ParsingUnfinished,
/// There is an extra comma after the last value in an array or map (line number, character number)
TrailingComma(usize, usize),
/// A colon is missing (line number, character number)
MissingColon(usize, usize),
/// A comma is missing (line number, character number)
MissingComma(usize, usize),
}
impl Error {
@ -101,6 +110,21 @@ impl Debug for ParseError {
Self::ParsingUnfinished => {
write!(f, "[Error]: Value has not been fully deserialized.")
}
Self::TrailingComma(line, pos) => {
write!(
f,
"[Line]: {line}, [Pos]: {pos}, [Error]: Has a comma after the last value in an array or map."
)
}
Self::MissingColon(line, pos) => {
write!(f, "[Line]: {line}, [Pos]: {pos}, [Error]: A colon is missing between key and value.")
}
Self::MissingComma(line, pos) => {
write!(
f,
"[Line]: {line}, [Pos]: {pos}, [Error]: A comma is missing before next value."
)
}
}
}
}

View File

@ -60,7 +60,6 @@ mod states;
mod value;
pub use error::{Error, ParseError};
pub use serializer_compact::to_string;
pub use value::{Array, Index, JsonValue, Number, Object};
pub(crate) use encoder::{CompactEncoder, FormattedEncoder};
@ -82,3 +81,4 @@ pub(crate) use linked_list::{Cursor, CursorMut, LinkedList};
pub use linked_list::{Iter, IterMut, Node};
pub use deserializer::{from_reader, from_slice, from_str};
pub use serializer_compact::{to_string, to_writer};

View File

@ -215,7 +215,7 @@ impl Index for str {
/// ```
fn index_into_mut<'a>(&self, value: &'a mut JsonValue) -> &'a mut JsonValue {
if let JsonValue::Object(ref mut object) = value {
#[cfg(any(feature = "list_object"))]
#[cfg(feature = "list_object")]
{
return object.get_key_mut_maybe_insert(self);
}

View File

@ -0,0 +1,442 @@
// Copyright (c) 2023 Huawei Device Co., Ltd.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use serde::Deserialize;
use std::borrow::Cow;
use ylong_json::from_str;
#[derive(Deserialize, PartialEq, Debug)]
struct ExampleOne {
#[serde(rename(deserialize = "Image"))]
image: InnerImage,
}
#[derive(Deserialize, PartialEq, Debug)]
struct InnerImage {
#[serde(rename(deserialize = "Width"))]
width: u32,
#[serde(rename(deserialize = "Height"))]
height: u32,
#[serde(rename(deserialize = "Title"))]
title: String,
#[serde(rename(deserialize = "Thumbnail"))]
thumbnail: InnerThumbnail,
#[serde(rename(deserialize = "Animated"))]
animated: bool,
#[serde(rename(deserialize = "IDs"))]
ids: Vec<u32>,
}
#[derive(Deserialize, PartialEq, Debug)]
struct InnerThumbnail {
#[serde(rename(deserialize = "Url"))]
url: String,
#[serde(rename(deserialize = "Height"))]
height: u32,
#[serde(rename(deserialize = "Width"))]
width: u32,
}
const RFC7159_EXAMPLE1: &str = r#"
{
"Image": {
"Width": 800,
"Height": 600,
"Title": "View from 15th Floor",
"Thumbnail": {
"Url": "http://www.example.com/image/481989943",
"Height": 125,
"Width": 100
},
"Animated" : false,
"IDs": [116, 943, 234, 38793]
}
}
"#;
#[test]
fn sdv_adapt_serde_example_one() {
let de_res = from_str::<ExampleOne>(RFC7159_EXAMPLE1);
let expected = ExampleOne {
image: InnerImage {
width: 800,
height: 600,
thumbnail: InnerThumbnail {
url: String::from("http://www.example.com/image/481989943"),
height: 125,
width: 100,
},
animated: false,
ids: vec![116, 943, 234, 38793],
title: String::from("View from 15th Floor"),
},
};
assert_eq!(expected, de_res.unwrap());
}
const RFC7159_EXAMPLE2: &str = r#"
[
{
"precision": "zip",
"Latitude": 37.7668,
"Longitude": -122.3959,
"Address": "",
"City": "SAN FRANCISCO",
"State": "CA",
"Zip": "94107",
"Country": "US"
},
{
"precision": "zip",
"Latitude": 37.371991,
"Longitude": -122.026020,
"Address": "",
"City": "SUNNYVALE",
"State": "CA",
"Zip": "94085",
"Country": "US"
}
]
"#;
#[derive(Deserialize, PartialEq, Debug)]
struct ExampleTwo<'a> {
precision: String,
#[serde(rename(deserialize = "Latitude"))]
latitude: f32,
#[serde(rename(deserialize = "Longitude"))]
longitude: f32,
#[serde(rename(deserialize = "Address"))]
address: String,
#[serde(rename(deserialize = "City"))]
city: String,
#[serde(rename(deserialize = "State"))]
state: String,
#[serde(rename(deserialize = "Zip"))]
zip: Cow<'a, str>,
#[serde(rename(deserialize = "Country"))]
country: Cow<'a, str>,
}
#[test]
fn sdv_adapt_serde_example_two() {
let de_res = from_str::<Vec<ExampleTwo>>(RFC7159_EXAMPLE2).unwrap();
let expected_0 = ExampleTwo {
precision: String::from("zip"),
latitude: 37.7668,
longitude: -122.3959,
address: String::from(""),
city: String::from("SAN FRANCISCO"),
state: String::from("CA"),
zip: Cow::from("94107"),
country: Cow::from("US"),
};
let expected_1 = ExampleTwo {
precision: String::from("zip"),
latitude: 37.371_991,
longitude: -122.026_02,
address: String::from(""),
city: String::from("SUNNYVALE"),
state: String::from("CA"),
zip: Cow::from("94085"),
country: Cow::from("US"),
};
assert_eq!(expected_0, de_res[0]);
assert_eq!(expected_1, de_res[1]);
}
const JSON_PARSE_EXAMPLE3: &str = r#"
{
"null_test" : {
"null1": null
},
"bool_test" : {
"boolean1": true,
"boolean2": false
},
"number_test" : {
"number1": 0,
"number2": -0,
"number3": 123,
"number4": -123,
"number5": 123.456,
"number6": -123.456,
"number7": 123.456e+7,
"number8": 123.456e-7,
"number9": 123.456E+7,
"number10": 123.456E-7,
"number11": -123.456e+7,
"number12": -123.456e-7,
"number13": -123.456E+7,
"number14": -123.456E-7,
"number15": 0.0,
"number16": -0.0e+7,
"number17": 3e2
},
"string_test" : {
"string1": "",
"string2": "Hello World",
"string3": "abcdefghijklmnopqrstuvwxyz",
"string4": "ABCDEFGHIJKLMNOPQRSTUVWXYZ",
"string5": "0123456789",
"string6": " \b\f\n\r\t",
"string7": "\"\\\/",
"string8": "`1~!@#$%^&*()_+-={':[,]}|;.</>?",
"string9": "\u0123\u4567\u89AB\uCDEF\uabcd\uef4A"
},
"array_test" : {
"array1": [ ],
"array2": [ true, false
],
"array3": [0 , 1 , -1 , 100 , -100],
"array4": [
0.0 , -0.0, 1.0 ,
-1.0, 12.34
, -12.34 ],
"array5": [[[[[[["nest"]]]]]]]
},
"object_test" : {
"object1": null,
"object2": null ,
"object3": {"key1":"Null","key2": {"Bool":true},
"key3":{"Number":0.0},"key4":{"StringVal":"string"},
"key5":{"Array":[]},"key6":{"Object":null}},
"object4": {
"key1" : "Null" , "key2"
: { "Bool" : true } , "key3" :
{ "Number" : 0.0 } , "key4":{"StringVal":"string"} ,
"key5": {"Array":[]}, "key6": {
"Object":null }
},
"object5": {"nest1": {"nest2": {"nest3": {"nest4": null}}}},
"": {
"": "key1",
"\/\\\"\uCAFE\uBABE\uAB98\uFCDE\ubcda\uef4A\b\f\n\r\t`1~!@#$%^&*()_+-=[]{}|;:',./<>?" : "key2"
}
}
}
"#;
#[derive(Deserialize, PartialEq, Debug)]
struct ParseTest {
null_test: NullTest,
bool_test: BoolTest,
number_test: NumberTest,
string_test: StringTest,
array_test: ArrayTest,
object_test: ObjectTest,
}
#[derive(Deserialize, PartialEq, Debug)]
struct StructNull;
#[derive(Deserialize, PartialEq, Debug)]
struct NullTest {
null1: StructNull,
}
#[derive(Deserialize, PartialEq, Debug)]
struct BoolTest {
boolean1: bool,
boolean2: bool,
}
#[derive(Deserialize, PartialEq, Debug)]
struct NumberTest {
number1: u8,
number2: i8,
number3: u16,
number4: i16,
number5: f32,
number6: f32,
number7: f64,
number8: f64,
number9: f64,
number10: f64,
number11: f64,
number12: f64,
number13: f64,
number14: f64,
number15: f64,
number16: f64,
number17: f64,
}
#[derive(Deserialize, PartialEq, Debug)]
struct StringTest {
string1: String,
string2: String,
string3: String,
string4: String,
string5: String,
string6: String,
string7: String,
string8: String,
string9: String,
}
#[derive(Deserialize, PartialEq, Debug)]
struct ArrayTest {
array1: Vec<StructNull>,
array2: Vec<bool>,
array3: Vec<i64>,
array4: Vec<f64>,
#[warn(clippy::type_complexity)]
array5: Vec<Vec<Vec<Vec<Vec<Vec<Vec<String>>>>>>>,
}
#[derive(Deserialize, PartialEq, Debug)]
struct ObjectTest {
object1: StructNull,
object2: StructNull,
object3: ObjectThreeFour,
object4: ObjectThreeFour,
object5: ObjectFive,
#[serde(rename(deserialize = ""))]
object6: ObjectSix,
}
#[derive(Deserialize, PartialEq, Debug)]
enum InnerValue {
Null,
Bool(bool),
Number(f64),
StringVal(String),
Array(Vec<InnerValue>),
Object(StructNull),
}
#[derive(Deserialize, PartialEq, Debug)]
struct ObjectThreeFour {
key1: InnerValue,
key2: InnerValue,
key3: InnerValue,
key4: InnerValue,
key5: InnerValue,
key6: InnerValue,
}
#[derive(Deserialize, PartialEq, Debug)]
struct ObjectFive {
nest1: NestOne,
}
#[derive(Deserialize, PartialEq, Debug)]
struct NestOne {
nest2: NestTwo,
}
#[derive(Deserialize, PartialEq, Debug)]
struct NestTwo {
nest3: NestThree,
}
#[derive(Deserialize, PartialEq, Debug)]
struct NestThree {
nest4: NestFour,
}
#[derive(Deserialize, PartialEq, Debug)]
struct NestFour;
#[derive(Deserialize, PartialEq, Debug)]
struct ObjectSix {
#[serde(rename(deserialize = ""))]
mem1: String,
#[serde(rename(
deserialize = "/\\\"\u{CAFE}\u{BABE}\u{AB98}\u{FCDE}\u{bcda}\u{ef4A}\u{0008}\u{000c}\n\r\t`1~!@#$%^&*()_+-=[]{}|;:',./<>?"
))]
mem2: String,
}
#[test]
fn sdv_adapt_serde_example_three() {
let de_res = from_str::<ParseTest>(JSON_PARSE_EXAMPLE3);
let expected = ParseTest {
null_test: NullTest { null1: StructNull },
bool_test: BoolTest {
boolean1: true,
boolean2: false,
},
number_test: NumberTest {
number1: 0,
number2: 0,
number3: 123,
number4: -123,
number5: 123.456,
number6: -123.456,
number7: 1234560000.0,
number8: 1.23456e-5,
number9: 1234560000.0,
number10: 1.23456e-5,
number11: -1234560000.0,
number12: -1.23456e-5,
number13: -1234560000.0,
number14: -1.23456e-5,
number15: 0.0,
number16: -0.0,
number17: 300.0,
},
string_test: StringTest {
string1: String::from(""),
string2: String::from("Hello World"),
string3: String::from("abcdefghijklmnopqrstuvwxyz"),
string4: String::from("ABCDEFGHIJKLMNOPQRSTUVWXYZ"),
string5: String::from("0123456789"),
string6: String::from(" \u{8}\u{c}\n\r\t"),
string7: String::from("\"\\/"),
string8: String::from("`1~!@#$%^&*()_+-={':[,]}|;.</>?"),
string9: String::from("ģ䕧覫췯ꯍ\u{ef4a}"),
},
array_test: ArrayTest {
array1: vec![],
array2: vec![true, false],
array3: vec![0, 1, -1, 100, -100],
array4: vec![0.0, -0.0, 1.0, -1.0, 12.34, -12.34],
array5: vec![vec![vec![vec![vec![vec![vec![String::from("nest")]]]]]]],
},
object_test: ObjectTest {
object1: StructNull,
object2: StructNull,
object3: ObjectThreeFour {
key1: InnerValue::Null,
key2: InnerValue::Bool(true),
key3: InnerValue::Number(0.0),
key4: InnerValue::StringVal(String::from("string")),
key5: InnerValue::Array(vec![]),
key6: InnerValue::Object(StructNull),
},
object4: ObjectThreeFour {
key1: InnerValue::Null,
key2: InnerValue::Bool(true),
key3: InnerValue::Number(0.0),
key4: InnerValue::StringVal(String::from("string")),
key5: InnerValue::Array(vec![]),
key6: InnerValue::Object(StructNull),
},
object5: ObjectFive {
nest1: NestOne {
nest2: NestTwo {
nest3: NestThree { nest4: NestFour },
},
},
},
object6: ObjectSix {
mem1: String::from("key1"),
mem2: String::from("key2"),
},
},
};
assert_eq!(expected, de_res.unwrap());
}