ylong_json code init

Signed-off-by: 薛磊 <xuelei3@huawei.com>
This commit is contained in:
薛磊
2023-06-19 15:37:21 +08:00
parent 637cee70d4
commit 714640966b
35 changed files with 16837 additions and 63 deletions
+42
View File
@@ -0,0 +1,42 @@
[package]
name = "ylong_json"
version = "0.1.0"
edition = "2018"
description = "A JSON serialization file format"
#readme = "README.md"
license = "Apache-2.0"
repository = "https://open.codehub.huawei.com/innersource/Ylong_Rust/ylong_rs/files?ref=master&filePath=src%2Flib%2Fparser%2Fylong_json"
keywords = ["ylong", "json", "serialization", "deserialization"]
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[lib]
name = "ylong_json"
crate-type = ["cdylib", "staticlib", "lib"]
[features]
default = ["btree_object", "vec_array"] # Object 默认使用 Btree 结构,Array 默认使用 Vec 结构。
c_adapter = ["libc"] # 使用 C 封装层接口
list_array = [] # Array 底层使用 LinkedList。在 Array 的平均子节点数较少(约小于 15 个)、查找数量较少时,性能较好。
vec_array = [] # Array 底层使用 Vec。在 Array 的平均子节点数较多(约大于 15 个)、查找数量较多时,性能较好。
list_object = [] # Object 底层使用 LinkedList。在 Object 的平均子节点数较少(约小于 15 个)、查找数量较少时,性能较好。
vec_object = [] # Object 底层使用 Vec。在 Object 的平均子节点数中等(约大于 15 个,小于 1024 个)、查找数量较少时,性能较好。
btree_object = [] # Object 底层使用 Btree。在 Object 的平均子节点数较多(约大于 1024 个)、查找数量较多时,性能较好。
ascii_only = [] # 仅使用 ASCII 字符,正常解析 unicode 字符,但超出 ASCII 的 UTF-8 字符在输出时保持不变。
[dependencies]
libc = { version = "0.2.134", optional = true }
serde = { version = "1.0.136", features = ["derive"] }
[dev-dependencies]
serde_json = "1.0.74"
[[test]]
name = "sdv_adapter_test"
path = "./tests/sdv_adapter_test.rs"
required-features = ["c_adapter"]
[[test]]
name = "ylong_json_sdv_test"
path = "./tests/ylong_json_sdv_test.rs"
required-features = []
+201
View File
@@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
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.
+71
View File
@@ -0,0 +1,71 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Copyright (c) 2021 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.
Notes:
This is project config file for OpenHarmony OSS Audit Tool, if you have any questions or concerns, please email chenyaxun@huawei.com.
-->
<!-- OAT(OSS Audit Tool) configuration guide:
basedir: Root dir, the basedir + project path is the real source file location.
licensefile:
1.If the project don't have "LICENSE" in root dir, please define all the license files in this project in , OAT will check license files according to this rule.
tasklist(only for batch mode):
1. task: Define oat check thread, each task will start a new thread.
2. task name: Only an name, no practical effect.
3. task policy: Default policy for projects under this task, this field is required and the specified policy must defined in policylist.
4. task filter: Default filefilter for projects under this task, this field is required and the specified filefilter must defined in filefilterlist.
5. task project: Projects to be checked, the path field define the source root dir of the project.
policyList:
1. policy: All policyitems will be merged to default OAT.xml rules, the name of policy doesn't affect OAT check process.
2. policyitem: The fields type, name, path, desc is required, and the fields rule, group, filefilter is optional,the default value is:
<policyitem type="" name="" path="" desc="" rule="may" group="defaultGroup" filefilter="defaultPolicyFilter"/>
3. policyitem type:
"compatibility" is used to check license compatibility in the specified path;
"license" is used to check source license header in the specified path;
"copyright" is used to check source copyright header in the specified path;
"import" is used to check source dependency in the specified path, such as import ... ,include ...
"filetype" is used to check file type in the specified path, supported file types: archive, binary
"filename" is used to check whether the specified file exists in the specified path(support projectroot in default OAT.xml), supported file names: LICENSE, README, README.OpenSource
4. policyitem name: This field is used for define the license, copyright, "*" means match all, the "!" prefix means could not match this value. For example, "!GPL" means can not use GPL license.
5. policyitem path: This field is used for define the source file scope to apply this policyitem, the "!" prefix means exclude the files. For example, "!.*/lib/.*" means files in lib dir will be exclude while process this policyitem.
6. policyitem rule and group: These two fields are used together to merge policy results. "may" policyitems in the same group means any one in this group passed, the result will be passed.
7. policyitem filefilter: Used to bind filefilter which define filter rules.
8. filefilter: Filter rules, the type filename is used to filter file name, the type filepath is used to filter file path.
Note:If the text contains special characters, please escape them according to the following rules:
" == &gt;
& == &gt;
' == &gt;
< == &gt;
> == &gt;
-->
<configuration>
<oatconfig>
<filefilterlist>
<filefilter name="binaryFileTypePolicyFilter" desc="Filters for binary file policies" >
<filteritem type="filename" name=".*.pem" desc="Testing of API for HTTPS configuration certificates requires a certificate input"/>
</filefilter>
<filefilter name="defaultPolicyFilter" desc="Filters for compatibilitylicense header policies">
<filteritem type="filename" name=".*.toml" desc="toml treats as readme file"/>
</filefilter>
<filefilter name="copyrightPolicyFilter" desc="Filters for copyright policies">
<filteritem type="filename" name=".*.toml" desc="toml treats as readme file"/>
</filefilter>
</filefilterlist>
</oatconfig>
</configuration>
-36
View File
@@ -1,36 +0,0 @@
# commonlibrary_rust_ylong_json
#### Description
{**When you're done, you can delete the content in this README and update the file with details for others getting started with your repository**}
#### Software Architecture
Software architecture description
#### Installation
1. xxxx
2. xxxx
3. xxxx
#### Instructions
1. xxxx
2. xxxx
3. xxxx
#### Contribution
1. Fork the repository
2. Create Feat_xxx branch
3. Commit your code
4. Create Pull Request
#### Gitee Feature
1. You can use Readme\_XXX.md to support different languages, such as Readme\_en.md, Readme\_zh.md
2. Gitee blog [blog.gitee.com](https://blog.gitee.com)
3. Explore open source project [https://gitee.com/explore](https://gitee.com/explore)
4. The most valuable open source project [GVP](https://gitee.com/gvp)
5. The manual of Gitee [https://gitee.com/help](https://gitee.com/help)
6. The most popular members [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/)
+284 -27
View File
@@ -1,39 +1,296 @@
# commonlibrary_rust_ylong_json
# ylong_json
#### 介绍
{**以下是 Gitee 平台说明,您可以替换此简介**
Gitee 是 OSCHINA 推出的基于 Git 的代码托管平台(同时支持 SVN)。专为开发者提供稳定、高效、安全的云端软件开发协作平台
无论是个人、团队、或是企业,都能够用 Gitee 实现代码托管、项目管理、协作开发。企业项目请看 [https://gitee.com/enterprises](https://gitee.com/enterprises)}
### 简介
#### 软件架构
软件架构说明
`ylong_json` 模块提供了 JSON 语法格式文本或字符串的序列化功能,以及对应生成实例的反序列化功能。
`ylong_json` 包含以下核心功能:
#### 安装教程
##### 功能一:生成 JSON 实例
`ylong_json` 提供了从 JSON 文本或字符串生成一个 `JsonValue` 实例的功能。
1. xxxx
2. xxxx
3. xxxx
1)可以通过以下方法创建 `JsonValue` 实例:
```rust
use std::fs::File;
use std::str::FromStr;
use std::io::Read;
use ylong_json::JsonValue;
#### 使用说明
fn create_json_value_instance() {
let str: &str = "";
// 可以使用 from_str 接口,从 &str 类型尝试生成 JsonValue 实例。
// 如果传入的 &str 不符合 JSON 语法,会返回对应的 Error。
let json_value = JsonValue::from_str(str);
let text: String = String::from("");
// 可以使用 from_text 接口,从一系列实现 AsRef<[u8]> 的类型生成 JsonValue 实例。
// 如果传入的文本内容不符合 JSON 语法,会返回对应的 Error。
let json_value = JsonValue::from_text(text);
let path: &str = "";
// 可以使用 from_file 接口,从对应路径的文件读取内容,并尝试生成 JsonValue 实例。
// 如果传入的 path 不合法或者文本内容不符合 JSON 语法,会返回对应的 Error。
let json_value = JsonValue::from_file(path);
let mut reader: Box<dyn Read> = Box::new(File::open("").unwrap());
// 可以使用 from_reader 接口,从实现了 io::Read 的实例中读取文本,并尝试生成 JsonValue 实例。
// 如果读取失败或者从 reader 中读取的内容不符合 JSON 语法,会返回对应的 Error。
let json_value = JsonValue::from_reader(&mut reader);
}
```
`JsonValue` 实例创建成功后,就可以尝试读取和修改对应的内容了。
1. xxxx
2. xxxx
3. xxxx
(2)如果 JSON 文本中的类型实现了第三方库 `serde::Deserialize` trait,则可以直接将文本内容反序列化为该类型的实例。
```rust
use std::fs::File;
use serde::Deserialize;
use ylong_json::deserializer::{from_reader, from_slice, from_st};
fn deserialize_json_to_instance() {
#[derive(Deserialize, PartialEq, Debug)]
struct Example {
int: u32,
seq: Vec<String>,
tup: (i32, i32, i32),
}
#### 参与贡献
// 可以使用 from_str 接口,从 &str 类型生成实例。
// 如果传入的 &str 不符合 JSON 语法,会返回对应的 Error。
let tr = r#"{"int":1,"seq":["abcd","efgh"],"tup":[1,2,3]}"#;
let example = from_str::<Example>(str).unwrap();
1. Fork 本仓库
2. 新建 Feat_xxx 分支
3. 提交代码
4. 新建 Pull Request
// 可以使用 from_slice 接口,从 &u8 类型生成实例。
// 如果传入的 &u8 不符合 JSON 语法,会返回对应的 Error。
let slice = str.as_bytes();
let example = from_slice::<Example>(slice).unwrap();
// 可以使用 from_reader 接口,从实现了 io::Write 的位置、文件、io流等生成实例。
// 如果传入的文本内容不符合 JSON 语法,会返回对应的 Error。
let mut file: File = File::open("./example.txt").unwrap();
let example = from_reader::<Example>(file).unwrap();
}
```
#### 特技
##### 功能二:读取、修改键值对
`JsonValue` 实例生成成功后,可以通过各种下标来查找对应的键值对(获取到对应 `JsonValue` 的普通引用)。
1. 使用 Readme\_XXX.md 来支持不同的语言,例如 Readme\_en.md, Readme\_zh.md
2. Gitee 官方博客 [blog.gitee.com](https://blog.gitee.com)
3. 你可以 [https://gitee.com/explore](https://gitee.com/explore) 这个地址来了解 Gitee 上的优秀开源项目
4. [GVP](https://gitee.com/gvp) 全称是 Gitee 最有价值开源项目,是综合评定出的优秀开源项目
5. Gitee 官方提供的使用手册 [https://gitee.com/help](https://gitee.com/help)
6. Gitee 封面人物是一档用来展示 Gitee 会员风采的栏目 [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/)
&str 和 String 类型的下标可以用于查找 Object 内的键值对;usize 类型的下标可以用于查找 Array 内的键值对。
```rust
use std::str::FromStr;
use ylong_json::JsonValue;
// 示例的 JSON 字符串
const JSON_TEXT: &str = r#"
{
"key": "value",
"array": [1, 2, 3]
}
"#;
fn find_key_value_pair() {
// 根据示例字符串创建 JsonValue 实例,语法正确所以此处解析必定成功,使用 unwrap。
let json_value = JsonValue::from_str(JSON_TEXT).unwrap();
// 由于 json 本身也是一个表,所以可以使用 &str 类型获取内部值的普通引用。
let value: &JsonValue = &json_value["key"];
// 可以通过 &str 类型先获取到 “array” 成员的普通引用,再根据 usize 类型获取对应元素的普通引用。
let array_item: &JsonValue = &json_value["array"][0];
// 如果尝试查找一个不存在表中的键,会返回 &JsonValue::Null。
let no_such_key: &JsonValue = &json_value["no_such_key"];
// 对 Array 类型查找时,若下标超过 Array 长度,也会返回 &JsonValue::Null。
let no_such_index: &JsonValue = &json_value["array"][100];
// 对一个 Object 和 Array 类型以外的 JsonValue 类型使用下标访问也会返回 &JsonValue::Null。
let invalid_index: &JsonValue = &json_value["key"]["invalid"];
let invalid_index: &JsonValue = &json_value["key"][0];
}
```
也可以通过相同方法获取到对应 `JsonValue` 的可变引用,获取到可变引用后可以对其进行修改,修改时需要注意符合 JSON 语法。
```rust
use ylong_json::JsonValue;
// 示例的 JSON 字符串
const JSON_TEXT: &str = r#"
{
"key": "value",
"array": [1, 2, 3]
}
"#;
fn modify_key_value_pair() {
// 根据示例字符串创建 JsonValue 实例,语法正确所以此处解析必定成功,使用 unwrap。
// 此处由于需要获取可变引用,JSON 实例需要可变。
let mut json_value = JsonValue::from_str(JSON_TEXT).unwrap();
// 通过 “key” 获取到对应成员的可变引用,并将其设置为数值 123。
// 库中给许多基本类型实现了从自身到 JsonValue 的转换,所以可以通过 into() 方法转换为 JsonValue。
// 执行此句代码后,表中内容如下:
// {
// "key": 123,
// "array": [1, 2, 3]
// }
json_value["key"] = 123_i32.into();
// 通过 “array” 和下标 0 获取到对应成员的可变引用,并将其设置为数值 123。
// 执行此句代码后,表中内容如下:
// {
// "key": 123,
// "array": [123, 2, 3]
// }
json_value["array"][0] = 123_i32.into();
// 如果尝试获取一个不存在表中的键的可变引用,会在表中插入该键且对应值为 JsonValue::Null,并在此基础上进行修改。
// 执行此行代码后,json_value 中会增加一个成员 “no_such_key”,且值为数值 123。
// 表中内容如下:
// {
// "key": 123,
// "array": [123, 2, 3],
// "no_such_key": 123
// }
json_value["no_such_key"] = 123_i32.into();
// 对 Array 类型的成员尝试获取可变引用时,若下标超过 Array 长度,
// 会在 Array 末尾插入一个 JsonValue::Null,并返回该位置的可变引用。
// 执行此行代码后,json_value 的 “array” 成员的长度变为 4。
// 表中内容如下:
// {
// "key": 123,
// "array": [123, 2, 3, 123],
// "no_such_key": 123
// }
json_value["array"][100] = 123_i32.into();
// 对一个非 Object 类型使用 &str 类型或 String 下标获取可变引用时,
// 会将该值替换为一个空 Object,然后再用此下标对其进行访问。
// 执行此代码后,json_value 的 array 成员变成 Object 类型,且含有一个键值对:“key” => 123。
// 表中内容如下:
// {
// "key": 123,
// "array": {
// "key": 123
// },
// "no_such_key": 123
// }
json_value["array"]["key"] = 123_i32.into();
// 对一个非 Array 类型使用 usize 类型下标获取可变引用时,
// 会将该值替换成一个空 Array,然后再用此下标对其进行访问。
// 执行此代码后,json_value 的 key 成员变成 Array 类型,且含有一个成员: key[0] => 123
// 表中内容如下:
// {
// "key": [123],
// "array": {
// "key": 123
// },
// "no_such_key": 123
// }
json_value["key"][0] = 123_i32.into();
}
```
##### 功能三:输出 JSON 文本
1)当拥有一个 `JsonValue` 实例时,可以将该 `JsonValue` 实例转化成文本并输出到指定位置:字符串、文件、网络等。
```rust
use std::fs::File;
use ylong_json::JsonValue;
fn output_json_text(json_value: JsonValue) {
// 使用 to_compact_string() 接口将 json_value 输出成一个字符串。
let string = json_value.to_compact_string().unwrap();
// 使用 compact_encode() 接口将 JSON 文本输出到指定实现了 io::Write 的位置,文件、io流等。
let mut file: File = File::open("").unwrap();
let _ = json_value.compact_encode(&mut file);
}
```
由于 JSON 内部元素没有较强的顺序要求,所以成员的输出顺序会有一定随机性,但是不影响 JSON 文本的语义。
2)可以将一个实现了第三方库 `serde::Serialize` trait 的类型实例序列化为 JSON 文本。
```rust
use std::fs::File;
use serde::Serialize;
use ylong_json::serializer_compact::{to_string, to_writer};
fn output_json_text() {
#[derive(Serialize)]
struct Exmaple {
int: u32,
seq: Vec<&'static str>,
tup: (i32, i32, i32),
}
let example = Example {
int: 1,
seq: vec!["a", "b"],
tup: (1, 2, 3),
};
// 使用 to_string() 接口将 value 输出成一个字符串。
let string = to_string(&example).unwrap();
// 使用 to_writer() 接口将 JSON 文本输出到指定实现了 io::Write 的位置,文件、io流等。
let mut file: File = File::open("./example.txt").unwrap();
let _ = to_writer(&example, &mut file);
}
```
### 性能测试
```
1.测试环境
操作系统:Linux
架构:x86_64
字节序:小端
CPU 型号:Intel(R) Xeon(R) Gold 6278C CPU @ 2.60GHz
CPU 核心数:8
内存:16G
2.测试结果
| 序列化 | ylong_json | serde_json |
-----------------------------------------------
| null | 150 ns/iter | 175 ns/iter |
| boolean | 155 ns/iter | 178 ns/iter |
| number | 309 ns/iter | 291 ns/iter |
| string | 513 ns/iter | 413 ns/iter |
| array | 998 ns/iter | 1,075 ns/iter |
| object | 1,333 ns/iter | 1,348 ns/iter |
| example1 | 12,537 ns/iter | 12,288 ns/iter |
| example2 | 23,754 ns/iter | 21,936 ns/iter |
| example3 | 103,061 ns/iter | 97,247 ns/iter |
| example4 | 15,234 ns/iter | 17,895 ns/iter |
| 反序列化 | ylong_json | serde_json |
-----------------------------------------------
| null | 257 ns/iter | 399 ns/iter |
| boolean | 260 ns/iter | 400 ns/iter |
| number | 1,507 ns/iter | 989 ns/iter |
| string | 414 ns/iter | 610 ns/iter |
| array | 2,258 ns/iter | 2,148 ns/iter |
| object | 810 ns/iter | 1,386 ns/iter |
| example1 | 10,191 ns/iter | 10,227 ns/iter |
| example2 | 15,753 ns/iter | 18,022 ns/iter |
| example3 | 55,910 ns/iter | 59,717 ns/iter |
| example4 | 18,461 ns/iter | 12,471 ns/iter |
```
### 目录
```
ylong_json
├─ examples # ylong_json 代码示例
├─ include # ylong_json.h
├─ src
│ ├─ value # Array, Object 类型定义和相关方法实现
│ ├─ adapter.rs # 适配 C 的接口实现
│ ├─ consts.rs # 一些常数与表格的定义
│ ├─ deserializer.rs # 适配 serde 的反序列化实现
│ ├─ encoder.rs # 为 JsonValue 类型序列化实现
│ ├─ error.rs # 错误类型定义,便于定位
│ ├─ link_list.rs # LinkedList 类型定义和相关方法实现
│ ├─ serializer_compact.rs # 适配 serde 的序列化实现
│ ├─ states.rs # 为 JsonValue 类型反序列化实现
│ └─ value.rs # JsonValue 类型定义和相关方法实现
└─ tests # 测试目录
```
+328
View File
@@ -0,0 +1,328 @@
# ylong_json
### Introduction
The `ylong_json` module provides serialization of text or string in JSON syntax format and deserialization of corresponding generated instances.
`ylong_json` contains the following core functionality:
##### Function 1: Generates a JSON instance
`ylong_json` provides the ability to generate an instance of `JsonValue` from JSON text or string. You need to use a series of instance creation methods for the "JsonValue" to use this feature.
(1) You can create a `JsonValue` instance by:
```rust
use std::fs::File;
use std::str::FromStr;
use std::io::Read;
use ylong_json::JsonValue;
fn create_json_value_instance() {
let str: &str = "";
// You can use `from_str` to try to generate a `JsonValue` instance from
// the &str type.
// If the passed &str does not conform to JSON syntax, the corresponding
// Error will be returned.
let json_value = JsonValue::from_str(str);
let text: String = String::from("");
// You can use `from_text` to generate a `JsonValue` instance from
// a series of types that implement AsRef<[u8]>.
// If the passed text content does not conform to JSON syntax, the
// corresponding Error will be returned.
let json_value = JsonValue::from_text(text);
let path: &str = "";
// You can use `from_file` to read a file from corresponding path and
// try to generate a `JsonValue` instance.
// If the passed path is not valid or the text content does not conform
// to JSON syntax, the corresponding Error will be returned.
let json_value = JsonValue::from_file(path);
let mut reader: Box<dyn Read> = Box::new(File::open("").unwrap());
// You can use `from_reader` interface to read text from an instance
// that implements io::Read and try to generate a `JsonValue` instance.
// If the read fails or if the content from the reader does not conform
// to JSON syntax, the corresponding Error will be returned.
let json_value = JsonValue::from_reader(&mut reader);
}
```
Once the `JsonValue` instance has been successfully created, you can attempt to read and modify the corresponding contents.
(2) If the type in the JSON text implements the third-party library `serde::Deserialize` trait, you can directly deserialize the text content to an instance of that type.
```rust
use std::fs::File;
use serde::Deserialize;
use ylong_json::deserializer::{from_reader, from_slice, from_st};
fn deserialize_json_to_instance() {
#[derive(Deserialize, PartialEq, Debug)]
struct Example {
int: u32,
seq: Vec<String>,
tup: (i32, i32, i32),
}
// You can use `from_str` to try to generate an instance from String.
// If the passed String does not conform to JSON syntax, the corresponding
// Error will be returned.
let str = r#"{"int":1,"seq":["abcd","efgh"],"tup":[1,2,3]}"#;
let example = from_str::<Example>(str).unwrap();
// You can use `from_slice` to try to generate an instance from &u8.
// If the passed &u8 does not conform to JSON syntax, the corresponding
// Error will be returned.
let slice = str.as_bytes();
let example = from_slice::<Example>(slice).unwrap();
// You can use `from_reader` to try to generate an instance from
// locations, files, io streams, and so on that implement io::Write.
// If the passed text content does not conform to JSON syntax,
// the corresponding Error will be returned.
let mut file: File = File::open("./example.txt").unwrap();
let example = from_reader::<Example>(file).unwrap();
}
```
##### Function 2: Reads and modifies a key-value pair
After a `JsonValue` instance is successfully generated, you can use a subscript to find the corresponding key-value pair (to obtain a common reference to the corresponding `JsonValue`).
A subscript of type &str or String can be used to find a key-value pair in Object;
A Subscript of type usize can be used to find a key-value pair in an Array.
```rust
use std::str::FromStr;
use ylong_json::JsonValue;
// JSON string for the example
const JSON_TEXT: &str = r#"
{
"key": "value",
"array": [1, 2, 3]
}
"#;
fn find_key_value_pair() {
// Creates a JsonValue instance from the example string, the syntax is
// correct so the parse must succeed here, so uses unwrap.
let json_value = JsonValue::from_str(JSON_TEXT).unwrap();
// Since json is itself a table, you can use the &str type to obtain
// a common reference to the internal value.
let value: &JsonValue = &json_value["key"];
// You can use the &str type to obtain a common reference to the "array" member, and
// then use the usize type to obtain a common reference to the corresponding element.
let array_item: &JsonValue = &json_value["array"][0];
// If you try to find a key that does not exist in a table,
// `&JsonValue::Null` will be returned.
let no_such_key: &JsonValue = &json_value["no_such_key"];
// When searching for the Array type, if the subscript exceeds the Array length,
// `&JsonValue::Null` will also be returned.
let no_such_index: &JsonValue = &json_value["array"][100];
// If you use a subscript to visit `JsonValue` types other than Object and Array,
// `&JsonValue::Null` will also be returned.
let invalid_index: &JsonValue = &json_value["key"]["invalid"];
let invalid_index: &JsonValue = &json_value["key"][0];
}
```
You can also use the same method to obtain a mutable reference to `JsonValue`.
After obtaining the mutable reference, you can modify it, but you need to make sure that it conforms to JSON syntax.
```rust
use ylong_json::JsonValue;
// JSON string for the example
const JSON_TEXT: &str = r#"
{
"key": "value",
"array": [1, 2, 3]
}
"#;
fn modify_key_value_pair() {
// Creates a JsonValue instance from the example string, the syntax is
// correct so the parse must succeed here, so uses unwrap.
// Here the JSON instance needs to be mutable because you need to obtain a mutable reference.
let mut json_value = JsonValue::from_str(JSON_TEXT).unwrap();
// Obtains a mutable reference to the member by "key" and set it to the number 123.
// In the libraty, many primitive types implement conversion from themselves to JsonValue,
// so they can be converted to `JsonValue` by using `into()` method.
// After executing this code, the contents of the table are as follows:
// {
// "key": 123,
// "array": [1, 2, 3]
// }
json_value["key"] = 123_i32.into();
// Obtains a mutable reference to the member by using "array" and the subscript 0,
// and set it to the number 123.
// After executing this code, the contents of the table are as follows:
// {
// "key": 123,
// "array": [123, 2, 3]
// }
json_value["array"][0] = 123_i32.into();
// If you try to obtain a mutable reference to a key that does not exist in the table,
// then the key will be inserted in the table with the corresponding value JsonValue::Null,
// and changes the value baesd on that.
// After executing this code, the json_value member "no_such_key" has been added,
// and the value is 123.
// The contents of the table are as follows:
// {
// "key": 123,
// "array": [123, 2, 3],
// "no_such_key": 123
// }
json_value["no_such_key"] = 123_i32.into();
// When trying to obtain a mutable reference to a member of the Array type, if the
// subscript exceeds the Array length, then a `JsonValue::Null` will be added at
// the end of the Array and will return a mutable reference to that position.
// After executing this code, the length of the array member of `json_value` becomes 4,
// and the value of the last member is 123.
// The contents of the table are as follows:
// {
// "key": 123,
// "array": [123, 2, 3, 123],
// "no_such_key": 123
// }
json_value["array"][100] = 123_i32.into();
// When using a subscript of &str type or String type to obtain a mutable reference to
// a non-Object type, will replace the value with an empty Object and then visit it with
// that subscript.
// After executing this code, the array member of `json_value` becomes of type Object
// and contains a key-value pair: "key" => 123.
// The contents of the table are as follows:
// {
// "key": 123,
// "array": {
// "key": 123
// },
// "no_such_key": 123
// }
json_value["array"]["key"] = 123_i32.into();
// When using a subscript of usize type to obtain a mutable reference to a non-Array
// type, will replace the value with an empty Array and then visit it with that subscript.
// After executing this code, the key member of `json_value` becomes of type Array,
// and contains a member: key[0] => 123.
// The contents of the table are as follows:
// {
// "key": [123],
// "array": {
// "key": 123
// },
// "no_such_key": 123
// }
json_value["key"][0] = 123_i32.into();
}
```
##### Function 3: Outputs JSON text
(1) When you have a JsonValue instance, you can convert it to text and output it to a specified location: string, file, network, etc.
```rust
use std::fs::File;
use ylong_json::JsonValue;
fn output_json_text(json_value: JsonValue) {
// Uses `to_compact_string()` to output the `json_value` as a string.
let string = json_value.to_compact_string().unwrap();
// Uses `compact_encode()` to output JSON text to a specified location,
// file, io stream, etc., which implements io::Write.
let mut file: File = File::open("").unwrap();
let _ = json_value.compact_encode(&mut file);
}
```
Because there is no strong order requirement for JSON internal elements,
the output order of members will have a certain randomness,
but it does not affect the semantics of JSON text.
(2) You can also serialize an instance of a type that implements the `serde::Serialize` trait to JSON text.
```rust
use std::fs::File;
use serde::Serialize;
use ylong_json::serializer_compact::{to_string, to_writer};
fn<V: Serialize> output_json_text(value: V) {
#[derive(Serialize)]
struct Exmaple {
int: u32,
seq: Vec<&'static str>,
tup: (i32, i32, i32),
}
let example = Example {
int: 1,
seq: vec!["a", "b"],
tup: (1, 2, 3),
};
// Uses `to_string()` to output the value as a string.
let string = to_string(&example).unwrap();
// Uses `to_writer()` to output JSON text to a specified location,
// file, io stream, etc., which implements io::Write.
let mut file: File = File::open("./example.txt").unwrap();
let _ = to_writer(&example, &mut file);
}
```
### Performance test
```
1.Test environment
OS: Linux
Architecture: x86_64
Byte Order: Little Endian
Model number: Intel(R) Xeon(R) Gold 6278C CPU @ 2.60GHz
CPU(s): 8
MemTotal: 16G
2.Test result
| Serialize | ylong_json | serde_json |
------------------------------------------------
| null | 150 ns/iter | 175 ns/iter |
| boolean | 155 ns/iter | 178 ns/iter |
| number | 309 ns/iter | 291 ns/iter |
| string | 513 ns/iter | 413 ns/iter |
| array | 998 ns/iter | 1,075 ns/iter |
| object | 1,333 ns/iter | 1,348 ns/iter |
| example1 | 12,537 ns/iter | 12,288 ns/iter |
| example2 | 23,754 ns/iter | 21,936 ns/iter |
| example3 | 103,061 ns/iter | 97,247 ns/iter |
| example4 | 15,234 ns/iter | 17,895 ns/iter |
| Deserialize | ylong_json | serde_json |
--------------------------------------------------
| null | 257 ns/iter | 399 ns/iter |
| boolean | 260 ns/iter | 400 ns/iter |
| number | 1,507 ns/iter | 989 ns/iter |
| string | 414 ns/iter | 610 ns/iter |
| array | 2,258 ns/iter | 2,148 ns/iter |
| object | 810 ns/iter | 1,386 ns/iter |
| example1 | 10,191 ns/iter | 10,227 ns/iter |
| example2 | 15,753 ns/iter | 18,022 ns/iter |
| example3 | 55,910 ns/iter | 59,717 ns/iter |
| example4 | 18,461 ns/iter | 12,471 ns/iter |
```
### Directory
```
ylong_json
├─ examples # ylong_json code example
├─ include # ylong_json.h
├─ src
│ ├─ value # Array and Object type definitions and related methods
│ ├─ adapter.rs # Adapts to the C interface implementation
│ ├─ consts.rs # Some definitions of constants and tables
│ ├─ deserializer.rs # Deserialization implementation of the adaptation serde
│ ├─ encoder.rs # Serialization implementation for the `JsonValue` type
│ ├─ error.rs # Error type definition, helpful to identify the problem
│ ├─ link_list.rs # LinkedList type definition and related methods
│ ├─ serializer_compact.rs # Serialization implementation of the adaptation serde
│ ├─ states.rs # Deserialization implementation for the `JsonValue` type
│ └─ value.rs # JsonValue type definition and related methods
└─ tests # Test directory
```
+211
View File
@@ -0,0 +1,211 @@
/*
* 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.
*/
//! Benchmarks for the json deserialization
#![feature(test)]
mod task_helpers;
#[cfg(test)]
mod serialize_cmp {
extern crate test;
use crate::task_helpers::*;
use test::Bencher;
use serde_json::Value;
use std::str::FromStr;
use ylong_json::JsonValue;
#[bench]
fn null_deserialize_perf_ylong_json(b: &mut Bencher) {
b.iter(|| {
for _ in 0..LOOPS_NUM {
let _value = JsonValue::from_str(NULL_EXAMPLE).unwrap();
}
});
}
#[bench]
fn boolean_deserialize_perf_ylong_json(b: &mut Bencher) {
b.iter(|| {
for _ in 0..LOOPS_NUM {
let _value = JsonValue::from_str(BOOLEAN_EXAMPLE).unwrap();
}
});
}
#[bench]
fn number_deserialize_perf_ylong_json(b: &mut Bencher) {
b.iter(|| {
for _ in 0..LOOPS_NUM {
let _value = JsonValue::from_str(NUMBER_EXAMPLE).unwrap();
}
});
}
#[bench]
fn string_deserialize_perf_ylong_json(b: &mut Bencher) {
b.iter(|| {
for _ in 0..LOOPS_NUM {
let _value = JsonValue::from_str(STRING_EXAMPLE).unwrap();
}
});
}
#[bench]
fn array_deserialize_perf_ylong_json(b: &mut Bencher) {
b.iter(|| {
for _ in 0..LOOPS_NUM {
let _value = JsonValue::from_str(ARRAY_EXAMPLE).unwrap();
}
});
}
#[bench]
fn object_deserialize_perf_ylong_json(b: &mut Bencher) {
b.iter(|| {
for _ in 0..LOOPS_NUM {
let _value = JsonValue::from_str(OBJECT_EXAMPLE).unwrap();
}
});
}
#[bench]
fn exp1_deserialize_perf_ylong_json(b: &mut Bencher) {
b.iter(|| {
for _ in 0..LOOPS_NUM {
let _value = JsonValue::from_str(RFC7159_EXAMPLE1).unwrap();
}
});
}
#[bench]
fn exp2_deserialize_perf_ylong_json(b: &mut Bencher) {
b.iter(|| {
for _ in 0..LOOPS_NUM {
let _value = JsonValue::from_str(RFC7159_EXAMPLE2).unwrap();
}
});
}
#[bench]
fn exp3_deserialize_perf_ylong_json(b: &mut Bencher) {
b.iter(|| {
for _ in 0..LOOPS_NUM {
let _value = JsonValue::from_str(JSON_PARSE_TEST).unwrap();
}
});
}
#[bench]
fn exp4_deserialize_perf_ylong_json(b: &mut Bencher) {
b.iter(|| {
for _ in 0..LOOPS_NUM {
let _value = JsonValue::from_str(LONG_KEY_VALUE).unwrap();
}
});
}
#[bench]
fn null_deserialize_perf_serde_json(b: &mut Bencher) {
b.iter(|| {
for _ in 0..LOOPS_NUM {
let _value: Value = serde_json::from_str(NULL_EXAMPLE).unwrap();
}
});
}
#[bench]
fn boolean_deserialize_perf_serde_json(b: &mut Bencher) {
b.iter(|| {
for _ in 0..LOOPS_NUM {
let _value: Value = serde_json::from_str(BOOLEAN_EXAMPLE).unwrap();
}
});
}
#[bench]
fn number_deserialize_perf_serde_json(b: &mut Bencher) {
b.iter(|| {
for _ in 0..LOOPS_NUM {
let _value: Value = serde_json::from_str(NUMBER_EXAMPLE).unwrap();
}
});
}
#[bench]
fn string_deserialize_perf_serde_json(b: &mut Bencher) {
b.iter(|| {
for _ in 0..LOOPS_NUM {
let _value: Value = serde_json::from_str(STRING_EXAMPLE).unwrap();
}
});
}
#[bench]
fn array_deserialize_perf_serde_json(b: &mut Bencher) {
b.iter(|| {
for _ in 0..LOOPS_NUM {
let _value: Value = serde_json::from_str(ARRAY_EXAMPLE).unwrap();
}
});
}
#[bench]
fn object_deserialize_perf_serde_json(b: &mut Bencher) {
b.iter(|| {
for _ in 0..LOOPS_NUM {
let _value: Value = serde_json::from_str(OBJECT_EXAMPLE).unwrap();
}
});
}
#[bench]
fn exp1_deserialize_perf_serde_json(b: &mut Bencher) {
b.iter(|| {
for _ in 0..LOOPS_NUM {
let _value: Value = serde_json::from_str(RFC7159_EXAMPLE1).unwrap();
}
});
}
#[bench]
fn exp2_deserialize_perf_serde_json(b: &mut Bencher) {
b.iter(|| {
for _ in 0..LOOPS_NUM {
let _value: Value = serde_json::from_str(RFC7159_EXAMPLE2).unwrap();
}
});
}
#[bench]
fn exp3_deserialize_perf_serde_json(b: &mut Bencher) {
b.iter(|| {
for _ in 0..LOOPS_NUM {
let _value: Value = serde_json::from_str(JSON_PARSE_TEST).unwrap();
}
});
}
#[bench]
fn exp4_deserialize_perf_serde_json(b: &mut Bencher) {
b.iter(|| {
for _ in 0..LOOPS_NUM {
let _value: Value = serde_json::from_str(LONG_KEY_VALUE).unwrap();
}
});
}
}
+231
View File
@@ -0,0 +1,231 @@
/*
* 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.
*/
//! Benchmarks for the json serialization
#![feature(test)]
mod task_helpers;
#[cfg(test)]
mod deserialize_cmp {
extern crate test;
use crate::task_helpers::*;
use test::Bencher;
use serde_json::Value;
use std::str::FromStr;
use ylong_json::JsonValue;
#[bench]
fn null_serialize_perf_ylong_json(b: &mut Bencher) {
let value = JsonValue::from_str(NULL_EXAMPLE).unwrap();
b.iter(|| {
for _ in 0..LOOPS_NUM {
let _ = value.to_compact_string();
}
});
}
#[bench]
fn boolean_serialize_perf_ylong_json(b: &mut Bencher) {
let value = JsonValue::from_str(BOOLEAN_EXAMPLE).unwrap();
b.iter(|| {
for _ in 0..LOOPS_NUM {
let _ = value.to_compact_string();
}
});
}
#[bench]
fn number_serialize_perf_ylong_json(b: &mut Bencher) {
let value = JsonValue::from_str(NUMBER_EXAMPLE).unwrap();
b.iter(|| {
for _ in 0..LOOPS_NUM {
let _ = value.to_compact_string();
}
});
}
#[bench]
fn string_serialize_perf_ylong_json(b: &mut Bencher) {
let value = JsonValue::from_str(STRING_EXAMPLE).unwrap();
b.iter(|| {
for _ in 0..LOOPS_NUM {
let _ = value.to_compact_string();
}
});
}
#[bench]
fn array_serialize_perf_ylong_json(b: &mut Bencher) {
let value = JsonValue::from_str(ARRAY_EXAMPLE).unwrap();
b.iter(|| {
for _ in 0..LOOPS_NUM {
let _ = value.to_compact_string();
}
});
}
#[bench]
fn object_serialize_perf_ylong_json(b: &mut Bencher) {
let value = JsonValue::from_str(OBJECT_EXAMPLE).unwrap();
b.iter(|| {
for _ in 0..LOOPS_NUM {
let _ = value.to_compact_string();
}
});
}
#[bench]
fn exp1_serialize_perf_ylong_json(b: &mut Bencher) {
let value = JsonValue::from_str(RFC7159_EXAMPLE1).unwrap();
b.iter(|| {
for _ in 0..LOOPS_NUM {
let _ = value.to_compact_string();
}
});
}
#[bench]
fn exp2_serialize_perf_ylong_json(b: &mut Bencher) {
let value = JsonValue::from_str(RFC7159_EXAMPLE2).unwrap();
b.iter(|| {
for _ in 0..LOOPS_NUM {
let _ = value.to_compact_string();
}
});
}
#[bench]
fn exp3_serialize_perf_ylong_json(b: &mut Bencher) {
let value = JsonValue::from_str(JSON_PARSE_TEST).unwrap();
b.iter(|| {
for _ in 0..LOOPS_NUM {
let _ = value.to_compact_string();
}
});
}
#[bench]
fn exp4_serialize_perf_ylong_json(b: &mut Bencher) {
let value = JsonValue::from_str(LONG_KEY_VALUE).unwrap();
b.iter(|| {
for _ in 0..LOOPS_NUM {
let _ = value.to_compact_string();
}
});
}
#[bench]
fn null_serialize_perf_serde_json(b: &mut Bencher) {
let value: Value = serde_json::from_str(NULL_EXAMPLE).unwrap();
b.iter(|| {
for _ in 0..LOOPS_NUM {
format!("{value}");
}
});
}
#[bench]
fn boolean_serialize_perf_serde_json(b: &mut Bencher) {
let value: Value = serde_json::from_str(BOOLEAN_EXAMPLE).unwrap();
b.iter(|| {
for _ in 0..LOOPS_NUM {
format!("{value}");
}
});
}
#[bench]
fn number_serialize_perf_serde_json(b: &mut Bencher) {
let value: Value = serde_json::from_str(NUMBER_EXAMPLE).unwrap();
b.iter(|| {
for _ in 0..LOOPS_NUM {
format!("{value}");
}
});
}
#[bench]
fn string_serialize_perf_serde_json(b: &mut Bencher) {
let value: Value = serde_json::from_str(STRING_EXAMPLE).unwrap();
b.iter(|| {
for _ in 0..LOOPS_NUM {
format!("{value}");
}
});
}
#[bench]
fn array_serialize_perf_serde_json(b: &mut Bencher) {
let value: Value = serde_json::from_str(ARRAY_EXAMPLE).unwrap();
b.iter(|| {
for _ in 0..LOOPS_NUM {
format!("{value}");
}
});
}
#[bench]
fn object_serialize_perf_serde_json(b: &mut Bencher) {
let value: Value = serde_json::from_str(OBJECT_EXAMPLE).unwrap();
b.iter(|| {
for _ in 0..LOOPS_NUM {
format!("{value}");
}
});
}
#[bench]
fn exp1_serialize_perf_serde_json(b: &mut Bencher) {
let value: Value = serde_json::from_str(RFC7159_EXAMPLE1).unwrap();
b.iter(|| {
for _ in 0..LOOPS_NUM {
format!("{value}");
}
});
}
#[bench]
fn exp2_serialize_perf_serde_json(b: &mut Bencher) {
let value: Value = serde_json::from_str(RFC7159_EXAMPLE2).unwrap();
b.iter(|| {
for _ in 0..LOOPS_NUM {
format!("{value}");
}
});
}
#[bench]
fn exp3_serialize_perf_serde_json(b: &mut Bencher) {
let value: Value = serde_json::from_str(JSON_PARSE_TEST).unwrap();
b.iter(|| {
for _ in 0..LOOPS_NUM {
format!("{value}");
}
});
}
#[bench]
fn exp4_serialize_perf_serde_json(b: &mut Bencher) {
let value: Value = serde_json::from_str(LONG_KEY_VALUE).unwrap();
b.iter(|| {
for _ in 0..LOOPS_NUM {
format!("{value}");
}
});
}
}
+155
View File
@@ -0,0 +1,155 @@
/*
* 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.
*/
pub const LOOPS_NUM: usize = 10;
pub const NULL_EXAMPLE: &str = "null";
pub const BOOLEAN_EXAMPLE: &str = "false";
pub const NUMBER_EXAMPLE: &str = "12.34";
pub const STRING_EXAMPLE: &str = "\"Hello\"";
pub const ARRAY_EXAMPLE: &str = "[false,null,12.34]";
pub const OBJECT_EXAMPLE: &str = r#"{"key":"value"}"#;
pub 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]
}
}
"#;
pub 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"
}
]
"#;
pub const JSON_PARSE_TEST: &str = r#"
[
{
"null1": null
},
{
"boolean1": true,
"boolean2": false
},
{
"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
},
{
"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"
},
{
"array1": [],
"array2": [
],
"array3": [null,true,0.0,"string",[],{}],
"array4": [
null , true, 0.0 ,
"string", []
, {} ],
"array5": [[[[[[["nest"]]]]]]]
},
{
"object1": {},
"object2": {
},
"object3": {"key1":null,"key2":true,"key3":0.0,"key4":"string","key5":[],"key6":{}},
"object4": {
"key1" : null , "key2"
: true , "key3" :
0.0 , "key4":"string" ,
"key5": [], "key6": {
}
},
"object5": {"nest1": {"nest2": {"nest3": {"nest4": {}}}}}
},
{
"": "key1",
"\/\\\"\uCAFE\uBABE\uAB98\uFCDE\ubcda\uef4A\b\f\n\r\t`1~!@#$%^&*()_+-=[]{}|;:',./<>?" : "key2"
},
{
"key_value1"
: "value"
, "key_value2" : [
] , "key_value3" :
{}
}
]
"#;
pub const LONG_KEY_VALUE: &str = r#"
{
"long_key_value_object":{
"-----LONG KEY-----uoTVt77ryiZ5GnfVXf6kEBJQS8hBMY2BMsyLyckIPrNEvknjp82jz9yatYV0S77uLb99nPR6WqSDPtrWzc1XHJVPLoIlxaDGKm4xB7KaFl95wdnYRvuyCEmrzdoZS1KtXyf31vYLD4r9BnFm6wBuefKvONcLNGi5bsZqq100MWmFXjQUYhd6nZDJWVTAtpF195PiyvoJiJxSkiwpallQCqTbcoZTMf5SJ7KH1umstVVPW6NvgRO5PwwHc2N7QytBvw":
"-----LONG VALUE-----by4iUNvpmeZ5ypvznYm7DSiY6gEgRy64yFGHB6pSgMGVRvElAnrSXpaSC8Exa9aMbx4hGkStSKMSbsk2t8JVxDqBKQVo7NdJiSwQf2p5YxFIU5aS2y4gazdDHcwuo7pqrp47AuXfxC799qUDD4q6VWD9u49Nuy7DXLjrdgLz17cC3uCaMwSZK3wc6Lu0Mri6Di4M9NEe36WGBN1xcmcHvm8GH7XXGikuuZ432HG76DEek1s99jHTzQZEILiDQAB",
"-----LONG KEY-----by4iUNvpmeZ5ypvznYm7DSiY6gEgRy64yFGHB6pSgMGVRvElAnrSXpaSC8Exa9aMbx4hGkStSKMSbsk2t8JVxDqBKQVo7NdJiSwQf2p5YxFIU5aS2y4gazdDHcwuo7pqrp47AuXfxC799qUDD4q6VWD9u49Nuy7DXLjrdgLz17cC3uCaMwSZK3wc6Lu0Mri6Di4M9NEe36WGBN1xcmcHvm8GH7XXGikuuZ432HG76DEek1s99jHTzQZEILiDQAB":
"-----LONG VALUE-----uoTVt77ryiZ5GnfVXf6kEBJQS8hBMY2BMsyLyckIPrNEvknjp82jz9yatYV0S77uLb99nPR6WqSDPtrWzc1XHJVPLoIlxaDGKm4xB7KaFl95wdnYRvuyCEmrzdoZS1KtXyf31vYLD4r9BnFm6wBuefKvONcLNGi5bsZqq100MWmFXjQUYhd6nZDJWVTAtpF195PiyvoJiJxSkiwpallQCqTbcoZTMf5SJ7KH1umstVVPW6NvgRO5PwwHc2N7QytBvw"
}
}
"#;
+43
View File
@@ -0,0 +1,43 @@
/*
* 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.
*/
//! cargo build --example ylong_json_example
//! Simple use examples of serialization and deserialization of JsonValue.
use std::io::stdout;
use ylong_json::JsonValue;
const JSON_TEXT: &str = r#"
{
"null": null,
"true": true,
"false": false,
"number": 3.14,
"string": "Hello World!",
"array": [1, 2, 3],
"object": {
"key1": 1,
"key2": 2,
"key3": 3
}
}
"#;
fn main() {
let value = JsonValue::from_text(JSON_TEXT).unwrap();
let mut console = stdout();
value.formatted_encode(&mut console).unwrap();
value.compact_encode(&mut console).unwrap();
}
+75
View File
@@ -0,0 +1,75 @@
/*
* 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.
*/
//! A performance testing suite for ylong_json.
//!
//! This performance testing suite compares the speed of the `ylong_json` crate
//! with `serde_json` for parsing JSON text and converting JSON objects into
//! strings. The test is run multiple times as defined by `LOOPS_NUM`.
//!
//! Example JSON used in this test represents an image object with various properties.
use serde_json::Value;
use std::str::FromStr;
use std::time::Instant;
use ylong_json::JsonValue;
const LOOPS_NUM: usize = 10000;
const JSON_TEXT: &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]
}
}
"#;
fn main() {
let value = JsonValue::from_str(JSON_TEXT).unwrap();
println!("{}", value.to_compact_string().unwrap());
let st = Instant::now();
for _ in 0..LOOPS_NUM {
let value = JsonValue::from_str(JSON_TEXT).unwrap();
let _ = value.to_compact_string();
}
let ed = Instant::now();
println!(
"ylong_json: {}ms",
ed.duration_since(st).as_secs_f64() * 1000f64
);
let value: Value = serde_json::from_str(JSON_TEXT).unwrap();
println!("{value}");
let st = Instant::now();
for _ in 0..LOOPS_NUM {
let value: Value = serde_json::from_str(JSON_TEXT).unwrap();
format!("{value}");
}
let ed = Instant::now();
println!(
"serde_json: {}ms",
ed.duration_since(st).as_secs_f64() * 1000f64
);
}
+3409
View File
File diff suppressed because it is too large Load Diff
+214
View File
@@ -0,0 +1,214 @@
/*
* 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.
*/
#![allow(dead_code)]
pub(crate) const COLON: u8 = b':';
pub(crate) const COMMA: u8 = b',';
pub(crate) const DECIMAL_POINT: u8 = b'.';
pub(crate) const LEFT_CURLY_BRACKET: u8 = b'{';
pub(crate) const LEFT_SQUARE_BRACKET: u8 = b'[';
pub(crate) const MINUS: u8 = b'-';
pub(crate) const PLUS: u8 = b'+';
pub(crate) const RIGHT_CURLY_BRACKET: u8 = b'}';
pub(crate) const RIGHT_SQUARE_BRACKET: u8 = b']';
pub(crate) const SPACE: u8 = b' ';
pub(crate) const ZERO: u8 = b'0';
pub(crate) const ONE: u8 = b'1';
pub(crate) const NINE: u8 = b'9';
pub(crate) const A_LOWER: u8 = b'a';
pub(crate) const A_UPPER: u8 = b'A';
pub(crate) const E_LOWER: u8 = b'e';
pub(crate) const E_UPPER: u8 = b'E';
pub(crate) const F_LOWER: u8 = b'f';
pub(crate) const F_UPPER: u8 = b'F';
pub(crate) const N_LOWER: u8 = b'n';
pub(crate) const T_LOWER: u8 = b't';
pub(crate) const WHITE_SPACE_SET: [u8; 4] =
[SPACE, HT_UNICODE as u8, LF_UNICODE as u8, CR_UNICODE as u8];
pub(crate) const BS: u8 = b'b';
pub(crate) const BS_UNICODE: char = '\u{0008}';
pub(crate) const BS_UNICODE_U8: u8 = 0x08;
pub(crate) const HT: u8 = b't';
pub(crate) const HT_UNICODE: char = '\u{0009}';
pub(crate) const HT_UNICODE_U8: u8 = 0x09;
pub(crate) const FF: u8 = b'f';
pub(crate) const FF_UNICODE: char = '\u{000c}';
pub(crate) const FF_UNICODE_U8: u8 = 0x0c;
pub(crate) const CR: u8 = b'r';
pub(crate) const CR_UNICODE: char = '\u{000d}';
pub(crate) const CR_UNICODE_U8: u8 = 0x0d;
pub(crate) const LF: u8 = b'n';
pub(crate) const LF_UNICODE: char = '\u{000a}';
pub(crate) const LF_UNICODE_U8: u8 = 0x0a;
pub(crate) const UNICODE: u8 = b'u';
pub(crate) const QUOTATION_MARK: u8 = b'\"';
pub(crate) const REVERSE_SOLIDUS: u8 = b'\\';
pub(crate) const SOLIDUS: u8 = b'/';
pub(crate) const JSON_REVERSE_SOLIDUS: &[u8] = b"\\\\";
pub(crate) const JSON_QUOTATION_MARK: &[u8] = b"\\\"";
pub(crate) const JSON_BS: &[u8] = b"\\b";
pub(crate) const JSON_FF: &[u8] = b"\\f";
pub(crate) const JSON_LF: &[u8] = b"\\n";
pub(crate) const JSON_CR: &[u8] = b"\\r";
pub(crate) const JSON_HT: &[u8] = b"\\t";
pub(crate) const NULL_STR: &[u8] = b"null";
pub(crate) const NULL_LEFT_STR: &[u8] = b"ull";
pub(crate) const FALSE_STR: &[u8] = b"false";
pub(crate) const FALSE_LEFT_STR: &[u8] = b"alse";
pub(crate) const TRUE_STR: &[u8] = b"true";
pub(crate) const TRUE_LEFT_STR: &[u8] = b"rue";
pub(crate) const UNICODE_START_STR: &[u8] = b"\\u";
pub(crate) const COLON_STR: &[u8] = b":";
pub(crate) const COMMA_STR: &[u8] = b",";
pub(crate) const FOUR_SPACES_STR: &[u8] = b" ";
pub(crate) const LEFT_CURLY_BRACKET_STR: &[u8] = b"{";
pub(crate) const LEFT_SQUARE_BRACKET_STR: &[u8] = b"[";
pub(crate) const LINE_FEED_STR: &[u8] = b"\n";
pub(crate) const QUOTATION_MARK_STR: &[u8] = b"\"";
pub(crate) const RIGHT_CURLY_BRACKET_STR: &[u8] = b"}";
pub(crate) const RIGHT_SQUARE_BRACKET_STR: &[u8] = b"]";
pub(crate) const SPACE_STR: &[u8] = b" ";
pub(crate) const RECURSION_LIMIT: u32 = 128;
// Improves the string read rate by looking up tables.
pub(crate) static ESCAPE: [bool; 256] = {
const CT: bool = true; // Control character \x00..=\x1F
const QU: bool = true; // Quotation mark \x22
const BS: bool = true; // Backslash \x5C
const __: bool = false; // Other character
[
// 1 2 3 4 5 6 7 8 9 A B C D E F
CT, CT, CT, CT, CT, CT, CT, CT, CT, CT, CT, CT, CT, CT, CT, CT, // 0
CT, CT, CT, CT, CT, CT, CT, CT, CT, CT, CT, CT, CT, CT, CT, CT, // 1
__, __, QU, __, __, __, __, __, __, __, __, __, __, __, __, __, // 2
__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // 3
__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // 4
__, __, __, __, __, __, __, __, __, __, __, __, BS, __, __, __, // 5
__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // 6
__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // 7
__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // 8
__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // 9
__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // A
__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // B
__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // C
__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // D
__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // E
__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // F
]
};
// TODO: Consider modifying the structure of PRINT_MAP.
#[cfg(not(feature = "ascii_only"))]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) enum PrintMapItem<'a> {
Other,
Control,
Special(&'a [u8]),
}
// Improves the string output rate by looking up the table.
#[cfg(not(feature = "ascii_only"))]
pub(crate) static PRINT_MAP: [PrintMapItem; 256] = {
const BS: PrintMapItem = PrintMapItem::Special(b"\\b"); // BS 退格 \x08
const HT: PrintMapItem = PrintMapItem::Special(b"\\t"); // HT 水平定位符 \x09
const LF: PrintMapItem = PrintMapItem::Special(b"\\n"); // LF 换行 \x0A
const FF: PrintMapItem = PrintMapItem::Special(b"\\f"); // FF 换页 \x0C
const CR: PrintMapItem = PrintMapItem::Special(b"\\r"); // CR 归位 \x0D
const QU: PrintMapItem = PrintMapItem::Special(b"\\\""); // 双引号 \x22
const SO: PrintMapItem = PrintMapItem::Special(b"/"); // 斜杠 \x2F
const RS: PrintMapItem = PrintMapItem::Special(b"\\\\"); // 反斜杠 \x5C
const CT: PrintMapItem = PrintMapItem::Control; // 控制字符 \x00..=\x1F
const __: PrintMapItem = PrintMapItem::Other; // 其他字符
[
// 1 2 3 4 5 6 7 8 9 A B C D E F
CT, CT, CT, CT, CT, CT, CT, CT, BS, HT, LF, CT, FF, CR, CT, CT, // 0
CT, CT, CT, CT, CT, CT, CT, CT, CT, CT, CT, CT, CT, CT, CT, CT, // 1
__, __, QU, __, __, __, __, __, __, __, __, __, __, __, __, SO, // 2
__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // 3
__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // 4
__, __, __, __, __, __, __, __, __, __, __, __, RS, __, __, __, // 5
__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // 6
__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // 7
__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // 8
__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // 9
__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // A
__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // B
__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // C
__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // D
__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // E
__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // F
]
};
#[cfg(not(feature = "ascii_only"))]
#[cfg(test)]
mod ut_consts {
use crate::consts::PrintMapItem;
/// UT test case for `PrintMapItem::clone`.
///
/// # Title
/// ut_print_map_item_clone
///
/// # Brief
/// 1. Creates a `PrintMapItem`.
/// 2. Calls `PrintMapItem::clone`.
/// 3. Checks if the results are correct.
#[allow(clippy::clone_on_copy)]
#[test]
fn ut_print_map_item_clone() {
let item = PrintMapItem::Other;
let item = item.clone();
assert_eq!(item, PrintMapItem::Other);
let item = PrintMapItem::Control;
let item = item.clone();
assert_eq!(item, PrintMapItem::Control);
let item = PrintMapItem::Special(b"abc");
let item = item.clone();
assert_eq!(item, PrintMapItem::Special(b"abc"));
}
/// UT test case for `PrintMapItem::copy`.
///
/// # Title
/// ut_print_map_item_copy
///
/// # Brief
/// 1. Creates a `PrintMapItem`.
/// 2. Calls `PrintMapItem::copy`.
/// 3. Checks if the results are correct.
#[test]
fn ut_print_map_item_copy() {
let item1 = PrintMapItem::Other;
let _item2 = item1;
assert_eq!(item1, PrintMapItem::Other);
let item1 = PrintMapItem::Control;
let _item2 = item1;
assert_eq!(item1, PrintMapItem::Control);
let item1 = PrintMapItem::Special(b"abc");
let _item2 = item1;
assert_eq!(item1, PrintMapItem::Special(b"abc"));
}
}
+1099
View File
File diff suppressed because it is too large Load Diff
+511
View File
@@ -0,0 +1,511 @@
/*
* 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 crate::{consts::*, Array, Error, JsonValue, Number, Object};
#[cfg(feature = "c_adapter")]
use std::ffi::CString;
use std::io::Write;
// todo: Considers extracting Encoder traits.
/// JSON encoder with additional formats, used to output JsonValue instances in JSON format to the specified location.
///
/// This encoder will add additional formatting control whitespace characters during encoding.
pub(crate) struct FormattedEncoder<'a, W: Write> {
output: &'a mut W,
/// The current number of nested layers
tab: usize,
}
impl<'a, W: Write> FormattedEncoder<'a, W> {
/// Creates
pub(crate) fn new(output: &'a mut W) -> Self {
Self { output, tab: 0 }
}
/// Encodes
pub(crate) fn encode(&mut self, value: &JsonValue) -> Result<(), Error> {
self.encode_value(value)?;
self.output.write_all(LINE_FEED_STR)?;
Ok(())
}
/// Encodes JsonValue
fn encode_value(&mut self, value: &JsonValue) -> Result<(), Error> {
match value {
JsonValue::Null => self.encode_null(),
JsonValue::Boolean(boolean) => self.encode_boolean(boolean),
JsonValue::Number(number) => self.encode_number(number),
JsonValue::String(string) => self.encode_string(string),
JsonValue::Array(array) => self.encode_array(array),
JsonValue::Object(object) => self.encode_object(object),
}
}
/// Add tabs to improve readability.
fn add_tab(&mut self) -> Result<(), Error> {
for _ in 0..self.tab {
self.output.write_all(FOUR_SPACES_STR)?;
}
Ok(())
}
/// Encodes Null
fn encode_null(&mut self) -> Result<(), Error> {
encode_null(self.output)
}
/// Encodes Boolean
fn encode_boolean(&mut self, boolean: &bool) -> Result<(), Error> {
encode_boolean(self.output, *boolean)
}
/// Encodes Number
fn encode_number(&mut self, number: &Number) -> Result<(), Error> {
encode_number(self.output, number)
}
/// Encodes Key
fn encode_key(&mut self, key: &str) -> Result<(), Error> {
encode_string(self.output, key)
}
/// Encodes String
#[cfg(feature = "c_adapter")]
fn encode_string(&mut self, string: &CString) -> Result<(), Error> {
encode_string(self.output, unsafe {
core::str::from_utf8_unchecked(string.as_bytes())
})
}
/// Encodes String
#[cfg(not(feature = "c_adapter"))]
fn encode_string(&mut self, string: &str) -> Result<(), Error> {
encode_string(self.output, string)
}
/// Encodes Array
fn encode_array(&mut self, array: &Array) -> Result<(), Error> {
// Check whether multiple lines are required. If array or object
// exists in the array value, multiple lines are required.
let mut multiple_line = false;
for v in array.iter() {
if v.is_array() | v.is_object() {
multiple_line = true;
break;
}
}
self.output.write_all(LEFT_SQUARE_BRACKET_STR)?;
if multiple_line {
self.output.write_all(LINE_FEED_STR)?;
self.tab += 1;
self.add_tab()?;
for (n, v) in array.iter().enumerate() {
if n != 0 {
self.output.write_all(COMMA_STR)?;
self.output.write_all(LINE_FEED_STR)?;
self.add_tab()?;
}
self.encode_value(v)?;
}
self.output.write_all(LINE_FEED_STR)?;
self.tab -= 1;
self.add_tab()?;
} else {
for (n, v) in array.iter().enumerate() {
if n != 0 {
self.output.write_all(COMMA_STR)?;
self.output.write_all(SPACE_STR)?;
}
self.encode_value(v)?;
}
}
self.output.write_all(RIGHT_SQUARE_BRACKET_STR)?;
Ok(())
}
/// Encodes Object
fn encode_object(&mut self, object: &Object) -> Result<(), Error> {
self.output.write_all(LEFT_CURLY_BRACKET_STR)?;
self.tab += 1;
for (u, (k, v)) in object.iter().enumerate() {
if u != 0 {
self.output.write_all(COMMA_STR)?;
}
self.output.write_all(LINE_FEED_STR)?;
self.add_tab()?;
self.encode_key(k)?;
self.output.write_all(COLON_STR)?;
self.output.write_all(SPACE_STR)?;
self.encode_value(v)?;
}
self.tab -= 1;
// Non-empty objects require additional newlines and tabs.
if !object.is_empty() {
self.output.write_all(LINE_FEED_STR)?;
self.add_tab()?;
}
self.output.write_all(RIGHT_CURLY_BRACKET_STR)?;
Ok(())
}
}
/// JSON encoder that outputs no extra whitespace characters ,
/// used to output a JsonValue instance in JSON format to a specified location.
pub(crate) struct CompactEncoder<'a, W: Write> {
output: &'a mut W,
}
impl<'a, W: Write> CompactEncoder<'a, W> {
/// Creates
pub(crate) fn new(output: &'a mut W) -> Self {
Self { output }
}
/// Encodes
pub(crate) fn encode(&mut self, value: &JsonValue) -> Result<(), Error> {
self.encode_value(value)
}
/// Encodes JsonValue
fn encode_value(&mut self, value: &JsonValue) -> Result<(), Error> {
match value {
JsonValue::Null => self.encode_null(),
JsonValue::Boolean(boolean) => self.encode_boolean(boolean),
JsonValue::Number(number) => self.encode_number(number),
JsonValue::String(string) => self.encode_string(string),
JsonValue::Array(array) => self.encode_array(array),
JsonValue::Object(object) => self.encode_object(object),
}
}
/// Encodes Null
fn encode_null(&mut self) -> Result<(), Error> {
encode_null(self.output)
}
/// Encodes Boolean
fn encode_boolean(&mut self, boolean: &bool) -> Result<(), Error> {
encode_boolean(self.output, *boolean)
}
/// Encodes Number
fn encode_number(&mut self, number: &Number) -> Result<(), Error> {
encode_number(self.output, number)
}
/// Encodes Key
fn encode_key(&mut self, key: &str) -> Result<(), Error> {
encode_string(self.output, key)
}
/// Encodes String
#[cfg(feature = "c_adapter")]
fn encode_string(&mut self, string: &CString) -> Result<(), Error> {
encode_string(self.output, unsafe {
std::str::from_utf8_unchecked(string.as_bytes())
})
}
/// Encodes String
#[cfg(not(feature = "c_adapter"))]
fn encode_string(&mut self, string: &str) -> Result<(), Error> {
encode_string(self.output, string)
}
/// Encodes Array
fn encode_array(&mut self, array: &Array) -> Result<(), Error> {
self.output.write_all(LEFT_SQUARE_BRACKET_STR)?;
for (n, v) in array.iter().enumerate() {
if n != 0 {
self.output.write_all(COMMA_STR)?;
}
self.encode_value(v)?;
}
self.output.write_all(RIGHT_SQUARE_BRACKET_STR)?;
Ok(())
}
/// Encodes Object
fn encode_object(&mut self, object: &Object) -> Result<(), Error> {
self.output.write_all(LEFT_CURLY_BRACKET_STR)?;
for (u, (k, v)) in object.iter().enumerate() {
if u != 0 {
self.output.write_all(COMMA_STR)?;
}
self.encode_key(k)?;
self.output.write_all(COLON_STR)?;
self.encode_value(v)?;
}
self.output.write_all(RIGHT_CURLY_BRACKET_STR)?;
Ok(())
}
}
#[inline]
fn encode_null(writer: &mut dyn Write) -> Result<(), Error> {
writer.write_all(NULL_STR)?;
Ok(())
}
#[inline]
fn encode_boolean(writer: &mut dyn Write, boolean: bool) -> Result<(), Error> {
if boolean {
writer.write_all(TRUE_STR)?;
} else {
writer.write_all(FALSE_STR)?;
}
Ok(())
}
#[inline]
pub(crate) fn encode_number(writer: &mut dyn Write, number: &Number) -> Result<(), Error> {
write!(writer, "{number}")?;
Ok(())
}
#[inline]
fn encode_string(writer: &mut dyn Write, string: &str) -> Result<(), Error> {
writer.write_all(QUOTATION_MARK_STR)?;
encode_string_inner(writer, string)?;
writer.write_all(QUOTATION_MARK_STR)?;
Ok(())
}
#[cfg(feature = "ascii_only")]
pub(crate) fn encode_string_inner(writer: &mut dyn Write, string: &str) -> Result<(), Error> {
let bytes = string.as_bytes();
let len = bytes.len();
let mut start = 0usize;
for i in 0..len {
let ch = &bytes[i];
if ESCAPE[(*ch) as usize] {
writer.write_all(&bytes[start..i])?;
start = i + 1;
match *ch {
REVERSE_SOLIDUS => writer.write_all(JSON_REVERSE_SOLIDUS)?,
QUOTATION_MARK => writer.write_all(JSON_QUOTATION_MARK)?,
BS_UNICODE_U8 => writer.write_all(JSON_BS)?,
FF_UNICODE_U8 => writer.write_all(JSON_FF)?,
LF_UNICODE_U8 => writer.write_all(JSON_LF)?,
CR_UNICODE_U8 => writer.write_all(JSON_CR)?,
HT_UNICODE_U8 => writer.write_all(JSON_HT)?,
x => write!(writer, "\\u{number:0>width$x}", number = x, width = 4)?,
}
}
}
if start != len {
writer.write_all(&bytes[start..len])?;
}
Ok(())
}
#[cfg(not(feature = "ascii_only"))]
pub(crate) fn encode_string_inner(writer: &mut dyn Write, string: &str) -> Result<(), Error> {
fn split_pattern(
writer: &mut dyn Write,
pattern: &mut &str,
split_pos: &mut usize,
ch: char,
) -> Result<(), Error> {
let (l, r) = (*pattern).split_at(*split_pos);
writer.write_all(l.as_bytes())?;
*pattern = r;
let (_, r) = (*pattern).split_at(ch.len_utf8());
*pattern = r;
*split_pos = 0;
Ok(())
}
let mut pattern = string;
let mut split_pos = 0usize;
for ch in string.chars() {
if ch.is_ascii() {
match PRINT_MAP[ch as usize] {
PrintMapItem::Other => {
split_pos += 1;
continue;
}
PrintMapItem::Special(x) => {
split_pattern(writer, &mut pattern, &mut split_pos, ch)?;
writer.write_all(x)?;
}
PrintMapItem::Control => {
split_pattern(writer, &mut pattern, &mut split_pos, ch)?;
let bytes = ch as u32;
write!(writer, "\\u{number:0>width$x}", number = bytes, width = 4)?;
}
}
continue;
}
split_pattern(writer, &mut pattern, &mut split_pos, ch)?;
let bytes = ch as u32;
write!(writer, "\\u{number:0>width$x}", number = bytes, width = 4)?;
}
if split_pos != 0 {
writer.write_all(pattern.as_bytes())?;
}
Ok(())
}
#[cfg(test)]
mod ut_encoder {
use crate::{CompactEncoder, FormattedEncoder, JsonValue};
use std::io::Write;
struct StringWriter {
string: String,
}
impl StringWriter {
fn new() -> Self {
Self {
string: String::new(),
}
}
}
impl Write for StringWriter {
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
self.string
.push_str(unsafe { std::str::from_utf8_unchecked(buf) });
self.flush()?;
Ok(buf.len())
}
fn flush(&mut self) -> std::io::Result<()> {
Ok(())
}
}
macro_rules! encoder_test_case {
($encoder: ident, $input: expr, $output: expr $(,)?) => {
let value = JsonValue::from_text($input).unwrap();
let mut writer = StringWriter::new();
let mut encoder = $encoder::new(&mut writer);
assert!(encoder.encode(&value).is_ok());
assert_eq!(writer.string, $output);
};
}
/// UT test for `FormattedEncoder`.
///
/// # Title
/// ut_formatted_encoder
///
/// # Brief
/// 1. Creates a `JsonValue` called `json_value`.
/// 2. Creates a `FormattedEncoder` called `encoder`.
/// 3. Uses `encoder` to encode `json_value`.
/// 4. Checks if the results are correct.
#[test]
fn ut_formatted_encoder() {
encoder_test_case!(
FormattedEncoder,
"{\"null\":null}",
"{\n \"null\": null\n}\n",
);
encoder_test_case!(
FormattedEncoder,
"{\"true\":true}",
"{\n \"true\": true\n}\n",
);
encoder_test_case!(
FormattedEncoder,
"{\"false\":false}",
"{\n \"false\": false\n}\n",
);
encoder_test_case!(
FormattedEncoder,
"{\"number\":3.14}",
"{\n \"number\": 3.14\n}\n",
);
encoder_test_case!(
FormattedEncoder,
"{\"string\":\"HelloWorld\"}",
"{\n \"string\": \"HelloWorld\"\n}\n",
);
encoder_test_case!(
FormattedEncoder,
"{\"array\":[1, 2, 3]}",
"{\n \"array\": [1, 2, 3]\n}\n",
);
encoder_test_case!(
FormattedEncoder,
"{\"object\":{\"key1\":1}}",
"{\n \"object\": {\n \"key1\": 1\n }\n}\n",
);
}
/// UT test for `CompactEncoder`.
///
/// # Title
/// ut_compact_encoder
///
/// # Brief
/// 1. Creates a `JsonValue` called `json_value`.
/// 2. Creates a `Compact` called `encoder`.
/// 3. Uses `encoder` to encode `json_value`.
/// 4. Checks if the results are correct.
#[test]
fn ut_compact_encoder() {
encoder_test_case!(CompactEncoder, "{\"null\":null}", "{\"null\":null}",);
encoder_test_case!(CompactEncoder, "{\"true\":true}", "{\"true\":true}",);
encoder_test_case!(CompactEncoder, "{\"false\":false}", "{\"false\":false}",);
encoder_test_case!(CompactEncoder, "{\"number\":3.14}", "{\"number\":3.14}",);
encoder_test_case!(
CompactEncoder,
"{\"string\":\"HelloWorld\"}",
"{\"string\":\"HelloWorld\"}",
);
#[cfg(not(feature = "ascii_only"))]
encoder_test_case!(
CompactEncoder,
"{\"string\":\"\\b\\t\\f\\n\\u0000\\u2764\"}",
"{\"string\":\"\\b\\t\\f\\n\\u0000\\u2764\"}",
);
#[cfg(feature = "ascii_only")]
encoder_test_case!(
CompactEncoder,
"{\"string\":\"\\b\\t\\f\\n\\u0000\\u2764\"}",
"{\"string\":\"\\b\\t\\f\\n\\u0000\u{2764}\"}",
);
encoder_test_case!(CompactEncoder, "{\"array\":[1,2,3]}", "{\"array\":[1,2,3]}",);
encoder_test_case!(
CompactEncoder,
"{\"object\":{\"key1\":1,\"key2\":2}}",
"{\"object\":{\"key1\":1,\"key2\":2}}",
);
}
}
+416
View File
@@ -0,0 +1,416 @@
/*
* 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 core::fmt::{Debug, Display, Formatter, Result};
use std::ffi::IntoStringError;
use std::string::FromUtf8Error;
/// Errors during parsing.
pub enum Error {
/// Parsing error.
Parsing(ParseError),
/// Io error.
Io(std::io::Error),
/// Parse number error.
ParseNumber,
/// Utf8 transform error.
Utf8Transform,
/// Type transform error.
TypeTransform,
/// Reader error.
Reader(Box<dyn std::error::Error>),
/// Incorrect serde usage error.
IncorrectSerdeUsage,
/// Used to convert serde-related errors.
Custom(String),
/// Exceeds the recursion limit.
ExceedRecursionLimit,
}
/// The specific location and character of the error during parsing.
pub enum ParseError {
/// Undesired character (line number, character number, current character)
UnexpectedCharacter(usize, usize, char),
/// Illegal UTF-8 character (line number)
InvalidUtf8Bytes(usize),
/// Undesired end-of-file character (line number)
UnexpectedEndOfJson(usize),
/// Expected Eof but not received (line number)
TrailingBytes(usize),
/// The input sequence has not yet been parsed.
ParsingUnfinished,
}
impl Error {
pub(crate) fn new_reader<E: Into<Box<dyn std::error::Error>>>(e: E) -> Self {
Error::Reader(e.into())
}
}
impl Debug for ParseError {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
Self::UnexpectedCharacter(line, pos, unexpected) => {
write!(
f,
"[Line]: {line}, [Pos]: {pos}, [Error]: Unexpected character: "
)?;
let mut str = match *unexpected {
'\u{8}' => Some("\'\\b\'"),
'\u{b}' => Some("\'\\v\'"),
'\u{c}' => Some("\'\\f\'"),
_ => None,
};
if let Some(s) = str.take() {
write!(f, "{s}.")
} else {
write!(f, "{unexpected:?}.")
}
}
Self::InvalidUtf8Bytes(line) => {
write!(f, "[line]: {line}, [Error]: Invalid UTF-8 byte.")
}
Self::UnexpectedEndOfJson(line) => {
write!(f, "[Line]: {line}, [Error]: Unexpected end of json.")
}
Self::TrailingBytes(line) => {
write!(f, "[Line]: {line}, [Error]: Expected end of json but not.")
}
Self::ParsingUnfinished => {
write!(f, "[Error]: Value has not been fully deserialized.")
}
}
}
}
impl Debug for Error {
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
match self {
Self::Parsing(e) => write!(f, "Parse Error: {e:?}"),
Self::Io(e) => write!(f, "Io Error: {e:?}"),
Self::ParseNumber => write!(f, "Parse Number Error"),
Self::TypeTransform => write!(f, "Type Transform Error"),
Self::Utf8Transform => write!(f, "Utf8 Transform Error"),
Self::IncorrectSerdeUsage => write!(f, "Incorrect Serde Usage Error"),
Self::Custom(s) => write!(f, "{s}"),
Self::Reader(e) => write!(f, "Reader Error:{e:?}"),
Self::ExceedRecursionLimit => write!(f, "Exceed the recursion limit"),
}
}
}
impl Display for Error {
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
Debug::fmt(self, f)
}
}
impl From<ParseError> for Error {
fn from(e: ParseError) -> Self {
Error::Parsing(e)
}
}
impl From<core::str::Utf8Error> for Error {
fn from(_: core::str::Utf8Error) -> Self {
Error::Utf8Transform
}
}
impl From<std::io::Error> for Error {
fn from(e: std::io::Error) -> Self {
Error::Io(e)
}
}
impl std::error::Error for Error {}
impl serde::ser::Error for Error {
fn custom<T>(msg: T) -> Self
where
T: Display,
{
Error::Custom(msg.to_string())
}
}
impl serde::de::Error for Error {
fn custom<T>(msg: T) -> Self
where
T: Display,
{
Error::Custom(msg.to_string())
}
}
impl From<FromUtf8Error> for Error {
fn from(_: FromUtf8Error) -> Self {
Error::Utf8Transform
}
}
impl From<IntoStringError> for Error {
fn from(_: IntoStringError) -> Self {
Error::TypeTransform
}
}
#[cfg(test)]
mod ut_error {
use crate::{Error, ParseError};
use std::ffi::CString;
use std::io::ErrorKind;
/// UT test for `Error::fmt`.
///
/// # Title
/// ut_error_fmt
///
/// # Brief
/// 1. Creates a `Error`.
/// 2. Calls `Error::fmt` on this error.
/// 3. Checks if the results are correct.
#[test]
fn ut_error_fmt() {
assert_eq!(
format!(
"{:?}",
Error::Parsing(ParseError::UnexpectedCharacter(1, 1, 'a'))
),
"Parse Error: [Line]: 1, [Pos]: 1, [Error]: Unexpected character: 'a'.",
);
assert_eq!(
format!(
"{:?}",
Error::Parsing(ParseError::UnexpectedCharacter(1, 1, '\u{8}'))
),
"Parse Error: [Line]: 1, [Pos]: 1, [Error]: Unexpected character: '\\b'.",
);
assert_eq!(
format!(
"{:?}",
Error::Parsing(ParseError::UnexpectedCharacter(1, 1, '\u{b}'))
),
"Parse Error: [Line]: 1, [Pos]: 1, [Error]: Unexpected character: '\\v'.",
);
assert_eq!(
format!(
"{:?}",
Error::Parsing(ParseError::UnexpectedCharacter(1, 1, '\u{c}'))
),
"Parse Error: [Line]: 1, [Pos]: 1, [Error]: Unexpected character: '\\f'.",
);
assert_eq!(
format!("{:?}", Error::Parsing(ParseError::InvalidUtf8Bytes(1))),
"Parse Error: [line]: 1, [Error]: Invalid UTF-8 byte.",
);
assert_eq!(
format!("{:?}", Error::Parsing(ParseError::UnexpectedEndOfJson(1))),
"Parse Error: [Line]: 1, [Error]: Unexpected end of json.",
);
assert_eq!(
format!("{:?}", Error::Parsing(ParseError::TrailingBytes(1))),
"Parse Error: [Line]: 1, [Error]: Expected end of json but not.",
);
assert_eq!(
format!("{:?}", Error::Parsing(ParseError::ParsingUnfinished)),
"Parse Error: [Error]: Value has not been fully deserialized.",
);
assert_eq!(
format!(
"{:?}",
Error::Io(std::io::Error::from(ErrorKind::AddrInUse))
),
"Io Error: Kind(AddrInUse)",
);
assert_eq!(format!("{:?}", Error::ParseNumber), "Parse Number Error",);
assert_eq!(
format!("{:?}", Error::Utf8Transform),
"Utf8 Transform Error",
);
assert_eq!(
format!("{:?}", Error::TypeTransform),
"Type Transform Error",
);
assert_eq!(
format!("{:?}", Error::IncorrectSerdeUsage),
"Incorrect Serde Usage Error",
);
assert_eq!(
format!("{:?}", Error::Custom(String::from("Custom Error"))),
"Custom Error",
);
assert_eq!(
format!("{:?}", Error::ExceedRecursionLimit),
"Exceed the recursion limit",
);
assert_eq!(
format!(
"{:?}",
Error::Reader(std::io::Error::from(ErrorKind::AddrInUse).into())
),
"Reader Error:Kind(AddrInUse)",
);
assert_eq!(
format!(
"{}",
Error::Parsing(ParseError::UnexpectedCharacter(1, 1, 'a'))
),
"Parse Error: [Line]: 1, [Pos]: 1, [Error]: Unexpected character: 'a'.",
);
assert_eq!(
format!(
"{}",
Error::Parsing(ParseError::UnexpectedCharacter(1, 1, '\u{8}'))
),
"Parse Error: [Line]: 1, [Pos]: 1, [Error]: Unexpected character: '\\b'.",
);
assert_eq!(
format!(
"{}",
Error::Parsing(ParseError::UnexpectedCharacter(1, 1, '\u{b}'))
),
"Parse Error: [Line]: 1, [Pos]: 1, [Error]: Unexpected character: '\\v'.",
);
assert_eq!(
format!(
"{}",
Error::Parsing(ParseError::UnexpectedCharacter(1, 1, '\u{c}'))
),
"Parse Error: [Line]: 1, [Pos]: 1, [Error]: Unexpected character: '\\f'.",
);
assert_eq!(
format!("{}", Error::Parsing(ParseError::InvalidUtf8Bytes(1))),
"Parse Error: [line]: 1, [Error]: Invalid UTF-8 byte.",
);
assert_eq!(
format!("{}", Error::Parsing(ParseError::UnexpectedEndOfJson(1))),
"Parse Error: [Line]: 1, [Error]: Unexpected end of json.",
);
assert_eq!(
format!("{}", Error::Parsing(ParseError::TrailingBytes(1))),
"Parse Error: [Line]: 1, [Error]: Expected end of json but not.",
);
assert_eq!(
format!("{}", Error::Io(std::io::Error::from(ErrorKind::AddrInUse))),
"Io Error: Kind(AddrInUse)",
);
assert_eq!(format!("{}", Error::ParseNumber), "Parse Number Error",);
assert_eq!(format!("{}", Error::Utf8Transform), "Utf8 Transform Error",);
assert_eq!(format!("{}", Error::TypeTransform), "Type Transform Error",);
assert_eq!(
format!(
"{}",
Error::Reader(std::io::Error::from(ErrorKind::AddrInUse).into())
),
"Reader Error:Kind(AddrInUse)",
);
}
/// UT test for `Error::from`.
///
/// # Title
/// ut_error_from
///
/// # Brief
/// 1. Creates some other errors.
/// 2. Calls `Error::from` on those error.
/// 3. Checks if the results are correct.
#[test]
fn ut_error_from() {
assert_eq!(
format!("{}", Error::from(ParseError::TrailingBytes(1))),
"Parse Error: [Line]: 1, [Error]: Expected end of json but not.",
);
assert_eq!(
format!(
"{}",
Error::from(std::io::Error::from(ErrorKind::AddrInUse))
),
"Io Error: Kind(AddrInUse)",
);
let str_vec = [0b10000000u8; 1];
assert_eq!(
format!(
"{}",
Error::from(std::str::from_utf8(&str_vec).err().unwrap())
),
"Utf8 Transform Error",
);
assert_eq!(
format!(
"{}",
Error::from(String::from_utf8(vec![129, 129, 129]).err().unwrap())
),
"Utf8 Transform Error",
);
assert_eq!(
format!(
"{}",
Error::from(
CString::new(vec![129, 129, 129])
.expect("CString::new failed")
.into_string()
.err()
.unwrap()
)
),
"Type Transform Error",
);
}
}
+86
View File
@@ -0,0 +1,86 @@
/*
* 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.
*/
//! ylong_json is a library for parsing and serializing JSON in Rust.
//! This library provides a convenient macro-based API for creating
//! JSON values, and utilities for reading and writing JSON data
//! from various sources.
// TODO: 1) Isolates ylong_json no_std.
// TODO: 2) Handles illegal Utf-8 bytes.
// TODO: 3) Refactors ylong_json.
// TODO: 4) JsonValue provides 'Contains' methods。
/// Creates an array with at least one but any number of elements.
#[macro_export]
macro_rules! array {
() => ({
Array::new()
});
($($x:expr),+ $(,)?) => ({
let mut array = Array::new();
$(
array.push($x.into());
)*
array
});
}
/// Creates an object with at least one but any number of key-value pairs.
#[macro_export]
macro_rules! object {
() => ({
Object::new()
});
($($k: expr => $v: expr);+ $(;)?) => ({
let mut object = Object::new();
$(
object.insert(String::from($k), $v.into());
)*
object
});
}
mod consts;
mod encoder;
mod error;
mod reader;
#[macro_use]
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};
pub(crate) use states::start_parsing;
#[cfg(feature = "c_adapter")]
mod adapter;
#[cfg(feature = "c_adapter")]
pub use adapter::*;
mod deserializer;
#[cfg(any(feature = "list_array", feature = "list_object"))]
mod linked_list;
mod serializer_compact;
#[cfg(any(feature = "list_array", feature = "list_object"))]
pub(crate) use linked_list::{Cursor, CursorMut, LinkedList};
#[cfg(any(feature = "list_array", feature = "list_object"))]
pub use linked_list::{Iter, IterMut, Node};
pub use deserializer::{from_reader, from_slice, from_str};
+979
View File
@@ -0,0 +1,979 @@
/*
* 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 core::fmt::{Debug, Formatter};
use core::marker::PhantomData;
use core::ptr::null;
// todo: Considers deleting PhantomData.
/// Linked list implementation, provides two sets of methods for getting nodes and members.
/// Only tail insertion, reading, and eject are supported.
pub(crate) struct LinkedList<T> {
head: *const Node<T>,
tail: *const Node<T>,
len: usize,
marker: PhantomData<Box<Node<T>>>,
}
impl<T> LinkedList<T> {
/// Creates LinkedList.
pub(crate) const fn new() -> Self {
LinkedList {
head: null(),
tail: null(),
len: 0,
marker: PhantomData,
}
}
/// Gets length of the list.
#[inline]
pub(crate) fn len(&self) -> usize {
self.len
}
/// Determines whether the linked list is empty.
#[inline]
pub(crate) fn is_empty(&self) -> bool {
self.len == 0
}
/// Inserts an element at the end of the list
pub(crate) fn push_back(&mut self, value: T) {
let mut node = Box::new(Node::new(value));
unsafe {
// Sets prev to LinkedList.tail
node.prev = self.tail;
// Gets an internal element pointer.
let node = Box::leak(node) as *const Node<T>;
if self.tail.is_null() {
self.head = node;
} else {
(*(self.tail as *mut Node<T>)).next = node;
}
self.tail = node;
self.len += 1;
}
}
/// Pops an element from the end of the list.
pub(crate) fn pop_back(&mut self) -> Option<T> {
if self.tail.is_null() {
None
} else {
unsafe {
let node = Box::from_raw(self.tail as *mut Node<T>);
self.tail = node.prev;
if self.tail.is_null() {
self.head = null();
} else {
(*(self.tail as *mut Node<T>)).next = null();
}
self.len -= 1;
Some(node.into_element())
}
}
}
/// Gets an ordinary iterator for a linked list.
#[inline]
pub(crate) fn iter(&self) -> Iter<'_, T> {
Iter {
head: self.head,
tail: self.tail,
len: self.len,
marker: PhantomData,
}
}
/// Gets a mutable iterator for the linked list.
#[inline]
pub(crate) fn iter_mut(&mut self) -> IterMut<'_, T> {
IterMut {
head: self.head,
tail: self.tail,
len: self.len,
marker: PhantomData,
}
}
/// Gets the normal cursor of the list and sets the starting point to the list header.
#[inline]
pub(crate) fn cursor_front(&self) -> Cursor<'_, T> {
Cursor {
index: 0,
current: self.head,
list: self,
}
}
/// Gets the variable cursor of the list and sets the starting point to the list header.
#[inline]
pub(crate) fn cursor_front_mut(&mut self) -> CursorMut<'_, T> {
CursorMut {
index: 0,
current: self.head,
list: self,
}
}
/// Gets the normal cursor of the list and sets the starting point to the end of the list.
#[cfg(feature = "list_array")]
#[inline]
pub(crate) fn cursor_back(&self) -> Cursor<'_, T> {
Cursor {
index: self.len.saturating_sub(1),
current: self.tail,
list: self,
}
}
/// Gets the variable cursor of the list and sets the start to the end of the list.
#[cfg(feature = "list_array")]
#[inline]
pub(crate) fn cursor_back_mut(&mut self) -> CursorMut<'_, T> {
CursorMut {
index: self.len.saturating_sub(1),
current: self.tail,
list: self,
}
}
/// Gets a mutable reference to the tail element of the list.
#[cfg(feature = "list_array")]
#[inline]
pub(crate) fn back(&self) -> Option<&T> {
if self.tail.is_null() {
None
} else {
unsafe { Some(&(*self.tail).element) }
}
}
/// Gets a mutable reference to the tail element of the list.
#[inline]
pub(crate) fn back_mut(&mut self) -> Option<&mut T> {
if self.tail.is_null() {
None
} else {
unsafe { Some(&mut (*(self.tail as *mut Node<T>)).element) }
}
}
/// Gets a common reference to the node at the end of the linked list.
#[cfg(feature = "list_array")]
#[inline]
pub(crate) fn back_node(&self) -> Option<&Node<T>> {
if self.tail.is_null() {
None
} else {
unsafe { Some(&(*self.tail)) }
}
}
/// Gets a mutable reference to the node at the end of the linked list.
#[cfg(feature = "list_array")]
#[inline]
pub(crate) fn back_node_mut(&mut self) -> Option<&mut Node<T>> {
if self.tail.is_null() {
None
} else {
unsafe {
// Sets node.parent to the current linked_list in order to delete node.
let node = &mut *(self.tail as *mut Node<T>);
node.parent = self as *const LinkedList<T>;
Some(node)
}
}
}
/// Removes a node from the linked list.
pub(crate) unsafe fn unlink_node(&mut self, node: *const Node<T>) {
let node = &mut (*(node as *mut Node<T>));
if node.prev.is_null() {
self.head = node.next;
} else {
(*(node.prev as *mut Node<T>)).next = node.next;
}
if node.next.is_null() {
self.tail = node.prev;
} else {
(*(node.next as *mut Node<T>)).prev = node.prev;
}
self.len -= 1;
}
}
impl<T> Default for LinkedList<T> {
fn default() -> Self {
Self::new()
}
}
impl<T: Debug> Debug for LinkedList<T> {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
for (n, item) in self.iter().enumerate() {
if n != 0 {
write!(f, ",")?;
}
write!(f, "{item:?}")?;
}
Ok(())
}
}
impl<T: PartialEq> PartialEq for LinkedList<T> {
fn eq(&self, other: &Self) -> bool {
if self.len != other.len {
return false;
}
for (a, b) in self.iter().zip(other.iter()) {
if a.ne(b) {
return false;
}
}
true
}
}
impl<T: Clone> Clone for LinkedList<T> {
fn clone(&self) -> Self {
let mut new_list = LinkedList::new();
for item in self.iter() {
new_list.push_back(item.clone());
}
new_list
}
}
impl<T> Drop for LinkedList<T> {
fn drop(&mut self) {
while self.len != 0 {
let _ = self.pop_back();
}
}
}
// We need to use static to store the JsonValue, so we need to make the LinkedList implement Send and Sync.
// However, when using this list, locking is still required under concurrent conditions.
unsafe impl<T: Send> Send for LinkedList<T> {}
unsafe impl<T: Sync> Sync for LinkedList<T> {}
/// Linked list node, only through a linked list cursor to get the node.
pub struct Node<T> {
next: *const Node<T>,
prev: *const Node<T>,
parent: *const LinkedList<T>,
element: T,
}
impl<T> Node<T> {
/// Creates a linked list node.
pub(crate) fn new(element: T) -> Self {
Node {
next: null(),
prev: null(),
parent: null(),
element,
}
}
/// Retrieves the member inside the list node.
pub(crate) fn into_element(self) -> T {
self.element
}
/// Gets a common reference to an internal member of a linked list node.
pub(crate) fn get_element_mut(&mut self) -> &mut T {
&mut self.element
}
/// Removes the node itself from the linked list and returns the member below.
#[cfg(feature = "c_adapter")]
pub(crate) fn remove_self(&mut self) -> Option<T> {
let list = unsafe { &mut *(self.parent as *mut LinkedList<T>) };
let mut cursor = CursorMut {
index: 0,
current: self as *const Node<T>,
list,
};
cursor.remove_current()
}
}
/// A common iterator of a linked list.
pub struct Iter<'a, T: 'a> {
head: *const Node<T>,
tail: *const Node<T>,
len: usize,
marker: PhantomData<&'a Node<T>>,
}
impl<'a, T> Iterator for Iter<'a, T> {
type Item = &'a T;
#[inline]
fn next(&mut self) -> Option<&'a T> {
if self.len == 0 || self.head.is_null() {
None
} else {
let node = unsafe { &*(self.head as *mut Node<T>) };
self.len -= 1;
self.head = node.next;
Some(&node.element)
}
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
// Returns a tuple representing the remaining range of iterators.
(self.len, Some(self.len))
}
#[inline]
fn last(mut self) -> Option<&'a T> {
// Uses the iterator traversal and returns the last element.
self.next_back()
}
}
impl<'a, T> DoubleEndedIterator for Iter<'a, T> {
fn next_back(&mut self) -> Option<&'a T> {
if self.len == 0 || self.tail.is_null() {
None
} else {
let node = unsafe { &*(self.tail as *mut Node<T>) };
self.len -= 1;
self.tail = node.prev;
Some(&node.element)
}
}
}
/// A variable iterator of a linked list.
pub struct IterMut<'a, T: 'a> {
head: *const Node<T>,
tail: *const Node<T>,
len: usize,
marker: PhantomData<&'a mut Node<T>>,
}
impl<'a, T> Iterator for IterMut<'a, T> {
type Item = &'a mut T;
#[inline]
fn next(&mut self) -> Option<&'a mut T> {
if self.len == 0 || self.head.is_null() {
None
} else {
let node = unsafe { &mut *(self.head as *mut Node<T>) };
self.len -= 1;
self.head = node.next;
Some(&mut node.element)
}
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
// Returns a tuple representing the remaining range of iterators.
(self.len, Some(self.len))
}
#[inline]
fn last(mut self) -> Option<&'a mut T> {
// Uses the iterator traversal and returns the last element.
self.next_back()
}
}
impl<'a, T> DoubleEndedIterator for IterMut<'a, T> {
#[inline]
fn next_back(&mut self) -> Option<&'a mut T> {
if self.len == 0 || self.tail.is_null() {
None
} else {
let node = unsafe { &mut *(self.tail as *mut Node<T>) };
self.len -= 1;
self.tail = node.prev;
Some(&mut node.element)
}
}
}
/// A common cursor for a linked list. When the list is empty,
/// it points to a virtual location (pointing to a node that does not actually exist).
pub(crate) struct Cursor<'a, T: 'a> {
index: usize,
current: *const Node<T>,
list: &'a LinkedList<T>,
}
impl<'a, T> Cursor<'a, T> {
/// Gets the position the cursor is pointing to.
/// If the cursor points to a virtual position, return None.
#[inline]
pub(crate) fn index(&self) -> Option<usize> {
if self.current.is_null() {
return None;
}
Some(self.index)
}
/// The cursor moves back.
#[inline]
pub(crate) fn move_next(&mut self) {
if self.current.is_null() {
self.current = self.list.head;
self.index = 0;
} else {
self.current = unsafe { (*self.current).next };
self.index += 1;
}
}
/// The cursor moves forward.
#[cfg(feature = "list_array")]
#[inline]
pub(crate) fn move_prev(&mut self) {
if self.current.is_null() {
self.current = self.list.tail;
self.index = self.list.len().saturating_sub(1);
} else {
self.current = unsafe { (*self.current).prev };
self.index = self.index.checked_sub(1).unwrap_or_else(|| self.list.len());
}
}
/// Gets the cursor.
#[inline]
pub(crate) fn current(&self) -> Option<&'a T> {
if self.current.is_null() {
None
} else {
unsafe { Some(&(*self.current).element) }
}
}
/// Gets a reference to the current node.
#[inline]
pub(crate) fn current_node(&self) -> Option<&'a Node<T>> {
if self.current.is_null() {
None
} else {
unsafe { Some(&*(self.current)) }
}
}
#[cfg(feature = "list_object")]
#[inline]
pub(crate) fn current_node_ptr(&self) -> *const Node<T> {
self.current
}
}
pub(crate) struct CursorMut<'a, T: 'a> {
index: usize,
current: *const Node<T>,
list: &'a mut LinkedList<T>,
}
impl<'a, T> CursorMut<'a, T> {
/// Gets the index.
#[inline]
pub(crate) fn index(&self) -> Option<usize> {
if self.current.is_null() {
return None;
}
Some(self.index)
}
/// The cursor moves beck.
#[inline]
pub(crate) fn move_next(&mut self) {
if self.current.is_null() {
self.current = self.list.head;
self.index = 0;
} else {
self.current = unsafe { (*self.current).next };
self.index += 1;
}
}
/// The cursor moves forward.
#[cfg(feature = "list_array")]
#[inline]
pub(crate) fn move_prev(&mut self) {
if self.current.is_null() {
self.current = self.list.tail;
self.index = self.list.len().saturating_sub(1);
} else {
self.current = unsafe { (*self.current).prev };
self.index = self.index.checked_sub(1).unwrap_or_else(|| self.list.len());
}
}
/// Gets a mutable reference to the current element.
#[cfg(feature = "list_object")]
#[inline]
pub(crate) fn current(&mut self) -> Option<&mut T> {
if self.current.is_null() {
None
} else {
unsafe { Some(&mut (*(self.current as *mut Node<T>)).element) }
}
}
/// Gets a mutable reference to the current node.
#[inline]
pub(crate) fn current_node(&mut self) -> Option<&'a mut Node<T>> {
if self.current.is_null() {
None
} else {
unsafe {
let node = &mut *(self.current as *mut Node<T>);
node.parent = self.list as *mut LinkedList<T>;
Some(node)
}
}
}
/// Deletes the node to which the cursor is pointing.
#[inline]
pub(crate) fn remove_current(&mut self) -> Option<T> {
if self.current.is_null() {
return None;
}
let unlinked_node = self.current;
unsafe {
self.current = (*unlinked_node).next;
self.list.unlink_node(unlinked_node);
let unlinked_node = Box::from_raw(unlinked_node as *mut Node<T>);
Some(unlinked_node.element)
}
}
}
#[cfg(test)]
mod ut_linked_list {
use crate::LinkedList;
/// UT test for `LinkedList::pop_back`.
///
/// # Title
/// ut_linked_list_pop_back
///
/// # Brief
/// 1. Creates a `LinkedList`.
/// 2. Calls `LinkedList::pop_back` on it.
/// 3. Checks if the test results are correct.
#[test]
fn ut_linked_list_pop_back() {
let mut list = LinkedList::new();
assert_eq!(list.pop_back(), None);
list.push_back(1i32);
assert_eq!(list.pop_back(), Some(1));
}
/// UT test for `LinkedList::iter_mut`.
///
/// # Title
/// ut_linked_list_iter_mut
///
/// # Brief
/// 1. Creates a `LinkedList`.
/// 2. Calls `LinkedList::iter_mut` on it.
/// 3. Checks if the test results are correct.
#[test]
fn ut_linked_list_iter_mut() {
let mut list = LinkedList::new();
list.push_back(1i32);
list.push_back(2i32);
let mut iter = list.iter_mut();
assert_eq!(iter.next(), Some(&mut 1));
assert_eq!(iter.next(), Some(&mut 2));
assert_eq!(iter.next(), None);
}
/// UT test for `LinkedList::back`.
///
/// # Title
/// ut_linked_list_back
///
/// # Brief
/// 1. Creates a `LinkedList`.
/// 2. Calls `LinkedList::back` on it.
/// 3. Checks if the test results are correct.
#[cfg(feature = "list_array")]
#[test]
fn ut_linked_list_back() {
let mut list = LinkedList::new();
assert_eq!(list.back(), None);
list.push_back(1i32);
assert_eq!(list.back(), Some(&1));
}
/// UT test for `LinkedList::back_mut`.
///
/// # Title
/// ut_linked_list_back_mut
///
/// # Brief
/// 1. Creates a `LinkedList`.
/// 2. Calls `LinkedList::back_mut` on it.
/// 3. Checks if the test results are correct.
#[test]
fn ut_linked_list_back_mut() {
let mut list = LinkedList::new();
assert_eq!(list.back_mut(), None);
list.push_back(1i32);
assert_eq!(list.back_mut(), Some(&mut 1));
}
/// UT test for `LinkedList::back_node`.
///
/// # Title
/// ut_linked_list_back_node
///
/// # Brief
/// 1. Creates a `LinkedList`.
/// 2. Calls `LinkedList::back_node` on it.
/// 3. Checks if the test results are correct.
#[cfg(feature = "list_array")]
#[test]
fn ut_linked_list_back_node() {
let mut list = LinkedList::new();
assert!(list.back_node().is_none());
list.push_back(1i32);
assert!(list.back_node().is_some());
}
/// UT test for `LinkedList::back_node_mut`.
///
/// # Title
/// ut_linked_list_back_node_mut
///
/// # Brief
/// 1. Creates a `LinkedList`.
/// 2. Calls `LinkedList::back_node_mut` on it.
/// 3. Checks if the test results are correct.
#[cfg(feature = "list_array")]
#[test]
fn ut_linked_list_back_node_mut() {
let mut list = LinkedList::new();
assert!(list.back_node_mut().is_none());
list.push_back(1i32);
assert!(list.back_node_mut().is_some());
}
/// UT test for `LinkedList::default`.
///
/// # Title
/// ut_linked_list_default
///
/// # Brief
/// 1. Calls `LinkedList::default` to create a `LinkedList`.
/// 2. Checks if the test results are correct.
#[test]
fn ut_linked_list_default() {
assert_eq!(LinkedList::<i32>::default(), LinkedList::<i32>::new());
}
/// UT test for `LinkedList::eq`.
///
/// # Title
/// ut_linked_list_eq
///
/// # Brief
/// 1. Creates some `LinkedList`s.
/// 2. Calls `LinkedList::eq` on them.
/// 3. Checks if the test results are correct.
#[test]
fn ut_linked_list_eq() {
let mut list1 = LinkedList::new();
list1.push_back(1i32);
let mut list2 = LinkedList::new();
list2.push_back(1i32);
list2.push_back(2i32);
let mut list3 = LinkedList::new();
list3.push_back(1i32);
list3.push_back(3i32);
assert_eq!(list1, list1);
assert_ne!(list1, list2);
assert_ne!(list2, list3);
}
/// UT test for `LinkedList::clone`.
///
/// # Title
/// ut_linked_list_clone
///
/// # Brief
/// 1. Creates a `LinkedList`.
/// 2. Calls `LinkedList::clone` to create a copy of it.
/// 3. Checks if the test results are correct.
#[test]
fn ut_linked_list_clone() {
let mut list1 = LinkedList::new();
list1.push_back(1i32);
let list2 = list1.clone();
assert_eq!(list1, list2);
}
/// UT test for `LinkedList::fmt`.
///
/// # Title
/// ut_linked_list_fmt
///
/// # Brief
/// 1. Creates a `LinkedList`.
/// 2. Calls `LinkedList::fmt` on it.
/// 3. Checks if the test results are correct.
#[test]
fn ut_linked_list_fmt() {
let mut list = LinkedList::new();
list.push_back(1i32);
list.push_back(2i32);
assert_eq!(format!("{list:?}"), "1,2");
}
/// UT test for `Cursor::index`.
///
/// # Title
/// ut_cursor_index
///
/// # Brief
/// 1. Creates a `LinkedList` and a `Cursor`.
/// 2. Calls `Cursor::index`.
/// 3. Checks if the test results are correct.
#[test]
fn ut_cursor_index() {
let mut list = LinkedList::new();
list.push_back(1i32);
let mut cursor = list.cursor_front();
assert_eq!(cursor.index(), Some(0));
cursor.move_next();
assert_eq!(cursor.index(), None);
}
/// UT test for `Cursor::move_next`.
///
/// # Title
/// ut_cursor_move_next
///
/// # Brief
/// 1. Creates a `LinkedList` and a `Cursor`.
/// 2. Calls `Cursor::move_next`.
/// 3. Checks if the test results are correct.
#[test]
fn ut_cursor_move_next() {
let mut list = LinkedList::new();
list.push_back(1i32);
list.push_back(2i32);
let mut cursor = list.cursor_front();
assert_eq!(cursor.current(), Some(&1));
cursor.move_next();
assert_eq!(cursor.current(), Some(&2));
cursor.move_next();
assert_eq!(cursor.current(), None);
cursor.move_next();
assert_eq!(cursor.current(), Some(&1));
}
/// UT test for `Cursor::move_prev`.
///
/// # Title
/// ut_cursor_move_prev
///
/// # Brief
/// 1. Creates a `LinkedList` and a `Cursor`.
/// 2. Calls `Cursor::move_prev`.
/// 3. Checks if the test results are correct.
#[cfg(feature = "list_array")]
#[test]
fn ut_cursor_move_prev() {
let mut list = LinkedList::new();
list.push_back(1i32);
list.push_back(2i32);
let mut cursor = list.cursor_front();
assert_eq!(cursor.current(), Some(&1));
cursor.move_prev();
assert_eq!(cursor.current(), None);
cursor.move_prev();
assert_eq!(cursor.current(), Some(&2));
cursor.move_prev();
assert_eq!(cursor.current(), Some(&1));
}
/// UT test for `Cursor::current_node`.
///
/// # Title
/// ut_cursor_current_node
///
/// # Brief
/// 1. Creates a `LinkedList` and a `Cursor`.
/// 2. Calls `Cursor::current_node`.
/// 3. Checks if the test results are correct.
#[test]
fn ut_cursor_current_node() {
let mut list = LinkedList::new();
list.push_back(1i32);
let mut cursor = list.cursor_front();
assert!(cursor.current_node().is_some());
cursor.move_next();
assert!(cursor.current_node().is_none());
}
/// UT test for `CursorMut::index`.
///
/// # Title
/// ut_cursor_mut_index
///
/// # Brief
/// 1. Creates a `LinkedList` and a `CursorMut`.
/// 2. Calls `CursorMut::index`.
/// 3. Checks if the test results are correct.
#[test]
fn ut_cursor_mut_index() {
let mut list = LinkedList::new();
list.push_back(1i32);
let mut cursor = list.cursor_front_mut();
assert_eq!(cursor.index(), Some(0));
cursor.move_next();
assert_eq!(cursor.index(), None);
}
/// UT test for `CursorMut::move_next`.
///
/// # Title
/// ut_cursor_mut_move_next
///
/// # Brief
/// 1. Creates a `LinkedList` and a `CursorMut`.
/// 2. Calls `CursorMut::move_next`.
/// 3. Checks if the test results are correct.
#[test]
fn ut_cursor_mut_move_next() {
let mut list = LinkedList::new();
list.push_back(1i32);
let mut cursor = list.cursor_front_mut();
assert!(cursor.current_node().is_some());
cursor.move_next();
assert!(cursor.current_node().is_none());
cursor.move_next();
assert!(cursor.current_node().is_some());
}
/// UT test for `CursorMut::move_prev`.
///
/// # Title
/// ut_cursor_mut_move_prev
///
/// # Brief
/// 1. Creates a `LinkedList` and a `CursorMut`.
/// 2. Calls `CursorMut::move_prev`.
/// 3. Checks if the test results are correct.
#[cfg(feature = "list_array")]
#[test]
fn ut_cursor_mut_move_prev() {
let mut list = LinkedList::new();
list.push_back(1i32);
let mut cursor = list.cursor_front_mut();
assert!(cursor.current_node().is_some());
cursor.move_prev();
assert!(cursor.current_node().is_none());
cursor.move_prev();
assert!(cursor.current_node().is_some());
}
/// UT test for `CursorMut::current`.
///
/// # Title
/// ut_cursor_mut_current
///
/// # Brief
/// 1. Creates a `LinkedList` and a `CursorMut`.
/// 2. Calls `CursorMut::current`.
/// 3. Checks if the test results are correct.
#[cfg(feature = "list_object")]
#[test]
fn ut_cursor_mut_current() {
let mut list = LinkedList::new();
list.push_back(1i32);
let mut cursor = list.cursor_front_mut();
assert_eq!(cursor.current(), Some(&mut 1));
cursor.move_next();
assert_eq!(cursor.current(), None);
}
/// UT test for `CursorMut::current`.
///
/// # Title
/// ut_cursor_mut_current
///
/// # Brief
/// 1. Creates a `LinkedList` and a `CursorMut`.
/// 2. Calls `CursorMut::current`.
/// 3. Checks if the test results are correct.
#[test]
fn ut_cursor_mut_remove_current() {
let mut list = LinkedList::new();
list.push_back(1i32);
let mut cursor = list.cursor_front_mut();
assert_eq!(cursor.remove_current(), Some(1));
assert_eq!(cursor.remove_current(), None);
}
}
+608
View File
@@ -0,0 +1,608 @@
/*
* 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 super::{BytesReader, Cacheable, Position};
use std::io::{Error, ErrorKind, Read, Result};
/// Reader for reading I\O. This reader implements `BytesReader` trait and
/// `Cacheable` trait.
///
/// # Examples
/// ```not run
/// use std::fs::File;
/// use ylong_bytes_reader::{IoReader, BytesReader};
///
/// let file = File::open("./test.txt").unwrap();
/// let mut io_reader = IoReader::new(file);
/// let char = io_reader.next();
/// let char = io_reader.peek();
/// ```
pub(crate) struct IoReader<R: Read> {
io: R,
buf: Vec<u8>, // Buffer for storing read bytes.
cur: usize, // The position of the cursor in the current buf.
idx: usize, // A counter of all bytes that have been read.
pos: Position,
cache: Option<Cache>,
}
// A simple cache implementation for `IoReader`.
struct Cache {
cache: Vec<u8>,
pre: usize, // Last cached location.
}
impl Cache {
/// Create a new `Cache`.
fn new() -> Self {
Self {
cache: Vec::new(),
pre: 0,
}
}
}
impl<R: Read> IoReader<R> {
/// Create a new `IoReader` from the given I\O.
pub(crate) fn new(io: R) -> Self {
Self {
io,
buf: Vec::with_capacity(1024), // Default size is 1024.
cur: 0,
idx: 0,
pos: Position::new(1, 1),
cache: None,
}
}
// Try to read some bytes from io to fill buf.
fn read_bytes(&mut self) -> Result<bool> {
unsafe {
self.buf.set_len(1024);
}
loop {
return match self.io.read(self.buf.as_mut_slice()) {
Ok(0) => unsafe {
self.buf.set_len(0);
Ok(false)
},
Ok(n) => unsafe {
self.buf.set_len(n);
Ok(true)
},
Err(ref e) if e.kind() == ErrorKind::WouldBlock => continue,
Err(e) => Err(e),
};
}
}
// If there is not enough bytes in buf, try to read some bytes from io and
// reset some parameters inside.
fn load(&mut self) -> Result<bool> {
if let Some(ref mut cacher) = self.cache {
cacher.cache.extend_from_slice(&self.buf[cacher.pre..]);
cacher.pre = 0;
}
let result = self.read_bytes();
if let Ok(true) = result {
self.cur = 0;
}
result
}
// Every time a user calls a cache-related interface, the cache content
// needs to be updated in time.
fn update_cache(&mut self) {
if let Some(ref mut cacher) = self.cache {
if self.cur > cacher.pre {
cacher
.cache
.extend_from_slice(&self.buf[cacher.pre..self.cur]);
}
cacher.pre = self.cur;
}
}
}
impl<R: Read> BytesReader for IoReader<R> {
type Error = Error;
fn next(&mut self) -> Result<Option<u8>> {
if self.cur == self.buf.len() {
match self.load() {
Ok(true) => {}
Ok(false) => return Ok(None),
Err(e) => return Err(e),
}
}
let ch = self.buf[self.cur];
self.cur += 1;
self.idx += 1;
if ch == b'\n' {
self.pos.line += 1;
self.pos.column = 1;
} else {
self.pos.column += 1;
}
Ok(Some(ch))
}
fn peek(&mut self) -> Result<Option<u8>> {
if self.cur == self.buf.len() {
match self.load() {
Ok(true) => {}
Ok(false) => return Ok(None),
Err(e) => return Err(e),
}
}
Ok(Some(self.buf[self.cur]))
}
fn discard(&mut self) {
if self.cur == self.buf.len() {
match self.load() {
Ok(true) => {}
Ok(false) => return,
Err(_) => return,
}
}
let ch = self.buf[self.cur];
self.cur += 1;
self.idx += 1;
if ch == b'\n' {
self.pos.line += 1;
self.pos.column = 1;
} else {
self.pos.column += 1;
}
}
#[inline]
fn index(&self) -> usize {
self.idx
}
#[inline]
fn position(&self) -> Position {
self.pos.clone()
}
}
impl<R: Read> Cacheable for IoReader<R> {
fn start_caching(&mut self) {
if let Some(ref mut cacher) = self.cache {
cacher.cache.clear();
cacher.pre = self.cur;
} else {
let mut cache = Cache::new();
cache.pre = self.cur;
self.cache = Some(cache);
}
}
fn cached_len(&mut self) -> Option<usize> {
self.update_cache();
self.cache.as_ref().map(|c| c.cache.len())
}
fn cached_slice(&mut self) -> Option<&[u8]> {
self.update_cache();
self.cache.as_ref().map(|c| c.cache.as_slice())
}
fn cached_data(&mut self) -> Option<Vec<u8>> {
self.update_cache();
self.cache.as_ref().map(|c| c.cache.clone())
}
fn end_caching(&mut self) {
self.cache = None;
}
fn take_cached_data(&mut self) -> Option<Vec<u8>> {
self.update_cache();
self.cache.take().map(|c| c.cache)
}
}
#[cfg(test)]
mod ut_io_reader {
use super::{BytesReader, Cacheable, IoReader};
use std::cmp;
use std::io::{ErrorKind, Read};
struct TestIo {
vec: Vec<u8>,
idx: usize,
}
impl TestIo {
fn new(vec: Vec<u8>) -> Self {
Self { vec, idx: 0 }
}
}
impl Read for TestIo {
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
if self.idx == self.vec.len() {
return Ok(0);
}
let last = cmp::min(self.idx + buf.len(), self.vec.len());
let len = last - self.idx;
buf[..len].copy_from_slice(&self.vec[self.idx..last]);
self.idx = last;
Ok(len)
}
}
struct TestWouldBlockIo {
cnt: usize,
}
impl TestWouldBlockIo {
fn new() -> Self {
Self { cnt: 0 }
}
fn is_finished(&self) -> bool {
self.cnt == 10
}
}
impl Read for TestWouldBlockIo {
fn read(&mut self, _buf: &mut [u8]) -> std::io::Result<usize> {
if self.cnt < 10 {
self.cnt += 1;
return Err(ErrorKind::WouldBlock.into());
}
Ok(0)
}
}
struct TestErrIo;
impl TestErrIo {
fn new() -> Self {
Self
}
}
impl Read for TestErrIo {
fn read(&mut self, _buf: &mut [u8]) -> std::io::Result<usize> {
Err(ErrorKind::AddrInUse.into())
}
}
/// UT test case for `IoReader::new`.
///
/// # Title
/// ut_io_reader_new
///
/// # Brief
/// 1. Call `IoReader::new`.
/// 2. Check that parts of the return value are default values.
#[test]
fn ut_io_reader_new() {
let io = TestIo::new(Vec::new());
let io_reader = IoReader::new(io);
assert_eq!(io_reader.cur, 0);
assert_eq!(io_reader.idx, 0);
assert_eq!(io_reader.pos.line, 1);
assert_eq!(io_reader.pos.column, 1);
assert_eq!(io_reader.buf.capacity(), 1024);
assert!(io_reader.buf.is_empty());
assert!(io_reader.cache.is_none());
}
/// UT test case for `IoReader::next`.
///
/// # Title
/// ut_test_case_io_reader_next
///
/// # Brief
/// 1. Create a `IoReader`.
/// 2. Call `IoReader::next`.
/// 3. Check the return value against the following conditions:
/// - If the end is not read, it returns `Ok(Some(..))`, and the index
/// is moved backward; if the end is read, it returns `Ok(None)`, and
/// the index is not moved.
#[test]
fn ut_io_reader_next() {
// Use TestIo.
let io = TestIo::new(vec![1u8; 1025]);
let mut io_reader = IoReader::new(io);
assert_eq!(io_reader.next().unwrap(), Some(1));
for _ in 0..1023 {
let _ = io_reader.next().unwrap();
}
assert_eq!(io_reader.next().unwrap(), Some(1));
assert_eq!(io_reader.next().unwrap(), None);
// Use TestWouldBlockIo.
let io = TestWouldBlockIo::new();
let mut io_reader = IoReader::new(io);
assert_eq!(io_reader.next().unwrap(), None);
assert!(io_reader.io.is_finished());
// Use TestErrIo
let io = TestErrIo::new();
let mut io_reader = IoReader::new(io);
assert!(io_reader.next().is_err());
}
/// UT test case for `IoReader::peek`.
///
/// # Title
/// ut_io_reader_peek
///
/// # Brief
/// 1. Create a `IoReader`.
/// 2. Call `IoReader::peek`.
/// 3. Check the return value against the following conditions:
/// - If the end is not read, it returns `Ok(Some(..))`; if the end is
/// read, it returns `Ok(None)`.
#[test]
fn ut_io_reader_peek() {
// Use TestIo.
let io = TestIo::new(vec![1u8; 1]);
let mut io_reader = IoReader::new(io);
assert_eq!(io_reader.peek().unwrap(), Some(1));
assert_eq!(io_reader.peek().unwrap(), Some(1));
assert_eq!(io_reader.next().unwrap(), Some(1));
assert_eq!(io_reader.peek().unwrap(), None);
// Use TestWouldBlockIo.
let io = TestWouldBlockIo::new();
let mut io_reader = IoReader::new(io);
assert_eq!(io_reader.peek().unwrap(), None);
assert!(io_reader.io.is_finished());
// Use TestErrorIo.
let io = TestErrIo::new();
let mut io_reader = IoReader::new(io);
assert!(io_reader.peek().is_err());
}
/// UT test case for `IoReader::discard`.
///
/// # Title
/// ut_io_reader_discard
///
/// # Brief
/// 1. Create a `IoReader`.
/// 2. Call `IoReader::discard`.
/// 3. Check `index` against the following conditions:
/// - If the end is not read, the index is moved backward; if the end is
/// read, the index is not moved.
#[test]
fn ut_io_reader_discard() {
let io = TestIo::new(vec![1u8; 1]);
let mut io_reader = IoReader::new(io);
assert_eq!(io_reader.index(), 0);
io_reader.discard();
assert_eq!(io_reader.index(), 1);
io_reader.discard();
assert_eq!(io_reader.index(), 1);
}
/// UT test case for `IoReader::index`.
///
/// # Title
/// ut_io_reader_index
///
/// # Brief
/// 1. Create a `IoReader`.
/// 2. Call `IoReader::index`.
/// 3. Check if the `index` is correct.
#[test]
fn ut_io_reader_index() {
let io = TestIo::new(vec![1u8; 1]);
let io_reader = IoReader::new(io);
assert_eq!(io_reader.index(), 0);
}
/// UT test case for `IoReader::position`.
///
/// # Title
/// ut_io_reader_position
///
/// # Brief
/// 1. Create a `IoReader`.
/// 2. Call `IoReader::position`.
/// 3. Check the return value against the following conditions:
/// - If `'\n'` is read, the line number will increase and the column
/// number will return to 1; if other characters are read, the line
/// number will remain unchanged and the column number will increase.
#[test]
fn ut_io_reader_position() {
let io = TestIo::new(vec![1u8, b'\n', 2, b'\n', 3]);
let mut io_reader = IoReader::new(io);
let position = io_reader.position();
assert_eq!(position.line(), 1);
assert_eq!(position.column(), 1);
assert_eq!(io_reader.next().unwrap(), Some(1));
// Use `next()`.
let position = io_reader.position();
assert_eq!(position.line(), 1);
assert_eq!(position.column(), 2);
assert_eq!(io_reader.next().unwrap(), Some(b'\n'));
let position = io_reader.position();
assert_eq!(position.line(), 2);
assert_eq!(position.column(), 1);
assert_eq!(io_reader.next().unwrap(), Some(2));
// Use `peek()` and `discard()`.
let position = io_reader.position();
assert_eq!(position.line(), 2);
assert_eq!(position.column(), 2);
assert_eq!(io_reader.peek().unwrap(), Some(b'\n'));
io_reader.discard();
let position = io_reader.position();
assert_eq!(position.line(), 3);
assert_eq!(position.column(), 1);
assert_eq!(io_reader.peek().unwrap(), Some(3));
io_reader.discard();
let position = io_reader.position();
assert_eq!(position.line(), 3);
assert_eq!(position.column(), 2);
assert_eq!(io_reader.peek().unwrap(), None);
}
/// UT test case for `IoReader::start_caching`.
///
/// # Title
/// ut_io_reader_start_caching
///
/// # Brief
/// 1. Create a `IoReader`.
/// 2. Call `IoReader::start_caching`.
/// 3. Check if `cache` is correct.
#[test]
fn ut_io_reader_start_caching() {
let io = TestIo::new(vec![1]);
let mut io_reader = IoReader::new(io);
assert!(io_reader.cache.is_none());
io_reader.start_caching();
assert!(io_reader.cache.is_some());
assert_eq!(io_reader.cached_len(), Some(0));
assert_eq!(io_reader.next().unwrap(), Some(1));
assert_eq!(io_reader.cached_len(), Some(1));
io_reader.start_caching();
assert_eq!(io_reader.cached_len(), Some(0));
}
/// UT test case for `IoReader::cached_len`.
///
/// # Title
/// ut_io_reader_cached_len
///
/// # Brief
/// 1. Create a `IoReader`.
/// 2. Call `IoReader::cached_len`.
/// 3. Check the return value against the following conditions:
/// - Returns `None` if caching is not enabled, otherwise returns
/// `Some(..)`.
#[test]
fn ut_io_reader_cached_len() {
let io = TestIo::new(Vec::new());
let mut io_reader = IoReader::new(io);
assert_eq!(io_reader.cached_len(), None);
io_reader.start_caching();
assert_eq!(io_reader.cached_len(), Some(0));
}
/// UT test case for `IoReader::cached_slice`.
///
/// # Title
/// ut_io_reader_cached_slice
///
/// # Brief
/// 1. Create a `IoReader`.
/// 2. Call `IoReader::cached_slice`.
/// 3. Check the return value against the following conditions:
/// - Returns `None` if caching is not enabled, otherwise returns
/// `Some(..)`.
#[test]
fn ut_io_reader_cached_slice() {
let io = TestIo::new(Vec::new());
let mut io_reader = IoReader::new(io);
assert_eq!(io_reader.cached_slice(), None);
io_reader.start_caching();
assert_eq!(io_reader.cached_slice(), Some([].as_slice()));
// Test 1025 bytes.
let mut input = vec![0; 1024];
input.push(1);
let io = TestIo::new(input);
let mut io_reader = IoReader::new(io);
for _ in 0..1023 {
let _ = io_reader.next();
}
io_reader.start_caching();
assert_eq!(io_reader.next().unwrap(), Some(0));
assert_eq!(io_reader.next().unwrap(), Some(1));
assert_eq!(io_reader.cached_len(), Some(2));
}
/// UT test case for `IoReader::cached_data`.
///
/// # Title
/// ut_io_reader_cached_slice
///
/// # Brief
/// 1. Create a `IoReader`.
/// 2. Call `IoReader::cached_data`.
/// 3. Check the return value against the following conditions:
/// - Returns `None` if caching is not enabled, otherwise returns
/// `Some(..)`.
#[test]
fn ut_io_reader_cached_data() {
let io = TestIo::new(Vec::new());
let mut io_reader = IoReader::new(io);
assert_eq!(io_reader.cached_data(), None);
io_reader.start_caching();
assert_eq!(io_reader.cached_data(), Some(Vec::new()));
}
/// UT test case for `IoReader::end_caching`.
///
/// # Title
/// ut_io_reader_end_caching
///
/// # Brief
/// 1. Create a `IoReader`.
/// 2. Call `IoReader::end_caching`.
/// 3. Check if `cache` is correct.
#[test]
fn ut_io_reader_end_caching() {
let io = TestIo::new(Vec::new());
let mut io_reader = IoReader::new(io);
io_reader.start_caching();
assert!(io_reader.cache.is_some());
io_reader.end_caching();
assert!(io_reader.cache.is_none());
}
/// UT test case for `IoReader::take_cached_data`.
///
/// # Title
/// ut_io_reader_take_cached_data
///
/// # Brief
/// 1. Create a `IoReader`.
/// 2. Call `IoReader::take_cached_data`.
/// 3. Check if the return value is correct.
#[test]
fn ut_io_reader_take_cached_data() {
let io = TestIo::new(Vec::new());
let mut io_reader = IoReader::new(io);
io_reader.start_caching();
assert!(io_reader.cache.is_some());
assert_eq!(io_reader.take_cached_data(), Some(Vec::new()));
assert!(io_reader.cache.is_none());
}
}
+198
View File
@@ -0,0 +1,198 @@
/*
* 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.
*/
mod io_reader;
pub(crate) use io_reader::IoReader;
mod slice_reader;
pub(crate) use slice_reader::SliceReader;
/// `BytesReader` provides the basic byte read interface, such as `next`,
/// `peek`, `index`. Users can obtain the next byte or the current read
/// position according to these interfaces.
pub(crate) trait BytesReader {
/// Errors that may occur during reading, usually in the I\O process.
type Error: Into<Box<dyn std::error::Error>>;
/// Get the next character and move the cursor to the next place.
fn next(&mut self) -> Result<Option<u8>, Self::Error>;
/// Get the next character, but don't move the cursor. So the next read
/// will get the same character.
fn peek(&mut self) -> Result<Option<u8>, Self::Error>;
/// Discard the next character and move the cursor to the next place.
fn discard(&mut self);
/// Get the current cursor position and return it as usize.
fn index(&self) -> usize;
/// Get the current cursor position and return it as `Position`.
fn position(&self) -> Position;
}
/// `Cacheable` provides some byte cache interfaces for caching a portion of
/// contiguous bytes in a byte stream.
pub(crate) trait Cacheable: BytesReader {
/// Start the cache operation. This interface needs to be used with
/// `end_caching` or `take_cached_data`.
fn start_caching(&mut self);
/// Get the length of the cached bytes. Since the logic of caching
/// operations is implementation-dependent, we provide an interface that
/// uses mutable references here.
fn cached_len(&mut self) -> Option<usize>;
/// Get a slice of the cached bytes. Since the logic of caching operations
/// is implementation-dependent, we provide an interface that uses mutable
/// references here.
fn cached_slice(&mut self) -> Option<&[u8]>;
/// Get a `Vec` of the cached bytes. Since the logic of caching operations
/// is implementation-dependent, we provide an interface that uses mutable
/// references here.
fn cached_data(&mut self) -> Option<Vec<u8>>;
/// End the cache operation. This interface needs to be used with
/// `start_caching`.
fn end_caching(&mut self);
/// End the cache operation and return the cached bytes. This interface
/// needs to be used with `start_caching`.
fn take_cached_data(&mut self) -> Option<Vec<u8>>;
}
/// `RemainderCountable` provides the interface related to the remainder.
pub(crate) trait RemainderCountable: BytesReader {
/// Get the length of the remainder.
fn remainder_len(&self) -> usize;
/// Get a slice of the remainder.
fn remainder_slice(&self) -> &[u8];
/// Get a `Vec<u8>` of the remainder.
fn remainder_data(&self) -> Vec<u8>;
}
/// `NBytesReadable` provides interfaces to read 'n' bytes at one time.
pub(crate) trait NBytesReadable: BytesReader {
/// Read the next 'n' bytes and move the cursor to the next nth position.
/// If there are not enough bytes remaining to satisfy 'n', return `None`
/// and do nothing.
fn next_n(&mut self, n: usize) -> Result<Option<&[u8]>, Self::Error>;
/// Get the next 'n' bytes and do not move the cursor. If there are not
/// enough bytes remaining to satisfy 'n', return `None` and do nothing.
fn peek_n(&mut self, n: usize) -> Result<Option<&[u8]>, Self::Error>;
/// Discard the next 'n' bytes and move the cursor to the next nth position.
/// If there are not enough bytes remaining to satisfy 'n', do nothing.
fn discard_n(&mut self, n: usize);
}
/// Position information which expressed in row and column.
#[derive(Clone)]
pub(crate) struct Position {
line: usize,
column: usize,
}
impl Position {
/// Create a `Position` from the given line and column.
#[inline]
pub(crate) fn new(line: usize, column: usize) -> Self {
Self { line, column }
}
/// Get line.
#[inline]
pub(crate) fn line(&self) -> usize {
self.line
}
/// Get column.
#[inline]
pub(crate) fn column(&self) -> usize {
self.column
}
}
#[cfg(test)]
mod ut_position {
use super::Position;
/// UT test for `Position::new`.
///
/// # Title
/// ut_position_new
///
/// # Brief
/// 1. Call `Position::new` to create a `Position`.
/// 2. Check if the results are correct.
#[test]
fn ut_position_new() {
let position = Position::new(1, 1);
assert_eq!(position.line, 1);
assert_eq!(position.column, 1);
}
/// UT test for `Position::line`.
///
/// # Title
/// ut_position_line
///
/// # Brief
/// 1. Create a `Position`.
/// 2. Call `Position::line` to get the line number of `Position`.
/// 3. Check if the results are correct.
#[test]
fn ut_position_line() {
let position = Position::new(1, 1);
assert_eq!(position.line(), 1);
}
/// UT test for `Position::column`.
///
/// # Title
/// ut_position_column
///
/// # Brief
/// 1. Create a `Position`.
/// 2. Call `Position::column` to get the column number of `Position`.
/// 3. Check if the results are correct.
#[test]
fn ut_position_column() {
let position = Position::new(1, 1);
assert_eq!(position.column(), 1);
}
/// UT test case for `Position::clone`.
///
/// # Title
/// ut_position_clone
///
/// # Brief
/// 1. Create a `Position`.
/// 2. Call `Position::clone` to get a copy of `Position`.
/// 3. Check if the results are correct.
#[allow(clippy::redundant_clone)]
#[test]
fn ut_position_clone() {
let position = Position::new(1, 1);
let position = position.clone();
assert_eq!(position.line, 1);
assert_eq!(position.column, 1);
}
}
+539
View File
@@ -0,0 +1,539 @@
/*
* 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 super::{BytesReader, Cacheable, NBytesReadable, Position, RemainderCountable};
use std::convert::Infallible;
/// Reader for reading slices. This reader implements `BytesReader` trait,
/// `Cacheable` trait and `Countable` trait.
///
/// let slice = "Hello World";
/// let mut reader = SliceReader::new(slice.as_bytes());
/// assert_eq!(reader.next(), Ok(Some(b'H')));
/// assert_eq!(reader.peek(), Ok(Some(b'e')));
/// assert_eq!(reader.peek(), Ok(Some(b'e')));
pub(crate) struct SliceReader<'a> {
slice: &'a [u8],
index: usize, // A cursor to the next character to be read.
cache: Option<Cache>, // A cache for storing accumulated characters.
}
// A simple cache implementation for `SliceReader`. We just need to save a
// starting position.
struct Cache(usize);
impl<'a> SliceReader<'a> {
/// Create a new `SliceReader` from the given slice.
///
/// let slice = "Hello World";
/// let reader = SliceReader::new(slice.as_bytes());
#[inline]
pub(crate) fn new(slice: &'a [u8]) -> Self {
Self {
slice,
index: 0,
cache: None,
}
}
}
impl<'a> BytesReader for SliceReader<'a> {
type Error = Infallible; // Use Infallible because no error will be returned in SliceReader.
#[inline]
fn next(&mut self) -> Result<Option<u8>, Self::Error> {
if self.index >= self.slice.len() {
return Ok(None);
}
let ch = self.slice[self.index];
self.index += 1;
Ok(Some(ch))
}
#[inline]
fn peek(&mut self) -> Result<Option<u8>, Self::Error> {
if self.index >= self.slice.len() {
return Ok(None);
}
Ok(Some(self.slice[self.index]))
}
#[inline]
fn discard(&mut self) {
if self.index < self.slice.len() {
self.index += 1;
}
}
#[inline]
fn index(&self) -> usize {
self.index
}
fn position(&self) -> Position {
// The traversal method is used to calculate the `Position`, which
// is expensive, and it is not recommended to call it frequently.
let index = core::cmp::min(self.index, self.slice.len());
let mut position = Position { line: 1, column: 1 };
for i in 0..index {
match self.slice[i] {
b'\n' => {
position.line += 1;
position.column = 1;
}
_ => {
position.column += 1;
}
}
}
position
}
}
impl<'a> Cacheable for SliceReader<'a> {
#[inline]
fn start_caching(&mut self) {
self.cache = Some(Cache(self.index));
}
#[inline]
fn cached_len(&mut self) -> Option<usize> {
self.cache.as_ref().map(|c| self.index - c.0)
}
#[inline]
fn cached_slice(&mut self) -> Option<&[u8]> {
self.cache.as_ref().map(|c| &self.slice[c.0..self.index])
}
#[inline]
fn cached_data(&mut self) -> Option<Vec<u8>> {
self.cache
.as_ref()
.map(|c| self.slice[c.0..self.index].to_vec())
}
#[inline]
fn end_caching(&mut self) {
self.cache = None;
}
#[inline]
fn take_cached_data(&mut self) -> Option<Vec<u8>> {
self.cache
.take()
.map(|c| self.slice[c.0..self.index].to_vec())
}
}
impl<'a> RemainderCountable for SliceReader<'a> {
#[inline]
fn remainder_len(&self) -> usize {
self.slice.len() - self.index
}
#[inline]
fn remainder_slice(&self) -> &[u8] {
&self.slice[self.index..]
}
#[inline]
fn remainder_data(&self) -> Vec<u8> {
self.remainder_slice().to_vec()
}
}
impl<'a> NBytesReadable for SliceReader<'a> {
fn next_n(&mut self, n: usize) -> Result<Option<&[u8]>, Self::Error> {
if self.index + n > self.slice.len() {
return Ok(None);
}
let result = &self.slice[self.index..self.index + n];
self.index += n;
Ok(Some(result))
}
fn peek_n(&mut self, n: usize) -> Result<Option<&[u8]>, Self::Error> {
if self.index + n > self.slice.len() {
return Ok(None);
}
Ok(Some(&self.slice[self.index..self.index + n]))
}
fn discard_n(&mut self, n: usize) {
if self.index + n > self.slice.len() {
return;
}
self.index += n;
}
}
#[cfg(test)]
mod ut_slice_reader {
use super::{BytesReader, Cacheable, NBytesReadable, RemainderCountable, SliceReader};
/// UT test case for `SliceReader::new`.
///
/// # Title
/// ut_slice_reader_new
///
/// # Brief
/// 1. Call `SliceReader::new`.
/// 2. Check that parts of the return value are default values.
#[test]
fn ut_slice_reader_new() {
let slice = "A";
let slice_reader = SliceReader::new(slice.as_bytes());
assert_eq!(slice_reader.slice, slice.as_bytes());
assert_eq!(slice_reader.index, 0);
assert!(slice_reader.cache.is_none());
}
/// UT test case for `SliceReader::next`.
///
/// # Title
/// ut_slice_reader_next
///
/// # Brief
/// 1. Create a `SliceReader`.
/// 2. Call `SliceReader::next`.
/// 3. Check the return value against the following conditions:
/// - If the end is not read, it returns `Ok(Some(..))`, and the index
/// is moved backward; if the end is read, it returns `Ok(None)`, and
/// the index is not moved.
#[test]
fn ut_slice_reader_next() {
let slice = "A";
let mut slice_reader = SliceReader::new(slice.as_bytes());
assert_eq!(slice_reader.next(), Ok(Some(b'A')));
assert_eq!(slice_reader.next(), Ok(None));
}
/// UT test case for `SliceReader::peek`.
///
/// # Title
/// ut_slice_reader_peek
///
/// # Brief
/// 1. Create a `SliceReader`.
/// 2. Call `SliceReader::peek`.
/// 3. Check the return value against the following conditions:
/// - If the end is not read, it returns `Ok(Some(..))`; if the end is
/// read, it returns `Ok(None)`.
#[test]
fn ut_slice_reader_peek() {
let slice = "A";
let mut slice_reader = SliceReader::new(slice.as_bytes());
assert_eq!(slice_reader.peek(), Ok(Some(b'A')));
assert_eq!(slice_reader.peek(), Ok(Some(b'A')));
assert_eq!(slice_reader.next(), Ok(Some(b'A')));
assert_eq!(slice_reader.peek(), Ok(None));
}
/// UT test case for `SliceReader::discard`.
///
/// # Title
/// ut_slice_reader_discard
///
/// # Brief
/// 1. Create a `SliceReader`.
/// 2. Call `SliceReader::discard`.
/// 3. Check `index` against the following conditions:
/// - If the end is not read, the index is moved backward; if the end is
/// read, the index is not moved.
#[test]
fn ut_slice_reader_discard() {
let slice = "A";
let mut slice_reader = SliceReader::new(slice.as_bytes());
assert_eq!(slice_reader.index, 0);
slice_reader.discard();
assert_eq!(slice_reader.index, 1);
slice_reader.discard();
assert_eq!(slice_reader.index, 1);
}
/// UT test case for `SliceReader::index`.
///
/// # Title
/// ut_slice_reader_index
///
/// # Brief
/// 1. Create a `SliceReader`.
/// 2. Call `SliceReader::index`.
/// 3. Check if the `index` is correct.
#[test]
fn ut_slice_reader_index() {
let slice = "A";
let slice_reader = SliceReader::new(slice.as_bytes());
assert_eq!(slice_reader.index(), 0);
}
/// UT test case for `SliceReader::position`.
///
/// # Title
/// ut_slice_reader_position
///
/// # Brief
/// 1. Create a `SliceReader`.
/// 2. Call `SliceReader::position`.
/// 3. Check the return value against the following conditions:
/// - If `'\n'` is read, the line number will increase and the column
/// number will return to 1; if other characters are read, the line
/// number will remain unchanged and the column number will increase.
#[test]
fn ut_slice_reader_position() {
let slice = "A\nB";
let mut slice_reader = SliceReader::new(slice.as_bytes());
let position = slice_reader.position();
assert_eq!(position.line(), 1);
assert_eq!(position.column(), 1);
assert_eq!(slice_reader.next(), Ok(Some(b'A')));
let position = slice_reader.position();
assert_eq!(position.line(), 1);
assert_eq!(position.column(), 2);
assert_eq!(slice_reader.next(), Ok(Some(b'\n')));
let position = slice_reader.position();
assert_eq!(position.line(), 2);
assert_eq!(position.column(), 1);
assert_eq!(slice_reader.next(), Ok(Some(b'B')));
let position = slice_reader.position();
assert_eq!(position.line(), 2);
assert_eq!(position.column(), 2);
assert_eq!(slice_reader.next(), Ok(None));
let position = slice_reader.position();
assert_eq!(position.line(), 2);
assert_eq!(position.column(), 2);
}
/// UT test case for `SliceReader::start_caching`.
///
/// # Title
/// ut_slice_reader_start_caching
///
/// # Brief
/// 1. Create a `SliceReader`.
/// 2. Call `SliceReader::start_caching`.
/// 3. Check if `cache` is correct.
#[test]
fn ut_slice_reader_start_caching() {
let slice = "A";
let mut slice_reader = SliceReader::new(slice.as_bytes());
assert!(slice_reader.cache.is_none());
slice_reader.start_caching();
assert_eq!(slice_reader.cache.as_ref().unwrap().0, 0);
}
/// UT test case for `SliceReader::cached_len`.
///
/// # Title
/// ut_slice_reader_cached_len
///
/// # Brief
/// 1. Create a `SliceReader`.
/// 2. Call `SliceReader::cached_len`.
/// 3. Check the return value against the following conditions:
/// - Returns `None` if caching is not enabled, otherwise returns
/// `Some(..)`.
#[test]
fn ut_slice_reader_cached_len() {
let slice = "A";
let mut slice_reader = SliceReader::new(slice.as_bytes());
assert_eq!(slice_reader.cached_len(), None);
slice_reader.start_caching();
assert_eq!(slice_reader.cached_len(), Some(0));
}
/// UT test case for `SliceReader::cached_slice`.
///
/// # Title
/// ut_slice_reader_cached_slice
///
/// # Brief
/// 1. Create a `SliceReader`.
/// 2. Call `SliceReader::cached_slice`.
/// 3. Check the return value against the following conditions:
/// - Returns `None` if caching is not enabled, otherwise returns
/// `Some(..)`.
#[test]
fn ut_slice_reader_cached_slice() {
let slice = "A";
let mut slice_reader = SliceReader::new(slice.as_bytes());
assert_eq!(slice_reader.cached_slice(), None);
slice_reader.start_caching();
assert_eq!(slice_reader.cached_slice(), Some([].as_slice()));
}
/// UT test case for `SliceReader::cached_data`.
///
/// # Title
/// ut_slice_reader_cached_slice
///
/// # Brief
/// 1. Create a `SliceReader`.
/// 2. Call `SliceReader::cached_data`.
/// 3. Check the return value against the following conditions:
/// - Returns `None` if caching is not enabled, otherwise returns
/// `Some(..)`.
#[test]
fn ut_slice_reader_cached_data() {
let slice = "A";
let mut slice_reader = SliceReader::new(slice.as_bytes());
assert_eq!(slice_reader.cached_data(), None);
slice_reader.start_caching();
assert_eq!(slice_reader.cached_data(), Some(Vec::new()));
}
/// UT test case for `SliceReader::end_caching`.
///
/// # Title
/// ut_slice_reader_end_caching
///
/// # Brief
/// 1. Create a `SliceReader`.
/// 2. Call `SliceReader::end_caching`.
/// 3. Check if `cache` is correct.
#[test]
fn ut_slice_reader_end_caching() {
let slice = "A";
let mut slice_reader = SliceReader::new(slice.as_bytes());
slice_reader.start_caching();
assert!(slice_reader.cache.is_some());
slice_reader.end_caching();
assert!(slice_reader.cache.is_none());
}
/// UT test case for `SliceReader::take_cached_data`.
///
/// # Title
/// ut_slice_reader_take_cached_data
///
/// # Brief
/// 1. Create a `SliceReader`.
/// 2. Call `SliceReader::take_cached_data`.
/// 3. Check if the return value is correct.
#[test]
fn ut_slice_reader_take_cached_data() {
let slice = "A";
let mut slice_reader = SliceReader::new(slice.as_bytes());
slice_reader.start_caching();
assert!(slice_reader.cache.is_some());
assert_eq!(slice_reader.take_cached_data(), Some(Vec::new()));
assert!(slice_reader.cache.is_none());
}
/// UT test case for `SliceReader::remainder_len`.
///
/// # Title
/// ut_slice_reader_remainder_len
///
/// # Brief
/// 1. Create a `SliceReader`.
/// 2. Call `SliceReader::remainder_len`.
/// 3. Check if the return value is correct.
#[test]
fn ut_slice_reader_remainder_len() {
let slice = "A";
let slice_reader = SliceReader::new(slice.as_bytes());
assert_eq!(slice_reader.remainder_len(), 1);
}
/// UT test case for `SliceReader::remainder_slice`.
///
/// # Title
/// ut_slice_reader_remainder_slice
///
/// # Brief
/// 1. Create a `SliceReader`.
/// 2. Call `SliceReader::remainder_slice`.
/// 3. Check if the return value is correct.
#[test]
fn ut_slice_reader_remainder_slice() {
let slice = "A";
let slice_reader = SliceReader::new(slice.as_bytes());
assert_eq!(slice_reader.remainder_slice(), slice.as_bytes());
}
/// UT test case for `SliceReader::remainder_data`.
///
/// # Title
/// ut_slice_reader_remainder_slice
///
/// # Brief
/// 1. Create a `SliceReader`.
/// 2. Call `SliceReader::remainder_slice`.
/// 3. Check if the return value is correct.
#[test]
fn ut_slice_reader_remainder_data() {
let slice = "A";
let slice_reader = SliceReader::new(slice.as_bytes());
assert_eq!(slice_reader.remainder_data(), slice.as_bytes().to_vec());
}
/// UT test case for `SliceReader::next_n`.
///
/// # Title
/// ut_slice_reader_next_n
///
/// # Brief
/// 1. Create a `SliceReader`.
/// 2. Call `SliceReader::next_n`.
/// 3. Check if the return value is correct.
#[test]
fn ut_slice_reader_next_n() {
let slice = "ABC";
let mut slice_reader = SliceReader::new(slice.as_bytes());
assert_eq!(slice_reader.next_n(2).unwrap(), Some("AB".as_bytes()));
assert_eq!(slice_reader.next_n(2).unwrap(), None);
}
/// UT test case for `SliceReader::peek_n`.
///
/// # Title
/// ut_slice_reader_peek_n
///
/// # Brief
/// 1. Create a `SliceReader`.
/// 2. Call `SliceReader::peek_n`.
/// 3. Check if the return value is correct.
#[test]
fn ut_slice_reader_peek_n() {
let slice = "ABC";
let mut slice_reader = SliceReader::new(slice.as_bytes());
assert_eq!(slice_reader.peek_n(2).unwrap(), Some("AB".as_bytes()));
assert_eq!(slice_reader.peek_n(4).unwrap(), None);
}
/// UT test case for `SliceReader::discard_n`.
///
/// # Title
/// ut_slice_reader_discard_n
///
/// # Brief
/// 1. Create a `SliceReader`.
/// 2. Call `SliceReader::discard_n`.
/// 3. Check if the return value is correct.
#[test]
fn ut_slice_reader_discard_n() {
let slice = "ABC";
let mut slice_reader = SliceReader::new(slice.as_bytes());
slice_reader.discard_n(2);
assert_eq!(slice_reader.next().unwrap(), Some(b'C'));
}
}
+712
View File
@@ -0,0 +1,712 @@
/*
* 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 crate::encoder::encode_string_inner;
use crate::{Error, Error::*};
use serde::{ser, ser::SerializeSeq, Serialize};
/// A data format that can serialize any data structure supported by Serde.
struct Serializer<W>
where
W: std::io::Write,
{
writer: W,
element_num: Vec<usize>, // Used to record the number of traveled elements in the sequence.
}
/// An auxiliary struct which implements Write trait used in 'to_string' function.
struct AuxiliaryWriter {
output: Vec<u8>,
}
impl std::io::Write for AuxiliaryWriter {
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
self.output.extend_from_slice(buf);
Ok(buf.len())
}
fn flush(&mut self) -> std::io::Result<()> {
Ok(())
}
}
/// ylong_json::serializer_compact supports two functions to produce as output: 'to_string' and 'to_writer'.
///
/// The to_string function serialize an instance which implements the Serialize Trait to a string and return.
pub fn to_string<T>(value: &T) -> Result<String, Error>
where
T: Serialize,
{
let mut writer = AuxiliaryWriter { output: Vec::new() };
to_writer(value, &mut writer)?;
Ok(unsafe { String::from_utf8_unchecked(writer.output) })
}
/// The to_writer function serialize an instance which implements the Serialize Trait and
/// writes result into the writer passed in by the user, which needs to implement the std::io::Write.
pub fn to_writer<T, W>(value: &T, writer: &mut W) -> Result<(), Error>
where
T: Serialize,
W: std::io::Write,
{
let mut serializer = Serializer {
writer,
element_num: Vec::new(),
};
value.serialize(&mut serializer)?;
Ok(())
}
impl<'a, W: std::io::Write> ser::Serializer for &'a mut Serializer<W> {
// Using `Ok` to propagate the data structure around simplifies Serializers
// which build in-memory data structures. Set 'ok=()' and write the serialization
// result to the buffer contained by the instance.
type Ok = ();
// The error type when serializing an instance may occur.
type Error = Error;
// Associative type composite data structures, such as sequences and maps,
// used to track other states at serialization time. In this case, no state
// is required other than what is already stored in the Serializer struct.
type SerializeSeq = Self;
type SerializeMap = Self;
type SerializeStruct = Self;
type SerializeStructVariant = Self;
type SerializeTuple = Self;
type SerializeTupleStruct = Self;
type SerializeTupleVariant = Self;
// The following 12 methods take one of the base types of the data model
// and map it to JSON by appending it to the output string.
fn serialize_bool(self, v: bool) -> Result<(), Error> {
self.writer.write_fmt(format_args!("{v}"))?;
Ok(())
}
// JSON does not distinguish between integers of different sizes,
// so all signed integers and all unsigned integers will be serialized in the same way.
// Therefore, all integers are converted to 64-bit integers and serialized here.
fn serialize_i8(self, v: i8) -> Result<(), Error> {
self.serialize_i64(i64::from(v))
}
fn serialize_i16(self, v: i16) -> Result<(), Error> {
self.serialize_i64(i64::from(v))
}
fn serialize_i32(self, v: i32) -> Result<(), Error> {
self.serialize_i64(i64::from(v))
}
fn serialize_i64(self, v: i64) -> Result<(), Error> {
self.writer.write_fmt(format_args!("{v}"))?;
Ok(())
}
fn serialize_u8(self, v: u8) -> Result<(), Error> {
self.serialize_u64(u64::from(v))
}
fn serialize_u16(self, v: u16) -> Result<(), Error> {
self.serialize_u64(u64::from(v))
}
fn serialize_u32(self, v: u32) -> Result<(), Error> {
self.serialize_u64(u64::from(v))
}
fn serialize_u64(self, v: u64) -> Result<(), Error> {
self.writer.write_fmt(format_args!("{v}"))?;
Ok(())
}
// Same way for floating-point types.
fn serialize_f32(self, v: f32) -> Result<(), Error> {
self.serialize_f64(f64::from(v))
}
fn serialize_f64(self, v: f64) -> Result<(), Error> {
self.writer.write_fmt(format_args!("{v:?}"))?;
Ok(())
}
fn serialize_char(self, v: char) -> Result<(), Error> {
self.serialize_str(v.encode_utf8(&mut [0; 4]))
}
fn serialize_str(self, v: &str) -> Result<(), Error> {
self.writer.write_all(b"\"")?;
encode_string_inner(&mut self.writer, v)?;
self.writer.write_all(b"\"")?;
Ok(())
}
// Serialize a byte array into an array of bytes.
// Binary formats will typically represent byte arrays more compactly.
fn serialize_bytes(self, v: &[u8]) -> Result<(), Error> {
let mut seq = self.serialize_seq(Some(v.len()))?;
for byte in v {
seq.serialize_element(byte)?;
}
seq.end()
}
// JSON `null` represent an absent optional.
fn serialize_none(self) -> Result<(), Error> {
self.serialize_unit()
}
// Represent an optional instance as the contained value.
fn serialize_some<T>(self, value: &T) -> Result<(), Error>
where
T: ?Sized + Serialize,
{
value.serialize(self)
}
// In Serde, unit represents an anonymous value that does not contain any data.
// Map this to JSON as "null".
fn serialize_unit(self) -> Result<(), Error> {
self.writer.write_all(b"null")?;
Ok(())
}
// Unit struct represents a named value that does not contain any data. Map it to JSON as "null".
fn serialize_unit_struct(self, _name: &'static str) -> Result<(), Error> {
self.serialize_unit()
}
// When serializing a unit variant (or any other kind of variant), formats
// can choose whether to track it by index or by name. Binary formats
// usually use index while human-readable formats usually use name.
fn serialize_unit_variant(
self,
_name: &'static str,
_variant_index: u32,
variant: &'static str, // The name of the variant.
) -> Result<(), Error> {
self.serialize_str(variant)
}
// Treat newtype structs as insignificant wrappers for the data they contain.
fn serialize_newtype_struct<T>(self, _name: &'static str, value: &T) -> Result<(), Error>
where
T: ?Sized + Serialize,
{
value.serialize(self)
}
// The newtype variant (and all other variant serialization methods)
// specifically refers to the enumerated representation of the "externally tagged".
//
// Serialize it to JSON with an outer tag of the form '{NAME: VALUE}'.
fn serialize_newtype_variant<T>(
self,
_name: &'static str,
_variant_index: u32,
variant: &'static str, // The name of the variant.
value: &T,
) -> Result<(), Error>
where
T: ?Sized + Serialize,
{
self.writer.write_all(b"{")?;
variant.serialize(&mut *self)?;
self.writer.write_all(b":")?;
value.serialize(&mut *self)?;
self.writer.write_all(b"}")?;
Ok(())
}
// The following is the serialization of compound types.
// The start of the sequence, each value, and the end use three separate method calls.
// The serializer can be able to support sequences for which the length is unknown up front.
//
// This one used to serialize the start of the sequence, which in JSON is `[`.
fn serialize_seq(self, _len: Option<usize>) -> Result<Self::SerializeSeq, Error> {
self.element_num.push(0); // Now there is no element in this sequence.
self.writer.write_all(b"[")?;
Ok(self)
}
// Tuples and sequences are represented similarly in JSON.
// Some formats can represent tuples more efficiently by omitting the length.
fn serialize_tuple(self, len: usize) -> Result<Self::SerializeTuple, Error> {
self.serialize_seq(Some(len))
}
// Tuple and sequences are represented similarly in JSON.
fn serialize_tuple_struct(
self,
_name: &'static str,
len: usize, // The number of data fields that will be serialized.
) -> Result<Self::SerializeTupleStruct, Error> {
self.serialize_seq(Some(len))
}
// Tuple variants are represented in JSON as `{ NAME: [DATA...] }`.
// This method used only for the externally tagged representation.
fn serialize_tuple_variant(
self,
_name: &'static str,
_variant_index: u32,
variant: &'static str, // The name of the variant.
_len: usize,
) -> Result<Self::SerializeTupleVariant, Error> {
self.element_num.push(0);
self.writer.write_all(b"{")?;
variant.serialize(&mut *self)?;
self.writer.write_all(b":[")?;
Ok(self)
}
// Maps are represented in JSON as `{ K: V, K: V, ... }`.
fn serialize_map(self, _len: Option<usize>) -> Result<Self::SerializeMap, Error> {
self.element_num.push(0);
self.writer.write_all(b"{")?;
Ok(self)
}
// Structs and maps are represented similarly in JSON.
fn serialize_struct(
self,
_name: &'static str,
len: usize, // The number of data fields that will be serialized.
) -> Result<Self::SerializeStruct, Error> {
self.serialize_map(Some(len))
}
// Struct variants are represented in JSON as `{ NAME: { K: V, ... } }`.
// This used for the externally tagged representation.
fn serialize_struct_variant(
self,
_name: &'static str,
_variant_index: u32,
variant: &'static str, // The name of the variant.
_len: usize,
) -> Result<Self::SerializeStructVariant, Error> {
self.element_num.push(0);
self.writer.write_all(b"{")?;
variant.serialize(&mut *self)?;
self.writer.write_all(b":{")?;
Ok(self)
}
}
impl<W> Serializer<W>
where
W: std::io::Write,
{
// Serialize a single member of sequence or map.
fn whether_to_add_comma(&mut self) -> Result<(), Error> {
match self.element_num.last_mut() {
None => return Err(IncorrectSerdeUsage),
Some(x) => {
// This is not the first element, add a comma before the element.
if *x > 0 {
self.writer.write_all(b",")?
};
*x += 1;
}
}
Ok(())
}
// Add another half of the parentheses at the end.
fn add_another_half(&mut self, buf: &[u8]) -> Result<(), Error> {
self.writer.write_all(buf)?;
Ok(())
}
}
// The following 7 impls used to serialize compound types like sequences and maps.
// At the beginning of serializing such types, one call of Serializer method.
// Next, zero or more calls which serializes a single element of the compound type.
// Finally, one call to end the serializing of the compound type.
//
// This impl is SerializeSeq so these methods are called after calling 'serialize_seq' on Serializer.
impl<'a, W: std::io::Write> ser::SerializeSeq for &'a mut Serializer<W> {
// Must match the `Ok` type of the serializer.
type Ok = ();
// Must match the `Error` type of the serializer.
type Error = Error;
// Serialize a single element in the sequence.
fn serialize_element<T>(&mut self, value: &T) -> Result<(), Error>
where
T: ?Sized + Serialize,
{
self.whether_to_add_comma()?;
value.serialize(&mut **self)
}
// Close the sequence.
fn end(self) -> Result<(), Error> {
self.element_num.pop();
self.add_another_half(b"]")
}
}
// Same thing but for tuples.
impl<'a, W: std::io::Write> ser::SerializeTuple for &'a mut Serializer<W> {
type Ok = ();
type Error = Error;
fn serialize_element<T>(&mut self, value: &T) -> Result<(), Error>
where
T: ?Sized + Serialize,
{
self.whether_to_add_comma()?;
value.serialize(&mut **self)
}
fn end(self) -> Result<(), Error> {
self.element_num.pop();
self.add_another_half(b"]")
}
}
// Same thing but for tuple structs.
impl<'a, W: std::io::Write> ser::SerializeTupleStruct for &'a mut Serializer<W> {
type Ok = ();
type Error = Error;
fn serialize_field<T>(&mut self, value: &T) -> Result<(), Error>
where
T: ?Sized + Serialize,
{
self.whether_to_add_comma()?;
value.serialize(&mut **self)
}
fn end(self) -> Result<(), Error> {
self.element_num.pop();
self.add_another_half(b"]")
}
}
// The tuple variants are slightly different. Refer back to the
// `serialize_tuple_variant` method above:
//
// self.writer.write_all(b"{");
// variant.serialize(&mut *self)?;
// self.writer.write_all(b":[");
//
// So the `end` method in this impl is responsible for closing
// both the `]` and the `}`.
impl<'a, W: std::io::Write> ser::SerializeTupleVariant for &'a mut Serializer<W> {
type Ok = ();
type Error = Error;
fn serialize_field<T>(&mut self, value: &T) -> Result<(), Error>
where
T: ?Sized + Serialize,
{
self.whether_to_add_comma()?;
value.serialize(&mut **self)
}
fn end(self) -> Result<(), Error> {
self.element_num.pop();
self.add_another_half(b"]}")
}
}
// Some "Serialize" types cannot hold both keys and values
// in memory, so the "SerializeMap" implementation needs to
// support "serialize_key" and "serialize_value" respectively.
//
// There is a third optional method on the `SerializeMap` trait.
// The 'serialize_entry' method allows the serializer to be optimized
// for cases where both keys and values are available. In JSON, it doesn't
// make a difference so the default behavior for `serialize_entry` is fine.
impl<'a, W: std::io::Write> ser::SerializeMap for &'a mut Serializer<W> {
type Ok = ();
type Error = Error;
// The Serde data model allows map keys to be any serializable type. JSON
// only allows string keys, so if the key is serialized to something other than a string,
// the following implementation will produce invalid JSON.
fn serialize_key<T>(&mut self, key: &T) -> Result<(), Error>
where
T: ?Sized + Serialize,
{
self.whether_to_add_comma()?;
key.serialize(&mut **self)
}
// It makes no difference whether the colon is printed at
// the end of 'serialize_key' or at the beginning of 'serialize_value'.
// Here we choose to print at the beginning of 'serialize_value'.
fn serialize_value<T>(&mut self, value: &T) -> Result<(), Error>
where
T: ?Sized + Serialize,
{
self.writer.write_all(b":")?;
value.serialize(&mut **self)
}
fn end(self) -> Result<(), Error> {
self.add_another_half(b"}")
}
}
// A structure is like a map where the keys are restricted to a compile-time constant string.
impl<'a, W: std::io::Write> ser::SerializeStruct for &'a mut Serializer<W> {
type Ok = ();
type Error = Error;
fn serialize_field<T>(&mut self, key: &'static str, value: &T) -> Result<(), Error>
where
T: ?Sized + Serialize,
{
self.whether_to_add_comma()?;
key.serialize(&mut **self)?;
self.writer.write_all(b":")?;
value.serialize(&mut **self)
}
fn end(self) -> Result<(), Error> {
self.element_num.pop();
self.add_another_half(b"}")
}
}
// Similar to 'SerializeTupleVariant', the 'end' method here is responsible for
// closing two curly braces opened by 'serialize_struct_variant'.
impl<'a, W: std::io::Write> ser::SerializeStructVariant for &'a mut Serializer<W> {
type Ok = ();
type Error = Error;
fn serialize_field<T>(&mut self, key: &'static str, value: &T) -> Result<(), Error>
where
T: ?Sized + Serialize,
{
self.whether_to_add_comma()?;
key.serialize(&mut **self)?;
self.writer.write_all(b":")?;
value.serialize(&mut **self)
}
fn end(self) -> Result<(), Error> {
self.element_num.pop();
self.add_another_half(b"}}")
}
}
#[cfg(test)]
mod ut_serializer {
use super::*;
use std::collections::HashMap;
/// UT test to serialize simple types.
///
/// # Title
/// ut_serialize_simple
///
/// # Brief
/// 1.Uses Serializer::to_string method to serialize simple types.
/// 2.Checks if the test results are correct.
#[test]
fn ut_serialize_simple() {
let value: Option<u32> = None;
let expected = "null";
assert_eq!(to_string(&value).unwrap(), expected);
let value: Option<u32> = Some(123);
let expected = "123";
assert_eq!(to_string(&value).unwrap(), expected);
let value = true;
let expected = "true";
assert_eq!(to_string(&value).unwrap(), expected);
let value: i8 = 123;
let expected = "123";
assert_eq!(to_string(&value).unwrap(), expected);
let value: i16 = 123;
let expected = "123";
assert_eq!(to_string(&value).unwrap(), expected);
let value: i32 = 123;
let expected = "123";
assert_eq!(to_string(&value).unwrap(), expected);
let value: i64 = 123;
let expected = "123";
assert_eq!(to_string(&value).unwrap(), expected);
let value: u8 = 123;
let expected = "123";
assert_eq!(to_string(&value).unwrap(), expected);
let value: u16 = 123;
let expected = "123";
assert_eq!(to_string(&value).unwrap(), expected);
let value: u32 = 123;
let expected = "123";
assert_eq!(to_string(&value).unwrap(), expected);
let value: u64 = 123;
let expected = "123";
assert_eq!(to_string(&value).unwrap(), expected);
let value: f32 = 1.0;
let expected = "1.0";
assert_eq!(to_string(&value).unwrap(), expected);
let value: f64 = 1.0;
let expected = "1.0";
assert_eq!(to_string(&value).unwrap(), expected);
let value = "abc";
let expected = "\"abc\"";
assert_eq!(to_string(&value).unwrap(), expected);
let value = b"abc";
let expected = "[97,98,99]";
assert_eq!(to_string(&value).unwrap(), expected);
}
/// UT test to serialize struct
///
/// # Title
/// ut_serialize_struct
///
/// # Brief
/// 1.Uses Serializer::to_string method to serialize struct.
/// 2.Checks if the test results are correct.
#[test]
fn ut_serialize_struct() {
#[derive(Serialize)]
struct TestUnit;
let test = TestUnit;
let expected = "null";
assert_eq!(to_string(&test).unwrap(), expected);
#[derive(Serialize)]
struct TestNewtype(u32);
let test = TestNewtype(123);
let expected = "123";
assert_eq!(to_string(&test).unwrap(), expected);
#[derive(Serialize)]
struct TestTuple(u32, u32, bool);
let test = TestTuple(123, 321, true);
let expected = "[123,321,true]";
assert_eq!(to_string(&test).unwrap(), expected);
#[derive(Serialize)]
struct Test {
int: u32,
seq: Vec<&'static str>,
tup: (i32, i32, i32),
}
let test = Test {
int: 1,
seq: vec!["a", "b"],
tup: (1, 2, 3),
};
let expected = r#"{"int":1,"seq":["a","b"],"tup":[1,2,3]}"#;
assert_eq!(to_string(&test).unwrap(), expected);
}
/// UT test to serialize enum
///
/// # Title
/// ut_serialize_enum
///
/// # Brief
/// 1.Uses Serializer::to_string method to serialize enum.
/// 2.Checks if the test results are correct.
#[test]
fn ut_serialize_enum() {
#[derive(Serialize)]
enum E {
Newtype(i32),
Unit,
Struct { a: u32 },
Tuple(u32, u32),
}
let n = E::Newtype(-1);
let expected = r#"{"Newtype":-1}"#;
assert_eq!(to_string(&n).unwrap(), expected);
let u = E::Unit;
let expected = r#""Unit""#;
assert_eq!(to_string(&u).unwrap(), expected);
let s = E::Struct { a: 10 };
let expected = r#"{"Struct":{"a":10}}"#;
assert_eq!(to_string(&s).unwrap(), expected);
let t = E::Tuple(100, 200);
let expected = r#"{"Tuple":[100,200]}"#;
assert_eq!(to_string(&t).unwrap(), expected);
}
/// UT test to serialize string
///
/// # Title
/// ut_serialize_string
///
/// # Brief
/// 1.Uses Serializer::to_string method to serialize string.
/// 2.Checks if the test results are correct.
#[test]
fn ut_serialize_string() {
let ch = 't';
let expected = r#""t""#;
assert_eq!(to_string(&ch).unwrap(), expected);
let value = String::from("test string.");
let expected = r#""test string.""#;
assert_eq!(to_string(&value).unwrap(), expected);
#[cfg(not(feature = "ascii_only"))]
{
let ch = '中';
let expected = r#""\u4e2d""#;
assert_eq!(to_string(&ch).unwrap(), expected);
let value = String::from("中文测试字符串");
let expected = r#""\u4e2d\u6587\u6d4b\u8bd5\u5b57\u7b26\u4e32""#;
assert_eq!(to_string(&value).unwrap(), expected);
}
}
/// UT test to serializer object
///
/// # Title
/// ut_serialize_object
///
/// # Brief
/// 1.Uses Serializer::to_string method to serialize object.
/// 2.Checks if the test results are correct.
#[test]
fn ut_serialize_object() {
let mut hash = HashMap::new();
hash.insert("apple", 1);
let expected = r#"{"apple":1}"#;
assert_eq!(to_string(&hash).unwrap(), expected);
hash.insert("banana", 2);
assert!(to_string(&hash).is_ok());
}
}
+1117
View File
File diff suppressed because it is too large Load Diff
+1769
View File
File diff suppressed because it is too large Load Diff
+24
View File
@@ -0,0 +1,24 @@
/*
* 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.
*/
#[cfg(feature = "list_array")]
mod linked_list;
#[cfg(feature = "list_array")]
pub use linked_list::Array;
#[cfg(feature = "vec_array")]
mod vec;
#[cfg(feature = "vec_array")]
pub use vec::Array;
+534
View File
@@ -0,0 +1,534 @@
/*
* 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 crate::{Cursor, CursorMut, Iter, IterMut, JsonValue, LinkedList, Node};
use core::fmt::{Debug, Display, Formatter};
/// Array type, implemented using LinkedList.
///
/// # Situation
/// * When the average number of Array entries does not exceed 15 (estimated value).
///
/// * When the average number of Array entries exceeds 15 (estimated value), but do not or rarely made query operation.
///
/// # Attention
/// * Only open `list_array` feature can be used, and conflicts with other array-related features.
///
/// # Examples
/// ```
/// use ylong_json::Array;
///
/// let array = Array::new();
/// ```
#[derive(Default, Clone, PartialEq)]
pub struct Array {
inner: LinkedList<JsonValue>,
}
impl Array {
/// Creates an empty Array instance.
///
/// # Examples
/// ```
/// use ylong_json::Array;
///
/// let array = Array::new();
/// ```
pub fn new() -> Self {
Self {
inner: LinkedList::new(),
}
}
/// Gets length of Array.
///
/// # Examples
/// ```
/// use ylong_json::{Array, JsonValue};
///
/// let mut array = Array::new();
/// assert_eq!(array.len(), 0);
///
/// array.push(JsonValue::Null);
/// assert_eq!(array.len(), 1);
/// ```
pub fn len(&self) -> usize {
self.inner.len()
}
/// Determines whether Array is empty.
///
/// # Examples
/// ```
/// use ylong_json::{Array, JsonValue};
///
/// let mut array = Array::new();
/// assert_eq!(array.is_empty(), true);
///
/// array.push(JsonValue::Null);
/// assert_eq!(array.is_empty(), false);
/// ```
pub fn is_empty(&self) -> bool {
self.inner.is_empty()
}
/// Insert a new JsonValue at the end of Array.
///
/// # Examples
/// ```
/// use ylong_json::{Array, JsonValue};
///
/// let mut array = Array::new();
/// assert_eq!(array.len(), 0);
///
/// array.push(JsonValue::Null);
/// assert_eq!(array.len(), 1);
/// ```
pub fn push(&mut self, value: JsonValue) {
self.inner.push_back(value);
}
/// Pops the element at the end of Array.
///
/// # Examples
/// ```
/// use ylong_json::{Array, JsonValue};
///
/// let mut array = Array::new();
/// assert_eq!(array.pop(), None);
///
/// array.push(JsonValue::Null);
/// assert_eq!(array.pop(), Some(JsonValue::Null));
/// ```
pub fn pop(&mut self) -> Option<JsonValue> {
self.inner.pop_back()
}
/// Gets a common iterator of Array.
///
/// # Examples
/// ```
/// use ylong_json::Array;
///
/// let array = Array::new();
/// let iter = array.iter();
/// ```
pub fn iter(&self) -> Iter<'_, JsonValue> {
self.inner.iter()
}
/// Gets a mutable iterator of Array.
///
/// # Examples
/// ```
/// use ylong_json::Array;
///
/// let mut array = Array::new();
/// let iter_mut = array.iter_mut();
/// ```
pub fn iter_mut(&mut self) -> IterMut<'_, JsonValue> {
self.inner.iter_mut()
}
/// Returns a common reference to the specified index ** member ** in Array.
///
/// # Examples
/// ```
/// use ylong_json::{Array, JsonValue};
///
/// let mut array = Array::new();
/// array.push(JsonValue::Null);
/// assert_eq!(array.get(0), Some(&JsonValue::Null));
/// assert_eq!(array.get(1), None);
/// ```
pub fn get(&self, index: usize) -> Option<&JsonValue> {
self.get_cursor(index)?.current()
}
/// Returns a mutable reference to the specified index ** member ** in Array.
///
/// # Examples
/// ```
/// use ylong_json::{Array, JsonValue};
///
/// let mut array = Array::new();
/// array.push(JsonValue::Null);
/// assert_eq!(array.get_mut(0), Some(&mut JsonValue::Null));
/// assert_eq!(array.get_mut(1), None);
/// ```
pub fn get_mut(&mut self, index: usize) -> Option<&mut JsonValue> {
// Using 'get_cursor_mut' causes a problem referencing temporary variables.
self.get_node_mut(index).map(|n| n.get_element_mut())
}
/// Returns a common reference to the trailing ** member ** in Array.
///
/// # Examples
/// ```
/// use ylong_json::{Array, JsonValue};
///
/// let mut array = Array::new();
/// assert_eq!(array.last(), None);
/// array.push(JsonValue::Null);
/// assert_eq!(array.last(), Some(&JsonValue::Null));
/// ```
pub fn last(&self) -> Option<&JsonValue> {
self.inner.back()
}
/// Returns a mutable reference to the trailing ** member ** in Array.
///
/// # Examples
/// ```
/// use ylong_json::{Array, JsonValue};
///
/// let mut array = Array::new();
/// assert_eq!(array.last_mut(), None);
/// array.push(JsonValue::Null);
/// assert_eq!(array.last_mut(), Some(&mut JsonValue::Null));
/// ```
pub fn last_mut(&mut self) -> Option<&mut JsonValue> {
self.inner.back_mut()
}
/// Removes the node in Array with the specified index.
///
/// # Examples
/// ```
/// use ylong_json::{Array, JsonValue};
///
/// let mut array = Array::new();
/// array.push(JsonValue::Null);
/// array.push(JsonValue::Boolean(true));
/// array.push(JsonValue::Null);
///
/// assert_eq!(array.len(), 3);
/// let second = array.remove(1);
/// assert_eq!(second, Some(JsonValue::Boolean(true)));
/// assert_eq!(array.len(), 2);
/// ```
pub fn remove(&mut self, index: usize) -> Option<JsonValue> {
self.get_cursor_mut(index)?.remove_current()
}
/// Returns a common reference to the specified index ** node ** in Array.
///
/// After getting a common reference to a node, the corresponding node cannot be released.
/// Otherwise undefined behavior will occur.
///
/// # Examples
/// ```
/// use ylong_json::{Array, JsonValue};
///
/// let mut array = Array::new();
/// array.push(JsonValue::Null);
/// assert_eq!(array.get_node(0).is_some(), true);
/// assert_eq!(array.get_node(1).is_none(), true);
/// ```
pub fn get_node(&self, index: usize) -> Option<&Node<JsonValue>> {
self.get_cursor(index)?.current_node()
}
/// Returns a mutable reference to the specified index ** node ** in Array.
///
/// After getting a mutable reference to a node, the corresponding node cannot be released.
/// Otherwise undefined behavior will occur.
///
/// # Examples
/// ```
/// use ylong_json::{Array, JsonValue};
///
/// let mut array = Array::new();
/// let value = JsonValue::Null;
/// array.push(value);
/// assert_eq!(array.get_node_mut(0).is_some(), true);
/// assert_eq!(array.get_node_mut(1).is_none(), true);
/// ```
pub fn get_node_mut(&mut self, index: usize) -> Option<&mut Node<JsonValue>> {
self.get_cursor_mut(index)?.current_node()
}
/// Returns a common reference to the trailing ** node ** in Array.
///
/// # Examples
/// ```
/// use ylong_json::{Array, JsonValue};
///
/// let mut array = Array::new();
/// assert_eq!(array.last_node().is_none(), true);
/// array.push(JsonValue::Null);
/// assert_eq!(array.last_node().is_some(), true);
/// ```
pub fn last_node(&self) -> Option<&Node<JsonValue>> {
self.inner.back_node()
}
/// Returns a mutable reference to the trailing ** node ** in Array.
///
/// # Examples
/// ```
/// use ylong_json::{Array, JsonValue};
///
/// let mut array = Array::new();
/// assert_eq!(array.last_node_mut().is_none(), true);
/// array.push(JsonValue::Null);
/// assert_eq!(array.last_node_mut().is_some(), true);
/// ```
pub fn last_node_mut(&mut self) -> Option<&mut Node<JsonValue>> {
self.inner.back_node_mut()
}
/// Gets the common cursor of the specified index node.
fn get_cursor(&self, index: usize) -> Option<Cursor<'_, JsonValue>> {
let len = self.len();
// If index is greater than the array length, returns.
// If index is less than half the array length, searches from front to back;
// If index is greater than half the array length, searches from the back to the front.
return if index >= len {
None
} else if index >= (len - 1) / 2 {
let mut steps = len - 1 - index;
let mut cursor = self.inner.cursor_back();
while steps != 0 {
let _ = cursor.index()?;
cursor.move_prev();
steps -= 1;
}
Some(cursor)
} else {
let mut steps = index;
let mut cursor = self.inner.cursor_front();
while steps != 0 {
let _ = cursor.index()?;
cursor.move_next();
steps -= 1;
}
Some(cursor)
};
}
/// Gets the mutable cursor of the specified index node.
fn get_cursor_mut(&mut self, index: usize) -> Option<CursorMut<'_, JsonValue>> {
let len = self.len();
// If index is greater than the array length, returns.
// If index is less than half the array length, searches from front to back;
// If index is greater than half the array length, searches from the back to the front.
return if index >= len {
None
} else if index >= (len - 1) / 2 {
let mut steps = len - 1 - index;
let mut cursor = self.inner.cursor_back_mut();
while steps != 0 {
let _ = cursor.index()?;
cursor.move_prev();
steps -= 1;
}
Some(cursor)
} else {
let mut steps = index;
let mut cursor = self.inner.cursor_front_mut();
while steps != 0 {
let _ = cursor.index()?;
cursor.move_next();
steps -= 1;
}
Some(cursor)
};
}
}
impl Display for Array {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
write!(f, "[")?;
for (n, item) in self.inner.iter().enumerate() {
if n != 0 {
write!(f, ",")?;
}
write!(f, "{item}")?;
}
write!(f, "]")
}
}
impl Debug for Array {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
Display::fmt(self, f)
}
}
#[cfg(test)]
mod ut_linked_list {
use crate::{Array, JsonValue};
/// UT test for `Array::is_empty`.
///
/// # Title
/// ut_array_is_empty
///
/// # Brief
/// 1. Creates some `Array`s.
/// 2. Calls `Array::is_empty`.
/// 3. Checks if the test results are correct.
#[test]
fn ut_array_is_empty() {
assert!(Array::new().is_empty());
assert!(!array!(1).is_empty());
}
/// UT test for `Array::pop`.
///
/// # Title
/// ut_array_pop
///
/// # Brief
/// 1. Creates some `Array`s.
/// 2. Calls `Array::pop`.
/// 3. Checks if the test results are correct.
#[test]
fn ut_array_pop() {
let mut array = array!(1);
assert_eq!(array.pop(), Some(JsonValue::new_number(1.into())));
assert_eq!(array.pop(), None);
}
/// UT test for `Array::iter_mut`.
///
/// # Title
/// ut_array_iter_mut
///
/// # Brief
/// 1. Creates some `Array`s.
/// 2. Calls `Array::iter_mut`.
/// 3. Checks if the test results are correct.
#[test]
fn ut_array_iter_mut() {
let mut array = array!(1);
let mut iter = array.iter_mut();
assert_eq!(iter.next(), Some(&mut JsonValue::new_number(1.into())));
assert_eq!(iter.next(), None);
}
/// UT test for `Array::last`.
///
/// # Title
/// ut_array_last
///
/// # Brief
/// 1. Creates some `Array`s.
/// 2. Calls `Array::last`.
/// 3. Checks if the test results are correct.
#[test]
fn ut_array_last() {
let array = array!(1);
assert_eq!(array.last(), Some(&JsonValue::new_number(1.into())));
let array = Array::new();
assert_eq!(array.last(), None);
}
/// UT test for `Array::get_node`.
///
/// # Title
/// ut_array_get_node
///
/// # Brief
/// 1. Creates some `Array`s.
/// 2. Calls `Array::get_node`.
/// 3. Checks if the test results are correct.
#[test]
fn ut_array_get_node() {
let array = array!(1, 2, 3, 4, 5, 6);
assert!(array.get_node(0).is_some());
assert!(array.get_node(1).is_some());
assert!(array.get_node(2).is_some());
assert!(array.get_node(3).is_some());
assert!(array.get_node(4).is_some());
assert!(array.get_node(5).is_some());
assert!(array.get_node(6).is_none());
}
/// UT test for `Array::get_node_mut`.
///
/// # Title
/// ut_array_get_node_mut
///
/// # Brief
/// 1. Creates some `Array`s.
/// 2. Calls `Array::get_node_mut`.
/// 3. Checks if the test results are correct.
#[test]
fn ut_array_get_node_mut() {
let mut array = array!(1, 2, 3, 4, 5, 6);
assert!(array.get_node_mut(0).is_some());
assert!(array.get_node_mut(1).is_some());
assert!(array.get_node_mut(2).is_some());
assert!(array.get_node_mut(3).is_some());
assert!(array.get_node_mut(4).is_some());
assert!(array.get_node_mut(5).is_some());
assert!(array.get_node_mut(6).is_none());
}
/// UT test for `Array::last_node`.
///
/// # Title
/// ut_array_last_node
///
/// # Brief
/// 1. Creates some `Array`s.
/// 2. Calls `Array::last_node`.
/// 3. Checks if the test results are correct.
#[test]
fn ut_array_last_node() {
let array = array!(1);
assert!(array.last_node().is_some());
let array = Array::new();
assert!(array.last_node().is_none());
}
/// UT test for `Array::last_node_mut`.
///
/// # Title
/// ut_array_last_node_mut
///
/// # Brief
/// 1. Creates some `Array`s.
/// 2. Calls `Array::last_node_mut`.
/// 3. Checks if the test results are correct.
#[test]
fn ut_array_last_node_mut() {
let mut array = array!(1);
assert!(array.last_node_mut().is_some());
let mut array = Array::new();
assert!(array.last_node_mut().is_none());
}
/// UT test for `Array::fmt`.
///
/// # Title
/// ut_array_fmt
///
/// # Brief
/// 1. Creates some `Array`s.
/// 2. Calls `Array::fmt`.
/// 3. Checks if the test results are correct.
#[test]
fn ut_array_fmt() {
let array = array!(1, 2);
assert_eq!(format!("{array}"), "[1,2]");
assert_eq!(format!("{array:?}"), "[1,2]");
}
}
+398
View File
@@ -0,0 +1,398 @@
/*
* 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 crate::JsonValue;
use core::fmt::{Debug, Display, Formatter};
use core::slice::{Iter, IterMut};
/// Array type, implemented using Vec.
///
/// # Situation
/// * When the average number of Array entries exceeds 15 (estimated value), and query operation exists.
///
/// # Attention
/// * 只有开启 `vec_array` feature 时才可以使用,且与其他的 array 相关 feature 冲突。(默认开启)
/// Only open `vec_array` feature can be used, and conflicts with other array-related features. (Enabled by default)
///
/// # Examples
/// ```
/// use ylong_json::Array;
///
/// let array = Array::new();
/// assert_eq!(array.is_empty(), true);
/// ```
#[derive(Default, Clone)]
pub struct Array {
inner: Vec<JsonValue>,
}
impl Array {
/// Creates an empty Array instance.
///
/// # Examples
/// ```
/// use ylong_json::Array;
///
/// let array = Array::new();
/// ```
pub fn new() -> Self {
Self { inner: Vec::new() }
}
/// Gets length of Array.
///
/// # Examples
/// ```
/// use ylong_json::{Array, JsonValue};
///
/// let mut array = Array::new();
/// assert_eq!(array.len(), 0);
///
/// array.push(JsonValue::Null);
/// assert_eq!(array.len(), 1);
/// ```
pub fn len(&self) -> usize {
self.inner.len()
}
/// Determines whether Array is empty.
///
/// # Examples
/// ```
/// use ylong_json::{Array, JsonValue};
///
/// let mut array = Array::new();
/// assert_eq!(array.is_empty(), true);
///
/// array.push(JsonValue::Null);
/// assert_eq!(array.is_empty(), false);
/// ```
pub fn is_empty(&self) -> bool {
self.inner.len() == 0
}
/// Insert a new JsonValue at the end of Array.
///
/// # Examples
/// ```
/// use ylong_json::{Array, JsonValue};
///
/// let mut array = Array::new();
/// assert_eq!(array.len(), 0);
///
/// array.push(JsonValue::Null);
/// assert_eq!(array.len(), 1);
/// ```
pub fn push(&mut self, value: JsonValue) {
self.inner.push(value)
}
/// Pops the element at the end of Array.
///
/// # Examples
/// ```
/// use ylong_json::{Array, JsonValue};
///
/// let mut array = Array::new();
/// assert_eq!(array.pop(), None);
///
/// array.push(JsonValue::Null);
/// assert_eq!(array.pop(), Some(JsonValue::Null));
/// ```
pub fn pop(&mut self) -> Option<JsonValue> {
self.inner.pop()
}
/// Gets a common iterator of Array.
///
/// # Examples
/// ```
/// use ylong_json::Array;
///
/// let array = Array::new();
/// let iter = array.iter();
/// ```
pub fn iter(&self) -> Iter<'_, JsonValue> {
self.inner.iter()
}
/// Gets a mutable iterator of Array.
///
/// # Examples
/// ```
/// use ylong_json::Array;
///
/// let mut array = Array::new();
/// let iter_mut = array.iter_mut();
/// ```
pub fn iter_mut(&mut self) -> IterMut<'_, JsonValue> {
self.inner.iter_mut()
}
/// Returns a common reference to the specified index ** member ** in Array.
///
/// # Examples
/// ```
/// use ylong_json::{Array, JsonValue};
///
/// let mut array = Array::new();
/// array.push(JsonValue::Null);
/// assert_eq!(array.get(0), Some(&JsonValue::Null));
/// assert_eq!(array.get(1), None);
/// ```
pub fn get(&self, index: usize) -> Option<&JsonValue> {
self.inner.get(index)
}
/// Returns a mutable reference to the specified index ** member ** in Array.
///
/// # Examples
/// ```
/// use ylong_json::{Array, JsonValue};
///
/// let mut array = Array::new();
/// array.push(JsonValue::Null);
/// assert_eq!(array.get_mut(0), Some(&mut JsonValue::Null));
/// assert_eq!(array.get_mut(1), None);
/// ```
pub fn get_mut(&mut self, index: usize) -> Option<&mut JsonValue> {
self.inner.get_mut(index)
}
/// Returns a common reference to the trailing ** member ** in Array.。
///
/// # Examples
/// ```
/// use ylong_json::{Array, JsonValue};
///
/// let mut array = Array::new();
/// assert_eq!(array.last(), None);
/// array.push(JsonValue::Null);
/// assert_eq!(array.last(), Some(&JsonValue::Null));
/// ```
pub fn last(&self) -> Option<&JsonValue> {
self.inner.last()
}
/// Returns a mutable reference to the trailing ** member ** in Array.
///
/// # Examples
/// ```
/// use ylong_json::{Array, JsonValue};
///
/// let mut array = Array::new();
/// assert_eq!(array.last_mut(), None);
/// array.push(JsonValue::Null);
/// assert_eq!(array.last_mut(), Some(&mut JsonValue::Null));
/// ```
pub fn last_mut(&mut self) -> Option<&mut JsonValue> {
self.inner.last_mut()
}
/// Removes the node in Array with the specified index.
///
/// # Examples
/// ```
/// use ylong_json::{Array, JsonValue};
///
/// let mut array = Array::new();
/// array.push(JsonValue::Null);
/// array.push(JsonValue::Boolean(true));
/// array.push(JsonValue::Null);
///
/// assert_eq!(array.len(), 3);
/// let second = array.remove(1);
/// assert_eq!(second, Some(JsonValue::Boolean(true)));
/// assert_eq!(array.len(), 2);
/// ```
pub fn remove(&mut self, index: usize) -> Option<JsonValue> {
if index >= self.inner.len() {
return None;
}
Some(self.inner.remove(index))
}
}
impl PartialEq for Array {
/// Determines whether two arrays are equal.
///
/// Two Arrays are equal: They have the same length and the elements in each position are equal.
///
/// # Examples
/// ```
/// use ylong_json::{Array, JsonValue};
///
/// let array1 = Array::new();
/// let array2 = Array::new();
/// let mut array3 = Array::new();
/// array3.push(JsonValue::Null);
///
/// assert_eq!(array1, array2);
/// assert_ne!(array1, array3);
/// ```
fn eq(&self, other: &Self) -> bool {
if self.len() != other.len() {
return false;
}
for (a, b) in self.iter().zip(other.iter()) {
if a != b {
return false;
}
}
true
}
}
impl Display for Array {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
write!(f, "[")?;
for (n, item) in self.inner.iter().enumerate() {
if n != 0 {
write!(f, ",")?;
}
write!(f, "{item}")?;
}
write!(f, "]")
}
}
impl Debug for Array {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
Display::fmt(self, f)
}
}
#[cfg(test)]
mod ut_vec {
use crate::{Array, JsonValue};
/// UT test for `Array::is_empty`.
///
/// # Title
/// ut_array_is_empty
///
/// # Brief
/// 1. Creates some `Array`s.
/// 2. Calls `Array::is_empty`.
/// 3. Checks if the test results are correct.
#[test]
fn ut_array_is_empty() {
assert!(Array::new().is_empty());
assert!(!array!(1).is_empty());
}
/// UT test for `Array::pop`.
///
/// # Title
/// ut_array_pop
///
/// # Brief
/// 1. Creates some `Array`s.
/// 2. Calls `Array::pop`.
/// 3. Checks if the test results are correct.
#[test]
fn ut_array_pop() {
let mut array = array!(1);
assert_eq!(array.pop(), Some(JsonValue::new_number(1.into())));
assert_eq!(array.pop(), None);
}
/// UT test for `Array::iter_mut`.
///
/// # Title
/// ut_array_iter_mut
///
/// # Brief
/// 1. Creates some `Array`s.
/// 2. Calls `Array::iter_mut`.
/// 3. Checks if the test results are correct.
#[test]
fn ut_array_iter_mut() {
let mut array = array!(1);
let mut iter = array.iter_mut();
assert_eq!(iter.next(), Some(&mut JsonValue::new_number(1.into())));
assert_eq!(iter.next(), None);
}
/// UT test for `Array::last`.
///
/// # Title
/// ut_array_last
///
/// # Brief
/// 1. Creates some `Array`s.
/// 2. Calls `Array::last`.
/// 3. Checks if the test results are correct.
#[test]
fn ut_array_last() {
let array = array!(1);
assert_eq!(array.last(), Some(&JsonValue::new_number(1.into())));
let array = Array::new();
assert_eq!(array.last(), None);
}
/// UT test for `Array::remove`.
///
/// # Title
/// ut_array_remove
///
/// # Brief
/// 1. Creates some `Array`s.
/// 2. Calls `Array::remove`.
/// 3. Checks if the test results are correct.
#[test]
fn ut_array_remove() {
let mut array = array!(1);
assert_eq!(array.remove(3), None);
assert_eq!(array.remove(0), Some(JsonValue::new_number(1.into())));
}
/// UT test for `Array::eq`.
///
/// # Title
/// ut_array_eq
///
/// # Brief
/// 1. Creates some `Array`s.
/// 2. Calls `Array::eq`.
/// 3. Checks if the test results are correct.
#[test]
fn ut_array_eq() {
let array1 = array!(1);
let array2 = array!(1, 2);
let array3 = array!(1, 3);
assert_eq!(array1, array1);
assert_ne!(array1, array2);
assert_ne!(array2, array3);
}
/// UT test for `Array::fmt`.
///
/// # Title
/// ut_array_fmt
///
/// # Brief
/// 1. Creates some `Array`s.
/// 2. Calls `Array::fmt`.
/// 3. Checks if the test results are correct.
#[test]
fn ut_array_fmt() {
let array = array!(1, 2);
assert_eq!(format!("{array}"), "[1,2]");
assert_eq!(format!("{array:?}"), "[1,2]");
}
}
+485
View File
@@ -0,0 +1,485 @@
/*
* 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 crate::{Array, JsonValue, Object};
/// Static NULL, which is returned if the searched key-value pair does not exist.
static NULL: JsonValue = JsonValue::Null;
/// This trait can be used to get an index based on the subscript of an internal member of JsonValue.
pub trait Index: private::IndexSealed {
/// Gets a common reference to the value with the specified subscript (or key) from a JsonValue.
fn index_into<'a>(&self, value: &'a JsonValue) -> &'a JsonValue;
/// Gets a mutable reference to the value of the specified subscript (or key) from a JsonValue.
fn index_into_mut<'a>(&self, value: &'a mut JsonValue) -> &'a mut JsonValue;
/// Removes the member with the specified subscript (or key) from a JsonValue.
fn index_remove(&self, value: &mut JsonValue) -> Option<JsonValue>;
}
impl Index for usize {
/// Uses the array subscript to visit the Array type of JsonValue
/// and get a common reference to the corresponding JsonValue.
/// A null type will be returned in the following two cases:
///
/// 1.Use a subscript to visit non-array types.
///
/// 2.The subscript exceeds the current length of the Array type.
///
/// # Examples
/// ```
/// use ylong_json::{JsonValue, Array};
///
/// // Non-array types
/// assert_eq!(JsonValue::Number(0.0.into())[0], JsonValue::Null);
///
/// // Array type
/// let mut array = Array::new();
/// array.push(JsonValue::Null);
/// array.push(JsonValue::Boolean(true));
/// array.push(JsonValue::Number(0.0.into()));
///
/// let value = JsonValue::Array(array);
///
/// // When subscript < length
/// assert_eq!(value[0], JsonValue::Null);
/// assert_eq!(value[1], JsonValue::Boolean(true));
/// assert_eq!(value[2], JsonValue::Number(0.0.into()));
/// // When subscript >= length
/// assert_eq!(value[3], JsonValue::Null);
/// ```
fn index_into<'a>(&self, value: &'a JsonValue) -> &'a JsonValue {
if let JsonValue::Array(ref array) = value {
if *self < array.len() {
return array.get(*self).unwrap();
}
}
&NULL
}
/// Uses the array subscript to visit the Array type of JsonValue
/// and get a mutable reference to the corresponding JsonValue.
///
/// If the visited JsonValue is not Array type, the JsonValue will be
/// replaced with an empty Array type and visits again with that subscript.
///
/// If the visited JsonValue is Array type, but the subscript exceeds the length of the array,
/// then adds a Null type JsonValue at the end of the array and return a mutable reference of it.
///
/// # Examples
/// ```
/// use ylong_json::{JsonValue, Array};
///
/// // Non-array types
/// let mut value = JsonValue::Null;
/// value[0] = JsonValue::Null;
///
/// let mut array = Array::new();
/// array.push(JsonValue::Null);
/// assert_eq!(value, JsonValue::Array(array));
///
/// // Array type
/// let mut array = Array::new();
/// array.push(JsonValue::Null);
/// let mut value = JsonValue::Array(array);
///
/// // Contains the subscript
/// value[0] = JsonValue::Number(0.0.into());
/// assert_eq!(value[0], JsonValue::Number(0.0.into()));
/// assert_eq!(value.try_as_array().unwrap().len(), 1);
///
/// // Does not contain the subscript
/// value[1] = JsonValue::Boolean(true);
/// assert_eq!(value[1], JsonValue::Boolean(true));
/// assert_eq!(value.try_as_array().unwrap().len(), 2);
/// ```
fn index_into_mut<'a>(&self, value: &'a mut JsonValue) -> &'a mut JsonValue {
if let JsonValue::Array(ref mut array) = value {
return if *self < array.len() {
array.get_mut(*self).unwrap()
} else {
array.push(JsonValue::Null);
array.last_mut().unwrap()
};
}
*value = JsonValue::new_array(Array::new());
self.index_into_mut(value)
}
/// Removes the element at the specified location of Array type JsonValue and returns that content.
///
/// # Examples
/// ```
/// use ylong_json::{JsonValue, Array};
///
/// let mut array = Array::new();
/// array.push(1i32.into());
///
/// let mut value: JsonValue = JsonValue::Array(array);
/// assert_eq!(value[0], 1i32.into());
///
/// let ret = value.remove(0);
/// assert_eq!(value[0], JsonValue::Null);
/// assert_eq!(ret.unwrap(), 1i32.into());
/// ```
fn index_remove(&self, value: &mut JsonValue) -> Option<JsonValue> {
if let JsonValue::Array(ref mut array) = value {
if *self < array.len() {
return array.remove(*self);
}
}
None
}
}
impl Index for str {
/// Uses key to visit Object type JsonValue, and returns a common reference to corresponding JsonValue.
/// A null type will be returned in the following two cases:
///
/// 1.Uses key to visit non-object types.
///
/// 2.The searched Object type does not contain the key.
///
/// # Examples
/// ```
/// use ylong_json::{JsonValue, Object};
///
/// // Non-object types
/// assert_eq!(JsonValue::Number(0.0.into())["key"], JsonValue::Null);
///
/// // Object type
/// let mut object = Object::new();
/// object.insert(String::from("key"), JsonValue::Number(0.0.into()));
///
/// let value = JsonValue::Object(object);
///
/// // The key exists.
/// assert_eq!(value["key"], JsonValue::Number(0.0.into()));
///
/// // The key does not exist.
/// assert_eq!(value["not exist"], JsonValue::Null);
/// ```
fn index_into<'a>(&self, value: &'a JsonValue) -> &'a JsonValue {
if let JsonValue::Object(ref object) = value {
return object.get(self).unwrap_or(&NULL);
}
&NULL
}
/// Uses key to visit Object type JsonValue, and returns a mutable reference to corresponding JsonValue.
///
/// If the visited JsonValue is not Object type, the JsonValue will be
/// replaced with an empty Object type and visits again with that key.
///
/// If the visited JsonValue is of object type but does not contain the key, a key-value pair of
/// the key and a null type will be inserted and returns a mutable reference to the JsonValue.
///
///
/// # Examples
/// ```
/// use ylong_json::{JsonValue, Object};
///
/// // Non-object types
/// let mut value = JsonValue::Null;
/// let mut object = Object::new();
/// object.insert(String::from("key"), JsonValue::Number(0.0.into()));
///
/// value["key"] = JsonValue::Number(0.0.into());
/// assert_eq!(value, JsonValue::Object(object));
///
/// // Object type
/// let mut object = Object::new();
/// object.insert(String::from("key"), JsonValue::Number(0.0.into()));
/// let mut value = JsonValue::Object(object);
///
/// // Contains the key.
/// value["key"] = JsonValue::Boolean(true);
/// assert_eq!(value["key"], JsonValue::Boolean(true));
/// assert_eq!(value.try_as_mut_object().unwrap().len(), 1);
///
/// // Dose not contain the key.
/// value["not exist"] = JsonValue::Number(1.1.into());
/// assert_eq!(value["not exist"], JsonValue::Number(1.1.into()));
/// assert_eq!(value.try_as_mut_object().unwrap().len(), 2);
/// ```
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"))]
{
return object.get_key_mut_maybe_insert(self);
}
#[cfg(feature = "vec_object")]
{
if let Some(pos) = object.iter().position(|(k, _)| k == self) {
return object.get_mut_by_position(pos).unwrap();
}
object.insert(String::from(self), JsonValue::Null);
return object.last_mut().unwrap();
}
#[cfg(feature = "btree_object")]
{
if !object.contains_key(self) {
object.insert(String::from(self), JsonValue::Null);
}
return object.get_mut(self).unwrap();
}
}
*value = JsonValue::Object(Object::new());
self.index_into_mut(value)
}
/// Removes the element at the specified location of Object type JsonValue and returns that content.
///
/// # Examples
/// ```
/// use ylong_json::{Object, JsonValue};
///
/// let mut object = Object::new();
/// object.insert(String::from("key"), "value".into());
///
/// let mut value: JsonValue = object.into();
/// assert_eq!(value["key"], "value".into());
///
/// let ret = value.remove("key");
/// assert_eq!(value["key"], JsonValue::Null);
/// assert_eq!(ret.unwrap(), "value".into());
/// ```
fn index_remove(&self, value: &mut JsonValue) -> Option<JsonValue> {
if let JsonValue::Object(ref mut object) = value {
return object.remove(self);
}
None
}
}
impl Index for String {
/// Same as 'Index for str'.
fn index_into<'a>(&self, value: &'a JsonValue) -> &'a JsonValue {
self.as_str().index_into(value)
}
/// Same as 'Index for str'.
fn index_into_mut<'a>(&self, value: &'a mut JsonValue) -> &'a mut JsonValue {
self.as_str().index_into_mut(value)
}
/// Same as 'Index for str'.
fn index_remove(&self, value: &mut JsonValue) -> Option<JsonValue> {
self.as_str().index_remove(value)
}
}
impl<'a, T> Index for &'a T
where
T: ?Sized + Index,
{
/// Implements Index for the relevant reference type.
fn index_into<'v>(&self, value: &'v JsonValue) -> &'v JsonValue {
(**self).index_into(value)
}
/// Implements Index for the relevant reference type.
fn index_into_mut<'v>(&self, value: &'v mut JsonValue) -> &'v mut JsonValue {
(**self).index_into_mut(value)
}
/// Implements Index for the relevant reference type.
fn index_remove(&self, value: &mut JsonValue) -> Option<JsonValue> {
(**self).index_remove(value)
}
}
// To prevent the Index by external implementation.
mod private {
pub trait IndexSealed {}
impl IndexSealed for usize {}
impl IndexSealed for str {}
impl IndexSealed for String {}
impl<'a, T> IndexSealed for &'a T where T: ?Sized + IndexSealed {}
}
#[cfg(test)]
mod ut_index {
use crate::{Array, Index, JsonValue, Object};
/// UT test for `usize::index_into`.
///
/// # Title
/// ut_usize_index_into
///
/// # Brief
/// 1. Creates some `usize`s and some `JsonValue`s.
/// 2. Calls `Index::index_into`.
/// 3. Checks if the test results are correct.
#[test]
fn ut_usize_index_into() {
let value = JsonValue::new_boolean(true);
assert!(1usize.index_into(&value).is_null());
}
/// UT test for `usize::index_into_mut`.
///
/// # Title
/// ut_usize_index_into_mut
///
/// # Brief
/// 1. Creates some `usize`s and some `JsonValue`s.
/// 2. Calls `Index::index_into_mut`.
/// 3. Checks if the test results are correct.
#[test]
fn ut_usize_index_into_mut() {
let mut value = JsonValue::new_array(array!(1));
assert!(0usize.index_into_mut(&mut value).is_number());
assert!(1usize.index_into_mut(&mut value).is_null());
let mut value = JsonValue::new_null();
assert!(0usize.index_into_mut(&mut value).is_null());
assert!(value.is_array())
}
/// UT test for `usize::index_remove`.
///
/// # Title
/// ut_usize_index_remove
///
/// # Brief
/// 1. Creates some `usize`s and some `JsonValue`s.
/// 2. Calls `Index::index_remove`.
/// 3. Checks if the test results are correct.
#[test]
fn ut_usize_index_remove() {
let mut value = JsonValue::new_array(array!(1));
assert_eq!(
0usize.index_remove(&mut value),
Some(JsonValue::new_number(1.into()))
);
assert!(0usize.index_remove(&mut value).is_none());
}
/// UT test for `str::index_into`.
///
/// # Title
/// ut_str_index_into
///
/// # Brief
/// 1. Creates some `str`s and some `JsonValue`s.
/// 2. Calls `Index::index_into`.
/// 3. Checks if the test results are correct.
#[test]
fn ut_str_index_into() {
let value = JsonValue::new_boolean(true);
assert!("key".index_into(&value).is_null());
}
/// UT test for `str::index_into_mut`.
///
/// # Title
/// ut_str_index_into_mut
///
/// # Brief
/// 1. Creates some `str`s and some `JsonValue`s.
/// 2. Calls `Index::index_into_mut`.
/// 3. Checks if the test results are correct.
#[test]
fn ut_str_index_into_mut() {
let mut value = JsonValue::new_object(object!("key1" => "value1"));
assert!("key1".index_into_mut(&mut value).is_string());
assert!("key2".index_into_mut(&mut value).is_null());
let mut value = JsonValue::new_null();
assert!("key1".index_into_mut(&mut value).is_null());
assert!(value.is_object())
}
/// UT test for `str::index_remove`.
///
/// # Title
/// ut_str_index_remove
///
/// # Brief
/// 1. Creates some `str`s and some `JsonValue`s.
/// 2. Calls `Index::index_remove`.
/// 3. Checks if the test results are correct.
#[test]
fn ut_str_index_remove() {
let mut value = JsonValue::new_object(object!("key1" => "value1"));
assert_eq!(
"key1".index_remove(&mut value),
Some(JsonValue::new_string("value1"))
);
let mut value = JsonValue::new_null();
assert!("key1".index_remove(&mut value).is_none());
}
/// UT test for `String::index_into`.
///
/// # Title
/// ut_string_index_into
///
/// # Brief
/// 1. Creates some `String`s and some `JsonValue`s.
/// 2. Calls `Index::index_into`.
/// 3. Checks if the test results are correct.
#[test]
fn ut_string_index_into() {
let value = JsonValue::new_boolean(true);
assert!(String::from("key").index_into(&value).is_null());
}
/// UT test for `String::index_into_mut`.
///
/// # Title
/// ut_string_index_into_mut
///
/// # Brief
/// 1. Creates some `String`s and some `JsonValue`s.
/// 2. Calls `Index::index_into_mut`.
/// 3. Checks if the test results are correct.
#[test]
fn ut_string_index_into_mut() {
let mut value = JsonValue::new_object(object!("key1" => "value1"));
assert!(String::from("key1").index_into_mut(&mut value).is_string());
assert!(String::from("key2").index_into_mut(&mut value).is_null());
let mut value = JsonValue::new_null();
assert!(String::from("key1").index_into_mut(&mut value).is_null());
assert!(value.is_object())
}
/// UT test for `String::index_remove`.
///
/// # Title
/// ut_string_index_remove
///
/// # Brief
/// 1. Creates some `String`s and some `JsonValue`s.
/// 2. Calls `Index::index_remove`.
/// 3. Checks if the test results are correct.
#[test]
fn ut_string_index_remove() {
let mut value = JsonValue::new_object(object!("key1" => "value1"));
assert_eq!(
String::from("key1").index_remove(&mut value),
Some(JsonValue::new_string("value1"))
);
assert!(String::from("key1").index_remove(&mut value).is_none());
}
}
+348
View File
@@ -0,0 +1,348 @@
/*
* 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 crate::Error;
use core::fmt::{Display, Formatter};
use std::fmt::Debug;
/// Numerical type
///
/// # Examples
/// ```
/// use ylong_json::Number;
///
/// let number: Number = 0.0.into();
/// assert_eq!(number.is_float(), true);
/// ```
#[derive(Clone)]
pub enum Number {
/// Unsigned integer
Unsigned(u64),
/// Signed integer
Signed(i64),
/// Floating point number
Float(f64),
}
impl Number {
/// Determines whether the number is an unsigned integer.
///
/// # Examples
/// ```
/// use ylong_json::Number;
///
/// let number: Number = 1u8.into();
/// assert_eq!(number.is_unsigned(), true);
///
/// let number: Number = 1i8.into();
/// assert_eq!(number.is_unsigned(), false);
/// ```
pub fn is_unsigned(&self) -> bool {
matches!(*self, Self::Unsigned(_))
}
/// Determines whether the number is a signed integer.
///
/// # Examples
/// ```
/// use ylong_json::Number;
///
/// let number: Number = 1i8.into();
/// assert_eq!(number.is_signed(), true);
///
/// let number: Number = 1u8.into();
/// assert_eq!(number.is_signed(), false);
/// ```
pub fn is_signed(&self) -> bool {
matches!(*self, Self::Signed(_))
}
/// Determines whether the number is a floating point number.
///
/// # Examples
/// ```
/// use ylong_json::Number;
///
/// let number: Number = 0.0.into();
/// assert_eq!(number.is_float(), true);
///
/// let number: Number = 1i8.into();
/// assert_eq!(number.is_float(), false);
/// ```
pub fn is_float(&self) -> bool {
matches!(*self, Self::Float(_))
}
/// Trys converting the number to u64. If conversion fails, returns Error.
///
/// Only Unsigned case means success, other cases return Error.
///
/// # Examples
/// ```
/// use ylong_json::Number;
///
/// let number: Number = 1u8.into();
/// assert_eq!(number.try_as_u64().unwrap(), 1u64);
///
/// let number: Number = 1i8.into();
/// assert_eq!(number.try_as_u64().is_err(), true);
/// ```
pub fn try_as_u64(&self) -> Result<u64, Error> {
match self {
Self::Unsigned(u) => Ok(*u),
_ => Err(Error::TypeTransform),
}
}
/// Trys converting the number to i64. If conversion fails, returns Error.
///
/// Only in 164 range unsigned numbers can be converted. Signed numbers can be converted.
/// Otherwise, returns Error.
///
/// # Examples
/// ```
/// use ylong_json::Number;
///
/// let number: Number = 1i8.into();
/// assert_eq!(number.try_as_i64().unwrap(), 1i64);
///
/// let number: Number = u64::MAX.into();
/// assert_eq!(number.try_as_i64().is_err(), true);
/// ```
pub fn try_as_i64(&self) -> Result<i64, Error> {
match self {
Self::Unsigned(u) => {
if *u <= i64::MAX as u64 {
Ok(*u as i64)
} else {
Err(Error::TypeTransform)
}
}
Self::Signed(i) => Ok(*i),
Self::Float(_) => Err(Error::TypeTransform),
}
}
/// Trys converting the number to f64. If conversion fails, returns Error.
///
/// All types can be converted to f64.
///
/// # Examples
/// ```
/// use ylong_json::Number;
///
/// let number: Number = 0.0.into();
/// assert_eq!(number.try_as_f64().unwrap(), 0.0f64);
/// ```
pub fn try_as_f64(&self) -> Result<f64, Error> {
match self {
Self::Unsigned(u) => Ok(*u as f64),
Self::Signed(i) => Ok(*i as f64),
Self::Float(f) => Ok(*f),
}
}
}
impl PartialEq for Number {
fn eq(&self, other: &Self) -> bool {
let a = self.try_as_f64().unwrap();
let b = other.try_as_f64().unwrap();
a == b
}
}
impl Display for Number {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
match self {
Number::Unsigned(x) => write!(f, "{x}"),
Number::Signed(x) => write!(f, "{x}"),
Number::Float(x) => write!(f, "{x:?}"),
}
}
}
impl Debug for Number {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
Display::fmt(self, f)
}
}
macro_rules! number_from_unsigned {
($($u: tt),* $(,)?) => {
$(
impl From<$u> for Number {
fn from(u: $u) -> Self {
Self::Unsigned(u as u64)
}
}
)*
}
}
macro_rules! number_from_signed {
($($i: tt),* $(,)?) => {
$(
impl From<$i> for Number {
fn from(i: $i) -> Self {
Self::Signed(i as i64)
}
}
)*
}
}
macro_rules! number_from_float {
($($f: tt),* $(,)?) => {
$(
impl From<$f> for Number {
fn from(f: $f) -> Self {
Self::Float(f as f64)
}
}
)*
}
}
number_from_unsigned!(u8, u16, u32, u64, usize);
number_from_signed!(i8, i16, i32, i64, isize);
number_from_float!(f32, f64);
#[cfg(test)]
mod ut_number {
use crate::Number;
/// UT test for `Number::fmt`.
///
/// # Title
/// ut_number_fmt
///
/// # Brief
/// 1. Creates some `Number`s.
/// 2. Calls `Number::fmt`.
/// 3. Checks if the test results are correct.
#[test]
fn ut_number_fmt() {
assert_eq!(format!("{}", Number::Unsigned(1)), "1");
assert_eq!(format!("{:?}", Number::Unsigned(1)), "1");
assert_eq!(format!("{}", Number::Signed(1)), "1");
assert_eq!(format!("{:?}", Number::Signed(1)), "1");
assert_eq!(format!("{}", Number::Float(1.0)), "1.0");
assert_eq!(format!("{:?}", Number::Float(1.0)), "1.0");
}
/// UT test for `Number::clone`.
///
/// # Title
/// ut_number_clone
///
/// # Brief
/// 1. Creates some `Number`s.
/// 2. Calls `Number::clone`.
/// 3. Checks if the test results are correct.
#[test]
fn ut_number_clone() {
let number1 = Number::Unsigned(1);
assert_eq!(number1, number1.clone());
let number1 = Number::Signed(1);
assert_eq!(number1, number1.clone());
let number1 = Number::Float(1.0);
assert_eq!(number1, number1.clone());
}
/// UT test for `Number::is_unsigned`.
///
/// # Title
/// ut_number_is_unsigned
///
/// # Brief
/// 1. Creates some `Number`s.
/// 2. Calls `Number::is_unsigned`.
/// 3. Checks if the test results are correct.
#[test]
fn ut_number_is_unsigned() {
assert!(Number::Unsigned(1).is_unsigned());
assert!(!Number::Signed(1).is_unsigned());
assert!(!Number::Float(1.0).is_unsigned());
}
/// UT test for `Number::is_signed`.
///
/// # Title
/// ut_number_is_signed
///
/// # Brief
/// 1. Creates some `Number`s.
/// 2. Calls `Number::is_signed`.
/// 3. Checks if the test results are correct.
#[test]
fn ut_number_is_signed() {
assert!(!Number::Unsigned(1).is_signed());
assert!(Number::Signed(1).is_signed());
assert!(!Number::Float(1.0).is_signed());
}
/// UT test for `Number::is_float`.
///
/// # Title
/// ut_number_is_float
///
/// # Brief
/// 1. Creates some `Number`s.
/// 2. Calls `Number::is_float`.
/// 3. Checks if the test results are correct.
#[test]
fn ut_number_is_float() {
assert!(!Number::Unsigned(1).is_float());
assert!(!Number::Signed(1).is_float());
assert!(Number::Float(1.0).is_float());
}
/// UT test for `Number::try_as_u64`.
///
/// # Title
/// ut_number_try_as_u64
///
/// # Brief
/// 1. Creates some `Number`s.
/// 2. Calls `Number::try_as_u64`.
/// 3. Checks if the test results are correct.
#[test]
fn ut_number_try_as_u64() {
assert!(Number::Unsigned(1).try_as_u64().is_ok());
assert!(Number::Signed(1).try_as_u64().is_err());
assert!(Number::Float(1.0).try_as_u64().is_err());
}
/// UT test for `Number::try_as_i64`.
///
/// # Title
/// ut_number_try_as_i64
///
/// # Brief
/// 1. Creates some `Number`s.
/// 2. Calls `Number::try_as_i64`.
/// 3. Checks if the test results are correct.
#[test]
fn ut_number_try_as_i64() {
assert!(Number::Unsigned(1).try_as_i64().is_ok());
assert!(Number::Unsigned(u64::MAX).try_as_i64().is_err());
assert!(Number::Signed(1).try_as_i64().is_ok());
assert!(Number::Float(1.0).try_as_i64().is_err());
}
}
+29
View File
@@ -0,0 +1,29 @@
/*
* 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.
*/
#[cfg(feature = "btree_object")]
mod btree;
#[cfg(feature = "btree_object")]
pub use btree::Object;
#[cfg(feature = "list_object")]
mod linked_list;
#[cfg(feature = "list_object")]
pub use linked_list::Object;
#[cfg(feature = "vec_object")]
mod vec;
#[cfg(feature = "vec_object")]
pub use vec::Object;
+279
View File
@@ -0,0 +1,279 @@
/*
* 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 crate::JsonValue;
use core::fmt::{Debug, Display, Formatter};
use std::collections::btree_map::{BTreeMap, Iter, IterMut};
/// Object type, implemented using the standard library Btree.
///
/// # Situation
/// * When the average number of objects exceeds 1024 (estimated value) but does not exceed 5000 (estimated value),
/// and the creation and query ratio is greater than 600.(Number of queries for 1 Object creation).
///
/// * When the average number of objects exceeds 5000 (estimated value).
///
/// # Attention
/// Only opening ` btree_object ` feature can be used, and associated with the object of other feature conflict. (Enabled by default)
///
/// # Examples
/// ```
/// use ylong_json::Object;
///
/// let object = Object::new();
/// assert_eq!(object.is_empty(), true);
/// ```
#[derive(Default, Clone, PartialEq)]
pub struct Object {
inner: BTreeMap<String, JsonValue>,
}
impl Object {
/// Creates an empty Object.
///
/// # Examples
/// ```
/// use ylong_json::Object;
///
/// let object = Object::new();
/// assert_eq!(object.is_empty(), true);
/// ```
pub fn new() -> Self {
Self {
inner: BTreeMap::new(),
}
}
/// Gets the length of Object.
///
/// # Examples
/// ```
/// use ylong_json::{JsonValue, Object};
///
/// let mut object = Object::new();
/// assert_eq!(object.len(), 0);
/// object.insert(String::from("null"), JsonValue::Null);
/// assert_eq!(object.len(), 1);
/// ```
pub fn len(&self) -> usize {
self.inner.len()
}
/// Determines whether the Object is empty.
///
/// # Examples
/// ```
/// use ylong_json::{JsonValue, Object};
///
/// let mut object = Object::new();
/// assert_eq!(object.is_empty(), true);
/// object.insert(String::from("null"), JsonValue::Null);
/// assert_eq!(object.is_empty(), false);
/// ```
pub fn is_empty(&self) -> bool {
self.inner.is_empty()
}
/// Checks whether the specified key exists in the Object.
///
/// # Examples
/// ```
/// use ylong_json::{JsonValue, Object, Number};
///
/// let mut object = Object::new();
/// object.insert(String::from("null"), JsonValue::Null);
///
/// assert_eq!(object.contains_key("null"), true);
/// assert_eq!(object.contains_key("no_such_key"), false);
/// ```
pub fn contains_key(&self, key: &str) -> bool {
self.inner.contains_key(key)
}
/// Inserts the specified key and value into the Object, and replaces the value if the key already exists in the Object.
///
/// # Examples
/// ```
/// use ylong_json::{JsonValue, Object};
///
/// let mut object = Object::new();
/// assert_eq!(object.len(), 0);
/// object.insert(String::from("null"), JsonValue::Null);
/// assert_eq!(object.len(), 1);
/// ```
pub fn insert(&mut self, key: String, value: JsonValue) {
self.inner.insert(key, value);
}
/// Removes the element under the specified Key from Object.
///
/// # Examples
/// ```
/// use ylong_json::{JsonValue, Object, Number};
///
/// let mut object = Object::new();
/// object.insert(String::from("null"), JsonValue::Null);
/// assert_eq!(object.len(), 1);
/// assert_eq!(object.remove("null"), Some(JsonValue::Null));
/// assert_eq!(object.len(), 0);
/// ```
pub fn remove(&mut self, key: &str) -> Option<JsonValue> {
self.inner.remove(key)
}
/// Gets a common iterator of Object.
///
/// # Examples
/// ```
/// use ylong_json::Object;
///
/// let object = Object::new();
/// let iter = object.iter();
/// ```
pub fn iter(&self) -> Iter<'_, String, JsonValue> {
self.inner.iter()
}
/// Gets a mutable iterator of Object.
///
/// # Examples
/// ```
/// use ylong_json::Object;
///
/// let mut object = Object::new();
/// let iter_mut = object.iter_mut();
/// ```
pub fn iter_mut(&mut self) -> IterMut<'_, String, JsonValue> {
self.inner.iter_mut()
}
/// Gets a common reference to the element in Object with the specified key.
///
/// # Examples
/// ```
/// use ylong_json::{JsonValue, Object, Number};
///
/// let mut object = Object::new();
/// object.insert(String::from("test"), JsonValue::Number(Number::from(123)));
///
/// assert_eq!(object.get("test"), Some(&JsonValue::Number(Number::from(123))));
/// assert_eq!(object.get("no_such_key"), None);
/// ```
pub fn get(&self, key: &str) -> Option<&JsonValue> {
self.inner.get(key)
}
/// Gets a mutable reference to the element in Object with the specified key.
///
/// # Examples
/// ```
/// use ylong_json::{JsonValue, Object};
///
/// let mut object = Object::new();
/// object.insert(String::from("null"), JsonValue::Null);
///
/// assert_eq!(object.get_mut("null"), Some(&mut JsonValue::Null));
/// assert_eq!(object.get_mut("no_such_key"), None);
/// ```
pub fn get_mut(&mut self, key: &str) -> Option<&mut JsonValue> {
self.inner.get_mut(key)
}
}
impl Display for Object {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
write!(f, "{{")?;
for (n, (key, value)) in self.inner.iter().enumerate() {
if n != 0 {
write!(f, ",")?;
}
write!(f, "\"{key}\":{value}")?;
}
write!(f, "}}")
}
}
impl Debug for Object {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
Display::fmt(self, f)
}
}
#[cfg(test)]
mod ut_btree {
use crate::{JsonValue, Object};
/// UT test for `Object::iter_mut`.
///
/// # Title
/// ut_object_iter_mut
///
/// # Brief
/// 1. Creates some `Object`s.
/// 2. Calls `Object::iter_mut`.
/// 3. Checks if the test results are correct.
#[test]
fn ut_object_iter_mut() {
let mut object = object!("key1" => "value1");
let mut iter = object.iter_mut();
assert_eq!(
iter.next(),
Some((&String::from("key1"), &mut JsonValue::new_string("value1")))
);
assert_eq!(iter.next(), None);
}
/// UT test for `Object::fmt`.
///
/// # Title
/// ut_object_fmt
///
/// # Brief
/// 1. Creates a `Object`.
/// 2. Calls `Object::fmt` on it.
/// 3. Checks if the test results are correct.
#[test]
fn ut_object_fmt() {
let object = object!("key1" => "value1"; "key2" => "value2");
assert_eq!(
format!("{object}"),
"{\"key1\":\"value1\",\"key2\":\"value2\"}"
);
assert_eq!(
format!("{object:?}"),
"{\"key1\":\"value1\",\"key2\":\"value2\"}"
);
}
/// UT test for `Object::eq`.
///
/// # Title
/// ut_object_fmt
///
/// # Brief
/// 1. Creates a `Object`.
/// 2. Calls `Object::eq` on it.
/// 3. Checks if the test results are correct.
#[test]
fn ut_object_eq() {
let object1 = object!("key1" => "value1");
let object2 = object!("key1" => "value1"; "key2" => "value2");
let object3 = object!("key1" => "value1"; "key3" => "value3");
assert_eq!(object1, object1);
assert_ne!(object1, object2);
assert_ne!(object2, object3);
}
}
+430
View File
@@ -0,0 +1,430 @@
/*
* 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 crate::{Cursor, CursorMut, Iter, IterMut, JsonValue, LinkedList, Node};
use core::fmt::{Debug, Display, Formatter};
use core::ptr::null;
/// Object type, implemented using LinkedList.
///
/// # Situation
/// * When the average number of items under Object is less than 15 (estimated value).
///
/// * When the average number of items under Object exceeds 15 (estimated), but do not or rarely made the query operation.
///
/// # Attention
/// * Only opening the 'list_object' feature, this Object type can be used , and it conflicts with other objects.
///
/// * This Object ** does not provide the ** de-duplicate function.
/// * Users are required to ensure that there are no duplicate entries.
///
/// * The output order of this Object is the same as the insertion order.
///
/// # Examples
/// ```
/// use ylong_json::Object;
///
/// let object = Object::new();
/// ```
#[derive(Default, Clone, PartialEq)]
pub struct Object {
inner: LinkedList<(String, JsonValue)>,
}
impl Object {
/// Creates an empty Object。
///
/// # Examples
/// ```
/// use ylong_json::Object;
///
/// let object = Object::new();
/// assert_eq!(object.is_empty(), true);
/// ```
pub fn new() -> Self {
Self {
inner: LinkedList::new(),
}
}
/// Gets the length of Object.
///
/// # Examples
/// ```
/// use ylong_json::{JsonValue, Object};
///
/// let mut object = Object::new();
/// assert_eq!(object.len(), 0);
/// object.insert(String::from("null"), JsonValue::Null);
/// assert_eq!(object.len(), 1);
/// ```
pub fn len(&self) -> usize {
self.inner.len()
}
/// Determines whether the Object is empty.
///
/// # Examples
/// ```
/// use ylong_json::{JsonValue, Object};
///
/// let mut object = Object::new();
/// assert_eq!(object.is_empty(), true);
/// object.insert(String::from("null"), JsonValue::Null);
/// assert_eq!(object.is_empty(), false);
/// ```
pub fn is_empty(&self) -> bool {
self.inner.is_empty()
}
/// Checks whether the specified key exists in the Object.
///
/// # Examples
/// ```
/// use ylong_json::{JsonValue, Object, Number};
///
/// let mut object = Object::new();
/// object.insert(String::from("null"), JsonValue::Null);
///
/// assert_eq!(object.contains_key("null"), true);
/// assert_eq!(object.contains_key("no_such_key"), false);
/// ```
pub fn contains_key(&self, key: &str) -> bool {
self.get_cursor(key).is_some()
}
/// Inserts the specified key and value into an Object, appending them to the end without deduplication.
///
/// # Examples
/// ```
/// use ylong_json::{JsonValue, Object};
///
/// let mut object = Object::new();
/// assert_eq!(object.len(), 0);
/// object.insert(String::from("null"), JsonValue::Null);
/// assert_eq!(object.len(), 1);
/// ```
pub fn insert(&mut self, key: String, value: JsonValue) {
self.inner.push_back((key, value))
}
/// Removes the element under the specified key from the Object.If there is an element with
/// the same name in the Object, deletes the one with the smallest subscript.
///
/// # Examples
/// ```
/// use ylong_json::{JsonValue, Object, Number};
///
/// let mut object = Object::new();
/// object.insert(String::from("null"), JsonValue::Null);
/// assert_eq!(object.len(), 1);
/// assert_eq!(object.remove("null"), Some(JsonValue::Null));
/// assert_eq!(object.len(), 0);
/// ```
pub fn remove(&mut self, key: &str) -> Option<JsonValue> {
self.get_cursor_mut(key)?.remove_current().map(|(_, v)| v)
}
/// Gets a common iterator of Object.
///
/// # Examples
/// ```
/// use ylong_json::Object;
///
/// let object = Object::new();
/// let iter = object.iter();
/// ```
pub fn iter(&self) -> Iter<'_, (String, JsonValue)> {
self.inner.iter()
}
/// Gets a mutable iterator of Object.
///
/// # Examples
/// ```
/// use ylong_json::Object;
///
/// let mut object = Object::new();
/// let iter_mut = object.iter_mut();
/// ```
pub fn iter_mut(&mut self) -> IterMut<'_, (String, JsonValue)> {
self.inner.iter_mut()
}
/// Gets a common reference to the element in Object with the specified key.
/// If there is an element with the same name, returns the one with the smallest subscript.
///
/// # Examples
/// ```
/// use ylong_json::{JsonValue, Object, Number};
///
/// let mut object = Object::new();
/// object.insert(String::from("test"), JsonValue::Number(Number::from(123)));
///
/// assert_eq!(object.get("test"), Some(&JsonValue::Number(Number::from(123))));
/// assert_eq!(object.get("no_such_key"), None);
/// ```
pub fn get(&self, key: &str) -> Option<&JsonValue> {
self.get_cursor(key)?.current().map(|(_, v)| v)
}
/// Gets a mutable reference to the element in Object with the specified key.
/// If there is an element with the same name, returns the one with the smallest subscript.
///
/// # Examples
/// ```
/// use ylong_json::{JsonValue, Object};
///
/// let mut object = Object::new();
/// object.insert(String::from("null"), JsonValue::Null);
///
/// assert_eq!(object.get_mut("null"), Some(&mut JsonValue::Null));
/// assert_eq!(object.get_mut("no_such_key"), None);
/// ```
pub fn get_mut(&mut self, key: &str) -> Option<&mut JsonValue> {
// Using get_cursor_mut causes a problem referencing temporary variables.
self.get_node_mut(key).map(|n| &mut n.get_element_mut().1)
}
/// Gets a common reference to the node in Object with the specified key.
/// If there is an element with the same name, returns the one with the smallest subscript.
///
/// After getting a common reference to a node, the node cannot be released. Otherwise, undefined behavior occurs.
///
/// # Examples
/// ```
/// use ylong_json::{JsonValue, Object};
///
/// let mut object = Object::new();
/// assert_eq!(object.get_node("no_such_key").is_none(), true);
///
/// object.insert(String::from("null"), JsonValue::Null);
/// assert_eq!(object.get_node("null").is_some(), true);
/// ```
pub fn get_node(&self, key: &str) -> Option<&Node<(String, JsonValue)>> {
self.get_cursor(key)?.current_node()
}
/// Gets a mutable reference to the node in Object with the specified key.
/// If there is an element with the same name, returns the one with the smallest subscript.
///
/// After getting a mutable reference to a node, the node cannot be released. Otherwise, undefined behavior occurs.
///
/// # Examples
/// ```
/// use ylong_json::{JsonValue, Object};
///
/// let mut object = Object::new();
/// assert_eq!(object.get_node_mut("no_such_key").is_none(), true);
///
/// object.insert(String::from("null"), JsonValue::Null);
/// assert_eq!(object.get_node_mut("null").is_some(), true);
/// ```
pub fn get_node_mut(&mut self, key: &str) -> Option<&mut Node<(String, JsonValue)>> {
self.get_cursor_mut(key)?.current_node()
}
/// Gets the last node.
#[cfg(feature = "c_adapter")]
pub(crate) fn last_node_mut(&mut self) -> Option<&mut Node<(String, JsonValue)>> {
let mut cursor = self.inner.cursor_back_mut();
let _ = cursor.index()?;
cursor.current_node()
}
/// Needs using this method to avoid the life cycle check, which involves unsafe operations.
pub(crate) fn get_key_mut_maybe_insert(&mut self, key: &str) -> &mut JsonValue {
let mut cursor = self.inner.cursor_front();
let mut ptr = null();
while cursor.index().is_some() {
let current = cursor.current().unwrap();
if current.0 == key {
ptr = cursor.current_node_ptr();
break;
}
cursor.move_next();
}
if ptr.is_null() {
self.insert(String::from(key), JsonValue::Null);
&mut self.inner.back_mut().unwrap().1
} else {
unsafe {
&mut (*(ptr as *mut Node<(String, JsonValue)>))
.get_element_mut()
.1
}
}
}
/// Gets the common cursor of the node corresponding to the specified key.
fn get_cursor(&self, key: &str) -> Option<Cursor<'_, (String, JsonValue)>> {
let mut cursor = self.inner.cursor_front();
while cursor.index().is_some() {
let (k, _) = cursor.current().unwrap();
if key == k {
return Some(cursor);
}
cursor.move_next();
}
None
}
/// Gets the mutable cursor of the node corresponding to the specified key.
fn get_cursor_mut(&mut self, key: &str) -> Option<CursorMut<'_, (String, JsonValue)>> {
let mut cursor = self.inner.cursor_front_mut();
while cursor.index().is_some() {
let (k, _) = cursor.current().unwrap();
if key == k {
return Some(cursor);
}
cursor.move_next();
}
None
}
}
impl Display for Object {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
write!(f, "{{")?;
for (n, (key, value)) in self.inner.iter().enumerate() {
if n != 0 {
write!(f, ",")?;
}
write!(f, "\"{key}\":{value}")?;
}
write!(f, "}}")
}
}
impl Debug for Object {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
Display::fmt(self, f)
}
}
#[cfg(test)]
mod ut_linked_list {
use crate::{JsonValue, Object};
/// UT test for `Object::contains_key`.
///
/// # Title
/// ut_object_contains_key
///
/// # Brief
/// 1. Creates a `Object`.
/// 2. Calls `Object::contains_key` on it.
/// 3. Checks if the test results are correct.
#[test]
fn ut_object_contains_key() {
let object = object!("key1" => "value1");
assert!(object.contains_key("key1"));
assert!(!object.contains_key("key2"));
}
/// UT test for `Object::iter_mut`.
///
/// # Title
/// ut_object_iter_mut
///
/// # Brief
/// 1. Creates a `Object`.
/// 2. Calls `Object::iter_mut` on it.
/// 3. Checks if the test results are correct.
#[test]
fn ut_object_iter_mut() {
let mut object = object!("key1" => "value1");
let mut iter_mut = object.iter_mut();
assert_eq!(
iter_mut.next(),
Some(&mut (String::from("key1"), JsonValue::new_string("value1")))
);
assert_eq!(iter_mut.next(), None);
}
/// UT test for `Object::get_mut`.
///
/// # Title
/// ut_object_get_mut
///
/// # Brief
/// 1. Creates a `Object`.
/// 2. Calls `Object::get_mut` on it.
/// 3. Checks if the test results are correct.
#[test]
fn ut_object_get_mut() {
let mut object = object!("key1" => "value1");
assert_eq!(
object.get_mut("key1"),
Some(&mut JsonValue::new_string("value1"))
);
assert_eq!(object.get_mut("key2"), None);
}
/// UT test for `Object::get_node`.
///
/// # Title
/// ut_object_get_node
///
/// # Brief
/// 1. Creates a `Object`.
/// 2. Calls `Object::get_node` on it.
/// 3. Checks if the test results are correct.
#[test]
fn ut_object_get_node() {
let object = object!("key1" => "value1");
assert!(object.get_node("key1").is_some());
assert!(object.get_node("key2").is_none());
}
/// UT test for `Object::get_node_mut`.
///
/// # Title
/// ut_object_get_node_mut
///
/// # Brief
/// 1. Creates a `Object`.
/// 2. Calls `Object::get_node_mut` on it.
/// 3. Checks if the test results are correct.
#[test]
fn ut_object_get_node_mut() {
let mut object = object!("key1" => "value1");
assert!(object.get_node_mut("key1").is_some());
assert!(object.get_node_mut("key2").is_none());
}
/// UT test for `Object::fmt`.
///
/// # Title
/// ut_object_fmt
///
/// # Brief
/// 1. Creates a `Object`.
/// 2. Calls `Object::fmt` on it.
/// 3. Checks if the test results are correct.
#[test]
fn ut_object_fmt() {
let object = object!("key1" => "value1"; "key2" => "value2");
assert_eq!(
format!("{object}"),
"{\"key1\":\"value1\",\"key2\":\"value2\"}"
);
assert_eq!(
format!("{object:?}"),
"{\"key1\":\"value1\",\"key2\":\"value2\"}"
);
}
}
+366
View File
@@ -0,0 +1,366 @@
/*
* 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 crate::JsonValue;
use core::fmt::{Debug, Display, Formatter};
use core::slice::{Iter, IterMut};
/// Object type, implemented using Vec.
///
/// # Situation
/// 1. When the average number of entries x under Object is about 15 <= x <= 100.
///
/// 2. When the average number of Object entries x is about 101 <= x <= 1024, and the creation to
/// query ratio (the average number of queries created once) < 600.
///
/// 3. When the average number of objects x is about 1025 <= x <= 10000, and the creation to
/// query ratio (the average number of queries created once) < 500.
///
/// # Attention
/// * Only opening the 'vec_object' feature, this Object type can be used , and it conflicts with other Objects.
///
/// * This Object ** does not provide the ** de-duplicate function.
/// * Users are required to ensure that there are no duplicate entries.
///
/// * The output order of this Object is the same as the insertion order.
/// # Examples
/// ```
/// use ylong_json::Object;
///
/// let object = Object::new();
/// assert_eq!(object.is_empty(), true);
/// ```
#[derive(Default, Clone)]
pub struct Object {
inner: Vec<(String, JsonValue)>,
}
impl Object {
/// Creates an empty Object.
///
/// # Examples
/// ```
/// use ylong_json::Object;
///
/// let object = Object::new();
/// assert_eq!(object.is_empty(), true);
/// ```
pub fn new() -> Self {
Self { inner: Vec::new() }
}
/// Gets the length of Object.
///
/// # Examples
/// ```
/// use ylong_json::{JsonValue, Object};
///
/// let mut object = Object::new();
/// assert_eq!(object.len(), 0);
/// object.insert(String::from("null"), JsonValue::Null);
/// assert_eq!(object.len(), 1);
/// ```
pub fn len(&self) -> usize {
self.inner.len()
}
/// Determines whether the Object is empty.
///
/// # Examples
/// ```
/// use ylong_json::{JsonValue, Object};
///
/// let mut object = Object::new();
/// assert_eq!(object.is_empty(), true);
/// object.insert(String::from("null"), JsonValue::Null);
/// assert_eq!(object.is_empty(), false);
/// ```
pub fn is_empty(&self) -> bool {
self.inner.is_empty()
}
/// Checks whether the specified key exists in the Object.
///
/// # Examples
/// ```
/// use ylong_json::{JsonValue, Object, Number};
///
/// let mut object = Object::new();
/// object.insert(String::from("null"), JsonValue::Null);
///
/// assert_eq!(object.contains_key("null"), true);
/// assert_eq!(object.contains_key("no_such_key"), false);
/// ```
pub fn contains_key(&self, key: &str) -> bool {
self.inner.iter().any(|(k, _)| k == key)
}
/// Inserts the specified key and value into an Object, appending them to the end without deduplication.
///
/// # Examples
/// ```
/// use ylong_json::{JsonValue, Object};
///
/// let mut object = Object::new();
/// assert_eq!(object.len(), 0);
/// object.insert(String::from("null"), JsonValue::Null);
/// assert_eq!(object.len(), 1);
/// ```
pub fn insert(&mut self, key: String, value: JsonValue) {
self.inner.push((key, value))
}
/// Removes the element under the specified key from the Object.If there is an element with
/// the same name in the Object, deletes the one with the smallest subscript.
///
/// # Examples
/// ```
/// use ylong_json::{JsonValue, Object, Number};
///
/// let mut object = Object::new();
/// object.insert(String::from("null"), JsonValue::Null);
/// assert_eq!(object.len(), 1);
/// assert_eq!(object.remove("null"), Some(JsonValue::Null));
/// assert_eq!(object.len(), 0);
/// ```
pub fn remove(&mut self, key: &str) -> Option<JsonValue> {
let pos = self.inner.iter().position(|(k, _)| k == key)?;
Some(self.inner.remove(pos).1)
}
/// Gets a common iterator of Object.
///
/// # Examples
/// ```
/// use ylong_json::Object;
///
/// let object = Object::new();
/// let iter = object.iter();
/// ```
pub fn iter(&self) -> Iter<'_, (String, JsonValue)> {
self.inner.iter()
}
/// Gets a mutable iterator of Object.
///
/// # Examples
/// ```
/// use ylong_json::Object;
///
/// let mut object = Object::new();
/// let iter_mut = object.iter_mut();
/// ```
pub fn iter_mut(&mut self) -> IterMut<'_, (String, JsonValue)> {
self.inner.iter_mut()
}
/// Gets a common reference to the element in Object with the specified key.
/// If there is an element with the same name, returns the one with the smallest subscript.
///
/// # Examples
/// ```
/// use ylong_json::{JsonValue, Object, Number};
///
/// let mut object = Object::new();
/// object.insert(String::from("test"), JsonValue::Number(Number::from(123)));
///
/// assert_eq!(object.get("test"), Some(&JsonValue::Number(Number::from(123))));
/// assert_eq!(object.get("no_such_key"), None);
/// ```
pub fn get(&self, key: &str) -> Option<&JsonValue> {
self.inner.iter().find(|(k, _)| k == key).map(|(_, v)| v)
}
/// Gets a mutable reference to the element in Object with the specified key.
/// If there is an element with the same name, returns the one with the smallest subscript.
///
/// # Examples
/// ```
/// use ylong_json::{JsonValue, Object};
///
/// let mut object = Object::new();
/// object.insert(String::from("null"), JsonValue::Null);
///
/// assert_eq!(object.get_mut("null"), Some(&mut JsonValue::Null));
/// assert_eq!(object.get_mut("no_such_key"), None);
/// ```
pub fn get_mut(&mut self, key: &str) -> Option<&mut JsonValue> {
self.inner
.iter_mut()
.find(|(k, _)| k == key)
.map(|(_, v)| v)
}
/// Gets a mutable reference to the last element.
pub(crate) fn last_mut(&mut self) -> Option<&mut JsonValue> {
self.inner.last_mut().map(|(_, v)| v)
}
pub(crate) fn get_mut_by_position(&mut self, index: usize) -> Option<&mut JsonValue> {
self.inner.get_mut(index).map(|(_, v)| v)
}
}
impl PartialEq for Object {
/// Determines whether two objects are equal.
///
/// The condition for two objects to be equal is that the two objects are of equal length
/// and the key-value pair can be one-to-one and exactly equal.
///
/// # Examples
/// ```
/// use ylong_json::{Object, JsonValue};
///
/// let object1 = Object::new();
/// let object2 = Object::new();
/// let mut object3 = Object::new();
/// object3.insert("test".to_string(), JsonValue::Null);
///
/// assert_eq!(object1, object2);
/// assert_ne!(object1, object3);
/// ```
fn eq(&self, other: &Self) -> bool {
if self.len() != other.len() {
return false;
}
for (k, v) in self.iter() {
if other.get(k) != Some(v) {
return false;
}
}
true
}
}
impl Display for Object {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
write!(f, "{{")?;
for (n, (key, value)) in self.inner.iter().enumerate() {
if n != 0 {
write!(f, ",")?;
}
write!(f, "\"{key}\":{value}")?;
}
write!(f, "}}")
}
}
impl Debug for Object {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
Display::fmt(self, f)
}
}
#[cfg(test)]
mod ut_vec {
use crate::{JsonValue, Object};
/// UT test for `Object::contains_key`.
///
/// # Title
/// ut_object_contains_key
///
/// # Brief
/// 1. Creates a `Object`.
/// 2. Calls `Object::contains_key` on it.
/// 3. Checks if the test results are correct.
#[test]
fn ut_object_contains_key() {
let object = object!("key1" => "value1");
assert!(object.contains_key("key1"));
assert!(!object.contains_key("key2"));
}
/// UT test for `Object::iter_mut`.
///
/// # Title
/// ut_object_iter_mut
///
/// # Brief
/// 1. Creates a `Object`.
/// 2. Calls `Object::iter_mut` on it.
/// 3. Checks if the test results are correct.
#[test]
fn ut_object_iter_mut() {
let mut object = object!("key1" => "value1");
let mut iter_mut = object.iter_mut();
assert_eq!(
iter_mut.next(),
Some(&mut (String::from("key1"), JsonValue::new_string("value1")))
);
assert_eq!(iter_mut.next(), None);
}
/// UT test for `Object::get_mut`.
///
/// # Title
/// ut_object_get_mut
///
/// # Brief
/// 1. Creates a `Object`.
/// 2. Calls `Object::get_mut` on it.
/// 3. Checks if the test results are correct.
#[test]
fn ut_object_get_mut() {
let mut object = object!("key1" => "value1");
assert_eq!(
object.get_mut("key1"),
Some(&mut JsonValue::new_string("value1"))
);
assert_eq!(object.get_mut("key2"), None);
}
/// UT test for `Object::fmt`.
///
/// # Title
/// ut_object_fmt
///
/// # Brief
/// 1. Creates a `Object`.
/// 2. Calls `Object::fmt` on it.
/// 3. Checks if the test results are correct.
#[test]
fn ut_object_fmt() {
let object = object!("key1" => "value1"; "key2" => "value2");
assert_eq!(
format!("{object}"),
"{\"key1\":\"value1\",\"key2\":\"value2\"}"
);
assert_eq!(
format!("{object:?}"),
"{\"key1\":\"value1\",\"key2\":\"value2\"}"
);
}
/// UT test for `Object::eq`.
///
/// # Title
/// ut_object_fmt
///
/// # Brief
/// 1. Creates a `Object`.
/// 2. Calls `Object::eq` on it.
/// 3. Checks if the test results are correct.
#[test]
fn ut_object_eq() {
let object1 = object!("key1" => "value1");
let object2 = object!("key1" => "value1"; "key2" => "value2");
let object3 = object!("key1" => "value1"; "key3" => "value3");
assert_eq!(object1, object1);
assert_ne!(object1, object2);
assert_ne!(object2, object3);
}
}
+265
View File
@@ -0,0 +1,265 @@
/*
* 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 std::ffi::{CStr, CString};
use std::os::raw::{c_char, c_double, c_int};
use std::ptr::*;
use ylong_json::*;
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]
}
}
"#;
macro_rules! test_json {
($json: expr) => {{
let target = str_to_c_char("Image");
let image = ylong_json_get_object_item($json, target);
let _ = CString::from_raw(target);
assert_eq!(ylong_json_is_object(image), 1);
let target = str_to_c_char("Width");
let width = ylong_json_get_object_item(image, target);
let _ = CString::from_raw(target);
let mut ptr: c_double = 0f64;
assert_eq!(
ylong_json_get_double_value_from_number(width, &mut ptr as *mut c_double),
1
);
assert_eq!(ptr, 800f64);
let target = str_to_c_char("Height");
let height = ylong_json_get_object_item(image, target);
let _ = CString::from_raw(target);
let mut ptr: c_double = 0f64;
assert_eq!(
ylong_json_get_double_value_from_number(height, &mut ptr as *mut c_double),
1
);
assert_eq!(ptr, 600f64);
let target = str_to_c_char("Title");
let title = ylong_json_get_object_item(image, target);
let _ = CString::from_raw(target);
let mut ptr: *mut c_char = null_mut::<c_char>();
assert_eq!(
ylong_json_get_value_from_string(title, &mut ptr as *mut *mut c_char),
1
);
assert_eq!(
CStr::from_ptr(ptr).to_str().unwrap(),
"View from 15th Floor"
);
let target = str_to_c_char("Thumbnail");
let thumbnail = ylong_json_get_object_item(image, target);
let _ = CString::from_raw(target);
assert_eq!(ylong_json_is_object(thumbnail), 1);
let target = str_to_c_char("Url");
let url = ylong_json_get_object_item(thumbnail, target);
let _ = CString::from_raw(target);
let mut ptr: *mut c_char = null_mut::<c_char>();
assert_eq!(
ylong_json_get_value_from_string(url, &mut ptr as *mut *mut c_char),
1
);
assert_eq!(
CStr::from_ptr(ptr).to_str().unwrap(),
"http://www.example.com/image/481989943"
);
let target = str_to_c_char("Height");
let height = ylong_json_get_object_item(thumbnail, target);
let _ = CString::from_raw(target);
let mut ptr: c_double = 0f64;
assert_eq!(
ylong_json_get_double_value_from_number(height, &mut ptr as *mut c_double),
1
);
assert_eq!(ptr, 125f64);
let target = str_to_c_char("Width");
let width = ylong_json_get_object_item(thumbnail, target);
let _ = CString::from_raw(target);
let mut ptr: c_double = 0f64;
assert_eq!(
ylong_json_get_double_value_from_number(width, &mut ptr as *mut c_double),
1
);
assert_eq!(ptr, 100f64);
let target = str_to_c_char("Animated");
let animated = ylong_json_get_object_item(image, target);
let _ = CString::from_raw(target);
let mut ptr: c_int = 0;
assert_eq!(
ylong_json_get_value_from_bool(animated, &mut ptr as *mut c_int),
1
);
assert_eq!(ptr, 0);
let target = str_to_c_char("IDs");
let ids = ylong_json_get_object_item(image, target);
let _ = CString::from_raw(target);
assert_eq!(ylong_json_is_array(ids), 1);
let item = ylong_json_get_array_item(ids, 0);
let mut ptr = 0f64;
assert_eq!(
ylong_json_get_double_value_from_number(item, &mut ptr as *mut c_double),
1
);
assert_eq!(ptr, 116f64);
let item = ylong_json_get_array_item(ids, 1);
let mut ptr = 0f64;
assert_eq!(
ylong_json_get_double_value_from_number(item, &mut ptr as *mut c_double),
1
);
assert_eq!(ptr, 943f64);
let item = ylong_json_get_array_item(ids, 2);
let mut ptr = 0f64;
assert_eq!(
ylong_json_get_double_value_from_number(item, &mut ptr as *mut c_double),
1
);
assert_eq!(ptr, 234f64);
let item = ylong_json_get_array_item(ids, 3);
let mut ptr = 0f64;
assert_eq!(
ylong_json_get_double_value_from_number(item, &mut ptr as *mut c_double),
1
);
assert_eq!(ptr, 38793f64);
}};
}
#[test]
fn sdv_adapter_test() {
unsafe {
sdv_adapter_parse_and_print();
sdv_adapter_parse_memory_check();
}
}
unsafe fn str_to_c_char(str: &str) -> *mut c_char {
CString::from_vec_unchecked(str.as_bytes().to_vec()).into_raw()
}
unsafe fn sdv_adapter_parse_and_print() {
let text = str_to_c_char(RFC7159_EXAMPLE1);
let msg = null_mut::<c_char>();
let mut json = Some(ylong_json_parse(
text,
&msg as *const *mut c_char as *mut *mut c_char,
));
for _ in 0..1000 {
let curr = json.take().unwrap();
let curr_str = ylong_json_print_unformatted(curr);
let msg = null_mut::<c_char>();
let new = ylong_json_parse(curr_str, &msg as *const *mut c_char as *mut *mut c_char);
let _ = CString::from_raw(curr_str);
test_json!(new);
json = Some(new);
ylong_json_delete(curr);
}
ylong_json_delete(json.take().unwrap());
// 析构 text
let _ = CString::from_raw(text);
}
unsafe fn sdv_adapter_parse_memory_check() {
const TEXT: &str = r#"
{
"null": null,
"true": true,
"false": false,
"number": 3.14,
"string": "Hello World!",
"array": [1, 2, 3],
"object": {
"key1": 1,
"key2": 2,
"key3": 3
}
}
"#;
let text = str_to_c_char(TEXT);
let msg = null_mut::<c_char>();
let json = ylong_json_parse(text, &msg as *const *mut c_char as *mut *mut c_char);
let _ = Box::from_raw(text);
assert!(msg.is_null());
let result = ylong_json_print_unformatted(json);
ylong_json_free_string(result);
let duplicate = ylong_json_duplicate(json, 1);
ylong_json_delete(duplicate);
let null = ylong_json_create_null();
ylong_json_delete(null);
let index = str_to_c_char("string");
let string = ylong_json_get_object_item(json, index);
let content = null_mut::<c_char>();
ylong_json_get_value_from_string(string, &content as *const *mut c_char as *mut *mut c_char);
let _ = Box::from_raw(index);
let null = ylong_json_create_null();
let index = str_to_c_char("123");
ylong_json_add_item_to_object(json, index, null);
let content = str_to_c_char("aaaa");
let string = ylong_json_create_string(content);
ylong_json_replace_object_item_by_index(json, index, string);
let _ = Box::from_raw(content);
let removed = ylong_json_remove_object_item_by_index(json, index);
ylong_json_delete(removed);
let _ = Box::from_raw(index);
extern "C" fn func(_value: *mut YlongJson) {}
ylong_json_for_each_object_item(json, func);
ylong_json_delete(json);
}
+381
View File
@@ -0,0 +1,381 @@
/*
* 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 ylong_json::{Array, JsonValue, Object};
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]
}
}
"#;
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"
}
]
"#;
const JSON_PARSE_TEST: &str = r#"
[
{
"null1": null
},
{
"boolean1": true,
"boolean2": false
},
{
"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
},
{
"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"
},
{
"array1": [],
"array2": [
],
"array3": [null,true,0.0,"string",[],{}],
"array4": [
null , true, 0.0 ,
"string", []
, {} ],
"array5": [[[[[[["nest"]]]]]]]
},
{
"object1": {},
"object2": {
},
"object3": {"key1":null,"key2":true,"key3":0.0,"key4":"string","key5":[],"key6":{}},
"object4": {
"key1" : null , "key2"
: true , "key3" :
0.0 , "key4":"string" ,
"key5": [], "key6": {
}
},
"object5": {"nest1": {"nest2": {"nest3": {"nest4": {}}}}}
},
{
"": "key1",
"\/\\\"\uCAFE\uBABE\uAB98\uFCDE\ubcda\uef4A\b\f\n\r\t`1~!@#$%^&*()_+-=[]{}|;:',./<>?" : "key2"
},
{
"key_value1"
: "value"
, "key_value2" : [
] , "key_value3" :
{}
}
]
"#;
macro_rules! rfc7159_example1_check {
($json: expr) => {
assert_eq!($json["Image"]["Width"], 800.into());
assert_eq!($json["Image"]["Height"], 600.into());
assert_eq!($json["Image"]["Title"], "View from 15th Floor".into());
assert_eq!(
$json["Image"]["Thumbnail"]["Url"],
"http://www.example.com/image/481989943".into()
);
assert_eq!($json["Image"]["Thumbnail"]["Height"], 125.into());
assert_eq!($json["Image"]["Thumbnail"]["Width"], 100.into());
assert_eq!($json["Image"]["Animated"], false.into());
assert_eq!($json["Image"]["IDs"][0], 116.into());
assert_eq!($json["Image"]["IDs"][1], 943.into());
assert_eq!($json["Image"]["IDs"][2], 234.into());
assert_eq!($json["Image"]["IDs"][3], 38793.into());
};
}
macro_rules! rfc7159_example2_check {
($json: expr) => {
assert_eq!($json[0]["precision"], "zip".into());
assert_eq!($json[0]["Latitude"], 37.7668.into());
assert_eq!($json[0]["Longitude"], (-122.3959).into());
assert_eq!($json[0]["Address"], "".into());
assert_eq!($json[0]["City"], "SAN FRANCISCO".into());
assert_eq!($json[0]["State"], "CA".into());
assert_eq!($json[0]["Zip"], "94107".into());
assert_eq!($json[0]["Country"], "US".into());
assert_eq!($json[1]["precision"], "zip".into());
assert_eq!($json[1]["Latitude"], 37.371991.into());
assert_eq!($json[1]["Longitude"], (-122.026020).into());
assert_eq!($json[1]["Address"], "".into());
assert_eq!($json[1]["City"], "SUNNYVALE".into());
assert_eq!($json[1]["State"], "CA".into());
assert_eq!($json[1]["Zip"], "94085".into());
assert_eq!($json[1]["Country"], "US".into());
};
}
macro_rules! json_parse_test_check {
($json: expr) => {
assert_eq!($json[0]["null1"], JsonValue::new_null());
assert_eq!($json[1]["boolean1"], true.into());
assert_eq!($json[1]["boolean2"], false.into());
assert_eq!($json[2]["number1"], 0.into());
assert_eq!($json[2]["number2"], 0.into());
assert_eq!($json[2]["number3"], 123.into());
assert_eq!($json[2]["number4"], (-123).into());
assert_eq!($json[2]["number5"], 123.456.into());
assert_eq!($json[2]["number6"], (-123.456).into());
assert_eq!($json[2]["number7"], 1234560000.into());
assert_eq!($json[2]["number8"], 0.0000123456.into());
assert_eq!($json[2]["number9"], 1234560000.into());
assert_eq!($json[2]["number10"], 0.0000123456.into());
assert_eq!($json[2]["number11"], (-1234560000).into());
assert_eq!($json[2]["number12"], (-0.0000123456).into());
assert_eq!($json[2]["number13"], (-1234560000).into());
assert_eq!($json[2]["number14"], (-0.0000123456).into());
assert_eq!($json[2]["number15"], 0.into());
assert_eq!($json[2]["number16"], 0.into());
assert_eq!($json[2]["number17"], 300.into());
assert_eq!($json[3]["string1"], "".into());
assert_eq!($json[3]["string2"], "Hello World".into());
assert_eq!($json[3]["string3"], "abcdefghijklmnopqrstuvwxyz".into());
assert_eq!($json[3]["string4"], "ABCDEFGHIJKLMNOPQRSTUVWXYZ".into());
assert_eq!($json[3]["string5"], "0123456789".into());
assert_eq!($json[3]["string6"], " \u{0008}\u{000c}\n\r\t".into());
assert_eq!($json[3]["string7"], "\"\\/".into());
assert_eq!($json[3]["string8"], "`1~!@#$%^&*()_+-={':[,]}|;.</>?".into());
assert_eq!($json[3]["string9"], "\u{0123}\u{4567}\u{89AB}\u{CDEF}\u{abcd}\u{ef4A}".into());
assert_eq!($json[4]["array1"], Array::new().into());
assert_eq!($json[4]["array2"], Array::new().into());
assert_eq!($json[4]["array3"][0], JsonValue::new_null());
assert_eq!($json[4]["array3"][1], true.into());
assert_eq!($json[4]["array3"][2], 0.into());
assert_eq!($json[4]["array3"][3], "string".into());
assert_eq!($json[4]["array3"][4], Array::new().into());
assert_eq!($json[4]["array3"][5], Object::new().into());
assert_eq!($json[4]["array4"][0], JsonValue::new_null());
assert_eq!($json[4]["array4"][1], true.into());
assert_eq!($json[4]["array4"][2], 0.into());
assert_eq!($json[4]["array4"][3], "string".into());
assert_eq!($json[4]["array4"][4], Array::new().into());
assert_eq!($json[4]["array4"][5], Object::new().into());
assert_eq!($json[4]["array5"][0][0][0][0][0][0][0], "nest".into());
assert_eq!($json[5]["object1"], Object::new().into());
assert_eq!($json[5]["object2"], Object::new().into());
assert_eq!($json[5]["object3"]["key1"], JsonValue::new_null());
assert_eq!($json[5]["object3"]["key2"], true.into());
assert_eq!($json[5]["object3"]["key3"], 0.into());
assert_eq!($json[5]["object3"]["key4"], "string".into());
assert_eq!($json[5]["object3"]["key5"], Array::new().into());
assert_eq!($json[5]["object3"]["key6"], Object::new().into());
assert_eq!($json[5]["object4"]["key1"], JsonValue::new_null());
assert_eq!($json[5]["object4"]["key2"], true.into());
assert_eq!($json[5]["object4"]["key3"], 0.into());
assert_eq!($json[5]["object4"]["key4"], "string".into());
assert_eq!($json[5]["object4"]["key5"], Array::new().into());
assert_eq!($json[5]["object4"]["key6"], Object::new().into());
assert_eq!($json[5]["object5"]["nest1"]["nest2"]["nest3"]["nest4"], Object::new().into());
assert_eq!($json[6][""], "key1".into());
assert_eq!(
$json[6]["/\\\"\u{CAFE}\u{BABE}\u{AB98}\u{FCDE}\u{bcda}\u{ef4A}\u{0008}\u{000c}\n\r\t`1~!@#$%^&*()_+-=[]{}|;:',./<>?"],
"key2".into()
);
assert_eq!($json[7]["key_value1"], "value".into());
assert_eq!($json[7]["key_value2"], Array::new().into());
assert_eq!($json[7]["key_value3"], Object::new().into());
}
}
/*
* @title ylong_json sdv 测试用例
* @design 使用路径覆盖
* @precon 无
* @brief 1. 准备一个 json 文本
* 2. 根据该文本创建一个 Json 实例
* 3. 修改该实例中的值
* 4. 以字符串形式输出到指定位置
* 5. 校验输出结果
* @expect 1. 得到预期输出的字符串。
* @auto 是
*/
#[test]
fn sdv_ylong_json() {
sdv_json_parse();
sdv_json_modify();
sdv_json_output();
}
fn sdv_json_parse() {
// 测试 RFC7159 13. Examples 里的两个 json 文本。
let json = JsonValue::from_text(RFC7159_EXAMPLE1).unwrap();
rfc7159_example1_check!(json);
let json = JsonValue::from_text(RFC7159_EXAMPLE2).unwrap();
rfc7159_example2_check!(json);
let json = JsonValue::from_text(JSON_PARSE_TEST).unwrap();
json_parse_test_check!(json);
}
fn sdv_json_modify() {
let json_text = "{}";
let mut json = JsonValue::from_text(json_text).unwrap();
// 初始时 json 为空。
assert!(json.try_as_object().unwrap().is_empty());
json["null"] = JsonValue::new_null();
json["boolean"] = true.into();
json["number"] = 123.into();
json["string"] = "Hello World".into();
json["array"] = Array::new().into();
json["object"] = Object::new().into();
assert!(json["null"].is_null());
assert_eq!(json["boolean"], true.into());
assert_eq!(json["number"], 123.into());
assert_eq!(json["string"], "Hello World".into());
assert_eq!(json["array"], Array::new().into());
assert_eq!(json["object"], Object::new().into());
assert_eq!(json.try_as_object().unwrap().len(), 6);
json["array"][0] = 123.into();
json["array"][1] = "string".into();
json["array"][2] = JsonValue::new_null();
assert_eq!(json["array"][0], 123.into());
assert_eq!(json["array"][1], "string".into());
assert_eq!(json["array"][2], JsonValue::new_null());
assert_eq!(json["array"].try_as_array().unwrap().len(), 3);
json["array"] = Array::new().into();
assert_eq!(json["array"].try_as_array().unwrap().len(), 0);
json["object"]["number"] = 123.into();
json["object"]["string"] = "string".into();
json["object"]["null"] = JsonValue::new_null();
assert_eq!(json["object"]["number"], 123.into());
assert_eq!(json["object"]["string"], "string".into());
assert_eq!(json["object"]["null"], JsonValue::new_null());
assert_eq!(json["object"].try_as_object().unwrap().len(), 3);
json["object"] = Object::new().into();
assert_eq!(json["object"].try_as_object().unwrap().len(), 0);
}
#[allow(unused_assignments)]
fn sdv_json_output() {
const LOOPS_NUM: usize = 1000;
let mut json = JsonValue::from_text(RFC7159_EXAMPLE1).unwrap();
let mut vec = Vec::new();
for _ in 0..LOOPS_NUM {
// 将 json 内容写入 vec 中
vec.clear();
assert!(json.formatted_encode(&mut vec).is_ok());
// 通过 vec 重新生成一个 json 实例
let temp = JsonValue::from_text(&vec).unwrap();
// 比较内容是否发生变化
rfc7159_example1_check!(temp);
json = temp;
}
let mut json = JsonValue::from_text(RFC7159_EXAMPLE2).unwrap();
let mut vec = Vec::new();
for _ in 0..LOOPS_NUM {
// 将 json 内容写入 vec 中
vec.clear();
assert!(json.formatted_encode(&mut vec).is_ok());
// 通过 vec 重新生成一个 json 实例
let temp = JsonValue::from_text(&vec).unwrap();
// 比较内容是否发生变化
rfc7159_example2_check!(temp);
json = temp;
}
let mut json = JsonValue::from_text(JSON_PARSE_TEST).unwrap();
let mut vec = Vec::new();
for _ in 0..LOOPS_NUM {
// 将 json 内容写入 vec 中
vec.clear();
assert!(json.formatted_encode(&mut vec).is_ok());
// 通过 vec 重新生成一个 json 实例
let temp = JsonValue::from_text(&vec).unwrap();
// 比较内容是否发生变化
json_parse_test_check!(temp);
json = temp;
}
}