diff --git a/Cargo.toml b/Cargo.toml
new file mode 100644
index 0000000000000000000000000000000000000000..e3a0c400ccef867caabe9013ad2e9cb8c755c599
--- /dev/null
+++ b/Cargo.toml
@@ -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 = []
\ No newline at end of file
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000000000000000000000000000000000000..261eeb9e9f8b2b4b0d119366dda99c6fd7d35c64
--- /dev/null
+++ b/LICENSE
@@ -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.
diff --git a/OAT.xml b/OAT.xml
new file mode 100644
index 0000000000000000000000000000000000000000..d09d3be7810c866745a4dea23919cdc2639097ea
--- /dev/null
+++ b/OAT.xml
@@ -0,0 +1,71 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/README.en.md b/README.en.md
deleted file mode 100644
index b7ad888eb7e41fa4ba66b2ea88376150bf474f08..0000000000000000000000000000000000000000
--- a/README.en.md
+++ /dev/null
@@ -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/)
diff --git a/README.md b/README.md
index 92e172385b7a5d5bea31b5ad9d3eb63a2a16c6fa..bee32da03612426153125cb68e35b5e0e4b8367f 100644
--- a/README.md
+++ b/README.md
@@ -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 = 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,
+ 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::(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::(slice).unwrap();
+
+ // 可以使用 from_reader 接口,从实现了 io::Write 的位置、文件、io流等生成实例。
+ // 如果传入的文本内容不符合 JSON 语法,会返回对应的 Error。
+ let mut file: File = File::open("./example.txt").unwrap();
+ let example = from_reader::(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 # 测试目录
+```
\ No newline at end of file
diff --git a/README_EN.md b/README_EN.md
new file mode 100644
index 0000000000000000000000000000000000000000..5ce124f223f16205d97146c6645005638af73654
--- /dev/null
+++ b/README_EN.md
@@ -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 = 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,
+ 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::(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::(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::(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 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
+```
\ No newline at end of file
diff --git a/benches/deserialize_json_cmp.rs b/benches/deserialize_json_cmp.rs
new file mode 100644
index 0000000000000000000000000000000000000000..4b3f6500ee83bee49546a5b748788c44cfca641c
--- /dev/null
+++ b/benches/deserialize_json_cmp.rs
@@ -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();
+ }
+ });
+ }
+}
diff --git a/benches/serialize_json_cmp.rs b/benches/serialize_json_cmp.rs
new file mode 100644
index 0000000000000000000000000000000000000000..27e0c3d21ecb804e2e6bb58904722d1c2c961c34
--- /dev/null
+++ b/benches/serialize_json_cmp.rs
@@ -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}");
+ }
+ });
+ }
+}
diff --git a/benches/task_helpers/mod.rs b/benches/task_helpers/mod.rs
new file mode 100644
index 0000000000000000000000000000000000000000..0d9775952c7766ca3d66eb3772d0295de9f9c219
--- /dev/null
+++ b/benches/task_helpers/mod.rs
@@ -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"
+ }
+}
+"#;
diff --git a/examples/ylong_json_example.rs b/examples/ylong_json_example.rs
new file mode 100644
index 0000000000000000000000000000000000000000..1ff754fbe50f84cc1949b2ac632a8b9634fa4fb3
--- /dev/null
+++ b/examples/ylong_json_example.rs
@@ -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();
+}
diff --git a/examples/ylong_json_perf.rs b/examples/ylong_json_perf.rs
new file mode 100644
index 0000000000000000000000000000000000000000..0472c3d17ea93bbe9b6dadba0f38066c1e23a5cc
--- /dev/null
+++ b/examples/ylong_json_perf.rs
@@ -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
+ );
+}
diff --git a/src/adapter.rs b/src/adapter.rs
new file mode 100644
index 0000000000000000000000000000000000000000..d9fdb8ffcbbbda133ea1f65a2d24b0d7c7d785a6
--- /dev/null
+++ b/src/adapter.rs
@@ -0,0 +1,3409 @@
+/*
+ * 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(clippy::missing_safety_doc)]
+
+use crate::*;
+use core::ptr::{null_mut, slice_from_raw_parts};
+use core::str::from_utf8_unchecked;
+use libc::{c_char, c_double, c_int, c_longlong, c_void, strlen};
+use std::ffi::CString;
+
+/// Boolean value mapping.
+const FALSE: c_int = 0;
+
+/// Operation success or failure.
+const SUCCESS: c_int = 1;
+const FAILURE: c_int = 0;
+
+/// Empty pointer of YlongJson*
+const NULL_MUT_YLONG_JSON: *mut YlongJson = null_mut::();
+/// Empty pointer of char*
+const NULL_MUT_CSTR: *mut c_char = null_mut::();
+
+/// A void* pointer is passed to C for use.
+pub type YlongJson = c_void;
+
+/// Parses a JSON text string.
+/// Returns a JSON object on success and null on failure.
+#[no_mangle]
+pub unsafe extern "C" fn ylong_json_parse(
+ value: *mut c_char,
+ err_msg: *mut *mut c_char,
+) -> *mut YlongJson {
+ // Using `ptr::slice_from_raw_parts` here dramatically
+ // reduces the cost of converting between char* and &[u8].
+ let len = strlen(value);
+ let slice = &*slice_from_raw_parts(value as *mut u8, len);
+
+ let value = match JsonValue::from_text(slice) {
+ Ok(v) => v,
+ Err(e) => {
+ // If an error occurs, writes error messages into err_msg.
+ *err_msg = CString::from_vec_unchecked(e.to_string().into_bytes()).into_raw();
+ return NULL_MUT_YLONG_JSON;
+ }
+ };
+
+ Box::into_raw(Box::from(value)) as *mut YlongJson
+}
+
+/// Frees a C string.
+#[no_mangle]
+pub unsafe extern "C" fn ylong_json_free_string(string: *mut c_char) {
+ if string.is_null() {
+ return;
+ }
+
+ let _ = Box::from_raw(string);
+}
+
+/// Outputs a JSON object to a string in plain format.
+/// Returns a C string on success and null on failure.
+#[no_mangle]
+pub unsafe extern "C" fn ylong_json_print_unformatted(item: *const YlongJson) -> *mut c_char {
+ if item.is_null() {
+ return NULL_MUT_CSTR;
+ }
+
+ let value = &mut *(item as *mut JsonValue);
+
+ // Requests 256 bytes of memory in advance to improve output efficiency.
+ // Here we use `Vec::with_capacity(256)`, which performs better when `12 < string.len() < 256`.
+ // If here we use `Vec::new()`, it performs better when `string.len() < 32 || 256 > string.len()`
+ // In most cases, `12 < the average string.len() < 256`, so we use `Vec::with_capacity()`.
+ let mut vec = Vec::with_capacity(256);
+ if value.compact_encode(&mut vec).is_err() {
+ return NULL_MUT_CSTR;
+ }
+
+ CString::from_vec_unchecked(vec).into_raw()
+}
+
+/// Deletes a JSON object.
+#[no_mangle]
+pub unsafe extern "C" fn ylong_json_delete(item: *mut YlongJson) {
+ if item.is_null() {
+ return;
+ }
+
+ let _ = Box::from_raw(item as *mut JsonValue);
+}
+
+/// Duplicates a JSON object.
+/// Return a new JSON object on success and null on failure.
+#[no_mangle]
+pub unsafe extern "C" fn ylong_json_duplicate(
+ item: *const YlongJson,
+ recurse: c_int,
+) -> *mut YlongJson {
+ if item.is_null() {
+ return NULL_MUT_YLONG_JSON;
+ }
+
+ if recurse == FALSE {
+ let value = &*(item as *mut JsonValue);
+ let value_clone = match value {
+ JsonValue::Array(_) => JsonValue::Array(Array::new()),
+ JsonValue::Object(_) => JsonValue::Object(Object::new()),
+ x => x.clone(),
+ };
+ return Box::into_raw(Box::from(value_clone)) as *mut YlongJson;
+ }
+
+ let value = &*(item as *mut JsonValue);
+ Box::into_raw(Box::from(value.clone())) as *mut YlongJson
+}
+
+/// Creates a JSON null object and returns a new JSON null object.
+#[no_mangle]
+pub unsafe extern "C" fn ylong_json_create_null() -> *mut YlongJson {
+ Box::into_raw(Box::from(JsonValue::Null)) as *mut YlongJson
+}
+
+/// Checks whether a JSON object is null.
+/// Returns a boolean value indicating whether the object is null.
+#[no_mangle]
+pub unsafe extern "C" fn ylong_json_is_null(item: *mut YlongJson) -> c_int {
+ if item.is_null() {
+ return FALSE;
+ }
+
+ let item = &*(item as *mut JsonValue);
+
+ item.is_null() as c_int
+}
+
+/// Creates a JSON boolean object.
+#[no_mangle]
+pub unsafe extern "C" fn ylong_json_create_bool(boolean: c_int) -> *mut YlongJson {
+ // If it is equal to 0, the result is false. Otherwise it is true.
+ Box::into_raw(Box::from(JsonValue::Boolean(boolean != FALSE))) as *mut YlongJson
+}
+
+/// Checks whether a JSON object is a boolean.
+#[no_mangle]
+pub unsafe extern "C" fn ylong_json_is_bool(item: *const YlongJson) -> c_int {
+ if item.is_null() {
+ return FALSE;
+ }
+
+ let item = &*(item as *mut JsonValue);
+
+ item.is_boolean() as c_int
+}
+
+/// Gets the boolean value of a JSON boolean object.
+/// Returns a boolean value on success and an error code on failure.
+#[no_mangle]
+pub unsafe extern "C" fn ylong_json_get_value_from_bool(
+ boolean: *const YlongJson,
+ value: *mut c_int,
+) -> c_int {
+ if boolean.is_null() {
+ return FAILURE;
+ }
+
+ let boolean = &*(boolean as *mut JsonValue);
+ let boolean = match boolean.try_as_boolean() {
+ Ok(b) => b,
+ Err(_) => return FAILURE,
+ };
+ // For c_int value, true maps to 1, while false maps to 0.
+ *value = *boolean as c_int;
+ SUCCESS
+}
+
+/// Sets the boolean value of a JSON boolean object.
+/// Returns a `c_int` indicating whether the operation was successful (SUCCESS) or failed (FAILURE).
+#[no_mangle]
+pub unsafe extern "C" fn ylong_json_set_value_to_bool(
+ boolean: *mut YlongJson,
+ value: c_int,
+) -> c_int {
+ if boolean.is_null() {
+ return FAILURE;
+ }
+
+ let boolean = &mut *(boolean as *mut JsonValue);
+ let boolean = match boolean.try_as_mut_boolean() {
+ Ok(b) => b,
+ Err(_) => return FAILURE,
+ };
+ // The *boolean is false if value is 0, and true if value is not 1.
+ *boolean = value != FALSE;
+ SUCCESS
+}
+
+/// Creates a JSON double number object.
+/// Returns a pointer to the newly created JSON number.
+#[no_mangle]
+pub unsafe extern "C" fn ylong_json_create_double_number(number: c_double) -> *mut YlongJson {
+ Box::into_raw(Box::from(JsonValue::Number(Number::Float(number)))) as *mut YlongJson
+}
+
+/// Creates a JSON integer number object.
+/// Returns a pointer to the newly created JSON number.
+#[no_mangle]
+pub unsafe extern "C" fn ylong_json_create_int_number(number: c_longlong) -> *mut YlongJson {
+ Box::into_raw(Box::from(JsonValue::Number(Number::Signed(number)))) as *mut YlongJson
+}
+
+/// Checks whether a JSON object is a number.
+/// Returns a `c_int` where TRUE indicates that the item is a number, and FALSE indicates otherwise.
+#[no_mangle]
+pub unsafe extern "C" fn ylong_json_is_number(item: *const YlongJson) -> c_int {
+ if item.is_null() {
+ return FALSE;
+ }
+
+ let item = &*(item as *mut JsonValue);
+ item.is_number() as c_int
+}
+
+/// Checks whether a JSON object is a double number.
+/// Returns a `c_int` where TRUE indicates that the number is a double, and FALSE indicates otherwise.
+#[no_mangle]
+pub unsafe extern "C" fn ylong_json_is_double_number(item: *const YlongJson) -> c_int {
+ if item.is_null() {
+ return FALSE;
+ }
+
+ let item = &*(item as *mut JsonValue);
+ match item.try_as_number() {
+ Ok(n) => matches!(n, Number::Float(_)) as c_int,
+ Err(_) => FALSE,
+ }
+}
+
+/// Checks whether a JSON object is an integer number.
+/// Returns a `c_int` where TRUE indicates that the number is an integer, and FALSE indicates otherwise.
+#[no_mangle]
+pub unsafe extern "C" fn ylong_json_is_int_number(item: *const YlongJson) -> c_int {
+ if item.is_null() {
+ return FALSE;
+ }
+
+ let item = &*(item as *mut JsonValue);
+ match item.try_as_number() {
+ Ok(n) => matches!(n, Number::Signed(_) | Number::Unsigned(_)) as c_int,
+ Err(_) => FALSE,
+ }
+}
+
+/// Gets the double value of a JSON number object.
+/// Returns a `c_int` indicating whether the operation was successful (SUCCESS) or failed (FAILURE).
+#[no_mangle]
+pub unsafe extern "C" fn ylong_json_get_double_value_from_number(
+ number: *const YlongJson,
+ value: *mut c_double,
+) -> c_int {
+ if number.is_null() {
+ return FAILURE;
+ }
+
+ let number = &*(number as *mut JsonValue);
+ let number = match number.try_as_number() {
+ Ok(n) => n,
+ Err(_) => return FAILURE,
+ };
+ // Coercing u64 or i64 to f64 may result in a loss of data accuracy.
+ match number {
+ Number::Float(f) => *value = *f as c_double,
+ Number::Unsigned(u) => *value = *u as c_double,
+ Number::Signed(i) => *value = *i as c_double,
+ }
+ SUCCESS
+}
+
+/// Gets the integer value of a JSON number object.
+/// Returns a `c_int` indicating whether the operation was successful (SUCCESS) or failed (FAILURE).
+#[no_mangle]
+pub unsafe extern "C" fn ylong_json_get_int_value_from_number(
+ number: *const YlongJson,
+ value: *mut c_longlong,
+) -> c_int {
+ if number.is_null() {
+ return FAILURE;
+ }
+
+ let number = &*(number as *mut JsonValue);
+ let number = match number.try_as_number() {
+ Ok(n) => n,
+ Err(_) => return FAILURE,
+ };
+ // Coercing u64 or i64 or f64 to i64 may result in a loss of data accuracy.
+ match number {
+ Number::Float(f) => *value = *f as c_longlong,
+ Number::Unsigned(u) => *value = *u as c_longlong,
+ Number::Signed(i) => *value = *i as c_longlong,
+ }
+ SUCCESS
+}
+
+/// Sets the double value of a JSON number object.
+/// Returns a `c_int` indicating whether the operation was successful (SUCCESS) or failed (FAILURE).
+#[no_mangle]
+pub unsafe extern "C" fn ylong_json_set_double_value_to_number(
+ number: *mut YlongJson,
+ value: c_double,
+) -> c_int {
+ if number.is_null() {
+ return FAILURE;
+ }
+
+ let number = &mut *(number as *mut JsonValue);
+ let number = match number.try_as_mut_number() {
+ Ok(n) => n,
+ Err(_) => return FAILURE,
+ };
+ *number = Number::Float(value);
+ SUCCESS
+}
+
+/// Sets the integer value of a JSON number object.
+/// Returns a `c_int` indicating whether the operation was successful (SUCCESS) or failed (FAILURE).
+#[no_mangle]
+pub unsafe extern "C" fn ylong_json_set_int_value_to_number(
+ number: *mut YlongJson,
+ value: c_longlong,
+) -> c_int {
+ if number.is_null() {
+ return FAILURE;
+ }
+
+ let number = &mut *(number as *mut JsonValue);
+ let number = match number.try_as_mut_number() {
+ Ok(n) => n,
+ Err(_) => return FAILURE,
+ };
+ *number = Number::Signed(value);
+ SUCCESS
+}
+
+/// Creates a `YlongJson` string from a given C-style string.
+/// If the input string is null, it returns a null `YlongJson`.
+#[no_mangle]
+pub unsafe extern "C" fn ylong_json_create_string(string: *const c_char) -> *mut YlongJson {
+ if string.is_null() {
+ return NULL_MUT_YLONG_JSON;
+ }
+
+ let len = strlen(string);
+ let slice = &*slice_from_raw_parts(string as *mut u8, len);
+ let string = CString::from_vec_unchecked(slice.to_vec());
+ Box::into_raw(Box::from(JsonValue::String(string))) as *mut YlongJson
+}
+
+/// Checks if the `YlongJson` item is a string.
+/// Returns `FALSE` if the item is null or not a string, and `TRUE` otherwise.
+#[no_mangle]
+pub unsafe extern "C" fn ylong_json_is_string(item: *const YlongJson) -> c_int {
+ if item.is_null() {
+ return FALSE;
+ }
+
+ let item = &*(item as *mut JsonValue);
+ item.is_string() as c_int
+}
+
+/// The char* returned by this function differs from the original data,
+/// meaning that any changes to this char* will not be reflected in the original data.
+#[no_mangle]
+pub unsafe extern "C" fn ylong_json_get_value_from_string(
+ string: *const YlongJson,
+ value: *mut *mut c_char,
+) -> c_int {
+ if string.is_null() {
+ return FAILURE;
+ }
+
+ let string = &*(string as *mut JsonValue);
+ let string = match string.try_as_string() {
+ Ok(s) => s,
+ Err(_) => return FAILURE,
+ };
+ // If `c_adapter` feature is on, the pointer of the inner char arrays can be obtained directly,
+ // because the string pointer actually points to a `CString`
+ *value = string.as_ptr() as *mut c_char;
+ SUCCESS
+}
+
+/// Sets a `YlongJson` string to a given C-style string.
+/// If the `YlongJson` string or the input string is null, it returns `FAILURE`.
+#[no_mangle]
+pub unsafe extern "C" fn ylong_json_set_value_to_string(
+ string: *mut YlongJson,
+ value: *const c_char,
+) -> c_int {
+ if string.is_null() || value.is_null() {
+ return FAILURE;
+ }
+
+ let string = &mut *(string as *mut JsonValue);
+ let string = match string.try_as_mut_string() {
+ Ok(s) => s,
+ Err(_) => return FAILURE,
+ };
+ let len = strlen(value);
+ let slice = &*slice_from_raw_parts(value as *mut u8, len);
+ *string = CString::from_vec_unchecked(slice.to_vec());
+ SUCCESS
+}
+
+/// Creates a `YlongJson` array.
+#[no_mangle]
+pub unsafe extern "C" fn ylong_json_create_array() -> *mut YlongJson {
+ Box::into_raw(Box::from(JsonValue::Array(Array::new()))) as *mut YlongJson
+}
+
+/// Checks if the `YlongJson` item is an array.
+/// Returns `FALSE` if the item is null or not an array, and `TRUE` otherwise.
+#[no_mangle]
+pub unsafe extern "C" fn ylong_json_is_array(item: *const YlongJson) -> c_int {
+ if item.is_null() {
+ return FALSE;
+ }
+
+ let item = &*(item as *mut JsonValue);
+ item.is_array() as c_int
+}
+
+/// Gets the size of a `YlongJson` array.
+/// If the `YlongJson` array or the size is null, it returns `FAILURE`.
+#[no_mangle]
+pub unsafe extern "C" fn ylong_json_get_array_size(
+ array: *const YlongJson,
+ size: *mut c_int,
+) -> c_int {
+ if array.is_null() || size.is_null() {
+ return FAILURE;
+ }
+
+ let array = &*(array as *mut JsonValue);
+ let array = match array.try_as_array() {
+ Ok(a) => a,
+ Err(_) => return FAILURE,
+ };
+
+ *size = array.len() as c_int;
+ SUCCESS
+}
+
+/// Gets a `YlongJson` item from an array by index.
+/// Returns null `YlongJson` if the array is null, the item doesn't exist, or any error occurs.
+#[no_mangle]
+pub unsafe extern "C" fn ylong_json_get_array_item(
+ array: *const YlongJson,
+ index: c_int,
+) -> *mut YlongJson {
+ if array.is_null() {
+ return NULL_MUT_YLONG_JSON;
+ }
+
+ let array_ref = &mut *(array as *mut JsonValue);
+ let array_ref = match array_ref.try_as_mut_array() {
+ Ok(a) => a,
+ Err(_) => return NULL_MUT_YLONG_JSON,
+ };
+
+ if index as usize >= array_ref.len() {
+ return NULL_MUT_YLONG_JSON;
+ }
+
+ array_ref.get_mut(index as usize).unwrap() as *mut JsonValue as *mut YlongJson
+}
+
+/// Adds a `YlongJson` item to an array.
+/// Returns `FAILURE` if the array or the item is null, and `SUCCESS` otherwise.
+#[no_mangle]
+pub unsafe extern "C" fn ylong_json_add_item_to_array(
+ array: *mut YlongJson,
+ item: *mut YlongJson,
+) -> c_int {
+ if array.is_null() || item.is_null() {
+ return FAILURE;
+ }
+
+ let array_ref = &mut *(array as *mut JsonValue);
+ let array_ref = match array_ref.try_as_mut_array() {
+ Ok(a) => a,
+ Err(_) => return FAILURE,
+ };
+
+ let value = Box::from_raw(item as *mut JsonValue);
+ array_ref.push(*value);
+
+ SUCCESS
+}
+
+/// Replaces a `YlongJson` item in an array by index with a new item.
+/// Returns `FAILURE` if the array or the new item is null, the index is out of bounds, or any error occurs, and `SUCCESS` otherwise.
+#[no_mangle]
+pub unsafe extern "C" fn ylong_json_replace_array_item_by_index(
+ array: *mut YlongJson,
+ index: c_int,
+ new_item: *mut YlongJson,
+) -> c_int {
+ if array.is_null() || new_item.is_null() {
+ return FAILURE;
+ }
+
+ let array_ref = &mut *(array as *mut JsonValue);
+ let array_ref = match array_ref.try_as_mut_array() {
+ Ok(o) => o,
+ Err(_) => return FAILURE,
+ };
+
+ if let Some(value) = array_ref.get_mut(index as usize) {
+ let new_value = Box::from_raw(new_item as *mut JsonValue);
+
+ *value = *new_value;
+
+ return SUCCESS;
+ }
+ FAILURE
+}
+
+/// Removes a `YlongJson` item from an array by index.
+/// Returns null `YlongJson` if the array is null, the item doesn't exist, or any error occurs.
+#[no_mangle]
+pub unsafe extern "C" fn ylong_json_remove_array_item_by_index(
+ array: *mut YlongJson,
+ index: c_int,
+) -> *mut YlongJson {
+ if array.is_null() {
+ return NULL_MUT_YLONG_JSON;
+ }
+
+ let array = &mut *(array as *mut JsonValue);
+ let array = match array.try_as_mut_array() {
+ Ok(a) => a,
+ Err(_) => return NULL_MUT_YLONG_JSON,
+ };
+
+ // Uses method 'remove' of Array, but not the method 'remove' of underlying data structure.
+ if let Some(v) = Array::remove(array, index as usize) {
+ return Box::into_raw(Box::new(v)) as *mut YlongJson;
+ }
+ NULL_MUT_YLONG_JSON
+}
+
+/// Deletes a `YlongJson` item from an array by index.
+#[no_mangle]
+pub unsafe extern "C" fn ylong_json_delete_array_item_by_index(
+ array: *mut YlongJson,
+ index: c_int,
+) {
+ if array.is_null() {
+ return;
+ }
+
+ let array = &mut *(array as *mut JsonValue);
+ let array = match array.try_as_mut_array() {
+ Ok(a) => a,
+ Err(_) => return,
+ };
+ array.remove(index as usize);
+}
+
+/// In list_array mode, it is more efficient to get a node through this method and then delete it.
+#[cfg(feature = "list_array")]
+#[no_mangle]
+pub unsafe extern "C" fn ylong_json_get_array_node(
+ array: *mut YlongJson,
+ index: c_int,
+) -> *mut YlongJson {
+ if array.is_null() {
+ return NULL_MUT_YLONG_JSON;
+ }
+
+ let array_ref = &mut *(array as *mut JsonValue);
+ let array_ref = match array_ref.try_as_mut_array() {
+ Ok(a) => a,
+ Err(_) => return NULL_MUT_YLONG_JSON,
+ };
+
+ if index as usize >= array_ref.len() {
+ return NULL_MUT_YLONG_JSON;
+ }
+
+ let node = array_ref.get_node_mut(index as usize).unwrap();
+ node as *mut Node as *mut YlongJson
+}
+
+/// Retrieves a `YlongJson` item from an array node.
+#[cfg(feature = "list_array")]
+#[no_mangle]
+pub unsafe extern "C" fn ylong_json_get_item_from_array_node(
+ array_node: *mut YlongJson,
+) -> *mut YlongJson {
+ if array_node.is_null() {
+ return NULL_MUT_YLONG_JSON;
+ }
+ let node = &mut *(array_node as *mut Node);
+ node.get_element_mut() as *mut JsonValue as *mut YlongJson
+}
+
+/// Adds a `YlongJson` item to an array, then returns the node.
+/// Returns null `YlongJson` if the array or the item is null.
+#[cfg(feature = "list_array")]
+#[no_mangle]
+pub unsafe extern "C" fn ylong_json_add_item_to_array_then_get_node(
+ array: *mut YlongJson,
+ item: *mut YlongJson,
+) -> *mut YlongJson {
+ if array.is_null() || item.is_null() {
+ return NULL_MUT_YLONG_JSON;
+ }
+
+ let array_ref = &mut *(array as *mut JsonValue);
+ let array_ref = match array_ref.try_as_mut_array() {
+ Ok(a) => a,
+ Err(_) => return NULL_MUT_YLONG_JSON,
+ };
+
+ let value = Box::from_raw(item as *mut JsonValue);
+ array_ref.push(*value);
+
+ array_ref.last_node_mut().unwrap() as *mut Node as *mut YlongJson
+}
+
+/// Replaces an item of an array node with a new item.
+/// Returns `FAILURE` if the array node or the new item is null, and `SUCCESS` otherwise.
+#[cfg(feature = "list_array")]
+#[no_mangle]
+pub unsafe extern "C" fn ylong_json_replace_item_of_array_node(
+ array_node: *mut YlongJson,
+ new_item: *mut YlongJson,
+) -> c_int {
+ if array_node.is_null() || new_item.is_null() {
+ return FAILURE;
+ }
+
+ let node = &mut *(array_node as *mut Node);
+ let value = node.get_element_mut();
+
+ let new_value = Box::from_raw(new_item as *mut JsonValue);
+ *value = *new_value;
+ SUCCESS
+}
+
+/// Removes an array node.
+#[cfg(feature = "list_array")]
+#[no_mangle]
+pub unsafe extern "C" fn ylong_json_remove_array_node(
+ array_node: *mut YlongJson,
+) -> *mut YlongJson {
+ if array_node.is_null() {
+ return NULL_MUT_YLONG_JSON;
+ }
+
+ let node = &mut *(array_node as *mut Node);
+ Box::into_raw(Box::new(node.remove_self().unwrap())) as *mut YlongJson
+}
+
+/// Deletes an array node.
+#[cfg(feature = "list_array")]
+#[no_mangle]
+pub unsafe extern "C" fn ylong_json_delete_array_node(array_node: *mut YlongJson) {
+ if array_node.is_null() {
+ return;
+ }
+
+ let node = &mut *(array_node as *mut Node);
+ let _ = node.remove_self();
+}
+
+/// Creates a `YlongJson` object.
+#[no_mangle]
+pub unsafe extern "C" fn ylong_json_create_object() -> *mut YlongJson {
+ Box::into_raw(Box::from(JsonValue::Object(Object::new()))) as *mut YlongJson
+}
+
+/// Checks if the `YlongJson` item is an object.
+/// Returns `FALSE` if the item is null or not an object, and `TRUE` otherwise.
+#[no_mangle]
+pub unsafe extern "C" fn ylong_json_is_object(item: *const YlongJson) -> c_int {
+ if item.is_null() {
+ return FALSE;
+ }
+
+ let item = &*(item as *mut JsonValue);
+ item.is_object() as c_int
+}
+
+/// Gets the size of a `YlongJson` object.
+/// If the `YlongJson` object or the size is null, it returns `FAILURE`.
+#[no_mangle]
+pub unsafe extern "C" fn ylong_json_get_object_size(
+ object: *mut YlongJson,
+ size: *mut c_int,
+) -> c_int {
+ if object.is_null() || size.is_null() {
+ return FAILURE;
+ }
+
+ let object = &mut *(object as *mut JsonValue);
+ let object = match object.try_as_mut_object() {
+ Ok(o) => o,
+ Err(_) => return FAILURE,
+ };
+
+ *size = object.len() as c_int;
+ SUCCESS
+}
+
+/// Checks if a JSON object has a specific item.
+/// Returns a `c_int` indicating whether the item exists (TRUE) or not (FALSE).
+#[no_mangle]
+pub unsafe extern "C" fn ylong_json_has_object_item(
+ object: *mut YlongJson,
+ string: *const c_char,
+) -> c_int {
+ if object.is_null() || string.is_null() {
+ return FALSE;
+ }
+
+ let object = &*(object as *mut JsonValue);
+ let object = match object.try_as_object() {
+ Ok(o) => o,
+ Err(_) => return FALSE,
+ };
+
+ // Using `ptr::slice_from_raw_parts` here dramatically
+ // reduces the cost of converting between char* and &[u8].
+ // Then use `from_utf8_unchecked` to further reduce cost.
+ let len = strlen(string);
+ let slice = &*slice_from_raw_parts(string as *mut u8, len);
+ let str = from_utf8_unchecked(slice);
+
+ object.contains_key(str) as c_int
+}
+
+/// Retrieves an item from a JSON object by key.
+/// Returns a mutable pointer to the retrieved JSON item.
+#[no_mangle]
+pub unsafe extern "C" fn ylong_json_get_object_item(
+ object: *const YlongJson,
+ string: *const c_char,
+) -> *mut YlongJson {
+ // If object is empty, the search fails.
+ if object.is_null() || string.is_null() {
+ return NULL_MUT_YLONG_JSON;
+ }
+
+ let object_ref = &mut *(object as *mut JsonValue);
+
+ // If the type is not object, return err.
+ let object_ref = match object_ref.try_as_mut_object() {
+ Ok(o) => o,
+ Err(_) => return NULL_MUT_YLONG_JSON,
+ };
+
+ // Using `ptr::slice_from_raw_parts` here dramatically
+ // reduces the cost of converting between char* and &[u8].
+ // Then use `from_utf8_unchecked` to further reduce cost.
+ let len = strlen(string);
+ let slice = &*slice_from_raw_parts(string as *mut u8, len);
+ let index = from_utf8_unchecked(slice);
+
+ let target = match object_ref.get_mut(index) {
+ Some(v) => v,
+ None => return NULL_MUT_YLONG_JSON,
+ };
+ target as *mut JsonValue as *mut YlongJson
+}
+
+/// Adds an item to a JSON object.
+/// Returns a `c_int` indicating whether the operation was successful (SUCCESS) or failed (FAILURE).
+#[no_mangle]
+pub unsafe extern "C" fn ylong_json_add_item_to_object(
+ object: *mut YlongJson,
+ string: *const c_char,
+ item: *mut YlongJson,
+) -> c_int {
+ // If object or string or item is empty, returns FAILED.
+ if object.is_null() || string.is_null() || item.is_null() {
+ return FAILURE;
+ }
+
+ let object_ref = &mut *(object as *mut JsonValue);
+ let object_ref = match object_ref.try_as_mut_object() {
+ Ok(o) => o,
+ Err(_) => return FAILURE,
+ };
+
+ // Using `ptr::slice_from_raw_parts` here dramatically
+ // reduces the cost of converting between char* and &[u8].
+ // Then use `from_utf8_unchecked` to further reduce cost.
+ let len = strlen(string);
+ let slice = &*slice_from_raw_parts(string as *mut u8, len);
+ let index = from_utf8_unchecked(slice);
+
+ let value = Box::from_raw(item as *mut JsonValue);
+
+ object_ref.insert(String::from(index), *value);
+
+ SUCCESS
+}
+
+/// Replaces an item in a JSON object by key.
+/// Returns a `c_int` indicating whether the operation was successful (SUCCESS) or failed (FAILURE).
+#[no_mangle]
+pub unsafe extern "C" fn ylong_json_replace_object_item_by_index(
+ object: *mut YlongJson,
+ index: *const c_char,
+ new_item: *mut YlongJson,
+) -> c_int {
+ if object.is_null() || index.is_null() || new_item.is_null() {
+ return FAILURE;
+ }
+
+ let object_ref = &mut *(object as *mut JsonValue);
+ let object_ref = match object_ref.try_as_mut_object() {
+ Ok(o) => o,
+ Err(_) => return FAILURE,
+ };
+
+ // Using `ptr::slice_from_raw_parts` here dramatically
+ // reduces the cost of converting between char* and &[u8].
+ // Then use `from_utf8_unchecked` to further reduce cost.
+ let len = strlen(index);
+ let slice = &*slice_from_raw_parts(index as *mut u8, len);
+ let index = from_utf8_unchecked(slice);
+
+ if let Some(value) = object_ref.get_mut(index) {
+ let new_value = Box::from_raw(new_item as *mut JsonValue);
+
+ *value = *new_value;
+
+ return SUCCESS;
+ }
+
+ FAILURE
+}
+
+/// Removes an item in a JSON object by index.
+/// Returns a new JSON object without the item if successful, NULL_MUT_YLONG_JSON otherwise.
+#[no_mangle]
+pub unsafe extern "C" fn ylong_json_remove_object_item_by_index(
+ object: *mut YlongJson,
+ index: *const c_char,
+) -> *mut YlongJson {
+ if object.is_null() || index.is_null() {
+ return NULL_MUT_YLONG_JSON;
+ }
+
+ let object = &mut *(object as *mut JsonValue);
+
+ // Using `ptr::slice_from_raw_parts` here dramatically
+ // reduces the cost of converting between char* and &[u8].
+ // Then use `from_utf8_unchecked` to further reduce cost.
+ let len = strlen(index);
+ let slice = &*slice_from_raw_parts(index as *mut u8, len);
+ let index = from_utf8_unchecked(slice);
+
+ if let Some(v) = object.remove(index) {
+ return Box::into_raw(Box::new(v)) as *mut YlongJson;
+ }
+ NULL_MUT_YLONG_JSON
+}
+
+/// Deletes an item in a JSON object by index.
+/// Does not return a value.
+#[no_mangle]
+pub unsafe extern "C" fn ylong_json_delete_object_item_by_index(
+ object: *mut YlongJson,
+ index: *const c_char,
+) {
+ if object.is_null() || index.is_null() {
+ return;
+ }
+
+ let object = &mut *(object as *mut JsonValue);
+
+ // Using ptr::slice_from_raw_parts here dramatically
+ // reduces the cost of converting between char* and &[u8].
+ // Then use from_utf8_unchecked to further reduce cost.
+ let len = strlen(index);
+ let slice = &*slice_from_raw_parts(index as *mut u8, len);
+ let index = from_utf8_unchecked(slice);
+
+ object.remove(index);
+}
+
+/// Gets all items from a JSON object.
+/// Returns SUCCESS if the operation is successful, FAILURE otherwise.
+#[no_mangle]
+pub unsafe extern "C" fn ylong_json_get_all_object_items(
+ object: *mut YlongJson,
+ key: *mut *mut c_char,
+ value: *mut *mut YlongJson,
+ len: *mut c_int,
+) -> c_int {
+ if object.is_null() || key.is_null() || value.is_null() || len.is_null() {
+ return FAILURE;
+ }
+
+ let object = &mut *(object as *mut JsonValue);
+ let object = match object.try_as_mut_object() {
+ Ok(o) => o,
+ Err(_) => return FAILURE,
+ };
+
+ for (n, (k, v)) in object.iter_mut().enumerate() {
+ // k.clone ().into_bytes() is more efficient than k.as_bytes ().to_vec().
+ let k = CString::from_vec_unchecked(k.clone().into_bytes()).into_raw();
+ let v = v as *mut JsonValue as *mut YlongJson;
+ *(key.add(n)) = k;
+ *(value.add(n)) = v;
+ }
+ *len = object.len() as c_int;
+ SUCCESS
+}
+
+/// Applies a function to each item in a JSON object.
+/// Returns SUCCESS if the operation is successful, FAILURE otherwise.
+#[no_mangle]
+pub unsafe extern "C" fn ylong_json_for_each_object_item(
+ object: *mut YlongJson,
+ func: unsafe extern "C" fn(*mut YlongJson),
+) -> c_int {
+ if object.is_null() {
+ return FAILURE;
+ }
+
+ let object = &mut *(object as *mut JsonValue);
+ let object = match object.try_as_mut_object() {
+ Ok(o) => o,
+ Err(_) => return FAILURE,
+ };
+
+ object.iter_mut().for_each(|(_k, v)| {
+ let value = v as *mut JsonValue as *mut YlongJson;
+ func(value);
+ });
+ SUCCESS
+}
+
+/// Gets an object node from a JSON object by key.
+/// Returns a pointer to the object node if successful, NULL_MUT_YLONG_JSON otherwise.
+#[cfg(feature = "list_object")]
+#[no_mangle]
+pub unsafe extern "C" fn ylong_json_get_object_node(
+ object: *const YlongJson,
+ string: *const c_char,
+) -> *mut YlongJson {
+ // If object is empty, the search fails.
+ if object.is_null() || string.is_null() {
+ return NULL_MUT_YLONG_JSON;
+ }
+
+ let object_ref = &mut *(object as *mut JsonValue);
+
+ // If the type is not object, returns err.
+ let object_ref = match object_ref.try_as_mut_object() {
+ Ok(o) => o,
+ Err(_) => return NULL_MUT_YLONG_JSON,
+ };
+
+ // Using `ptr::slice_from_raw_parts` here dramatically
+ // reduces the cost of converting between char* and &[u8].
+ // Then use `from_utf8_unchecked` to further reduce cost.
+ let len = strlen(string);
+ let slice = &*slice_from_raw_parts(string as *mut u8, len);
+ let index = from_utf8_unchecked(slice);
+
+ // When using list to get a node, the return value points to the memory is CursorMut.
+ let target = match object_ref.get_node_mut(index) {
+ Some(v) => v,
+ None => return NULL_MUT_YLONG_JSON,
+ };
+ target as *mut Node<(String, JsonValue)> as *mut YlongJson
+}
+
+/// Gets an item from an object node.
+/// Returns a pointer to the item if successful, NULL_MUT_YLONG_JSON otherwise.
+#[cfg(feature = "list_object")]
+#[no_mangle]
+pub unsafe extern "C" fn ylong_json_get_item_from_object_node(
+ object_node: *mut YlongJson,
+) -> *mut YlongJson {
+ if object_node.is_null() {
+ return NULL_MUT_YLONG_JSON;
+ }
+
+ let node = &mut *(object_node as *mut Node<(String, JsonValue)>);
+ (&mut node.get_element_mut().1) as *mut JsonValue as *mut YlongJson
+}
+
+/// Adds an item to a JSON object, then returns a pointer to the object node.
+/// Returns a pointer to the object node if successful, NULL_MUT_YLONG_JSON otherwise.
+#[cfg(feature = "list_object")]
+#[no_mangle]
+pub unsafe extern "C" fn ylong_json_add_item_to_object_then_get_node(
+ object: *mut YlongJson,
+ string: *const c_char,
+ item: *mut YlongJson,
+) -> *mut YlongJson {
+ // If object or item is empty, returns NULL_MUT_YLONG_JSON.
+ if object.is_null() || string.is_null() || item.is_null() {
+ return NULL_MUT_YLONG_JSON;
+ }
+
+ let object_ref = &mut *(object as *mut JsonValue);
+ let object_ref = match object_ref.try_as_mut_object() {
+ Ok(v) => v,
+ Err(_) => return NULL_MUT_YLONG_JSON,
+ };
+
+ // Using `ptr::slice_from_raw_parts` here dramatically
+ // reduces the cost of converting between char* and &[u8].
+ // Then use `from_utf8_unchecked` to further reduce cost.
+ let len = strlen(string);
+ let slice = &*slice_from_raw_parts(string as *mut u8, len);
+ let string = from_utf8_unchecked(slice);
+
+ let value = Box::from_raw(item as *mut JsonValue);
+ object_ref.insert(String::from(string), *value);
+
+ let target = object_ref.last_node_mut().unwrap();
+ target as *mut Node<(String, JsonValue)> as *mut YlongJson
+}
+
+/// Replaces an item in an object node.
+/// Returns SUCCESS if the operation is successful, FAILURE otherwise.
+#[cfg(feature = "list_object")]
+#[no_mangle]
+pub unsafe extern "C" fn ylong_json_replace_item_of_object_node(
+ object_node: *mut YlongJson,
+ new_item: *mut YlongJson,
+) -> c_int {
+ if object_node.is_null() || new_item.is_null() {
+ return FAILURE;
+ }
+
+ let node = &mut *(object_node as *mut Node<(String, JsonValue)>);
+ let (_, value) = node.get_element_mut();
+ let new_value = Box::from_raw(new_item as *mut JsonValue);
+ *value = *new_value;
+
+ SUCCESS
+}
+
+/// Removes an object node.
+/// Returns a pointer to the removed item if successful, NULL_MUT_YLONG_JSON otherwise.
+#[cfg(feature = "list_object")]
+#[no_mangle]
+pub unsafe extern "C" fn ylong_json_remove_object_node(
+ object_node: *mut YlongJson,
+) -> *mut YlongJson {
+ if object_node.is_null() {
+ return NULL_MUT_YLONG_JSON;
+ }
+
+ let node = &mut *(object_node as *mut Node<(String, JsonValue)>);
+ Box::into_raw(Box::new(node.remove_self().unwrap().1)) as *mut YlongJson
+}
+
+/// Deletes a node from a JSON object.
+#[cfg(feature = "list_object")]
+#[no_mangle]
+pub unsafe extern "C" fn ylong_json_delete_object_node(object_node: *mut YlongJson) {
+ if object_node.is_null() {
+ return;
+ }
+
+ let node = &mut *(object_node as *mut Node<(String, JsonValue)>);
+ let _ = node.remove_self();
+}
+
+#[cfg(test)]
+mod ut_adapter {
+ use crate::*;
+ use libc::*;
+ use std::ffi::{CStr, CString};
+ use std::mem::size_of;
+ use std::ptr::{null, null_mut};
+
+ 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
+ }
+}
+"#;
+
+ unsafe fn str_to_c_char(str: &str) -> *mut c_char {
+ CString::from_vec_unchecked(str.as_bytes().to_vec()).into_raw()
+ }
+
+ /// UT test for `ylong_json_parse`.
+ ///
+ /// # Title
+ /// ut_ylong_json_parse
+ ///
+ /// # Brief
+ /// 1. Calls `ylong_json_parse` to generate a JsonValue as YlongJson*.
+ /// 2. Checks if the test results are correct.
+ #[test]
+ fn ut_ylong_json_parse() {
+ unsafe {
+ // Passes in the correct syntax text string.
+ let str = str_to_c_char(JSON_TEXT);
+ let err = null_mut::();
+ let json = ylong_json_parse(str, &err as *const *mut c_char as *mut *mut c_char);
+ // No error message.
+ assert!(err.is_null());
+ // The data structure is correct.
+ assert!(!json.is_null());
+
+ // Destruction
+ let _ = Box::from_raw(str);
+ ylong_json_delete(json);
+
+ // Passes in the incorrect syntax text string.
+ let str = str_to_c_char("{");
+ let err = null_mut::();
+ let json = ylong_json_parse(str, &err as *const *mut c_char as *mut *mut c_char);
+ // Here is an error message.
+ assert!(!err.is_null());
+ // No correct syntax structure.
+ assert!(json.is_null());
+
+ // Destruction
+ ylong_json_free_string(err);
+ let _ = Box::from_raw(str);
+ ylong_json_delete(json);
+ }
+ }
+
+ //noinspection SpellCheckingInspection
+ //noinspection ALL
+ /// UT test for `ylong_json_free_string`.
+ ///
+ /// # Title
+ /// ut_ylong_json_free_string
+ ///
+ /// # Brief
+ /// 1. Calls `ylong_json_free_string` to free a YlongJson*(`C` string).
+ /// 2. Checks if the test results are correct.
+ #[test]
+ fn ut_ylong_json_free_string() {
+ unsafe {
+ // Null ptr scene, if the process does not exit abnormally, it is successful.
+ let string = null_mut();
+ ylong_json_free_string(string);
+
+ let str = str_to_c_char(JSON_TEXT);
+ let err = null_mut::();
+ let json = ylong_json_parse(str, &err as *const *mut c_char as *mut *mut c_char);
+ assert!(err.is_null());
+ assert!(!json.is_null());
+
+ // The char* generated by `ylong_json_print_unformatted` needs
+ // to be destructed by calling `ylong_json_free_string`.
+ let result = ylong_json_print_unformatted(json);
+ ylong_json_free_string(result);
+
+ // Destruction
+ let _ = Box::from_raw(str);
+ ylong_json_delete(json);
+ }
+ }
+
+ /// UT test for `ylong_json_print_unformatted`.
+ ///
+ /// # Title
+ /// ut_ylong_json_print_unformatted
+ ///
+ /// # Brief
+ /// 1. Calls `ylong_json_print_unformatted` to print the value as `C` string.
+ /// 2. Checks if the test results are correct.
+ #[test]
+ fn ut_ylong_json_print_unformatted() {
+ unsafe {
+ // Null ptr
+ let json = null_mut();
+ assert!(ylong_json_print_unformatted(json).is_null());
+
+ // Correct scene
+ let str = str_to_c_char("{\"array\":[1,2,3]}");
+ let err = null_mut::();
+ let json = ylong_json_parse(str, &err as *const *mut c_char as *mut *mut c_char);
+ assert!(err.is_null());
+ assert!(!json.is_null());
+
+ let result = ylong_json_print_unformatted(json);
+ let result = CString::from_raw(result).into_string().unwrap();
+ assert_eq!(result, "{\"array\":[1,2,3]}");
+
+ // Destruction
+ let _ = Box::from_raw(str);
+ ylong_json_delete(json);
+ }
+ }
+
+ /// UT test for `ylong_json_delete`.
+ ///
+ /// # Title
+ /// ut_ylong_json_delete
+ ///
+ /// # Brief
+ /// 1. Calls `ylong_json_delete` to delete the value.
+ /// 2. Checks if the test results are correct.
+ #[test]
+ fn ut_ylong_json_delete() {
+ unsafe {
+ // Null ptr scene, if the process does not exit abnormally, it is successful.
+ let json = null_mut();
+ ylong_json_delete(json);
+
+ // The YlongJson* generated by `ylong_json_parse` needs
+ // to be destructed by calling `ylong_json_delete`.
+ let str = str_to_c_char(JSON_TEXT);
+ let err = null_mut::();
+ let json = ylong_json_parse(str, &err as *const *mut c_char as *mut *mut c_char);
+ assert!(err.is_null());
+ assert!(!json.is_null());
+ let _ = Box::from_raw(str);
+ ylong_json_delete(json);
+
+ // If the YlongJson* generated by the function starting with
+ // `ylong_json_create` is not inserted into another YlongJson*,
+ // YlongJson* needs to be destructed by calling `ylong_json_delete`.
+ let null = ylong_json_create_null();
+ ylong_json_delete(null);
+ }
+ }
+
+ /// UT test for `ylong_json_duplicate`.
+ ///
+ /// # Title
+ /// ut_ylong_json_duplicate
+ ///
+ /// # Brief
+ /// 1. Calls `ylong_json_duplicate` to clone the value.
+ /// 2. Checks if the test results are correct.
+ #[test]
+ fn ut_ylong_json_duplicate() {
+ unsafe {
+ // Null ptr
+ let json = null_mut();
+ assert!(ylong_json_duplicate(json, 0).is_null());
+
+ // Null ptr
+ let json = null_mut();
+ assert!(ylong_json_duplicate(json, 1).is_null());
+
+ let str = str_to_c_char(JSON_TEXT);
+ let err = null_mut::();
+ let json = ylong_json_parse(str, &err as *const *mut c_char as *mut *mut c_char);
+ assert!(err.is_null());
+ assert!(!json.is_null());
+
+ // If recurse is 0, does not clone recursively.
+ let duplicate = ylong_json_duplicate(json, 0);
+ let result = ylong_json_print_unformatted(duplicate);
+ let result = CString::from_raw(result).into_string().unwrap();
+ assert_eq!(result, "{}");
+ // Destruction
+ let _ = Box::from_raw(str);
+ ylong_json_delete(duplicate);
+
+ // If recurse is not 0, do recursive cloning.
+ let duplicate = ylong_json_duplicate(json, 1);
+ let result = ylong_json_print_unformatted(duplicate);
+ let result = CString::from_raw(result).into_string().unwrap();
+ let origin = ylong_json_print_unformatted(json);
+ let origin = CString::from_raw(origin).into_string().unwrap();
+ // The json address value is not equal to duplicate,
+ // which means it is a different instance.
+ assert_ne!(duplicate, json);
+ // But the output is the same.
+ assert_eq!(result, origin);
+ // Destruction
+ ylong_json_delete(duplicate);
+ ylong_json_delete(json);
+ }
+ }
+
+ /// UT test for `ylong_json_create_null`.
+ ///
+ /// # Title
+ /// ut_ylong_json_create_null
+ ///
+ /// # Brief
+ /// 1. Calls `ylong_json_create_null` to create a null.
+ /// 2. Checks if the test results are correct.
+ #[test]
+ fn ut_ylong_json_create_null() {
+ unsafe {
+ let null = ylong_json_create_null();
+ assert_eq!(ylong_json_is_null(null), 1);
+ ylong_json_delete(null);
+ }
+ }
+
+ /// UT test for `ylong_json_is_null`.
+ ///
+ /// # Title
+ /// ut_ylong_json_is_null
+ ///
+ /// # Brief
+ /// 1. Calls `ylong_json_is_null` to determine whether the underlying structure is null.
+ /// 2. Checks if the test results are correct.
+ #[test]
+ fn ut_ylong_json_is_null() {
+ unsafe {
+ // Null ptr
+ let null = null_mut();
+ assert_eq!(ylong_json_is_null(null), 0);
+
+ // If the underlying structure is Null, returns true.
+ let null = ylong_json_create_null();
+ assert_eq!(ylong_json_is_null(null), 1);
+ ylong_json_delete(null);
+
+ // Else returns false.
+ let bool = ylong_json_create_bool(0xffff);
+ assert_eq!(ylong_json_is_null(bool), 0);
+ ylong_json_delete(bool);
+ }
+ }
+
+ /// UT test for `ylong_json_create_bool`.
+ ///
+ /// # Title
+ /// ut_ylong_json_create_bool
+ ///
+ /// # Brief
+ /// 1. Calls `ylong_json_create_bool` to create a bool.
+ /// 2. Checks if the test results are correct.
+ #[test]
+ fn ut_ylong_json_create_bool() {
+ unsafe {
+ // Creates true.
+ let bool = ylong_json_create_bool(0xffff);
+ let mut val = 0;
+ ylong_json_get_value_from_bool(bool, &mut val as *mut c_int);
+ assert_eq!(val, 1);
+ ylong_json_delete(bool);
+
+ // Creates false.
+ let bool = ylong_json_create_bool(0);
+ let mut val = 1;
+ ylong_json_get_value_from_bool(bool, &mut val as *mut c_int);
+ assert_eq!(val, 0);
+ ylong_json_delete(bool);
+ }
+ }
+
+ /// UT test for `ylong_json_is_bool`.
+ ///
+ /// # Title
+ /// ut_ylong_json_is_bool
+ ///
+ /// # Brief
+ /// 1. Calls `ylong_json_is_bool` to determine whether the underlying structure is bool.
+ /// 2. Checks if the test results are correct.
+ #[test]
+ fn ut_ylong_json_is_bool() {
+ unsafe {
+ // Null ptr
+ let bool = null_mut();
+ assert_eq!(ylong_json_is_bool(bool), 0);
+
+ // True
+ let bool = ylong_json_create_bool(0xffff);
+ assert_eq!(ylong_json_is_bool(bool), 1);
+ ylong_json_delete(bool);
+
+ // False
+ let bool = ylong_json_create_bool(0);
+ assert_eq!(ylong_json_is_bool(bool), 1);
+ ylong_json_delete(bool);
+
+ // Non-bool case
+ let null = ylong_json_create_null();
+ assert_eq!(ylong_json_is_bool(null), 0);
+ ylong_json_delete(null);
+ }
+ }
+
+ /// UT test for `ylong_json_get_value_from_bool`.
+ ///
+ /// # Title
+ /// ut_ylong_json_get_value_from_bool
+ ///
+ /// # Brief
+ /// 1. Calls `ylong_json_get_value_from_bool` to get value from bool.
+ /// 2. Checks if the test results are correct.
+ #[test]
+ fn ut_ylong_json_get_value_from_bool() {
+ unsafe {
+ // Null ptr
+ let bool = null_mut();
+ let mut val = 0i32;
+ assert_eq!(
+ ylong_json_get_value_from_bool(bool, &mut val as *mut c_int),
+ 0
+ );
+
+ let bool = ylong_json_create_bool(0xffff);
+ let mut val = 0;
+ assert_eq!(
+ ylong_json_get_value_from_bool(bool, &mut val as *mut c_int),
+ 1
+ );
+ assert_eq!(val, 1);
+ ylong_json_delete(bool);
+
+ let null = ylong_json_create_null();
+ let mut val = 0;
+ assert_eq!(
+ ylong_json_get_value_from_bool(null, &mut val as *mut c_int),
+ 0
+ );
+ ylong_json_delete(null);
+ }
+ }
+
+ /// UT test for `ylong_json_set_value_to_bool`.
+ ///
+ /// # Title
+ /// ut_ylong_json_set_value_to_bool
+ ///
+ /// # Brief
+ /// 1. Calls `ylong_json_set_value_to_bool` to set value to bool.
+ /// 2. Checks if the test results are correct.
+ #[test]
+ fn ut_ylong_json_set_value_to_bool() {
+ unsafe {
+ // Null ptr
+ let bool = null_mut();
+ assert_eq!(ylong_json_set_value_to_bool(bool, 1), 0);
+
+ let bool = ylong_json_create_bool(0xffff);
+ let mut val = 0;
+ assert_eq!(
+ ylong_json_get_value_from_bool(bool, &mut val as *mut c_int),
+ 1
+ );
+ assert_eq!(val, 1);
+
+ assert_eq!(ylong_json_set_value_to_bool(bool, 0), 1);
+ assert_eq!(
+ ylong_json_get_value_from_bool(bool, &mut val as *mut c_int),
+ 1
+ );
+ assert_eq!(val, 0);
+ ylong_json_delete(bool);
+
+ let null = ylong_json_create_null();
+ assert_eq!(ylong_json_set_value_to_bool(null, 0), 0);
+ ylong_json_delete(null);
+ }
+ }
+
+ /// UT test for `ylong_json_create_double_number`.
+ ///
+ /// # Title
+ /// ut_ylong_json_create_double_number
+ ///
+ /// # Brief
+ /// 1. Calls `ylong_json_create_double_number` to create a double number.
+ /// 2. Checks if the test results are correct.
+ #[test]
+ fn ut_ylong_json_create_double_number() {
+ unsafe {
+ let double = ylong_json_create_double_number(3.24);
+ let mut number = 0f64;
+ ylong_json_get_double_value_from_number(double, &mut number as *mut c_double);
+ assert_eq!(number, 3.24);
+ ylong_json_delete(double);
+ }
+ }
+
+ /// UT test for `ylong_json_create_int_number`.
+ ///
+ /// # Title
+ /// ut_ylong_json_create_int_number
+ ///
+ /// # Brief
+ /// 1. Calls `ylong_json_create_int_number` to create a int number.
+ /// 2. Checks if the test results are correct.
+ #[test]
+ fn ut_ylong_json_create_int_number() {
+ unsafe {
+ let int = ylong_json_create_int_number(0xffff);
+ let mut number = 0i64;
+ ylong_json_get_int_value_from_number(int, &mut number as *mut c_longlong);
+ assert_eq!(number, 0xffff);
+ ylong_json_delete(int);
+ }
+ }
+
+ /// UT test for `ylong_json_is_number`.
+ ///
+ /// # Title
+ /// ut_ylong_json_is_number
+ ///
+ /// # Brief
+ /// 1. Calls `ylong_json_is_number` to determine whether the value is number.
+ /// 2. Checks if the test results are correct.
+ #[test]
+ fn ut_ylong_json_is_number() {
+ unsafe {
+ // Null ptr
+ let number = null_mut();
+ assert_eq!(ylong_json_is_number(number), 0);
+
+ let int = ylong_json_create_int_number(1i64);
+ assert_eq!(ylong_json_is_number(int), 1);
+ ylong_json_delete(int);
+
+ let double = ylong_json_create_double_number(3.24);
+ assert_eq!(ylong_json_is_number(double), 1);
+ ylong_json_delete(double);
+
+ let null = ylong_json_create_null();
+ assert_eq!(ylong_json_is_number(null), 0);
+ ylong_json_delete(null);
+ }
+ }
+
+ /// UT test for `ylong_json_is_double_number`.
+ ///
+ /// # Title
+ /// ut_ylong_json_is_double_number
+ ///
+ /// # Brief
+ /// 1. Calls `ylong_json_is_double_number` to determine whether the value is double number.
+ /// 2. Checks if the test results are correct.
+ #[test]
+ fn ut_ylong_json_is_double_number() {
+ unsafe {
+ // Null ptr
+ let double = null_mut();
+ assert_eq!(ylong_json_is_double_number(double), 0);
+
+ let int = ylong_json_create_int_number(1i64);
+ assert_eq!(ylong_json_is_double_number(int), 0);
+ ylong_json_delete(int);
+
+ let double = ylong_json_create_double_number(3.24);
+ assert_eq!(ylong_json_is_double_number(double), 1);
+ ylong_json_delete(double);
+
+ let null = ylong_json_create_null();
+ assert_eq!(ylong_json_is_double_number(null), 0);
+ ylong_json_delete(null);
+ }
+ }
+
+ /// UT test for `ylong_json_is_int_number`.
+ ///
+ /// # Title
+ /// ut_ylong_json_is_int_number
+ ///
+ /// # Brief
+ /// 1. Calls `ylong_json_is_int_number` to determine whether the value is int number.
+ /// 2. Checks if the test results are correct.
+ #[test]
+ fn ut_ylong_json_is_int_number() {
+ unsafe {
+ // Null ptr
+ let int = null_mut();
+ assert_eq!(ylong_json_is_int_number(int), 0);
+
+ let int = ylong_json_create_int_number(1i64);
+ assert_eq!(ylong_json_is_int_number(int), 1);
+ ylong_json_delete(int);
+
+ let double = ylong_json_create_double_number(3.24);
+ assert_eq!(ylong_json_is_int_number(double), 0);
+ ylong_json_delete(double);
+
+ let null = ylong_json_create_null();
+ assert_eq!(ylong_json_is_int_number(null), 0);
+ ylong_json_delete(null);
+ }
+ }
+
+ /// UT test for `ylong_json_get_double_value_from_number`.
+ ///
+ /// # Title
+ /// ut_ylong_json_get_double_value_from_number
+ ///
+ /// # Brief
+ /// 1. Calls `ylong_json_get_double_value_from_number` to get double value from number.
+ /// 2. Checks if the test results are correct.
+ #[test]
+ fn ut_ylong_json_get_double_value_from_number() {
+ unsafe {
+ // Null ptr
+ let double = null_mut();
+ let mut number = 0f64;
+ assert_eq!(
+ ylong_json_get_double_value_from_number(double, &mut number as *mut c_double),
+ 0
+ );
+
+ let int = ylong_json_create_int_number(1i64);
+ let mut number = 0f64;
+ assert_eq!(
+ ylong_json_get_double_value_from_number(int, &mut number as *mut c_double),
+ 1
+ );
+ assert_eq!(number, 1.0);
+ ylong_json_delete(int);
+
+ let double = ylong_json_create_double_number(3.24);
+ let mut number = 0f64;
+ assert_eq!(
+ ylong_json_get_double_value_from_number(double, &mut number as *mut c_double),
+ 1
+ );
+ assert_eq!(number, 3.24);
+ ylong_json_delete(double);
+
+ let null = ylong_json_create_null();
+ let mut number = 0f64;
+ assert_eq!(
+ ylong_json_get_double_value_from_number(null, &mut number as *mut c_double),
+ 0
+ );
+ ylong_json_delete(null);
+ }
+ }
+
+ /// UT test for `ylong_json_get_int_value_from_number`.
+ ///
+ /// # Title
+ /// ut_ylong_json_get_int_value_from_number
+ ///
+ /// # Brief
+ /// 1. Calls `ylong_json_get_int_value_from_number` to get int value from number.
+ /// 2. Checks if the test results are correct.
+ #[test]
+ fn ut_ylong_json_get_int_value_from_number() {
+ unsafe {
+ // Null ptr
+ let int = null_mut();
+ let mut number = 0i64;
+ assert_eq!(
+ ylong_json_get_int_value_from_number(int, &mut number as *mut c_longlong),
+ 0
+ );
+
+ let int = ylong_json_create_int_number(1i64);
+ let mut number = 0i64;
+ assert_eq!(
+ ylong_json_get_int_value_from_number(int, &mut number as *mut c_longlong),
+ 1
+ );
+ assert_eq!(number, 1i64);
+ ylong_json_delete(int);
+
+ let double = ylong_json_create_double_number(3.24);
+ let mut number = 0i64;
+ assert_eq!(
+ ylong_json_get_int_value_from_number(double, &mut number as *mut c_longlong),
+ 1
+ );
+ assert_eq!(number, 3i64);
+ ylong_json_delete(double);
+
+ let null = ylong_json_create_null();
+ let mut number = 0i64;
+ assert_eq!(
+ ylong_json_get_int_value_from_number(null, &mut number as *mut c_longlong),
+ 0
+ );
+ ylong_json_delete(null);
+ }
+ }
+
+ /// UT test for `ylong_json_set_double_value_to_number`.
+ ///
+ /// # Title
+ /// ut_ylong_json_set_double_value_to_number
+ ///
+ /// # Brief
+ /// 1. Calls `ylong_json_set_double_value_to_number` to set double value to number.
+ /// 2. Checks if the test results are correct.
+ #[test]
+ fn ut_ylong_json_set_double_value_to_number() {
+ unsafe {
+ // Null ptr
+ let number = null_mut();
+ assert_eq!(ylong_json_set_double_value_to_number(number, 3.24), 0);
+
+ let double = ylong_json_create_double_number(3.24);
+ let mut number = 0f64;
+ ylong_json_get_double_value_from_number(double, &mut number as *mut c_double);
+ assert_eq!(number, 3.24);
+ assert_eq!(ylong_json_set_double_value_to_number(double, 1.23), 1);
+ ylong_json_get_double_value_from_number(double, &mut number as *mut c_double);
+ assert_eq!(number, 1.23);
+ ylong_json_delete(double);
+
+ let int = ylong_json_create_int_number(1i64);
+ let mut number = 0i64;
+ ylong_json_get_int_value_from_number(int, &mut number as *mut c_longlong);
+ assert_eq!(number, 1i64);
+ assert_eq!(ylong_json_set_double_value_to_number(int, 3.24), 1);
+ ylong_json_get_int_value_from_number(int, &mut number as *mut c_longlong);
+ assert_eq!(number, 3i64);
+ ylong_json_delete(int);
+
+ let null = ylong_json_create_null();
+ assert_eq!(ylong_json_set_double_value_to_number(null, 3.24), 0);
+ ylong_json_delete(null);
+ }
+ }
+
+ /// UT test for `ylong_json_set_int_value_to_number`.
+ ///
+ /// # Title
+ /// ut_ylong_json_set_int_value_to_number
+ ///
+ /// # Brief
+ /// 1. Calls `ylong_json_set_int_value_to_number` to set int value to number.
+ /// 2. Checks if the test results are correct.
+ #[test]
+ fn ut_ylong_json_set_int_value_to_number() {
+ unsafe {
+ // Null ptr
+ let number = null_mut();
+ assert_eq!(ylong_json_set_int_value_to_number(number, 1), 0);
+
+ let int = ylong_json_create_int_number(1i64);
+ let mut number = 0i64;
+ ylong_json_get_int_value_from_number(int, &mut number as *mut c_longlong);
+ assert_eq!(number, 1i64);
+ assert_eq!(ylong_json_set_int_value_to_number(int, 3i64), 1);
+ ylong_json_get_int_value_from_number(int, &mut number as *mut c_longlong);
+ assert_eq!(number, 3i64);
+ ylong_json_delete(int);
+
+ let double = ylong_json_create_double_number(3.24);
+ let mut number = 0f64;
+ ylong_json_get_double_value_from_number(double, &mut number as *mut c_double);
+ assert_eq!(number, 3.24);
+ assert_eq!(ylong_json_set_int_value_to_number(double, 1), 1);
+ ylong_json_get_double_value_from_number(double, &mut number as *mut c_double);
+ assert_eq!(number, 1.0);
+ ylong_json_delete(double);
+
+ let null = ylong_json_create_null();
+ assert_eq!(ylong_json_set_int_value_to_number(null, 1), 0);
+ ylong_json_delete(null);
+ }
+ }
+
+ /// UT test for `ylong_json_create_string`.
+ ///
+ /// # Title
+ /// ut_ylong_json_create_string
+ ///
+ /// # Brief
+ /// 1. Calls `ylong_json_create_string` to create a string from *mut c_char.
+ /// 2. Checks if the test results are correct.
+ #[test]
+ fn ut_ylong_json_create_string() {
+ unsafe {
+ // Null ptr
+ let str = null();
+ assert!(ylong_json_create_string(str).is_null());
+
+ let str = str_to_c_char("Hello World");
+ let string = ylong_json_create_string(str);
+ let mut content = null_mut();
+ ylong_json_get_value_from_string(string, &mut content as *mut *mut c_char);
+ let result = String::from_utf8_unchecked(CStr::from_ptr(content).to_bytes().to_vec());
+ assert_eq!(result, "Hello World");
+ // Destruction
+ let _ = Box::from_raw(str);
+ ylong_json_delete(string);
+ }
+ }
+
+ /// UT test for `ylong_json_is_string`.
+ ///
+ /// # Title
+ /// ut_ylong_json_is_string
+ ///
+ /// # Brief
+ /// 1. Calls `ylong_json_is_string` to determine whether the value is string.
+ /// 2. Checks if the test results are correct.
+ #[test]
+ fn ut_ylong_json_is_string() {
+ unsafe {
+ // Null ptr
+ let string = null_mut();
+ assert_eq!(ylong_json_is_string(string), 0);
+
+ let str = str_to_c_char("Hello World");
+ let string = ylong_json_create_string(str);
+ assert_eq!(ylong_json_is_string(string), 1);
+ let _ = Box::from_raw(str);
+ ylong_json_delete(string);
+
+ let null = ylong_json_create_null();
+ assert_eq!(ylong_json_is_string(null), 0);
+ ylong_json_delete(null);
+ }
+ }
+
+ /// UT test for `ylong_json_get_value_from_string`.
+ ///
+ /// # Title
+ /// ut_ylong_json_get_value_from_string
+ ///
+ /// # Brief
+ /// 1. Calls `ylong_json_get_value_from_string` to get value from string.
+ /// 2. Checks if the test results are correct.
+ #[test]
+ fn ut_ylong_json_get_value_from_string() {
+ unsafe {
+ // Null ptr
+ let string = null_mut();
+ let mut str = null_mut();
+ assert_eq!(
+ ylong_json_get_value_from_string(string, &mut str as *mut *mut c_char),
+ 0
+ );
+
+ let str = str_to_c_char("Hello World");
+ let string = ylong_json_create_string(str);
+ let mut content = null_mut();
+ assert_eq!(
+ ylong_json_get_value_from_string(string, &mut content as *mut *mut c_char),
+ 1
+ );
+ let result = String::from_utf8_unchecked(CStr::from_ptr(content).to_bytes().to_vec());
+ assert_eq!(result, "Hello World");
+ let _ = Box::from_raw(str);
+ ylong_json_delete(string);
+
+ let null = ylong_json_create_null();
+ let mut content = null_mut();
+ assert_eq!(
+ ylong_json_get_value_from_string(null, &mut content as *mut *mut c_char),
+ 0
+ );
+ ylong_json_delete(null);
+ }
+ }
+
+ /// UT test for `ylong_json_set_value_to_string`.
+ ///
+ /// # Title
+ /// ut_ylong_json_set_value_to_string
+ ///
+ /// # Brief
+ /// 1. Calls `ylong_json_set_value_to_string` to set value to string.
+ /// 2. Checks if the test results are correct.
+ #[test]
+ fn ut_ylong_json_set_value_to_string() {
+ unsafe {
+ // Null ptr
+ let string = null_mut();
+ let str = str_to_c_char("Hello World");
+ assert_eq!(ylong_json_set_value_to_string(string, str), 0);
+ let _ = Box::from_raw(str);
+
+ // Null ptr
+ let str = str_to_c_char("Hello World");
+ let string = ylong_json_create_string(str);
+ let _ = Box::from_raw(str);
+ let str = null();
+ assert_eq!(ylong_json_set_value_to_string(string, str), 0);
+ ylong_json_delete(string);
+
+ let str = str_to_c_char("Hello World");
+ let string = ylong_json_create_string(str);
+ // Check if the original value is "Hello World".
+ let mut content = null_mut();
+ ylong_json_get_value_from_string(string, &mut content as *mut *mut c_char);
+ let result = String::from_utf8_unchecked(CStr::from_ptr(content).to_bytes().to_vec());
+ assert_eq!(result, "Hello World");
+ let _ = Box::from_raw(str);
+ // Use the function to set the content to "New String".
+ let str = str_to_c_char("New String");
+ assert_eq!(ylong_json_set_value_to_string(string, str), 1);
+ // Check whether the Settings are successful.
+ ylong_json_get_value_from_string(string, &mut content as *mut *mut c_char);
+ let result = String::from_utf8_unchecked(CStr::from_ptr(content).to_bytes().to_vec());
+ assert_eq!(result, "New String");
+ let _ = Box::from_raw(str);
+ ylong_json_delete(string);
+
+ let null = ylong_json_create_null();
+ let str = str_to_c_char("New String");
+ assert_eq!(ylong_json_set_value_to_string(null, str), 0);
+ let _ = Box::from_raw(str);
+ ylong_json_delete(null);
+ }
+ }
+
+ /// UT test for `ylong_json_create_array`.
+ ///
+ /// # Title
+ /// ut_ylong_json_create_array
+ ///
+ /// # Brief
+ /// 1. Calls `ylong_json_create_array` to create an array.
+ /// 2. Checks if the test results are correct.
+ #[test]
+ fn ut_ylong_json_create_array() {
+ unsafe {
+ let array = ylong_json_create_array();
+ let result = ylong_json_print_unformatted(array);
+ let result = CString::from_raw(result).into_string().unwrap();
+ assert_eq!(result, "[]");
+ ylong_json_delete(array);
+ }
+ }
+
+ /// UT test for `ut_ylong_json_is_array`.
+ ///
+ /// # Title
+ /// ut_ylong_json_is_array
+ ///
+ /// # Brief
+ /// 1. Calls `long_json_is_array` to determine whether the value is an array.
+ /// 2. Checks if the test results are correct.
+ #[test]
+ fn ut_ylong_json_is_array() {
+ unsafe {
+ // Null ptr
+ let array = null_mut();
+ assert_eq!(ylong_json_is_array(array), 0);
+
+ let array = ylong_json_create_array();
+ assert_eq!(ylong_json_is_array(array), 1);
+ ylong_json_delete(array);
+
+ let null = ylong_json_create_null();
+ assert_eq!(ylong_json_is_array(null), 0);
+ ylong_json_delete(null);
+ }
+ }
+
+ /// UT test for `ylong_json_get_array_size`.
+ ///
+ /// # Title
+ /// ut_ylong_json_get_array_size
+ ///
+ /// # Brief
+ /// 1. Calls `ylong_json_get_array_size` to get size of the array.
+ /// 2. Checks if the test results are correct.
+ #[test]
+ fn ut_ylong_json_get_array_size() {
+ unsafe {
+ // Null ptr
+ let array = null_mut();
+ let mut len = 0i32;
+ assert_eq!(ylong_json_get_array_size(array, &mut len as *mut c_int), 0);
+
+ // Null ptr
+ let array = ylong_json_create_array();
+ let len = null_mut();
+ assert_eq!(ylong_json_get_array_size(array, len), 0);
+ ylong_json_delete(array);
+
+ let array = ylong_json_create_array();
+ let mut len = 1i32;
+ assert_eq!(ylong_json_get_array_size(array, &mut len as *mut c_int), 1);
+ assert_eq!(len, 0);
+ ylong_json_delete(array);
+
+ let null = ylong_json_create_null();
+ let mut len = 1i32;
+ assert_eq!(ylong_json_get_array_size(null, &mut len as *mut c_int), 0);
+ ylong_json_delete(null);
+ }
+ }
+
+ /// UT test for `ylong_json_get_array_item`.
+ ///
+ /// # Title
+ /// ut_ylong_json_get_array_item
+ ///
+ /// # Brief
+ /// 1. Calls `ylong_json_get_array_item` to get an item of the array.
+ /// 2. Checks if the test results are correct.
+ #[test]
+ fn ut_ylong_json_get_array_item() {
+ unsafe {
+ // Null ptr
+ let array = null_mut();
+ assert!(ylong_json_get_array_item(array, 0).is_null());
+
+ const TEXT: &str = "[null, 1.0, true, \"Test\"]";
+ let str = str_to_c_char(TEXT);
+ let mut msg = null_mut();
+ let array = ylong_json_parse(str, &mut msg as *mut *mut c_char);
+ let _ = Box::from_raw(str);
+ assert_eq!(ylong_json_is_array(array), 1);
+
+ let item0 = ylong_json_get_array_item(array, 0);
+ assert_eq!(ylong_json_is_null(item0), 1);
+
+ let item1 = ylong_json_get_array_item(array, 1);
+ assert_eq!(ylong_json_is_double_number(item1), 1);
+ let mut number = 0f64;
+ assert_eq!(
+ ylong_json_get_double_value_from_number(item1, &mut number as *mut c_double),
+ 1
+ );
+ assert_eq!(number, 1.0);
+
+ let item2 = ylong_json_get_array_item(array, 2);
+ assert_eq!(ylong_json_is_bool(item2), 1);
+ let mut bool = 0i32;
+ assert_eq!(
+ ylong_json_get_value_from_bool(item2, &mut bool as *mut c_int),
+ 1
+ );
+ assert_eq!(bool, 1i32);
+
+ let item3 = ylong_json_get_array_item(array, 3);
+ assert_eq!(ylong_json_is_string(item3), 1);
+ let mut content = null_mut();
+ assert_eq!(
+ ylong_json_get_value_from_string(item3, &mut content as *mut *mut c_char),
+ 1
+ );
+ let result = String::from_utf8_unchecked(CStr::from_ptr(content).to_bytes().to_vec());
+ assert_eq!(result, "Test");
+
+ assert!(ylong_json_get_array_item(array, 4).is_null());
+
+ ylong_json_delete(array);
+
+ let null = ylong_json_create_null();
+ assert!(ylong_json_get_array_item(null, 0).is_null());
+ ylong_json_delete(null);
+ }
+ }
+
+ /// UT test for `ylong_json_add_item_to_array`.
+ ///
+ /// # Title
+ /// ut_ylong_json_add_item_to_array
+ ///
+ /// # Brief
+ /// 1. Calls `ylong_json_add_item_to_array` to add an item to the array.
+ /// 2. Checks if the test results are correct.
+ #[test]
+ fn ut_ylong_json_add_item_to_array() {
+ unsafe {
+ // Null ptr
+ let array = null_mut();
+ let item = ylong_json_create_null();
+ assert_eq!(ylong_json_add_item_to_array(array, item), 0);
+ ylong_json_delete(item);
+
+ let array = ylong_json_create_array();
+ let item = null_mut();
+ assert_eq!(ylong_json_add_item_to_array(array, item), 0);
+ ylong_json_delete(array);
+
+ let array = ylong_json_create_array();
+ let null = ylong_json_create_null();
+ assert_eq!(ylong_json_add_item_to_array(array, null), 1);
+ let result = ylong_json_print_unformatted(array);
+ let result = CString::from_raw(result).into_string().unwrap();
+ assert_eq!(result, "[null]");
+ ylong_json_delete(array);
+
+ let null = ylong_json_create_null();
+ let null2 = ylong_json_create_null();
+ assert_eq!(ylong_json_add_item_to_array(null, null2), 0);
+ ylong_json_delete(null);
+ ylong_json_delete(null2);
+ }
+ }
+
+ /// UT test for `ylong_json_replace_item_in_array`.
+ ///
+ /// # Title
+ /// ut_ylong_json_replace_item_in_array
+ ///
+ /// # Brief
+ /// 1. Calls `ylong_json_replace_item_in_array` to replace an item in the array.
+ /// 2. Checks if the test results are correct.
+ #[test]
+ fn ut_ylong_json_replace_item_in_array() {
+ unsafe {
+ // Null ptr
+ let array = null_mut();
+ let item = ylong_json_create_null();
+ assert_eq!(ylong_json_replace_array_item_by_index(array, 0, item), 0);
+ ylong_json_delete(item);
+
+ // Null ptr
+ let array = ylong_json_create_array();
+ let item = null_mut();
+ assert_eq!(ylong_json_replace_array_item_by_index(array, 0, item), 0);
+ ylong_json_delete(array);
+
+ let array = ylong_json_create_array();
+ let null = ylong_json_create_null();
+ assert_eq!(ylong_json_add_item_to_array(array, null), 1);
+ let result = ylong_json_print_unformatted(array);
+ let result = CString::from_raw(result).into_string().unwrap();
+ assert_eq!(result, "[null]");
+ let replace = ylong_json_create_bool(1);
+ assert_eq!(ylong_json_replace_array_item_by_index(array, 0, replace), 1);
+ let result = ylong_json_print_unformatted(array);
+ let result = CString::from_raw(result).into_string().unwrap();
+ assert_eq!(result, "[true]");
+ ylong_json_delete(array);
+
+ let null = ylong_json_create_null();
+ let null2 = ylong_json_create_null();
+ assert_eq!(ylong_json_replace_array_item_by_index(null, 0, null2), 0);
+ ylong_json_delete(null);
+ ylong_json_delete(null2);
+ }
+ }
+
+ /// UT test for `ylong_json_remove_array_item_by_index`.
+ ///
+ /// # Title
+ /// ut_ylong_json_remove_array_item_by_index
+ ///
+ /// # Brief
+ /// 1. Calls `ylong_json_remove_array_item_by_index` to remove an item in the array by index.
+ /// (Uses the method 'remove' of Array.)
+ /// 2. Checks if the test results are correct.
+ #[test]
+ fn ut_ylong_json_remove_array_item_by_index() {
+ unsafe {
+ // Null ptr
+ let array = null_mut();
+ assert!(ylong_json_remove_array_item_by_index(array, 0).is_null());
+
+ const TEXT: &str = "[null, 1.0, true, \"Test\"]";
+ let str = str_to_c_char(TEXT);
+ let mut msg = null_mut();
+ let array = ylong_json_parse(str, &mut msg as *mut *mut c_char);
+ let _ = Box::from_raw(str);
+ let mut len = 0i32;
+ assert_eq!(ylong_json_get_array_size(array, &mut len as *mut c_int), 1);
+ assert_eq!(len, 4);
+
+ let item0 = ylong_json_remove_array_item_by_index(array, 0);
+ assert_eq!(ylong_json_is_null(item0), 1);
+ assert_eq!(ylong_json_get_array_size(array, &mut len as *mut c_int), 1);
+ assert_eq!(len, 3);
+ ylong_json_delete(item0);
+
+ let item3 = ylong_json_remove_array_item_by_index(array, 2);
+ assert_eq!(ylong_json_is_string(item3), 1);
+ assert_eq!(ylong_json_get_array_size(array, &mut len as *mut c_int), 1);
+ assert_eq!(len, 2);
+ ylong_json_delete(item3);
+
+ let item1 = ylong_json_remove_array_item_by_index(array, 0);
+ assert_eq!(ylong_json_is_number(item1), 1);
+ assert_eq!(ylong_json_get_array_size(array, &mut len as *mut c_int), 1);
+ assert_eq!(len, 1);
+ ylong_json_delete(item1);
+
+ let item2 = ylong_json_remove_array_item_by_index(array, 0);
+ assert_eq!(ylong_json_is_bool(item2), 1);
+ assert_eq!(ylong_json_get_array_size(array, &mut len as *mut c_int), 1);
+ assert_eq!(len, 0);
+ ylong_json_delete(item2);
+ ylong_json_delete(array);
+
+ let null = ylong_json_create_null();
+ let item = ylong_json_remove_array_item_by_index(null, 0);
+ assert!(item.is_null());
+ ylong_json_delete(null);
+ }
+ }
+
+ /// UT test for `ylong_json_delete_array_item_by_index`.
+ ///
+ /// # Title
+ /// ut_ylong_json_delete_array_item_by_index
+ ///
+ /// # Brief
+ /// 1. Calls `ylong_json_delete_array_item_by_index` to delete an item in the array by index.
+ /// (Uses the method 'remove' of underlying data structure.)
+ /// 2. Checks if the test results are correct.
+ #[test]
+ fn ut_ylong_json_delete_array_item_by_index() {
+ unsafe {
+ // Null ptr scene, if the process does not exit abnormally, it is successful.
+ let array = null_mut();
+ ylong_json_delete_array_item_by_index(array, 0);
+
+ const TEXT: &str = "[null, 1.0, true, \"Test\"]";
+ let str = str_to_c_char(TEXT);
+ let mut msg = null_mut();
+ let array = ylong_json_parse(str, &mut msg as *mut *mut c_char);
+ let mut len = 0i32;
+ assert_eq!(ylong_json_get_array_size(array, &mut len as *mut c_int), 1);
+ assert_eq!(len, 4);
+
+ ylong_json_delete_array_item_by_index(array, 0);
+ assert_eq!(ylong_json_get_array_size(array, &mut len as *mut c_int), 1);
+ assert_eq!(len, 3);
+
+ ylong_json_delete_array_item_by_index(array, 0);
+ assert_eq!(ylong_json_get_array_size(array, &mut len as *mut c_int), 1);
+ assert_eq!(len, 2);
+
+ ylong_json_delete_array_item_by_index(array, 0);
+ assert_eq!(ylong_json_get_array_size(array, &mut len as *mut c_int), 1);
+ assert_eq!(len, 1);
+
+ ylong_json_delete_array_item_by_index(array, 0);
+ assert_eq!(ylong_json_get_array_size(array, &mut len as *mut c_int), 1);
+ assert_eq!(len, 0);
+
+ let _ = Box::from_raw(str);
+ ylong_json_delete(array);
+
+ let null = ylong_json_create_null();
+ ylong_json_delete_array_item_by_index(null, 0);
+ ylong_json_delete(null);
+ }
+ }
+
+ /// UT test for `ylong_json_get_array_node`.
+ ///
+ /// # Title
+ /// ut_ylong_json_get_array_node
+ ///
+ /// # Brief
+ /// 1. Calls `ylong_json_get_array_node` to get an array node.
+ /// 2. Checks if the test results are correct.
+ #[cfg(feature = "list_array")]
+ #[test]
+ fn ut_ylong_json_get_array_node() {
+ unsafe {
+ // Null ptr
+ let array = null_mut();
+ assert!(ylong_json_get_array_node(array, 0).is_null());
+
+ const TEXT: &str = "[null, 1.0, true, \"Test\"]";
+ let str = str_to_c_char(TEXT);
+ let mut msg = null_mut();
+ let array = ylong_json_parse(str, &mut msg as *mut *mut c_char);
+ let _ = Box::from_raw(str);
+ assert_eq!(ylong_json_is_array(array), 1);
+
+ let node0 = ylong_json_get_array_node(array, 0);
+ assert!(!node0.is_null());
+
+ let node1 = ylong_json_get_array_node(array, 1);
+ assert!(!node1.is_null());
+
+ let node2 = ylong_json_get_array_node(array, 2);
+ assert!(!node2.is_null());
+
+ let node3 = ylong_json_get_array_node(array, 3);
+ assert!(!node3.is_null());
+
+ let node4 = ylong_json_get_array_node(array, 4);
+ assert!(node4.is_null());
+
+ ylong_json_delete(array);
+
+ let null = ylong_json_create_null();
+ assert!(ylong_json_get_array_node(null, 0).is_null());
+ ylong_json_delete(null);
+ }
+ }
+
+ /// UT test for `ylong_json_get_item_from_array_node`.
+ ///
+ /// # Title
+ /// ut_ylong_json_get_item_from_array_node
+ ///
+ /// # Brief
+ /// 1. Calls `ylong_json_get_item_from_array_node` to get the item of an array node.
+ /// 2. Checks if the test results are correct.
+ #[cfg(feature = "list_array")]
+ #[test]
+ fn ut_ylong_json_get_item_from_array_node() {
+ unsafe {
+ // Null ptr
+ let node = null_mut();
+ assert!(ylong_json_get_array_node(node, 0).is_null());
+
+ const TEXT: &str = "[null, 1.0, true, \"Test\"]";
+ let str = str_to_c_char(TEXT);
+ let mut msg = null_mut();
+ let array = ylong_json_parse(str, &mut msg as *mut *mut c_char);
+ let _ = Box::from_raw(str);
+ assert_eq!(ylong_json_is_array(array), 1);
+
+ let node0 = ylong_json_get_array_node(array, 0);
+ assert!(!node0.is_null());
+ let item0 = ylong_json_get_item_from_array_node(node0);
+ assert_eq!(ylong_json_is_null(item0), 1);
+
+ let node1 = ylong_json_get_array_node(array, 1);
+ assert!(!node1.is_null());
+ let item1 = ylong_json_get_item_from_array_node(node1);
+ let mut number = 0f64;
+ assert_eq!(
+ ylong_json_get_double_value_from_number(item1, &mut number as *mut c_double),
+ 1
+ );
+ assert_eq!(number, 1.0);
+
+ let node2 = ylong_json_get_array_node(array, 2);
+ assert!(!node2.is_null());
+ let item2 = ylong_json_get_item_from_array_node(node2);
+ let mut bool = 0i32;
+ assert_eq!(
+ ylong_json_get_value_from_bool(item2, &mut bool as *mut c_int),
+ 1
+ );
+ assert_eq!(bool, 1i32);
+
+ let node3 = ylong_json_get_array_node(array, 3);
+ assert!(!node3.is_null());
+ let item3 = ylong_json_get_item_from_array_node(node3);
+ let mut content = null_mut();
+ assert_eq!(
+ ylong_json_get_value_from_string(item3, &mut content as *mut *mut c_char),
+ 1
+ );
+ let result = String::from_utf8_unchecked(CStr::from_ptr(content).to_bytes().to_vec());
+ assert_eq!(result, "Test");
+
+ ylong_json_delete(array);
+ }
+ }
+
+ /// UT test for `ylong_json_add_item_to_array_then_get_node`.
+ ///
+ /// # Title
+ /// ut_ylong_json_add_item_to_array_then_get_node
+ ///
+ /// # Brief
+ /// 1. Calls `ylong_json_add_item_to_array_then_get_node` to add an item to array and get the corresponding node.
+ /// 2. Checks if the test results are correct.
+ #[cfg(feature = "list_array")]
+ #[test]
+ fn ut_ylong_json_add_item_to_array_then_get_node() {
+ unsafe {
+ // Null ptr
+ let array = null_mut();
+ let item = ylong_json_create_null();
+ assert!(ylong_json_add_item_to_array_then_get_node(array, item).is_null());
+ ylong_json_delete(item);
+
+ // Null ptr
+ let array = ylong_json_create_array();
+ let item = null_mut();
+ assert!(ylong_json_add_item_to_array_then_get_node(array, item).is_null());
+ ylong_json_delete(array);
+
+ let array = ylong_json_create_array();
+ let null = ylong_json_create_null();
+ let node0 = ylong_json_add_item_to_array_then_get_node(array, null);
+ assert!(!node0.is_null());
+ let mut len = 0i32;
+ assert_eq!(ylong_json_get_array_size(array, &mut len as *mut c_int), 1);
+ assert_eq!(len, 1);
+ let item0 = ylong_json_get_item_from_array_node(node0);
+ assert!(!item0.is_null());
+ assert_eq!(ylong_json_is_null(item0), 1);
+ let item0 = ylong_json_remove_array_node(node0);
+ ylong_json_delete(item0);
+ assert_eq!(ylong_json_get_array_size(array, &mut len as *mut c_int), 1);
+ assert_eq!(len, 0);
+ ylong_json_delete(array);
+ }
+ }
+
+ /// UT test for `ylong_json_replace_item_of_array_node`.
+ ///
+ /// # Title
+ /// ut_ylong_json_replace_item_of_array_node
+ ///
+ /// # Brief
+ /// 1. Calls `ylong_json_replace_item_of_array_node` to replace the item of an array node.
+ /// 2. Checks if the test results are correct.
+ #[cfg(feature = "list_array")]
+ #[test]
+ fn ut_ylong_json_replace_item_of_array_node() {
+ unsafe {
+ // Null ptr
+ let node = null_mut();
+ let item = ylong_json_create_null();
+ assert_eq!(ylong_json_replace_item_of_array_node(node, item), 0);
+ ylong_json_delete(item);
+
+ // Null ptr scene, if the process does not exit abnormally, it is successful.
+ let array = ylong_json_create_array();
+ let null = ylong_json_create_null();
+ let node = ylong_json_add_item_to_array_then_get_node(array, null);
+ let item = null_mut();
+ assert_eq!(ylong_json_replace_item_of_array_node(node, item), 0);
+ ylong_json_delete(array);
+
+ let array = ylong_json_create_array();
+ let null = ylong_json_create_null();
+ let node = ylong_json_add_item_to_array_then_get_node(array, null);
+ let result = ylong_json_print_unformatted(array);
+ let result = CString::from_raw(result).into_string().unwrap();
+ assert_eq!(result, "[null]");
+
+ let bool = ylong_json_create_bool(1);
+ assert_eq!(ylong_json_replace_item_of_array_node(node, bool), 1);
+ let result = ylong_json_print_unformatted(array);
+ let result = CString::from_raw(result).into_string().unwrap();
+ assert_eq!(result, "[true]");
+
+ ylong_json_delete(array);
+ }
+ }
+
+ /// UT test for `ylong_json_remove_array_node`.
+ ///
+ /// # Title
+ /// ut_ylong_json_remove_array_node
+ ///
+ /// # Brief
+ /// 1. Calls `ylong_json_remove_array_node` to remove an array node.
+ /// 2. Checks if the test results are correct.
+ #[cfg(feature = "list_array")]
+ #[test]
+ fn ut_ylong_json_remove_array_node() {
+ unsafe {
+ // Null ptr
+ let node = null_mut();
+ assert!(ylong_json_remove_array_node(node).is_null());
+
+ const TEXT: &str = "[null, 1.0, true, \"Test\"]";
+ let str = str_to_c_char(TEXT);
+ let mut msg = null_mut();
+ let array = ylong_json_parse(str, &mut msg as *mut *mut c_char);
+ let _ = Box::from_raw(str);
+ assert_eq!(ylong_json_is_array(array), 1);
+ let mut len = 0i32;
+ assert_eq!(ylong_json_get_array_size(array, &mut len as *mut c_int), 1);
+ assert_eq!(len, 4);
+
+ let node0 = ylong_json_get_array_node(array, 0);
+ assert!(!node0.is_null());
+ let item0 = ylong_json_remove_array_node(node0);
+ assert!(!item0.is_null());
+ assert_eq!(ylong_json_get_array_size(array, &mut len as *mut c_int), 1);
+ assert_eq!(len, 3);
+ assert_eq!(ylong_json_is_null(item0), 1);
+ ylong_json_delete(item0);
+
+ let node0 = ylong_json_get_array_node(array, 0);
+ assert!(!node0.is_null());
+ let item0 = ylong_json_remove_array_node(node0);
+ assert!(!item0.is_null());
+ assert_eq!(ylong_json_get_array_size(array, &mut len as *mut c_int), 1);
+ assert_eq!(len, 2);
+ let mut number = 0f64;
+ assert_eq!(
+ ylong_json_get_double_value_from_number(item0, &mut number as *mut c_double),
+ 1
+ );
+ assert_eq!(number, 1.0);
+ ylong_json_delete(item0);
+
+ let node0 = ylong_json_get_array_node(array, 0);
+ assert!(!node0.is_null());
+ let item0 = ylong_json_remove_array_node(node0);
+ assert!(!item0.is_null());
+ assert_eq!(ylong_json_get_array_size(array, &mut len as *mut c_int), 1);
+ assert_eq!(len, 1);
+ let mut bool = 0i32;
+ assert_eq!(
+ ylong_json_get_value_from_bool(item0, &mut bool as *mut c_int),
+ 1
+ );
+ assert_eq!(bool, 1i32);
+ ylong_json_delete(item0);
+
+ let node0 = ylong_json_get_array_node(array, 0);
+ assert!(!node0.is_null());
+ let item0 = ylong_json_remove_array_node(node0);
+ assert!(!item0.is_null());
+ assert_eq!(ylong_json_get_array_size(array, &mut len as *mut c_int), 1);
+ assert_eq!(len, 0);
+ let mut content = null_mut();
+ assert_eq!(
+ ylong_json_get_value_from_string(item0, &mut content as *mut *mut c_char),
+ 1
+ );
+ let result = String::from_utf8_unchecked(CStr::from_ptr(content).to_bytes().to_vec());
+ assert_eq!(result, "Test");
+ ylong_json_delete(item0);
+
+ ylong_json_delete(array);
+ }
+ }
+
+ /// UT test for `ylong_json_delete_array_node`.
+ ///
+ /// # Title
+ /// ut_ylong_json_delete_array_node
+ ///
+ /// # Brief
+ /// 1. Calls `ylong_json_delete_array_node` to delete an array node.
+ /// 2. Checks if the test results are correct.
+ #[cfg(feature = "list_array")]
+ #[test]
+ fn ut_ylong_json_delete_array_node() {
+ unsafe {
+ // Null ptr scene, if the process does not exit abnormally, it is successful.
+ let node = null_mut();
+ ylong_json_delete_array_node(node);
+
+ const TEXT: &str = "[null, 1.0, true, \"Test\"]";
+ let str = str_to_c_char(TEXT);
+ let mut msg = null_mut();
+ let array = ylong_json_parse(str, &mut msg as *mut *mut c_char);
+ let _ = Box::from_raw(str);
+ let mut len = 0i32;
+ assert_eq!(ylong_json_get_array_size(array, &mut len as *mut c_int), 1);
+ assert_eq!(len, 4);
+
+ let node0 = ylong_json_get_array_node(array, 0);
+ ylong_json_delete_array_node(node0);
+ assert_eq!(ylong_json_get_array_size(array, &mut len as *mut c_int), 1);
+ assert_eq!(len, 3);
+
+ let node1 = ylong_json_get_array_node(array, 0);
+ ylong_json_delete_array_node(node1);
+ assert_eq!(ylong_json_get_array_size(array, &mut len as *mut c_int), 1);
+ assert_eq!(len, 2);
+
+ let node2 = ylong_json_get_array_node(array, 0);
+ ylong_json_delete_array_node(node2);
+ assert_eq!(ylong_json_get_array_size(array, &mut len as *mut c_int), 1);
+ assert_eq!(len, 1);
+
+ let node3 = ylong_json_get_array_node(array, 0);
+ ylong_json_delete_array_node(node3);
+ assert_eq!(ylong_json_get_array_size(array, &mut len as *mut c_int), 1);
+ assert_eq!(len, 0);
+
+ ylong_json_delete(array);
+ }
+ }
+
+ /// UT test for `ylong_json_create_object`.
+ ///
+ /// # Title
+ /// ut_ylong_json_create_object
+ ///
+ /// # Brief
+ /// 1. Calls `ylong_json_create_object` to create an object.
+ /// 2. Checks if the test results are correct.
+ #[test]
+ fn ut_ylong_json_create_object() {
+ unsafe {
+ let object = ylong_json_create_object();
+ assert_eq!(ylong_json_is_object(object), 1);
+ let result = ylong_json_print_unformatted(object);
+ let result = CString::from_raw(result).into_string().unwrap();
+ assert_eq!(result, "{}");
+ ylong_json_delete(object);
+ }
+ }
+
+ /// UT test for `ylong_json_is_object`.
+ ///
+ /// # Title
+ /// ut_ylong_json_is_object
+ ///
+ /// # Brief
+ /// 1. Calls `ylong_json_is_object` to determine whether the value is object.
+ /// 2. Checks if the test results are correct.
+ #[test]
+ fn ut_ylong_json_is_object() {
+ unsafe {
+ // Null ptr
+ let object = null_mut();
+ assert_eq!(ylong_json_is_object(object), 0);
+
+ let object = ylong_json_create_object();
+ assert_eq!(ylong_json_is_object(object), 1);
+ ylong_json_delete(object);
+
+ let null = ylong_json_create_null();
+ assert_eq!(ylong_json_is_object(null), 0);
+ ylong_json_delete(null);
+ }
+ }
+
+ /// UT test for `ylong_json_get_object_size`.
+ ///
+ /// # Title
+ /// ut_ylong_json_get_object_size
+ ///
+ /// # Brief
+ /// 1. Calls `ylong_json_get_object_size` to get size of an object.
+ /// 2. Checks if the test results are correct.
+ #[test]
+ fn ut_ylong_json_get_object_size() {
+ unsafe {
+ // Null ptr
+ let object = null_mut();
+ let mut len = 0i32;
+ assert_eq!(
+ ylong_json_get_object_size(object, &mut len as *mut c_int),
+ 0
+ );
+
+ // Null ptr
+ let object = ylong_json_create_object();
+ let len = null_mut();
+ assert_eq!(ylong_json_get_object_size(object, len), 0);
+ ylong_json_delete(object);
+
+ let object = ylong_json_create_object();
+ let mut len = 1i32;
+ assert_eq!(
+ ylong_json_get_object_size(object, &mut len as *mut c_int),
+ 1
+ );
+ assert_eq!(len, 0);
+ ylong_json_delete(object);
+
+ let null = ylong_json_create_null();
+ let mut len = 0i32;
+ assert_eq!(ylong_json_get_object_size(null, &mut len as *mut c_int), 0);
+ ylong_json_delete(null);
+ }
+ }
+
+ /// UT test for `ylong_json_has_object_item`.
+ ///
+ /// # Title
+ /// ut_ylong_json_has_object_item
+ ///
+ /// # Brief
+ /// 1. Calls `ylong_json_has_object_item` to determine whether the item exists in the object.
+ /// 2. Checks if the test results are correct.
+ #[test]
+ fn ut_ylong_json_has_object_item() {
+ unsafe {
+ // Null ptr
+ let object = null_mut();
+ let str = str_to_c_char("Hello World");
+ assert_eq!(ylong_json_has_object_item(object, str), 0);
+ let _ = Box::from_raw(str);
+
+ // Null ptr
+ let object = ylong_json_create_object();
+ let str = null();
+ assert_eq!(ylong_json_has_object_item(object, str), 0);
+ ylong_json_delete(object);
+
+ const TEXT: &str = "{\"null\":null}";
+ let str = str_to_c_char(TEXT);
+ let mut msg = null_mut();
+ let object = ylong_json_parse(str, &mut msg as *mut *mut c_char);
+ let _ = Box::from_raw(str);
+
+ let str = str_to_c_char("null");
+ assert_eq!(ylong_json_has_object_item(object, str), 1);
+ let _ = Box::from_raw(str);
+
+ let str = str_to_c_char("no_such_key");
+ assert_eq!(ylong_json_has_object_item(object, str), 0);
+ let _ = Box::from_raw(str);
+
+ ylong_json_delete(object);
+
+ let null = ylong_json_create_null();
+ let str = str_to_c_char("Invalid");
+ assert_eq!(ylong_json_has_object_item(null, str), 0);
+ let _ = Box::from_raw(str);
+ ylong_json_delete(null);
+ }
+ }
+
+ /// UT test for `ylong_json_get_object_item`.
+ ///
+ /// # Title
+ /// ut_ylong_json_get_object_item
+ ///
+ /// # Brief
+ /// 1. Calls `ylong_json_get_object_item` to get an item in the object.
+ /// 2. Checks if the test results are correct.
+ #[test]
+ fn ut_ylong_json_get_object_item() {
+ unsafe {
+ // Null ptr
+ let object = null_mut();
+ let str = str_to_c_char("Hello World");
+ assert!(ylong_json_get_object_item(object, str).is_null());
+ let _ = Box::from_raw(str);
+
+ // Null ptr
+ let object = ylong_json_create_object();
+ let str = null();
+ assert!(ylong_json_get_object_item(object, str).is_null());
+ ylong_json_delete(object);
+
+ const TEXT: &str = "{\"null\":null}";
+ let str = str_to_c_char(TEXT);
+ let mut msg = null_mut();
+ let object = ylong_json_parse(str, &mut msg as *mut *mut c_char);
+ let _ = Box::from_raw(str);
+
+ let str = str_to_c_char("null");
+ let item = ylong_json_get_object_item(object, str);
+ assert_eq!(ylong_json_is_null(item), 1);
+ let _ = Box::from_raw(str);
+
+ let str = str_to_c_char("no_such_key");
+ let item = ylong_json_get_object_item(object, str);
+ assert!(item.is_null());
+ let _ = Box::from_raw(str);
+
+ ylong_json_delete(object);
+
+ let null = ylong_json_create_null();
+ let str = str_to_c_char("Invalid");
+ assert!(ylong_json_get_object_item(null, str).is_null());
+ let _ = Box::from_raw(str);
+ ylong_json_delete(null);
+ }
+ }
+
+ /// UT test for `ylong_json_add_item_to_object`.
+ ///
+ /// # Title
+ /// ut_ylong_json_add_item_to_object
+ ///
+ /// # Brief
+ /// 1. Calls `ylong_json_add_item_to_object` to add an item to the object.
+ /// 2. Checks if the test results are correct.
+ #[test]
+ fn ut_ylong_json_add_item_to_object() {
+ unsafe {
+ // Null ptr
+ let object = null_mut();
+ let str = str_to_c_char("Hello World");
+ let item = ylong_json_create_null();
+ assert_eq!(ylong_json_add_item_to_object(object, str, item), 0);
+ let _ = Box::from_raw(str);
+ ylong_json_delete(item);
+
+ // Null ptr
+ let object = ylong_json_create_object();
+ let str = null();
+ let item = ylong_json_create_null();
+ assert_eq!(ylong_json_add_item_to_object(object, str, item), 0);
+ ylong_json_delete(object);
+ ylong_json_delete(item);
+
+ // Null ptr
+ let object = ylong_json_create_object();
+ let str = str_to_c_char("Hello World");
+ let item = null_mut();
+ assert_eq!(ylong_json_add_item_to_object(object, str, item), 0);
+ ylong_json_delete(object);
+ let _ = Box::from_raw(str);
+
+ let object = ylong_json_create_object();
+ let mut len = 0i32;
+ assert_eq!(
+ ylong_json_get_object_size(object, &mut len as *mut c_int),
+ 1
+ );
+ assert_eq!(len, 0);
+ let str = str_to_c_char("Hello World");
+ let item = ylong_json_create_null();
+ assert_eq!(ylong_json_add_item_to_object(object, str, item), 1);
+ let _ = Box::from_raw(str);
+ assert_eq!(
+ ylong_json_get_object_size(object, &mut len as *mut c_int),
+ 1
+ );
+ assert_eq!(len, 1);
+ ylong_json_delete(object);
+
+ let null = ylong_json_create_null();
+ let str = str_to_c_char("Hello World");
+ let item = ylong_json_create_null();
+ assert_eq!(ylong_json_add_item_to_object(null, str, item), 0);
+ ylong_json_delete(null);
+ let _ = Box::from_raw(str);
+ ylong_json_delete(item);
+ }
+ }
+
+ /// UT test for `ylong_json_replace_object_item_by_index`.
+ ///
+ /// # Title
+ /// ut_ylong_json_replace_object_item_by_index
+ ///
+ /// # Brief
+ /// 1. Calls `ylong_json_replace_object_item_by_index` to replace an item in the object by index.
+ /// 2. Checks if the test results are correct.
+ #[test]
+ fn ut_ylong_json_replace_object_item_by_index() {
+ unsafe {
+ // Null ptr
+ let object = null_mut();
+ let str = str_to_c_char("Hello World");
+ let item = ylong_json_create_null();
+ assert_eq!(
+ ylong_json_replace_object_item_by_index(object, str, item),
+ 0
+ );
+ let _ = Box::from_raw(str);
+ ylong_json_delete(item);
+
+ // Null ptr
+ let object = ylong_json_create_object();
+ let str = null();
+ let item = ylong_json_create_null();
+ assert_eq!(
+ ylong_json_replace_object_item_by_index(object, str, item),
+ 0
+ );
+ ylong_json_delete(object);
+ ylong_json_delete(item);
+
+ // Null ptr
+ let object = ylong_json_create_object();
+ let str = str_to_c_char("Hello World");
+ let item = null_mut();
+ assert_eq!(
+ ylong_json_replace_object_item_by_index(object, str, item),
+ 0
+ );
+ ylong_json_delete(object);
+ let _ = Box::from_raw(str);
+
+ let object = ylong_json_create_object();
+ let str = str_to_c_char("Init");
+ let item = ylong_json_create_null();
+ assert_eq!(ylong_json_add_item_to_object(object, str, item), 1);
+ let result = ylong_json_print_unformatted(object);
+ let result = CString::from_raw(result).into_string().unwrap();
+ assert_eq!(result, "{\"Init\":null}");
+ let item = ylong_json_create_bool(1);
+ assert_eq!(
+ ylong_json_replace_object_item_by_index(object, str, item),
+ 1
+ );
+ let _ = Box::from_raw(str);
+ let result = ylong_json_print_unformatted(object);
+ let result = CString::from_raw(result).into_string().unwrap();
+ assert_eq!(result, "{\"Init\":true}");
+ ylong_json_delete(object);
+
+ let null = ylong_json_create_null();
+ let str = str_to_c_char("Hello World");
+ let item = ylong_json_create_null();
+ assert_eq!(ylong_json_replace_object_item_by_index(null, str, item), 0);
+ ylong_json_delete(null);
+ let _ = Box::from_raw(str);
+ ylong_json_delete(item);
+ }
+ }
+
+ /// UT test for `ylong_json_remove_object_item_by_index`.
+ ///
+ /// # Title
+ /// ut_ylong_json_remove_object_item_by_index
+ ///
+ /// # Brief
+ /// 1. Calls `ylong_json_remove_object_item_by_index` to remove an item in the object by index.
+ /// 2. Checks if the test results are correct.
+ #[test]
+ fn ut_ylong_json_remove_object_item_by_index() {
+ unsafe {
+ // Null ptr
+ let object = null_mut();
+ let str = str_to_c_char("Hello World");
+ assert!(ylong_json_remove_object_item_by_index(object, str).is_null());
+ let _ = Box::from_raw(str);
+
+ // Null ptr
+ let object = ylong_json_create_object();
+ let str = null();
+ assert!(ylong_json_remove_object_item_by_index(object, str).is_null());
+ ylong_json_delete(object);
+
+ let object = ylong_json_create_object();
+ let str = str_to_c_char("Init");
+ let item = ylong_json_create_null();
+ assert_eq!(ylong_json_add_item_to_object(object, str, item), 1);
+ let result = ylong_json_print_unformatted(object);
+ let result = CString::from_raw(result).into_string().unwrap();
+ assert_eq!(result, "{\"Init\":null}");
+ let item = ylong_json_remove_object_item_by_index(object, str);
+ assert!(!item.is_null());
+ assert_eq!(ylong_json_is_null(item), 1);
+ let result = ylong_json_print_unformatted(object);
+ let result = CString::from_raw(result).into_string().unwrap();
+ assert_eq!(result, "{}");
+ ylong_json_delete(object);
+ let _ = Box::from_raw(str);
+ ylong_json_delete(item);
+
+ let null = ylong_json_create_null();
+ let str = str_to_c_char("Hello World");
+ assert!(ylong_json_remove_object_item_by_index(null, str).is_null());
+ ylong_json_delete(null);
+ let _ = Box::from_raw(str);
+ }
+ }
+
+ /// UT test for `ylong_json_delete_object_by_index`.
+ ///
+ /// # Title
+ /// ut_ylong_json_delete_object_by_index
+ ///
+ /// # Brief
+ /// 1. Calls `ylong_json_delete_object_by_index` to delete an item in the object by index.
+ /// 2. Checks if the test results are correct.
+ #[test]
+ fn ut_ylong_json_delete_object_by_index() {
+ unsafe {
+ // Null ptr
+ let object = null_mut();
+ let str = str_to_c_char("Hello World");
+ ylong_json_delete_object_item_by_index(object, str);
+ let _ = Box::from_raw(str);
+
+ // Null ptr
+ let object = ylong_json_create_object();
+ let str = null();
+ ylong_json_delete_object_item_by_index(object, str);
+ ylong_json_delete(object);
+
+ let object = ylong_json_create_object();
+ let str = str_to_c_char("Init");
+ let item = ylong_json_create_null();
+ assert_eq!(ylong_json_add_item_to_object(object, str, item), 1);
+ let result = ylong_json_print_unformatted(object);
+ let result = CString::from_raw(result).into_string().unwrap();
+ assert_eq!(result, "{\"Init\":null}");
+ ylong_json_delete_object_item_by_index(object, str);
+ let result = ylong_json_print_unformatted(object);
+ let result = CString::from_raw(result).into_string().unwrap();
+ assert_eq!(result, "{}");
+ ylong_json_delete(object);
+ let _ = Box::from_raw(str);
+
+ let null = ylong_json_create_null();
+ let str = str_to_c_char("Hello World");
+ ylong_json_delete_object_item_by_index(null, str);
+ ylong_json_delete(null);
+ let _ = Box::from_raw(str);
+ }
+ }
+
+ /// UT test for `ylong_json_get_all_object_items`.
+ ///
+ /// # Title
+ /// ut_ylong_json_get_all_object_items
+ ///
+ /// # Brief
+ /// 1. Calls `ylong_json_get_all_object_items` to get all items in the object.
+ /// 2. Checks if the test results are correct.
+ #[test]
+ fn ut_ylong_json_get_all_object_items() {
+ unsafe {
+ // Null ptr
+ let object = null_mut();
+ let mut len = 1i32;
+ let keys = malloc(size_of::<*mut c_char>() * (len as usize)) as *mut *mut c_char;
+ let values =
+ malloc(size_of::<*mut YlongJson>() * (len as usize)) as *mut *mut YlongJson;
+ assert_eq!(
+ ylong_json_get_all_object_items(object, keys, values, &mut len as *mut c_int),
+ 0
+ );
+ free(keys as *mut c_void);
+ free(values as *mut c_void);
+
+ // Null ptr
+ let object = ylong_json_create_object();
+ let mut len = 1i32;
+ let keys = null_mut();
+ let values =
+ malloc(size_of::<*mut YlongJson>() * (len as usize)) as *mut *mut YlongJson;
+ assert_eq!(
+ ylong_json_get_all_object_items(object, keys, values, &mut len as *mut c_int),
+ 0
+ );
+ ylong_json_delete(object);
+ free(values as *mut c_void);
+
+ // Null ptr
+ let object = ylong_json_create_object();
+ let mut len = 1i32;
+ let keys = malloc(size_of::<*mut c_char>() * (len as usize)) as *mut *mut c_char;
+ let values = null_mut();
+ assert_eq!(
+ ylong_json_get_all_object_items(object, keys, values, &mut len as *mut c_int),
+ 0
+ );
+ ylong_json_delete(object);
+ free(keys as *mut c_void);
+
+ // Null ptr
+ let object = ylong_json_create_object();
+ let len = 1i32;
+ let keys = malloc(size_of::<*mut c_char>() * (len as usize)) as *mut *mut c_char;
+ let values =
+ malloc(size_of::<*mut YlongJson>() * (len as usize)) as *mut *mut YlongJson;
+ let len = null_mut();
+ assert_eq!(
+ ylong_json_get_all_object_items(object, keys, values, len),
+ 0
+ );
+ ylong_json_delete(object);
+ free(keys as *mut c_void);
+ free(values as *mut c_void);
+
+ const TEXT: &str = r#"{"A":null,"B":1.0,"C":true,"D":"Test"}"#;
+ let text = str_to_c_char(TEXT);
+ let mut err_msg = null_mut();
+ let object = ylong_json_parse(text, &mut err_msg as *mut *mut c_char);
+ let _ = Box::from_raw(text);
+ let mut len = 0i32;
+ assert_eq!(
+ ylong_json_get_object_size(object, &mut len as *mut c_int),
+ 1
+ );
+ assert_eq!(len, 4);
+ let keys = malloc(size_of::<*mut c_char>() * (len as usize)) as *mut *mut c_char;
+ let values =
+ malloc(size_of::<*mut YlongJson>() * (len as usize)) as *mut *mut YlongJson;
+ assert_eq!(
+ ylong_json_get_all_object_items(object, keys, values, &mut len as *mut c_int),
+ 1
+ );
+ let mut cnt = 0;
+ let key_result = ["A", "B", "C", "D"];
+ let value_result = ["null", "1.0", "true", "\"Test\""];
+ while cnt != len {
+ let key = *(keys.offset(cnt as isize));
+ let key_str = CStr::from_ptr(key).to_str().unwrap();
+ assert_eq!(key_str, key_result[cnt as usize]);
+ ylong_json_free_string(key);
+
+ let item = *(values.offset(cnt as isize));
+ let value = ylong_json_print_unformatted(item);
+ let value_str = CString::from_raw(value).into_string().unwrap();
+ assert_eq!(value_str, value_result[cnt as usize]);
+ cnt += 1;
+ }
+ free(keys as *mut c_void);
+ free(values as *mut c_void);
+ ylong_json_delete(object);
+
+ // 非 object
+ let null = ylong_json_create_null();
+ let mut len = 1i32;
+ let keys = malloc(size_of::<*mut c_char>() * (len as usize)) as *mut *mut c_char;
+ let values =
+ malloc(size_of::<*mut YlongJson>() * (len as usize)) as *mut *mut YlongJson;
+ assert_eq!(
+ ylong_json_get_all_object_items(null, keys, values, &mut len as *mut c_int),
+ 0
+ );
+ ylong_json_delete(null);
+ free(keys as *mut c_void);
+ free(values as *mut c_void);
+ }
+ }
+
+ /// UT test for `ylong_json_for_each_object_item`.
+ ///
+ /// # Title
+ /// ut_ylong_json_for_each_object_item
+ ///
+ /// # Brief
+ /// 1. Calls `ylong_json_for_each_object_item` to do `func` for each item in the object.
+ /// 2. Checks if the test results are correct.
+ #[test]
+ fn ut_ylong_json_for_each_object_item() {
+ unsafe {
+ unsafe extern "C" fn func(target: *mut YlongJson) {
+ ylong_json_set_int_value_to_number(target, 1000);
+ }
+
+ // Null ptr
+ let object = null_mut();
+ assert_eq!(ylong_json_for_each_object_item(object, func), 0);
+
+ const TEXT: &str = r#"{"A":1,"B":2,"C":3,"D":null,"E":1.0}"#;
+ let text = str_to_c_char(TEXT);
+ let err_msg = null_mut();
+ let object = ylong_json_parse(text, err_msg);
+ let _ = Box::from_raw(text);
+ let result = ylong_json_print_unformatted(object);
+ let result = CString::from_raw(result).into_string().unwrap();
+ assert_eq!(result, "{\"A\":1,\"B\":2,\"C\":3,\"D\":null,\"E\":1.0}");
+ assert_eq!(ylong_json_for_each_object_item(object, func), 1);
+ let result = ylong_json_print_unformatted(object);
+ let result = CString::from_raw(result).into_string().unwrap();
+ assert_eq!(
+ result,
+ "{\"A\":1000,\"B\":1000,\"C\":1000,\"D\":null,\"E\":1000}"
+ );
+ ylong_json_delete(object);
+
+ let null = ylong_json_create_null();
+ assert_eq!(ylong_json_for_each_object_item(null, func), 0);
+ ylong_json_delete(null);
+ }
+ }
+
+ /// UT test for `ylong_json_get_object_node`.
+ ///
+ /// # Title
+ /// ut_ylong_json_get_object_node
+ ///
+ /// # Brief
+ /// 1. Calls `ylong_json_get_object_node` to get an object node.
+ /// 2. Checks if the test results are correct.
+ #[cfg(feature = "list_object")]
+ #[test]
+ fn ut_ylong_json_get_object_node() {
+ unsafe {
+ // Null ptr
+ let object = null_mut();
+ let str = str_to_c_char("Hello World");
+ let node = ylong_json_get_object_node(object, str);
+ assert!(node.is_null());
+ let _ = Box::from_raw(str);
+
+ // Null ptr
+ let object = ylong_json_create_object();
+ let str = null_mut();
+ let node = ylong_json_get_object_node(object, str);
+ assert!(node.is_null());
+ ylong_json_delete(object);
+
+ const TEXT: &str = r#"{"null":null}"#;
+ let text = str_to_c_char(TEXT);
+ let err_msg = null_mut();
+ let object = ylong_json_parse(text, err_msg);
+ let _ = Box::from_raw(text);
+ let str = str_to_c_char("null");
+ let node = ylong_json_get_object_node(object, str);
+ let _ = Box::from_raw(str);
+ assert!(!node.is_null());
+ let item = ylong_json_get_item_from_object_node(node);
+ assert_eq!(ylong_json_is_null(item), 1);
+ ylong_json_delete(object);
+
+ // Non-object
+ let null = ylong_json_create_null();
+ let str = str_to_c_char("Hello World");
+ let node = ylong_json_get_object_node(null, str);
+ let _ = Box::from_raw(str);
+ assert!(node.is_null());
+ ylong_json_delete(null);
+ }
+ }
+
+ /// UT test for `ylong_json_get_item_from_object_node`.
+ ///
+ /// # Title
+ /// ut_ylong_json_get_item_from_object_node
+ ///
+ /// # Brief
+ /// 1. Calls `ylong_json_get_item_from_object_node` to get the item of an object node.
+ /// 2. Checks if the test results are correct.
+ #[cfg(feature = "list_object")]
+ #[test]
+ fn ut_ylong_json_get_item_from_object_node() {
+ unsafe {
+ // Null ptr
+ let node = null_mut();
+ let item = ylong_json_get_item_from_object_node(node);
+ assert!(item.is_null());
+
+ const TEXT: &str = r#"{"null":null}"#;
+ let text = str_to_c_char(TEXT);
+ let err_msg = null_mut();
+ let object = ylong_json_parse(text, err_msg);
+ let str = str_to_c_char("null");
+ let node = ylong_json_get_object_node(object, str);
+ assert!(!node.is_null());
+ let item = ylong_json_get_item_from_object_node(node);
+ assert_eq!(ylong_json_is_null(item), 1);
+ let _ = Box::from_raw(text);
+ let _ = Box::from_raw(str);
+ ylong_json_delete(object);
+ }
+ }
+
+ /// UT test for `ylong_json_add_item_to_object_then_get_node`.
+ ///
+ /// # Title
+ /// ut_ylong_json_add_item_to_object_then_get_node
+ ///
+ /// # Brief
+ /// 1. Calls `ylong_json_add_item_to_object_then_get_node` to add an item to the object and get the corresponding node.
+ /// 2. Checks if the test results are correct.
+ #[cfg(feature = "list_object")]
+ #[test]
+ fn ut_ylong_json_add_item_to_object_then_get_node() {
+ unsafe {
+ // Null ptr
+ let object = null_mut();
+ let str = str_to_c_char("null");
+ let item = ylong_json_create_null();
+ let node = ylong_json_add_item_to_object_then_get_node(object, str, item);
+ assert!(node.is_null());
+ let _ = Box::from_raw(str);
+ ylong_json_delete(item);
+
+ // Null ptr
+ let object = ylong_json_create_object();
+ let str = null_mut();
+ let item = ylong_json_create_null();
+ let node = ylong_json_add_item_to_object_then_get_node(object, str, item);
+ assert!(node.is_null());
+ ylong_json_delete(object);
+ ylong_json_delete(item);
+
+ // Null ptr
+ let object = ylong_json_create_object();
+ let str = str_to_c_char("null");
+ let item = null_mut();
+ let node = ylong_json_add_item_to_object_then_get_node(object, str, item);
+ assert!(node.is_null());
+ ylong_json_delete(object);
+ let _ = Box::from_raw(str);
+
+ let object = ylong_json_create_object();
+ let str = str_to_c_char("null");
+ let item = ylong_json_create_null();
+ let node = ylong_json_add_item_to_object_then_get_node(object, str, item);
+ assert!(!node.is_null());
+ let item = ylong_json_get_item_from_object_node(node);
+ assert_eq!(ylong_json_is_null(item), 1);
+ ylong_json_delete(object);
+ let _ = Box::from_raw(str);
+
+ let null = ylong_json_create_null();
+ let str = str_to_c_char("null");
+ let item = ylong_json_create_null();
+ let node = ylong_json_add_item_to_object_then_get_node(null, str, item);
+ assert!(node.is_null());
+ ylong_json_delete(null);
+ let _ = Box::from_raw(str);
+ ylong_json_delete(item);
+ }
+ }
+
+ /// UT test for `ylong_json_replace_item_of_object_node`.
+ ///
+ /// # Title
+ /// ut_ylong_json_replace_item_of_object_node
+ ///
+ /// # Brief
+ /// 1. Calls `ylong_json_replace_item_of_object_node` to replace the item of an object node.
+ /// 2. Checks if the test results are correct.
+ #[cfg(feature = "list_object")]
+ #[test]
+ fn ut_ylong_json_replace_item_of_object_node() {
+ unsafe {
+ // Null ptr
+ let node = null_mut();
+ let item = ylong_json_create_null();
+ assert_eq!(ylong_json_replace_item_of_object_node(node, item), 0);
+ ylong_json_delete(item);
+
+ // Null ptr
+ let object = ylong_json_create_object();
+ let str = str_to_c_char("null");
+ let item = ylong_json_create_null();
+ let node = ylong_json_add_item_to_object_then_get_node(object, str, item);
+ let item = null_mut();
+ assert_eq!(ylong_json_replace_item_of_object_node(node, item), 0);
+ ylong_json_delete(object);
+ let _ = Box::from_raw(str);
+
+ let object = ylong_json_create_object();
+ let str = str_to_c_char("null");
+ let item = ylong_json_create_null();
+ let node = ylong_json_add_item_to_object_then_get_node(object, str, item);
+ let result = ylong_json_print_unformatted(object);
+ let result = CString::from_raw(result).into_string().unwrap();
+ assert_eq!(result, "{\"null\":null}");
+ let item = ylong_json_create_bool(1);
+ assert_eq!(ylong_json_replace_item_of_object_node(node, item), 1);
+ let result = ylong_json_print_unformatted(object);
+ let result = CString::from_raw(result).into_string().unwrap();
+ assert_eq!(result, "{\"null\":true}");
+ ylong_json_delete(object);
+ let _ = Box::from_raw(str);
+ }
+ }
+
+ /// UT test for `ylong_json_remove_object_node`.
+ ///
+ /// # Title
+ /// ut_ylong_json_remove_object_node
+ ///
+ /// # Brief
+ /// 1. Calls `ylong_json_remove_object_node` to remove an object node.
+ /// 2. Checks if the test results are correct.
+ #[cfg(feature = "list_object")]
+ #[test]
+ fn ut_ylong_json_remove_object_node() {
+ unsafe {
+ // Null ptr
+ let node = null_mut();
+ let item = ylong_json_remove_object_node(node);
+ assert!(item.is_null());
+
+ let object = ylong_json_create_object();
+ let str = str_to_c_char("null");
+ let item = ylong_json_create_null();
+ let node = ylong_json_add_item_to_object_then_get_node(object, str, item);
+ let _ = Box::from_raw(str);
+ let result = ylong_json_print_unformatted(object);
+ let result = CString::from_raw(result).into_string().unwrap();
+ assert_eq!(result, "{\"null\":null}");
+ let item = ylong_json_remove_object_node(node);
+ assert_eq!(ylong_json_is_null(item), 1);
+ let result = ylong_json_print_unformatted(object);
+ let result = CString::from_raw(result).into_string().unwrap();
+ assert_eq!(result, "{}");
+ ylong_json_delete(item);
+ ylong_json_delete(object);
+ }
+ }
+
+ /// UT test for `ylong_json_delete_object_node`.
+ ///
+ /// # Title
+ /// ut_ylong_json_delete_object_node
+ ///
+ /// # Brief
+ /// 1. Calls `ylong_json_delete_object_node` to delete an object node.
+ /// 2. Checks if the test results are correct.
+ #[cfg(feature = "list_object")]
+ #[test]
+ fn ut_ylong_json_delete_object_node() {
+ unsafe {
+ // Null ptr scene, the process is correct if it exits without exception.
+ let node = null_mut();
+ ylong_json_delete_object_node(node);
+
+ let object = ylong_json_create_object();
+ let str = str_to_c_char("null");
+ let item = ylong_json_create_null();
+ let node = ylong_json_add_item_to_object_then_get_node(object, str, item);
+ let result = ylong_json_print_unformatted(object);
+ let result = CString::from_raw(result).into_string().unwrap();
+ assert_eq!(result, "{\"null\":null}");
+ ylong_json_delete_object_node(node);
+ let result = ylong_json_print_unformatted(object);
+ let result = CString::from_raw(result).into_string().unwrap();
+ assert_eq!(result, "{}");
+ let _ = Box::from_raw(str);
+ ylong_json_delete(object);
+ }
+ }
+}
diff --git a/src/consts.rs b/src/consts.rs
new file mode 100644
index 0000000000000000000000000000000000000000..ba71ba8b6f87ccebf633d948426ab2433e689783
--- /dev/null
+++ b/src/consts.rs
@@ -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"));
+ }
+}
diff --git a/src/deserializer.rs b/src/deserializer.rs
new file mode 100644
index 0000000000000000000000000000000000000000..43de3571aa72da0fcf400c34d44c7a876128f7dd
--- /dev/null
+++ b/src/deserializer.rs
@@ -0,0 +1,1099 @@
+/*
+ * 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::reader::{BytesReader, Cacheable, IoReader, SliceReader};
+use serde::de;
+use serde::de::{
+ DeserializeOwned, DeserializeSeed, EnumAccess, IntoDeserializer, MapAccess, SeqAccess,
+ VariantAccess, Visitor,
+};
+use serde::Deserialize;
+use std::io::Read;
+
+use crate::{consts::*, error::*, states::*, Number, ParseError::*};
+
+#[cfg(feature = "c_adapter")]
+type JsonString = CString;
+#[cfg(not(feature = "c_adapter"))]
+type JsonString = String;
+
+impl Number {
+ fn visit<'de, V>(self, visitor: V) -> Result
+ where
+ V: Visitor<'de>,
+ {
+ match self {
+ Number::Unsigned(x) => visitor.visit_u64(x),
+ Number::Signed(x) => visitor.visit_i64(x),
+ Number::Float(x) => visitor.visit_f64(x),
+ }
+ }
+}
+
+/// A struct that can deserialize JSON into Rust values of user's types.
+pub(crate) struct Deserializer
+where
+ R: BytesReader + Cacheable,
+{
+ pub(crate) reader: R,
+ pub(crate) recursion_depth: u32,
+}
+
+impl Deserializer
+where
+ R: BytesReader + Cacheable,
+{
+ /// Creates a new instance of Deserializer.
+ /// This method is usually used in the following methods:
+ /// - Deserializer::new_from_reader
+ /// - Deserializer::new_from_slice
+ pub fn new(reader: R) -> Self {
+ Deserializer {
+ reader,
+ recursion_depth: 0,
+ }
+ }
+}
+
+/// Creates an instance of Deserializer from reader.
+impl Deserializer> {
+ pub fn new_from_io(reader: R) -> Self {
+ Deserializer::new(IoReader::new(reader))
+ }
+}
+
+/// Creates an instance of Deserializer from slice.
+impl<'a> Deserializer> {
+ pub fn new_from_slice(slice: &'a [u8]) -> Self {
+ Deserializer::new(SliceReader::new(slice))
+ }
+}
+
+/// Deserializes an instance of type `T` from an IO stream of JSON.
+/// # Example
+/// ```not run
+/// use serde::Deserialize;
+/// use std::fs::File;
+/// use ylong_json::from_reader;
+///
+/// #[derive(Deserialize, PartialEq, Debug)]
+/// struct Test {
+/// int: u32,
+/// seq: Vec,
+/// tup: (i32, i32, i32),
+/// }
+///
+/// let expected = Test {
+/// int: 1,
+/// seq: vec![String::from("abcd"), String::from("efgh")],
+/// tup: (1, 2, 3),
+/// };
+/// let file = File::open("./test.txt").unwrap();
+/// assert_eq!(expected, from_reader(file).unwrap());
+/// ```
+pub fn from_reader(reader: R) -> Result
+where
+ R: Read,
+ T: DeserializeOwned,
+{
+ let mut deserializer = Deserializer::new_from_io(reader);
+ let t = T::deserialize(&mut deserializer)?;
+ match deserializer.reader.peek() {
+ Ok(None) => Ok(t),
+ _ => Err(Error::Parsing(ParsingUnfinished)),
+ }
+}
+
+/// Deserializes an instance of type `T` from bytes.
+/// # Example
+/// ```
+/// use serde::Deserialize;
+/// use ylong_json::from_slice;
+///
+/// #[derive(Deserialize, PartialEq, Debug)]
+/// struct Test {
+/// int: u32,
+/// seq: Vec,
+/// tup: (i32, i32, i32),
+/// }
+///
+/// let slice = r#"{"int":1,"seq":["abcd","efgh"],"tup":[1,2,3]}"#.as_bytes();
+/// let expected = Test {
+/// int: 1,
+/// seq: vec![String::from("abcd"), String::from("efgh")],
+/// tup: (1, 2, 3),
+/// };
+/// assert_eq!(expected, from_slice(slice).unwrap())
+/// ```
+pub fn from_slice<'a, T>(slice: &'a [u8]) -> Result
+where
+ T: Deserialize<'a>,
+{
+ let mut deserializer = Deserializer::new_from_slice(slice);
+ let t = T::deserialize(&mut deserializer)?;
+ match deserializer.reader.peek() {
+ Ok(None) => Ok(t),
+ _ => Err(Error::Parsing(ParsingUnfinished)),
+ }
+}
+
+/// Deserializes an instance of type `T` from str.
+/// # Example
+/// ```
+/// use serde::Deserialize;
+/// use ylong_json::from_str;
+///
+/// #[derive(Deserialize, PartialEq, Debug)]
+/// struct Test {
+/// int: u32,
+/// seq: Vec,
+/// tup: (i32, i32, i32),
+/// }
+///
+/// let str = r#"{"int":1,"seq":["abcd","efgh"],"tup":[1,2,3]}"#;
+/// let expected = Test {
+/// int: 1,
+/// seq: vec![String::from("abcd"), String::from("efgh")],
+/// tup: (1, 2, 3),
+/// };
+/// assert_eq!(expected, from_str(str).unwrap())
+/// ```
+pub fn from_str<'a, T>(str: &'a str) -> Result
+where
+ T: Deserialize<'a>,
+{
+ from_slice(str.as_bytes())
+}
+
+impl Deserializer
+where
+ R: BytesReader + Cacheable,
+{
+ // Look at the next character without moving cursor.
+ fn peek_char(&mut self) -> Result