├── .cargo └── config ├── .editorconfig ├── .github └── workflows │ └── Basic.yml ├── .gitignore ├── .prettierignore ├── .prettierrc.json ├── CHANGELOG.md ├── Cargo.lock ├── Cargo.toml ├── LICENSE-APACHE ├── LICENSE-MIT ├── README.md ├── devtools └── format_md.sh └── src ├── de ├── enum_.rs ├── errors.rs ├── map.rs ├── mod.rs ├── seq.rs └── unescape.rs ├── lib.rs └── ser ├── map.rs ├── mod.rs ├── seq.rs └── struct_.rs /.cargo/config: -------------------------------------------------------------------------------- 1 | [alias] 2 | wasm = "build --release --target wasm32-unknown-unknown" -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome: https://EditorConfig.org 2 | 3 | # top-most EditorConfig file 4 | root = true 5 | 6 | [*] 7 | indent_style = space 8 | indent_size = 2 9 | charset = utf-8 10 | trim_trailing_whitespace = true 11 | insert_final_newline = true 12 | 13 | [*.rs] 14 | indent_size = 4 15 | -------------------------------------------------------------------------------- /.github/workflows/Basic.yml: -------------------------------------------------------------------------------- 1 | # Based on https://github.com/actions-rs/example/blob/master/.github/workflows/quickstart.yml 2 | 3 | on: [push, pull_request] 4 | 5 | name: Basic 6 | 7 | jobs: 8 | 9 | tests: 10 | name: Tests 11 | runs-on: ubuntu-latest 12 | steps: 13 | - name: Checkout sources 14 | uses: actions/checkout@v2 15 | 16 | - name: Install stable toolchain 17 | uses: actions-rs/toolchain@v1 18 | with: 19 | profile: minimal 20 | toolchain: 1.59.0 21 | target: wasm32-unknown-unknown 22 | override: true 23 | 24 | - name: Run tests 25 | uses: actions-rs/cargo@v1 26 | with: 27 | command: test 28 | args: --locked 29 | env: 30 | RUST_BACKTRACE: 1 31 | RUSTFLAGS: "-D warnings" 32 | 33 | - name: Compile to Wasm 34 | uses: actions-rs/cargo@v1 35 | with: 36 | command: wasm 37 | args: --locked 38 | env: 39 | RUST_BACKTRACE: 1 40 | RUSTFLAGS: "-D warnings" 41 | 42 | sanity: 43 | name: Sanity 44 | runs-on: ubuntu-latest 45 | steps: 46 | - name: Checkout sources 47 | uses: actions/checkout@v2 48 | 49 | - name: Install stable toolchain 50 | uses: actions-rs/toolchain@v1 51 | with: 52 | profile: minimal 53 | toolchain: 1.59.0 54 | override: true 55 | components: rustfmt, clippy 56 | 57 | - name: Run cargo fmt 58 | uses: actions-rs/cargo@v1 59 | with: 60 | command: fmt 61 | args: -- --check 62 | 63 | - name: Run cargo clippy 64 | uses: actions-rs/cargo@v1 65 | with: 66 | command: clippy 67 | args: --all-targets -- -D warnings 68 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | **/*.rs.bk 2 | .#* 3 | /target 4 | .idea 5 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | # Used for *.md formatting in devtools/format_md.sh 2 | target/ 3 | -------------------------------------------------------------------------------- /.prettierrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "overrides": [ 3 | { 4 | "files": "*.md", 5 | "options": { 6 | "proseWrap": "always" 7 | } 8 | } 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | The format is based on [Keep a Changelog](http://keepachangelog.com/) and this 6 | project adheres to [Semantic Versioning](http://semver.org/). 7 | 8 | ## [Unreleased] 9 | 10 | ## [1.0.1] - 2024-01-23 11 | 12 | ### Changed 13 | 14 | - Add recursion limit to deserialization ([#65]). 15 | 16 | [#65]: https://github.com/CosmWasm/serde-json-wasm/pull/65 17 | 18 | ## [1.0.0] - 2023-08-04 19 | 20 | ### Changed 21 | 22 | - Introduce `std` (enabled by default) and `unstable` features ([#58]). They 23 | enable corresponding serde’s features and if either is enabled, `Error` 24 | implements `std::error::Error` trait. By itself, `serde-json-wasm` is now 25 | `no_std`; it’s up to serde’s features whether the entire build is.
26 | **Please note:** this potentially breaks `default-features = false` builds. If 27 | you need the `Error` trait impl, enable one of the two features explicitly. 28 | 29 | - Serialize / deserialize `u128`/`i128` types as numbers instead of strings 30 | ([#59]).
**Please note:** this breaks deserialization of `u128`/`i128` 31 | serialized with older versions of `serde-json-wasm`. 32 | 33 | [#58]: https://github.com/CosmWasm/serde-json-wasm/pull/58 34 | [#59]: https://github.com/CosmWasm/serde-json-wasm/pull/59 35 | 36 | ## [0.5.1] - 2023-04-11 37 | 38 | ### Added 39 | 40 | - Add support for `collect_str` serialization ([#51], [#55]). 41 | 42 | [#51]: https://github.com/CosmWasm/serde-json-wasm/pull/51 43 | [#55]: https://github.com/CosmWasm/serde-json-wasm/pull/55 44 | 45 | ## [0.5.0] - 2022-12-06 46 | 47 | ### Added 48 | 49 | - Add support for map (de)serialization. 50 | - Add support for `#[serde(flatten)]` (de)serialization ([#20]). 51 | 52 | [#20]: https://github.com/CosmWasm/serde-json-wasm/issues/20 53 | 54 | ### Changed 55 | 56 | - Bump min supported Rust version to 1.59.0 (same as cosmwasm-std) 57 | - Upgrade codebase to Rust edition 2021 58 | 59 | ## [0.4.1] - 2022-05-05 60 | 61 | ### Changed 62 | 63 | - Properly serialize `u128`/`i128` types when embedded in structs 64 | 65 | ## [0.4.0] - 2022-03-29 66 | 67 | ### Added 68 | 69 | - Add support for `#[serde(untagged)]` enums representation 70 | 71 | ## [0.3.2] - 2021-12-14 72 | 73 | ### Added 74 | 75 | - Add support for u128/i128 serialization and deserialization ([#32], 76 | [#33]).
**Please note:** this is 77 | [incompatible with serde-json and schemars](https://github.com/CosmWasm/cosmwasm/issues/1605) 78 | and for this reason discouraged to use. 79 | 80 | [#32]: https://github.com/CosmWasm/serde-json-wasm/issues/32 81 | [#33]: https://github.com/CosmWasm/serde-json-wasm/pull/33 82 | 83 | ## [0.3.1] - 2021-01-19 84 | 85 | ### Added 86 | 87 | - Add support for Unit () deserialization. 88 | 89 | ## [0.3.0] - 2021-01-14 90 | 91 | ### Changed 92 | 93 | Maintenance release: 94 | 95 | - Update clippy version in CI to 1.49.0. 96 | - Fix `clippy::manual-non-exhaustive` warnings. 97 | 98 | ## [0.2.3] - 2021-01-14 99 | 100 | ### Changed 101 | 102 | - Optimize string serialization / deserialization. 103 | 104 | ## [0.2.2] - 2021-01-13 105 | 106 | ### Added 107 | 108 | - Add support for unit structs serialization / deserialization. 109 | - Add support for tuple variants serialization / deserialization. 110 | - Add support for unit serialization / deserialization. 111 | 112 | ## [0.2.1] - 2020-05-07 113 | 114 | ### Changed 115 | 116 | - Remove unused Travis CI config 117 | - Polish Cargo.toml 118 | 119 | ## [0.2.0] - 2020-05-07 120 | 121 | ### Fixed 122 | 123 | - The end of strings is now detected correctly in deserialization (#11) 124 | 125 | ### Changed 126 | 127 | - Strings are now escaped during serialization (#10) 128 | - `from_str`/`from_slice` now work for `T: DeserializeOwned` instead of 129 | `T: Deserialize<'de>`, making it impossible to deserialize into non-owned 130 | reference fields. This is necessary since string unescaping requires creating 131 | a mutated copy of the source data and only JSON strings without escape 132 | sequences can be deserialized copy-free. The same limitation applies to 133 | serde_json, where the problem shows up at 134 | [runtime instead of compile time](https://github.com/serde-rs/json/issues/530). 135 | - Strings are now unescaped during deserialization (#13) 136 | 137 | ## [0.1.3] - 2020-03-12 138 | 139 | - Expose deserializer and serializer 140 | 141 | ## [0.1.2] - 2019-12-20 142 | 143 | - Add newtype string support 144 | 145 | ## [0.1.1] - 2019-10-27 146 | 147 | - Fix embeded enums 148 | 149 | ## [0.1.0] - 2019-10-27 150 | 151 | Initial release after forking from 152 | [serde-json-core](https://github.com/japaric/serde-json-core) at 153 | [bf5533a0](https://github.com/japaric/serde-json-core/commit/bf5533a042a0). 154 | 155 | [unreleased]: https://github.com/CosmWasm/serde-json-wasm/compare/v1.0.1...HEAD 156 | [1.0.1]: https://github.com/CosmWasm/serde-json-wasm/compare/v1.0.0...v1.0.1 157 | [1.0.0]: https://github.com/CosmWasm/serde-json-wasm/compare/v0.5.1...v1.0.0 158 | [0.5.1]: https://github.com/CosmWasm/serde-json-wasm/compare/v0.5.0...v0.5.1 159 | [0.5.0]: https://github.com/CosmWasm/serde-json-wasm/compare/v0.4.1...v0.5.0 160 | [0.4.1]: https://github.com/CosmWasm/serde-json-wasm/compare/v0.4.0...v0.4.1 161 | [0.4.0]: https://github.com/CosmWasm/serde-json-wasm/compare/v0.3.2...v0.4.0 162 | [0.3.2]: https://github.com/CosmWasm/serde-json-wasm/compare/v0.3.1...v0.3.2 163 | [0.3.1]: https://github.com/CosmWasm/serde-json-wasm/compare/v0.3.0...v0.3.1 164 | [0.3.0]: https://github.com/CosmWasm/serde-json-wasm/compare/v0.2.3...v0.3.0 165 | [0.2.3]: https://github.com/CosmWasm/serde-json-wasm/compare/v0.2.2...v0.2.3 166 | [0.2.2]: https://github.com/CosmWasm/serde-json-wasm/compare/v0.2.1...v0.2.2 167 | [0.2.1]: https://github.com/CosmWasm/serde-json-wasm/compare/v0.2.0...v0.2.1 168 | [0.2.0]: https://github.com/CosmWasm/serde-json-wasm/compare/v0.1.3...v0.2.0 169 | [0.1.3]: https://github.com/CosmWasm/serde-json-wasm/compare/v0.1.2...v0.1.3 170 | [0.1.2]: https://github.com/CosmWasm/serde-json-wasm/compare/v0.1.1...v0.1.2 171 | [0.1.1]: https://github.com/CosmWasm/serde-json-wasm/compare/v0.1.0...v0.1.1 172 | [0.1.0]: https://github.com/CosmWasm/serde-json-wasm/tree/v0.1.0 173 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "itoa" 7 | version = "1.0.1" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35" 10 | 11 | [[package]] 12 | name = "proc-macro2" 13 | version = "1.0.36" 14 | source = "registry+https://github.com/rust-lang/crates.io-index" 15 | checksum = "c7342d5883fbccae1cc37a2353b09c87c9b0f3afd73f5fb9bba687a1f733b029" 16 | dependencies = [ 17 | "unicode-xid", 18 | ] 19 | 20 | [[package]] 21 | name = "quote" 22 | version = "1.0.17" 23 | source = "registry+https://github.com/rust-lang/crates.io-index" 24 | checksum = "632d02bff7f874a36f33ea8bb416cd484b90cc66c1194b1a1110d067a7013f58" 25 | dependencies = [ 26 | "proc-macro2", 27 | ] 28 | 29 | [[package]] 30 | name = "ryu" 31 | version = "1.0.9" 32 | source = "registry+https://github.com/rust-lang/crates.io-index" 33 | checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f" 34 | 35 | [[package]] 36 | name = "serde" 37 | version = "1.0.181" 38 | source = "registry+https://github.com/rust-lang/crates.io-index" 39 | checksum = "6d3e73c93c3240c0bda063c239298e633114c69a888c3e37ca8bb33f343e9890" 40 | 41 | [[package]] 42 | name = "serde-json-wasm" 43 | version = "1.0.1" 44 | dependencies = [ 45 | "serde", 46 | "serde_derive", 47 | "serde_json", 48 | ] 49 | 50 | [[package]] 51 | name = "serde_derive" 52 | version = "1.0.136" 53 | source = "registry+https://github.com/rust-lang/crates.io-index" 54 | checksum = "08597e7152fcd306f41838ed3e37be9eaeed2b61c42e2117266a554fab4662f9" 55 | dependencies = [ 56 | "proc-macro2", 57 | "quote", 58 | "syn", 59 | ] 60 | 61 | [[package]] 62 | name = "serde_json" 63 | version = "1.0.99" 64 | source = "registry+https://github.com/rust-lang/crates.io-index" 65 | checksum = "46266871c240a00b8f503b877622fe33430b3c7d963bdc0f2adc511e54a1eae3" 66 | dependencies = [ 67 | "itoa", 68 | "ryu", 69 | "serde", 70 | ] 71 | 72 | [[package]] 73 | name = "syn" 74 | version = "1.0.90" 75 | source = "registry+https://github.com/rust-lang/crates.io-index" 76 | checksum = "704df27628939572cd88d33f171cd6f896f4eaca85252c6e0a72d8d8287ee86f" 77 | dependencies = [ 78 | "proc-macro2", 79 | "quote", 80 | "unicode-xid", 81 | ] 82 | 83 | [[package]] 84 | name = "unicode-xid" 85 | version = "0.2.2" 86 | source = "registry+https://github.com/rust-lang/crates.io-index" 87 | checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" 88 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | authors = [ 3 | "Jorge Aparicio ", 4 | "Ethan Frey ", 5 | "Simon Warta ", 6 | "Mauro Lacy ", 7 | "Bartłomiej Kuras ", 8 | ] 9 | categories = ["wasm"] 10 | description = "serde_json for Wasm programs (small, deterministic, no floats)" 11 | documentation = "https://docs.rs/serde-json-wasm" 12 | edition = "2021" 13 | keywords = ["serde", "json", "wasm"] 14 | license = "MIT OR Apache-2.0" 15 | name = "serde-json-wasm" 16 | readme = "README.md" 17 | repository = "https://github.com/CosmWasm/serde-json-wasm" 18 | version = "1.0.1" 19 | exclude = [ 20 | ".cargo/", 21 | ".github/", 22 | ".gitignore", 23 | ] 24 | 25 | [dependencies] 26 | serde = { version = "^1.0.181", default-features = false, features = ["alloc"] } 27 | 28 | [dev-dependencies] 29 | serde_derive = "^1.0.80" 30 | serde_json = "^1.0.99" 31 | 32 | [features] 33 | default = ["std"] 34 | std = ["serde/std"] 35 | unstable = ["serde/unstable"] 36 | -------------------------------------------------------------------------------- /LICENSE-APACHE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Copyright (c) 2018 Jorge Aparicio 2 | 3 | Permission is hereby granted, free of charge, to any 4 | person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the 6 | Software without restriction, including without 7 | limitation the rights to use, copy, modify, merge, 8 | publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software 10 | is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice 14 | shall be included in all copies or substantial portions 15 | of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 19 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 20 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 21 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 24 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 | DEALINGS IN THE SOFTWARE. 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # serde-json-wasm 2 | 3 | [![serde-json-wasm on crates.io](https://img.shields.io/crates/v/serde-json-wasm.svg)](https://crates.io/crates/serde-json-wasm) 4 | [![Docs](https://docs.rs/serde-json-wasm/badge.svg)](https://docs.rs/serde-json-wasm) 5 | 6 | A [serde-json] alternative for [CosmWasm] smart contracts. 7 | 8 | [serde-json]: https://crates.io/crates/serde_json 9 | [cosmwasm]: https://cosmwasm.com/ 10 | 11 | ## License 12 | 13 | Licensed under either of 14 | 15 | - Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or 16 | http://www.apache.org/licenses/LICENSE-2.0) 17 | - MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) 18 | 19 | at your option. 20 | 21 | ### Contribution 22 | 23 | Unless you explicitly state otherwise, any contribution intentionally submitted 24 | for inclusion in the work by you, as defined in the Apache-2.0 license, shall be 25 | dual licensed as above, without any additional terms or conditions. 26 | -------------------------------------------------------------------------------- /devtools/format_md.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -o errexit -o nounset -o pipefail 3 | command -v shellcheck >/dev/null && shellcheck "$0" 4 | 5 | # Running with -c makes the script only validate instead of editing in place. 6 | op="write" 7 | while getopts c option; do 8 | case "${option}" in 9 | c) op="check" ;; 10 | *) ;; 11 | esac 12 | done 13 | 14 | npx prettier@2.7.1 --$op "./**/*.md" 15 | -------------------------------------------------------------------------------- /src/de/enum_.rs: -------------------------------------------------------------------------------- 1 | use serde::de; 2 | 3 | use crate::de::{Deserializer, Error, Result}; 4 | 5 | pub(crate) struct UnitVariantAccess<'a, 'b> { 6 | de: &'a mut Deserializer<'b>, 7 | } 8 | 9 | impl<'a, 'b> UnitVariantAccess<'a, 'b> { 10 | pub(crate) fn new(de: &'a mut Deserializer<'b>) -> Self { 11 | UnitVariantAccess { de } 12 | } 13 | } 14 | 15 | impl<'a, 'de> de::EnumAccess<'de> for UnitVariantAccess<'a, 'de> { 16 | type Error = Error; 17 | type Variant = Self; 18 | 19 | fn variant_seed(self, seed: V) -> Result<(V::Value, Self)> 20 | where 21 | V: de::DeserializeSeed<'de>, 22 | { 23 | let variant = seed.deserialize(&mut *self.de)?; 24 | Ok((variant, self)) 25 | } 26 | } 27 | 28 | impl<'de, 'a> de::VariantAccess<'de> for UnitVariantAccess<'a, 'de> { 29 | type Error = Error; 30 | 31 | fn unit_variant(self) -> Result<()> { 32 | Ok(()) 33 | } 34 | 35 | fn newtype_variant_seed(self, _seed: T) -> Result 36 | where 37 | T: de::DeserializeSeed<'de>, 38 | { 39 | Err(Error::InvalidType) 40 | } 41 | 42 | fn tuple_variant(self, _len: usize, _visitor: V) -> Result 43 | where 44 | V: de::Visitor<'de>, 45 | { 46 | Err(Error::InvalidType) 47 | } 48 | 49 | fn struct_variant(self, _fields: &'static [&'static str], _visitor: V) -> Result 50 | where 51 | V: de::Visitor<'de>, 52 | { 53 | Err(Error::InvalidType) 54 | } 55 | } 56 | 57 | pub(crate) struct StructVariantAccess<'a, 'b> { 58 | de: &'a mut Deserializer<'b>, 59 | } 60 | 61 | impl<'a, 'b> StructVariantAccess<'a, 'b> { 62 | pub fn new(de: &'a mut Deserializer<'b>) -> Self { 63 | StructVariantAccess { de } 64 | } 65 | } 66 | 67 | impl<'a, 'de> de::EnumAccess<'de> for StructVariantAccess<'a, 'de> { 68 | type Error = Error; 69 | type Variant = Self; 70 | 71 | fn variant_seed(self, seed: V) -> Result<(V::Value, Self)> 72 | where 73 | V: de::DeserializeSeed<'de>, 74 | { 75 | let val = seed.deserialize(&mut *self.de)?; 76 | self.de.parse_object_colon()?; 77 | Ok((val, self)) 78 | } 79 | } 80 | 81 | impl<'a, 'de> de::VariantAccess<'de> for StructVariantAccess<'a, 'de> { 82 | type Error = Error; 83 | 84 | fn unit_variant(self) -> Result<()> { 85 | Err(Error::InvalidType) 86 | } 87 | 88 | fn newtype_variant_seed(self, seed: T) -> Result 89 | where 90 | T: de::DeserializeSeed<'de>, 91 | { 92 | let value = seed.deserialize(&mut *self.de)?; 93 | // we remove trailing '}' to be consistent with struct_variant algorithm 94 | match self 95 | .de 96 | .parse_whitespace() 97 | .ok_or(Error::EofWhileParsingValue)? 98 | { 99 | b'}' => { 100 | self.de.eat_char(); 101 | Ok(value) 102 | } 103 | _ => Err(Error::ExpectedSomeValue), 104 | } 105 | } 106 | 107 | fn tuple_variant(self, len: usize, visitor: V) -> Result 108 | where 109 | V: de::Visitor<'de>, 110 | { 111 | let value = de::Deserializer::deserialize_tuple(&mut *self.de, len, visitor)?; 112 | match self 113 | .de 114 | .parse_whitespace() 115 | .ok_or(Error::EofWhileParsingValue)? 116 | { 117 | b'}' => { 118 | self.de.eat_char(); 119 | Ok(value) 120 | } 121 | _ => Err(Error::ExpectedSomeValue), 122 | } 123 | } 124 | 125 | fn struct_variant(self, fields: &'static [&'static str], visitor: V) -> Result 126 | where 127 | V: de::Visitor<'de>, 128 | { 129 | let value = de::Deserializer::deserialize_struct(&mut *self.de, "", fields, visitor)?; 130 | match self 131 | .de 132 | .parse_whitespace() 133 | .ok_or(Error::EofWhileParsingValue)? 134 | { 135 | b'}' => { 136 | self.de.eat_char(); 137 | Ok(value) 138 | } 139 | _ => Err(Error::ExpectedSomeValue), 140 | } 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /src/de/errors.rs: -------------------------------------------------------------------------------- 1 | use alloc::string::{String, ToString}; 2 | 3 | use serde::de; 4 | 5 | /// Deserialization result 6 | pub type Result = core::result::Result; 7 | 8 | /// This type represents all possible errors that can occur when deserializing 9 | /// JSON data 10 | /// 11 | /// It implements [`std::error::Error`] trait so long as either `std` or 12 | /// `unstable` features are enabled. `std` is enabled by default and disabling 13 | /// it makes the crate `no_std`. `unstable` makes it necessary to build code 14 | /// with nightly compiler. 15 | #[derive(Debug, PartialEq, Eq)] 16 | #[non_exhaustive] 17 | pub enum Error { 18 | /// Control character (U+0000 to U+001F) found in string. Those must always be escaped. 19 | ControlCharacterInString, 20 | 21 | /// EOF while parsing a list. 22 | EofWhileParsingList, 23 | 24 | /// EOF while parsing an object. 25 | EofWhileParsingObject, 26 | 27 | /// EOF while parsing a string. 28 | EofWhileParsingString, 29 | 30 | /// EOF while parsing a JSON value. 31 | EofWhileParsingValue, 32 | 33 | /// Expected this character to be a `':'`. 34 | ExpectedColon, 35 | 36 | /// Expected a high surrogate (D800–DBFF) but found something else 37 | ExpectedHighSurrogate, 38 | 39 | /// Expected this character to be either a `','` or a `']'`. 40 | ExpectedListCommaOrEnd, 41 | 42 | /// Expected a low surrogate (DC00–DFFF) but found something else 43 | ExpectedLowSurrogate, 44 | 45 | /// Expected this character to be either a `','` or a `'}'`. 46 | ExpectedObjectCommaOrEnd, 47 | 48 | /// Expected to parse either a `true`, `false`, or a `null`. 49 | ExpectedSomeIdent, 50 | 51 | /// Expected this character to start a JSON value. 52 | ExpectedSomeValue, 53 | 54 | /// Invalid escape sequence 55 | InvalidEscape, 56 | 57 | /// Invalid number. 58 | InvalidNumber, 59 | 60 | /// Invalid type 61 | InvalidType, 62 | 63 | /// Invalid unicode code point. 64 | InvalidUnicodeCodePoint, 65 | 66 | /// Object key is not a string. 67 | KeyMustBeAString, 68 | 69 | /// Found a lone surrogate, which can exist in JSON but cannot be encoded to UTF-8 70 | LoneSurrogateFound, 71 | 72 | /// JSON has non-whitespace trailing characters after the value. 73 | TrailingCharacters, 74 | 75 | /// JSON has a comma after the last value in an array or map. 76 | TrailingComma, 77 | 78 | /// JSON is nested too deeply, exceeded the recursion limit. 79 | RecursionLimitExceeded, 80 | 81 | /// Custom error message from serde 82 | Custom(String), 83 | } 84 | 85 | impl de::StdError for Error {} 86 | 87 | impl de::Error for Error { 88 | fn custom(msg: T) -> Self { 89 | Error::Custom(msg.to_string()) 90 | } 91 | } 92 | 93 | impl core::fmt::Display for Error { 94 | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { 95 | write!( 96 | f, 97 | "{}", 98 | match self { 99 | Error::ControlCharacterInString => "Control character found in string.", 100 | Error::EofWhileParsingList => "EOF while parsing a list.", 101 | Error::EofWhileParsingObject => "EOF while parsing an object.", 102 | Error::EofWhileParsingString => "EOF while parsing a string.", 103 | Error::EofWhileParsingValue => "EOF while parsing a JSON value.", 104 | Error::ExpectedColon => "Expected this character to be a `':'`.", 105 | Error::ExpectedHighSurrogate => "Expected a high surrogate (D800–DBFF).", 106 | Error::ExpectedListCommaOrEnd => { 107 | "Expected this character to be either a `','` or\ 108 | a \ 109 | `']'`." 110 | } 111 | Error::ExpectedLowSurrogate => "Expected a low surrogate (DC00–DFFF).", 112 | Error::ExpectedObjectCommaOrEnd => { 113 | "Expected this character to be either a `','` \ 114 | or a \ 115 | `'}'`." 116 | } 117 | Error::ExpectedSomeIdent => { 118 | "Expected to parse either a `true`, `false`, or a \ 119 | `null`." 120 | } 121 | Error::ExpectedSomeValue => "Expected this character to start a JSON value.", 122 | Error::InvalidEscape => "Invalid escape sequence.", 123 | Error::InvalidNumber => "Invalid number.", 124 | Error::InvalidType => "Invalid type", 125 | Error::InvalidUnicodeCodePoint => "Invalid unicode code point.", 126 | Error::KeyMustBeAString => "Object key is not a string.", 127 | Error::LoneSurrogateFound => "Found a lone surrogate, which can exist in JSON but cannot be encoded to UTF-8.", 128 | Error::TrailingCharacters => { 129 | "JSON has non-whitespace trailing characters after \ 130 | the \ 131 | value." 132 | } 133 | Error::TrailingComma => "JSON has a comma after the last value in an array or map.", 134 | Error::RecursionLimitExceeded => "JSON is nested too deeply, exceeded the recursion limit.", 135 | Error::Custom(msg) => msg, 136 | } 137 | ) 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /src/de/map.rs: -------------------------------------------------------------------------------- 1 | use crate::de::{Deserializer, Error}; 2 | use serde::de::{self, Visitor}; 3 | 4 | pub struct MapAccess<'a, 'b> { 5 | de: &'a mut Deserializer<'b>, 6 | first: bool, 7 | } 8 | 9 | impl<'a, 'b> MapAccess<'a, 'b> { 10 | pub(crate) fn new(de: &'a mut Deserializer<'b>) -> Self { 11 | MapAccess { de, first: true } 12 | } 13 | } 14 | 15 | macro_rules! deserialize_signed_key { 16 | ($self:ident, $visitor:ident, $ixx:ident, $visit_ixx:ident) => {{ 17 | let de = $self.de; 18 | match de.parse_whitespace().ok_or(Error::EofWhileParsingValue)? { 19 | b'"' => de.eat_char(), 20 | _ => return Err(Error::InvalidType), 21 | }; 22 | 23 | let result = match de.peek() { 24 | // after rust merged or-patterns feature, these two clause can be merged. 25 | // error[E0658]: or-patterns syntax is experimental 26 | Some(b'0'..=b'9') => super::deserialize_signed!(de, $visitor, $ixx, $visit_ixx), 27 | Some(b'-') => super::deserialize_signed!(de, $visitor, $ixx, $visit_ixx), 28 | _ => return Err(Error::InvalidType), 29 | }; 30 | match de.peek() { 31 | Some(b'"') => { 32 | de.eat_char(); 33 | result 34 | } 35 | _ => Err(Error::InvalidType), 36 | } 37 | }}; 38 | } 39 | 40 | macro_rules! deserialize_unsigned_key { 41 | ($self:ident, $visitor:ident, $ixx:ident, $visit_ixx:ident) => {{ 42 | let de = $self.de; 43 | match de.parse_whitespace().ok_or(Error::EofWhileParsingValue)? { 44 | b'"' => de.eat_char(), 45 | _ => return Err(Error::InvalidType), 46 | }; 47 | 48 | let result = match de.peek() { 49 | // after rust merged or-patterns feature, these two clause can be merged. 50 | // error[E0658]: or-patterns syntax is experimental 51 | Some(b'0'..=b'9') => super::deserialize_unsigned!(de, $visitor, $ixx, $visit_ixx), 52 | Some(b'-') => super::deserialize_unsigned!(de, $visitor, $ixx, $visit_ixx), 53 | _ => return Err(Error::InvalidType), 54 | }; 55 | match de.peek() { 56 | Some(b'"') => { 57 | de.eat_char(); 58 | result 59 | } 60 | _ => Err(Error::InvalidType), 61 | } 62 | }}; 63 | } 64 | 65 | impl<'a, 'de> de::MapAccess<'de> for MapAccess<'a, 'de> { 66 | type Error = Error; 67 | 68 | fn next_key_seed(&mut self, seed: K) -> Result, Error> 69 | where 70 | K: de::DeserializeSeed<'de>, 71 | { 72 | let peek = match self 73 | .de 74 | .parse_whitespace() 75 | .ok_or(Error::EofWhileParsingObject)? 76 | { 77 | b'}' => return Ok(None), 78 | b',' if !self.first => { 79 | self.de.eat_char(); 80 | self.de.parse_whitespace() 81 | } 82 | b => { 83 | if self.first { 84 | self.first = false; 85 | Some(b) 86 | } else { 87 | return Err(Error::ExpectedObjectCommaOrEnd); 88 | } 89 | } 90 | }; 91 | 92 | match peek.ok_or(Error::EofWhileParsingValue)? { 93 | b'"' => seed.deserialize(MapKey { de: &mut *self.de }).map(Some), 94 | b'}' => Err(Error::TrailingComma), 95 | _ => Err(Error::KeyMustBeAString), 96 | } 97 | } 98 | 99 | fn next_value_seed(&mut self, seed: V) -> Result 100 | where 101 | V: de::DeserializeSeed<'de>, 102 | { 103 | self.de.parse_object_colon()?; 104 | 105 | seed.deserialize(&mut *self.de) 106 | } 107 | } 108 | 109 | struct MapKey<'a, 'b> { 110 | de: &'a mut Deserializer<'b>, 111 | } 112 | 113 | impl<'de, 'a> de::Deserializer<'de> for MapKey<'a, 'de> { 114 | type Error = Error; 115 | 116 | fn deserialize_any(self, visitor: V) -> Result 117 | where 118 | V: Visitor<'de>, 119 | { 120 | // Only identifiers are proper json object keys 121 | self.deserialize_identifier(visitor) 122 | } 123 | 124 | fn deserialize_bool(self, _visitor: V) -> Result 125 | where 126 | V: Visitor<'de>, 127 | { 128 | unreachable!() 129 | } 130 | 131 | fn deserialize_i8(self, visitor: V) -> Result 132 | where 133 | V: Visitor<'de>, 134 | { 135 | deserialize_signed_key!(self, visitor, i8, visit_i8) 136 | } 137 | 138 | fn deserialize_i16(self, visitor: V) -> Result 139 | where 140 | V: Visitor<'de>, 141 | { 142 | deserialize_signed_key!(self, visitor, i16, visit_i16) 143 | } 144 | 145 | fn deserialize_i32(self, visitor: V) -> Result 146 | where 147 | V: Visitor<'de>, 148 | { 149 | deserialize_signed_key!(self, visitor, i32, visit_i32) 150 | } 151 | 152 | fn deserialize_i64(self, visitor: V) -> Result 153 | where 154 | V: Visitor<'de>, 155 | { 156 | deserialize_signed_key!(self, visitor, i64, visit_i64) 157 | } 158 | 159 | fn deserialize_i128(self, visitor: V) -> Result 160 | where 161 | V: Visitor<'de>, 162 | { 163 | deserialize_signed_key!(self, visitor, i128, visit_i128) 164 | } 165 | 166 | fn deserialize_u8(self, visitor: V) -> Result 167 | where 168 | V: Visitor<'de>, 169 | { 170 | deserialize_unsigned_key!(self, visitor, u8, visit_u8) 171 | } 172 | 173 | fn deserialize_u16(self, visitor: V) -> Result 174 | where 175 | V: Visitor<'de>, 176 | { 177 | deserialize_unsigned_key!(self, visitor, u16, visit_u16) 178 | } 179 | 180 | fn deserialize_u32(self, visitor: V) -> Result 181 | where 182 | V: Visitor<'de>, 183 | { 184 | deserialize_unsigned_key!(self, visitor, u32, visit_u32) 185 | } 186 | 187 | fn deserialize_u64(self, visitor: V) -> Result 188 | where 189 | V: Visitor<'de>, 190 | { 191 | deserialize_unsigned_key!(self, visitor, u64, visit_u64) 192 | } 193 | 194 | fn deserialize_u128(self, visitor: V) -> Result 195 | where 196 | V: Visitor<'de>, 197 | { 198 | deserialize_unsigned_key!(self, visitor, u128, visit_u128) 199 | } 200 | 201 | fn deserialize_f32(self, _visitor: V) -> Result 202 | where 203 | V: Visitor<'de>, 204 | { 205 | unreachable!() 206 | } 207 | 208 | fn deserialize_f64(self, _visitor: V) -> Result 209 | where 210 | V: Visitor<'de>, 211 | { 212 | unreachable!() 213 | } 214 | 215 | fn deserialize_char(self, _visitor: V) -> Result 216 | where 217 | V: Visitor<'de>, 218 | { 219 | unreachable!() 220 | } 221 | 222 | fn deserialize_str(self, visitor: V) -> Result 223 | where 224 | V: Visitor<'de>, 225 | { 226 | self.de.deserialize_str(visitor) 227 | } 228 | 229 | fn deserialize_string(self, visitor: V) -> Result 230 | where 231 | V: Visitor<'de>, 232 | { 233 | self.de.deserialize_string(visitor) 234 | } 235 | 236 | fn deserialize_bytes(self, _visitor: V) -> Result 237 | where 238 | V: Visitor<'de>, 239 | { 240 | unreachable!() 241 | } 242 | 243 | fn deserialize_byte_buf(self, _visitor: V) -> Result 244 | where 245 | V: Visitor<'de>, 246 | { 247 | unreachable!() 248 | } 249 | 250 | fn deserialize_option(self, _visitor: V) -> Result 251 | where 252 | V: Visitor<'de>, 253 | { 254 | unreachable!() 255 | } 256 | 257 | fn deserialize_unit(self, _visitor: V) -> Result 258 | where 259 | V: Visitor<'de>, 260 | { 261 | unreachable!() 262 | } 263 | 264 | fn deserialize_unit_struct( 265 | self, 266 | _name: &'static str, 267 | _visitor: V, 268 | ) -> Result 269 | where 270 | V: Visitor<'de>, 271 | { 272 | unreachable!() 273 | } 274 | 275 | fn deserialize_newtype_struct( 276 | self, 277 | _name: &'static str, 278 | _visitor: V, 279 | ) -> Result 280 | where 281 | V: Visitor<'de>, 282 | { 283 | unreachable!() 284 | } 285 | 286 | fn deserialize_seq(self, _visitor: V) -> Result 287 | where 288 | V: Visitor<'de>, 289 | { 290 | unreachable!() 291 | } 292 | 293 | fn deserialize_tuple(self, _len: usize, _visitor: V) -> Result 294 | where 295 | V: Visitor<'de>, 296 | { 297 | unreachable!() 298 | } 299 | 300 | fn deserialize_tuple_struct( 301 | self, 302 | _name: &'static str, 303 | _len: usize, 304 | _visitor: V, 305 | ) -> Result 306 | where 307 | V: Visitor<'de>, 308 | { 309 | unreachable!() 310 | } 311 | 312 | fn deserialize_map(self, _visitor: V) -> Result 313 | where 314 | V: Visitor<'de>, 315 | { 316 | unreachable!() 317 | } 318 | 319 | fn deserialize_struct( 320 | self, 321 | _name: &'static str, 322 | _fields: &'static [&'static str], 323 | _visitor: V, 324 | ) -> Result 325 | where 326 | V: Visitor<'de>, 327 | { 328 | unreachable!() 329 | } 330 | 331 | fn deserialize_enum( 332 | self, 333 | _name: &'static str, 334 | _variants: &'static [&'static str], 335 | _visitor: V, 336 | ) -> Result 337 | where 338 | V: Visitor<'de>, 339 | { 340 | unreachable!() 341 | } 342 | 343 | fn deserialize_identifier(self, visitor: V) -> Result 344 | where 345 | V: Visitor<'de>, 346 | { 347 | self.deserialize_str(visitor) 348 | } 349 | 350 | fn deserialize_ignored_any(self, visitor: V) -> Result 351 | where 352 | V: Visitor<'de>, 353 | { 354 | // Even if we’re ignoring the contents of the map, we still need to 355 | // deserialize the string here in order to chomp the key’s characters. 356 | self.deserialize_str(visitor) 357 | } 358 | } 359 | -------------------------------------------------------------------------------- /src/de/mod.rs: -------------------------------------------------------------------------------- 1 | //! Deserialize JSON data to a Rust data structure 2 | 3 | mod enum_; 4 | mod errors; 5 | mod map; 6 | mod seq; 7 | mod unescape; 8 | 9 | use alloc::string::String; 10 | 11 | pub use errors::{Error, Result}; 12 | 13 | use serde::de::{self, Visitor}; 14 | 15 | use self::enum_::{StructVariantAccess, UnitVariantAccess}; 16 | use self::map::MapAccess; 17 | use self::seq::SeqAccess; 18 | 19 | /// Deserializer will parse serde-json-wasm flavored JSON into a 20 | /// serde-annotated struct 21 | pub struct Deserializer<'b> { 22 | slice: &'b [u8], 23 | index: usize, 24 | 25 | /// Remaining depth until we hit the recursion limit 26 | remaining_depth: u8, 27 | } 28 | 29 | enum StringLike<'a> { 30 | Borrowed(&'a str), 31 | Owned(String), 32 | } 33 | 34 | impl<'a> Deserializer<'a> { 35 | fn new(slice: &'a [u8]) -> Deserializer<'_> { 36 | Deserializer { 37 | slice, 38 | index: 0, 39 | remaining_depth: 128, 40 | } 41 | } 42 | 43 | fn eat_char(&mut self) { 44 | self.index += 1; 45 | } 46 | 47 | fn end(&mut self) -> Result<()> { 48 | match self.parse_whitespace() { 49 | Some(_) => Err(Error::TrailingCharacters), 50 | None => Ok(()), 51 | } 52 | } 53 | 54 | fn end_seq(&mut self) -> Result<()> { 55 | match self.parse_whitespace().ok_or(Error::EofWhileParsingList)? { 56 | b']' => { 57 | self.eat_char(); 58 | Ok(()) 59 | } 60 | b',' => { 61 | self.eat_char(); 62 | match self.parse_whitespace() { 63 | Some(b']') => Err(Error::TrailingComma), 64 | _ => Err(Error::TrailingCharacters), 65 | } 66 | } 67 | _ => Err(Error::TrailingCharacters), 68 | } 69 | } 70 | 71 | fn end_map(&mut self) -> Result<()> { 72 | match self 73 | .parse_whitespace() 74 | .ok_or(Error::EofWhileParsingObject)? 75 | { 76 | b'}' => { 77 | self.eat_char(); 78 | Ok(()) 79 | } 80 | b',' => Err(Error::TrailingComma), 81 | _ => Err(Error::TrailingCharacters), 82 | } 83 | } 84 | 85 | fn next_char(&mut self) -> Option { 86 | let ch = self.slice.get(self.index); 87 | 88 | if ch.is_some() { 89 | self.index += 1; 90 | } 91 | 92 | ch.cloned() 93 | } 94 | 95 | fn parse_ident(&mut self, ident: &[u8]) -> Result<()> { 96 | for c in ident { 97 | if Some(*c) != self.next_char() { 98 | return Err(Error::ExpectedSomeIdent); 99 | } 100 | } 101 | 102 | Ok(()) 103 | } 104 | 105 | fn parse_object_colon(&mut self) -> Result<()> { 106 | match self 107 | .parse_whitespace() 108 | .ok_or(Error::EofWhileParsingObject)? 109 | { 110 | b':' => { 111 | self.eat_char(); 112 | Ok(()) 113 | } 114 | _ => Err(Error::ExpectedColon), 115 | } 116 | } 117 | 118 | fn parse_string(&mut self) -> Result> { 119 | let start = self.index; 120 | let mut contains_backslash = false; 121 | let mut escaped = false; 122 | loop { 123 | match self.peek() { 124 | Some(b'"') => { 125 | if escaped { 126 | escaped = false; 127 | self.eat_char(); // just continue 128 | } else { 129 | let end = self.index; 130 | self.eat_char(); 131 | return if contains_backslash { 132 | Ok(StringLike::Owned(unescape::unescape( 133 | &self.slice[start..end], 134 | )?)) 135 | } else { 136 | Ok(StringLike::Borrowed( 137 | core::str::from_utf8(&self.slice[start..end]) 138 | .map_err(|_| Error::InvalidUnicodeCodePoint)?, 139 | )) 140 | }; 141 | } 142 | } 143 | Some(b'\\') => { 144 | contains_backslash = true; 145 | escaped = !escaped; 146 | self.eat_char() 147 | } 148 | Some(_) => { 149 | escaped = false; 150 | self.eat_char() 151 | } 152 | None => return Err(Error::EofWhileParsingString), 153 | } 154 | } 155 | } 156 | 157 | /// Consumes all the whitespace characters and returns a peek into the next character 158 | fn parse_whitespace(&mut self) -> Option { 159 | loop { 160 | match self.peek() { 161 | Some(b' ') | Some(b'\n') | Some(b'\t') | Some(b'\r') => { 162 | self.eat_char(); 163 | } 164 | other => { 165 | return other; 166 | } 167 | } 168 | } 169 | } 170 | 171 | fn peek(&mut self) -> Option { 172 | self.slice.get(self.index).cloned() 173 | } 174 | } 175 | 176 | // NOTE(deserialize_*signed) we avoid parsing into u64 and then casting to a smaller integer, which 177 | // is what upstream does, to avoid pulling in 64-bit compiler intrinsics, which waste a few KBs of 178 | // Flash, when targeting non 64-bit architectures 179 | macro_rules! deserialize_unsigned { 180 | ($self:ident, $visitor:ident, $uxx:ident, $visit_uxx:ident) => {{ 181 | let peek = $self 182 | .parse_whitespace() 183 | .ok_or(Error::EofWhileParsingValue)?; 184 | 185 | match peek { 186 | b'-' => Err(Error::InvalidNumber), 187 | b'0' => { 188 | $self.eat_char(); 189 | $visitor.$visit_uxx(0) 190 | } 191 | b'1'..=b'9' => { 192 | $self.eat_char(); 193 | 194 | let mut number = (peek - b'0') as $uxx; 195 | loop { 196 | match $self.peek() { 197 | Some(c @ b'0'..=b'9') => { 198 | $self.eat_char(); 199 | number = number 200 | .checked_mul(10) 201 | .ok_or(Error::InvalidNumber)? 202 | .checked_add((c - b'0') as $uxx) 203 | .ok_or(Error::InvalidNumber)?; 204 | } 205 | _ => break, 206 | } 207 | } 208 | $visitor.$visit_uxx(number) 209 | } 210 | _ => Err(Error::InvalidType), 211 | } 212 | }}; 213 | } 214 | pub(crate) use deserialize_unsigned; 215 | 216 | macro_rules! deserialize_signed { 217 | ($self:ident, $visitor:ident, $ixx:ident, $visit_ixx:ident) => {{ 218 | let signed = match $self 219 | .parse_whitespace() 220 | .ok_or(Error::EofWhileParsingValue)? 221 | { 222 | b'-' => { 223 | $self.eat_char(); 224 | true 225 | } 226 | _ => false, 227 | }; 228 | 229 | match $self.peek().ok_or(Error::EofWhileParsingValue)? { 230 | b'0' => { 231 | $self.eat_char(); 232 | $visitor.$visit_ixx(0) 233 | } 234 | c @ b'1'..=b'9' => { 235 | $self.eat_char(); 236 | 237 | let mut number = (c - b'0') as $ixx * if signed { -1 } else { 1 }; 238 | loop { 239 | match $self.peek() { 240 | Some(c @ b'0'..=b'9') => { 241 | $self.eat_char(); 242 | number = number 243 | .checked_mul(10) 244 | .ok_or(Error::InvalidNumber)? 245 | .checked_add((c - b'0') as $ixx * if signed { -1 } else { 1 }) 246 | .ok_or(Error::InvalidNumber)?; 247 | } 248 | _ => break, 249 | } 250 | } 251 | $visitor.$visit_ixx(number) 252 | } 253 | _ => return Err(Error::InvalidType), 254 | } 255 | }}; 256 | } 257 | pub(crate) use deserialize_signed; 258 | 259 | impl<'a, 'de> de::Deserializer<'de> for &'a mut Deserializer<'de> { 260 | type Error = Error; 261 | 262 | fn deserialize_any(self, visitor: V) -> Result 263 | where 264 | V: Visitor<'de>, 265 | { 266 | match self.parse_whitespace().ok_or(Error::EofWhileParsingValue)? { 267 | b'n' => { 268 | self.eat_char(); 269 | self.parse_ident(b"ull")?; 270 | visitor.visit_unit() 271 | } 272 | b't' => { 273 | self.eat_char(); 274 | self.parse_ident(b"rue")?; 275 | visitor.visit_bool(true) 276 | } 277 | b'f' => { 278 | self.eat_char(); 279 | self.parse_ident(b"alse")?; 280 | visitor.visit_bool(false) 281 | } 282 | b'-' => { 283 | deserialize_signed!(self, visitor, i64, visit_i64) 284 | } 285 | b'0'..=b'9' => { 286 | deserialize_unsigned!(self, visitor, u64, visit_u64) 287 | } 288 | b'"' => { 289 | self.eat_char(); 290 | let str_like = self.parse_string()?; 291 | match str_like { 292 | StringLike::Borrowed(str) => visitor.visit_borrowed_str(str), 293 | StringLike::Owned(string) => visitor.visit_string(string), 294 | } 295 | } 296 | b'[' => { 297 | check_recursion! { 298 | self.eat_char(); 299 | let ret = visitor.visit_seq(SeqAccess::new(self)); 300 | } 301 | let ret = ret?; 302 | 303 | self.end_seq()?; 304 | 305 | Ok(ret) 306 | } 307 | b'{' => { 308 | check_recursion! { 309 | self.eat_char(); 310 | let ret = visitor.visit_map(MapAccess::new(self)); 311 | } 312 | let ret = ret?; 313 | 314 | self.end_map()?; 315 | 316 | Ok(ret) 317 | } 318 | _ => Err(Error::ExpectedSomeValue), 319 | } 320 | } 321 | 322 | fn deserialize_bool(self, visitor: V) -> Result 323 | where 324 | V: Visitor<'de>, 325 | { 326 | let peek = self.parse_whitespace().ok_or(Error::EofWhileParsingValue)?; 327 | 328 | match peek { 329 | b't' => { 330 | self.eat_char(); 331 | self.parse_ident(b"rue")?; 332 | visitor.visit_bool(true) 333 | } 334 | b'f' => { 335 | self.eat_char(); 336 | self.parse_ident(b"alse")?; 337 | visitor.visit_bool(false) 338 | } 339 | _ => Err(Error::InvalidType), 340 | } 341 | } 342 | 343 | fn deserialize_i8(self, visitor: V) -> Result 344 | where 345 | V: Visitor<'de>, 346 | { 347 | deserialize_signed!(self, visitor, i8, visit_i8) 348 | } 349 | 350 | fn deserialize_i16(self, visitor: V) -> Result 351 | where 352 | V: Visitor<'de>, 353 | { 354 | deserialize_signed!(self, visitor, i16, visit_i16) 355 | } 356 | 357 | fn deserialize_i32(self, visitor: V) -> Result 358 | where 359 | V: Visitor<'de>, 360 | { 361 | deserialize_signed!(self, visitor, i32, visit_i32) 362 | } 363 | 364 | fn deserialize_i64(self, visitor: V) -> Result 365 | where 366 | V: Visitor<'de>, 367 | { 368 | deserialize_signed!(self, visitor, i64, visit_i64) 369 | } 370 | 371 | fn deserialize_i128(self, visitor: V) -> Result 372 | where 373 | V: Visitor<'de>, 374 | { 375 | deserialize_signed!(self, visitor, i128, visit_i128) 376 | } 377 | 378 | fn deserialize_u8(self, visitor: V) -> Result 379 | where 380 | V: Visitor<'de>, 381 | { 382 | deserialize_unsigned!(self, visitor, u8, visit_u8) 383 | } 384 | 385 | fn deserialize_u16(self, visitor: V) -> Result 386 | where 387 | V: Visitor<'de>, 388 | { 389 | deserialize_unsigned!(self, visitor, u16, visit_u16) 390 | } 391 | 392 | fn deserialize_u32(self, visitor: V) -> Result 393 | where 394 | V: Visitor<'de>, 395 | { 396 | deserialize_unsigned!(self, visitor, u32, visit_u32) 397 | } 398 | 399 | fn deserialize_u64(self, visitor: V) -> Result 400 | where 401 | V: Visitor<'de>, 402 | { 403 | deserialize_unsigned!(self, visitor, u64, visit_u64) 404 | } 405 | 406 | fn deserialize_u128(self, visitor: V) -> Result 407 | where 408 | V: Visitor<'de>, 409 | { 410 | deserialize_unsigned!(self, visitor, u128, visit_u128) 411 | } 412 | 413 | fn deserialize_f32(self, _visitor: V) -> Result 414 | where 415 | V: Visitor<'de>, 416 | { 417 | unreachable!() 418 | } 419 | 420 | fn deserialize_f64(self, _visitor: V) -> Result 421 | where 422 | V: Visitor<'de>, 423 | { 424 | unreachable!() 425 | } 426 | 427 | fn deserialize_char(self, _visitor: V) -> Result 428 | where 429 | V: Visitor<'de>, 430 | { 431 | unreachable!() 432 | } 433 | 434 | fn deserialize_str(self, visitor: V) -> Result 435 | where 436 | V: Visitor<'de>, 437 | { 438 | self.deserialize_string(visitor) 439 | } 440 | 441 | fn deserialize_string(self, visitor: V) -> Result 442 | where 443 | V: Visitor<'de>, 444 | { 445 | let peek = self.parse_whitespace().ok_or(Error::EofWhileParsingValue)?; 446 | 447 | match peek { 448 | b'"' => { 449 | self.eat_char(); 450 | let str_like = self.parse_string()?; 451 | match str_like { 452 | StringLike::Borrowed(str) => visitor.visit_borrowed_str(str), 453 | StringLike::Owned(string) => visitor.visit_string(string), 454 | } 455 | } 456 | _ => Err(Error::InvalidType), 457 | } 458 | } 459 | 460 | /// Unsupported 461 | fn deserialize_bytes(self, _visitor: V) -> Result 462 | where 463 | V: Visitor<'de>, 464 | { 465 | unreachable!() 466 | } 467 | 468 | /// Unsupported 469 | fn deserialize_byte_buf(self, _visitor: V) -> Result 470 | where 471 | V: Visitor<'de>, 472 | { 473 | unreachable!() 474 | } 475 | 476 | fn deserialize_option(self, visitor: V) -> Result 477 | where 478 | V: Visitor<'de>, 479 | { 480 | match self.parse_whitespace().ok_or(Error::EofWhileParsingValue)? { 481 | b'n' => { 482 | self.eat_char(); 483 | self.parse_ident(b"ull")?; 484 | visitor.visit_none() 485 | } 486 | _ => visitor.visit_some(self), 487 | } 488 | } 489 | 490 | /// Resolves "null" to () 491 | fn deserialize_unit(self, visitor: V) -> Result 492 | where 493 | V: Visitor<'de>, 494 | { 495 | let peek = self.parse_whitespace().ok_or(Error::EofWhileParsingValue)?; 496 | 497 | if peek == b'n' { 498 | self.eat_char(); 499 | self.parse_ident(b"ull")?; 500 | let ret = visitor.visit_unit()?; 501 | Ok(ret) 502 | } else { 503 | Err(Error::InvalidType) 504 | } 505 | } 506 | 507 | /// Resolves "null" to requested unit struct 508 | fn deserialize_unit_struct(self, _name: &'static str, visitor: V) -> Result 509 | where 510 | V: Visitor<'de>, 511 | { 512 | self.deserialize_unit(visitor) 513 | } 514 | 515 | /// Unsupported. We can’t parse newtypes because we don’t know the underlying type. 516 | fn deserialize_newtype_struct(self, _name: &'static str, visitor: V) -> Result 517 | where 518 | V: Visitor<'de>, 519 | { 520 | visitor.visit_newtype_struct(self) 521 | } 522 | 523 | fn deserialize_seq(self, visitor: V) -> Result 524 | where 525 | V: Visitor<'de>, 526 | { 527 | match self.parse_whitespace().ok_or(Error::EofWhileParsingValue)? { 528 | b'[' => { 529 | check_recursion! { 530 | self.eat_char(); 531 | let ret = visitor.visit_seq(SeqAccess::new(self)); 532 | } 533 | let ret = ret?; 534 | 535 | self.end_seq()?; 536 | 537 | Ok(ret) 538 | } 539 | _ => Err(Error::InvalidType), 540 | } 541 | } 542 | 543 | fn deserialize_tuple(self, _len: usize, visitor: V) -> Result 544 | where 545 | V: Visitor<'de>, 546 | { 547 | self.deserialize_seq(visitor) 548 | } 549 | 550 | fn deserialize_tuple_struct( 551 | self, 552 | _name: &'static str, 553 | _len: usize, 554 | visitor: V, 555 | ) -> Result 556 | where 557 | V: Visitor<'de>, 558 | { 559 | self.deserialize_seq(visitor) 560 | } 561 | 562 | fn deserialize_map(self, visitor: V) -> Result 563 | where 564 | V: Visitor<'de>, 565 | { 566 | let peek = self.parse_whitespace().ok_or(Error::EofWhileParsingValue)?; 567 | 568 | if peek == b'{' { 569 | check_recursion! { 570 | self.eat_char(); 571 | let ret = visitor.visit_map(MapAccess::new(self)); 572 | } 573 | let ret = ret?; 574 | 575 | self.end_map()?; 576 | 577 | Ok(ret) 578 | } else { 579 | Err(Error::InvalidType) 580 | } 581 | } 582 | 583 | fn deserialize_struct( 584 | self, 585 | _name: &'static str, 586 | _fields: &'static [&'static str], 587 | visitor: V, 588 | ) -> Result 589 | where 590 | V: Visitor<'de>, 591 | { 592 | self.deserialize_map(visitor) 593 | } 594 | 595 | fn deserialize_enum( 596 | self, 597 | _name: &'static str, 598 | _variants: &'static [&'static str], 599 | visitor: V, 600 | ) -> Result 601 | where 602 | V: Visitor<'de>, 603 | { 604 | match self.parse_whitespace().ok_or(Error::EofWhileParsingValue)? { 605 | // if it is a string enum 606 | b'"' => visitor.visit_enum(UnitVariantAccess::new(self)), 607 | // if it is a struct enum 608 | b'{' => { 609 | check_recursion! { 610 | self.eat_char(); 611 | let value = visitor.visit_enum(StructVariantAccess::new(self)); 612 | } 613 | value 614 | } 615 | _ => Err(Error::ExpectedSomeIdent), 616 | } 617 | } 618 | 619 | fn deserialize_identifier(self, visitor: V) -> Result 620 | where 621 | V: Visitor<'de>, 622 | { 623 | self.deserialize_str(visitor) 624 | } 625 | 626 | /// Used to throw out fields from JSON objects that we don’t want to 627 | /// keep in our structs. 628 | fn deserialize_ignored_any(self, visitor: V) -> Result 629 | where 630 | V: Visitor<'de>, 631 | { 632 | match self.parse_whitespace().ok_or(Error::EofWhileParsingValue)? { 633 | b'"' => self.deserialize_str(visitor), 634 | b'[' => self.deserialize_seq(visitor), 635 | b'{' => self.deserialize_struct("ignored", &[], visitor), 636 | b',' | b'}' | b']' => Err(Error::ExpectedSomeValue), 637 | // If it’s something else then we chomp until we get to an end delimiter. 638 | // This does technically allow for illegal JSON since we’re just ignoring 639 | // characters rather than parsing them. 640 | _ => loop { 641 | match self.peek() { 642 | // The visitor is expected to be UnknownAny’s visitor, which 643 | // implements visit_unit to return its unit Ok result. 644 | Some(b',') | Some(b'}') | Some(b']') => break visitor.visit_unit(), 645 | Some(_) => self.eat_char(), 646 | None => break Err(Error::EofWhileParsingString), 647 | } 648 | }, 649 | } 650 | } 651 | } 652 | 653 | /// Deserializes an instance of type `T` from bytes of JSON text 654 | pub fn from_slice(v: &[u8]) -> Result 655 | where 656 | T: de::DeserializeOwned, 657 | { 658 | let mut de = Deserializer::new(v); 659 | let value = de::Deserialize::deserialize(&mut de)?; 660 | de.end()?; 661 | 662 | Ok(value) 663 | } 664 | 665 | /// Deserializes an instance of type T from a string of JSON text 666 | pub fn from_str(s: &str) -> Result 667 | where 668 | T: de::DeserializeOwned, 669 | { 670 | from_slice(s.as_bytes()) 671 | } 672 | 673 | macro_rules! check_recursion { 674 | ($this:ident $($body:tt)*) => { 675 | $this.remaining_depth -= 1; 676 | if $this.remaining_depth == 0 { 677 | return Err($crate::de::Error::RecursionLimitExceeded); 678 | } 679 | 680 | $this $($body)* 681 | 682 | $this.remaining_depth += 1; 683 | }; 684 | } 685 | pub(crate) use check_recursion; 686 | 687 | #[cfg(test)] 688 | mod tests { 689 | use super::from_str; 690 | 691 | use alloc::string::{String, ToString}; 692 | use alloc::vec; 693 | use alloc::vec::Vec; 694 | 695 | use serde_derive::{Deserialize, Serialize}; 696 | 697 | #[derive(Debug, Deserialize, PartialEq)] 698 | enum Type { 699 | #[serde(rename = "boolean")] 700 | Boolean, 701 | #[serde(rename = "number")] 702 | Number, 703 | #[serde(rename = "thing")] 704 | Thing, 705 | } 706 | 707 | #[test] 708 | fn parse_whitespace() { 709 | assert_eq!(from_str(" true"), Ok(true)); 710 | assert_eq!(from_str("\ttrue"), Ok(true)); 711 | assert_eq!(from_str("\ntrue"), Ok(true)); 712 | assert_eq!(from_str("\rtrue"), Ok(true)); 713 | assert_eq!(from_str("\n\rtrue"), Ok(true)); 714 | assert_eq!(from_str("\r\ntrue"), Ok(true)); 715 | assert_eq!(from_str("true "), Ok(true)); 716 | assert_eq!(from_str("true\t"), Ok(true)); 717 | assert_eq!(from_str("true\n"), Ok(true)); 718 | assert_eq!(from_str("true\r"), Ok(true)); 719 | assert_eq!(from_str("true\n\r"), Ok(true)); 720 | assert_eq!(from_str("true\r\n"), Ok(true)); 721 | 722 | assert_eq!(from_str("[4,5]"), Ok([4, 5])); 723 | assert_eq!(from_str(" [4,5]"), Ok([4, 5])); 724 | assert_eq!(from_str("\t[4,5]"), Ok([4, 5])); 725 | assert_eq!(from_str("\n[4,5]"), Ok([4, 5])); 726 | assert_eq!(from_str("\r[4,5]"), Ok([4, 5])); 727 | assert_eq!(from_str("\n\r[4,5]"), Ok([4, 5])); 728 | assert_eq!(from_str("\r\n[4,5]"), Ok([4, 5])); 729 | assert_eq!(from_str("[ 4,5]"), Ok([4, 5])); 730 | assert_eq!(from_str("[\t4,5]"), Ok([4, 5])); 731 | assert_eq!(from_str("[\n4,5]"), Ok([4, 5])); 732 | assert_eq!(from_str("[\r4,5]"), Ok([4, 5])); 733 | assert_eq!(from_str("[\n\r4,5]"), Ok([4, 5])); 734 | assert_eq!(from_str("[\r\n4,5]"), Ok([4, 5])); 735 | assert_eq!(from_str("[4 ,5]"), Ok([4, 5])); 736 | assert_eq!(from_str("[4\t,5]"), Ok([4, 5])); 737 | assert_eq!(from_str("[4\n,5]"), Ok([4, 5])); 738 | assert_eq!(from_str("[4\r,5]"), Ok([4, 5])); 739 | assert_eq!(from_str("[4\n\r,5]"), Ok([4, 5])); 740 | assert_eq!(from_str("[4\r\n,5]"), Ok([4, 5])); 741 | assert_eq!(from_str("[4, 5]"), Ok([4, 5])); 742 | assert_eq!(from_str("[4,\t5]"), Ok([4, 5])); 743 | assert_eq!(from_str("[4,\n5]"), Ok([4, 5])); 744 | assert_eq!(from_str("[4,\r5]"), Ok([4, 5])); 745 | assert_eq!(from_str("[4,\n\r5]"), Ok([4, 5])); 746 | assert_eq!(from_str("[4,\r\n5]"), Ok([4, 5])); 747 | assert_eq!(from_str("[4,5 ]"), Ok([4, 5])); 748 | assert_eq!(from_str("[4,5\t]"), Ok([4, 5])); 749 | assert_eq!(from_str("[4,5\n]"), Ok([4, 5])); 750 | assert_eq!(from_str("[4,5\r]"), Ok([4, 5])); 751 | assert_eq!(from_str("[4,5\n\r]"), Ok([4, 5])); 752 | assert_eq!(from_str("[4,5\r\n]"), Ok([4, 5])); 753 | assert_eq!(from_str("[4,5] "), Ok([4, 5])); 754 | assert_eq!(from_str("[4,5]\t"), Ok([4, 5])); 755 | assert_eq!(from_str("[4,5]\n"), Ok([4, 5])); 756 | assert_eq!(from_str("[4,5]\r"), Ok([4, 5])); 757 | assert_eq!(from_str("[4,5]\n\r"), Ok([4, 5])); 758 | assert_eq!(from_str("[4,5]\r\n"), Ok([4, 5])); 759 | } 760 | 761 | #[test] 762 | fn integer128() { 763 | assert_eq!( 764 | from_str::(r#""0""#), 765 | Err(crate::de::Error::InvalidType) 766 | ); 767 | assert_eq!(from_str::(r#"0"#), Ok(0)); 768 | assert_eq!(from_str::(r#"1"#), Ok(1)); 769 | assert_eq!(from_str::(r#"-1"#), Ok(-1)); 770 | // max i128 771 | assert_eq!( 772 | from_str::(r#"170141183460469231731687303715884105727"#), 773 | Ok(170141183460469231731687303715884105727) 774 | ); 775 | assert_eq!( 776 | from_str::(r#"170141183460469231731687303715884105728"#), 777 | Err(crate::de::Error::InvalidNumber) 778 | ); 779 | // min i128 780 | assert_eq!( 781 | from_str::(r#"-170141183460469231731687303715884105728"#), 782 | Ok(-170141183460469231731687303715884105728) 783 | ); 784 | assert_eq!( 785 | from_str::(r#"-170141183460469231731687303715884105729"#), 786 | Err(crate::de::Error::InvalidNumber) 787 | ); 788 | 789 | assert_eq!( 790 | from_str::(r#""0""#), 791 | Err(crate::de::Error::InvalidType) 792 | ); 793 | assert_eq!(from_str::(r#"0"#), Ok(0)); 794 | assert_eq!(from_str::(r#"1"#), Ok(1)); 795 | assert_eq!( 796 | from_str::(r#"-1"#), 797 | Err(crate::de::Error::InvalidNumber) 798 | ); 799 | // max u128 800 | assert_eq!( 801 | from_str::(r#"340282366920938463463374607431768211455"#), 802 | Ok(340282366920938463463374607431768211455) 803 | ); 804 | assert_eq!( 805 | from_str::(r#"340282366920938463463374607431768211456"#), 806 | Err(crate::de::Error::InvalidNumber) 807 | ) 808 | } 809 | 810 | #[test] 811 | fn array() { 812 | assert_eq!(from_str::<[i32; 0]>("[]"), Ok([])); 813 | assert_eq!(from_str("[0, 1, 2]"), Ok([0, 1, 2])); 814 | 815 | // errors 816 | assert!(from_str::<[i32; 2]>("[0, 1,]").is_err()); 817 | } 818 | 819 | #[allow(clippy::let_unit_value)] 820 | #[allow(clippy::unit_cmp)] 821 | #[test] 822 | fn tuple() { 823 | type Pair = (i64, i64); 824 | type Wrapped = (i64,); // Comma differentiates one element tuple from a primary type surrounded by parentheses 825 | type Unit = (); 826 | 827 | let pair: Pair = (1, 2); 828 | assert_eq!(from_str("[1,2]"), Ok(pair)); 829 | assert_eq!(serde_json::from_str::("[1,2]").unwrap(), pair); 830 | 831 | let wrapped: Wrapped = (5,); 832 | assert_eq!(from_str("[5]"), Ok(wrapped)); 833 | assert_eq!(serde_json::from_str::("[5]").unwrap(), wrapped); 834 | 835 | let unit: Unit = (); 836 | assert_eq!(from_str("null"), Ok(unit)); 837 | assert_eq!(serde_json::from_str::<()>("null").unwrap(), unit); 838 | } 839 | 840 | #[test] 841 | fn tuple_variant() { 842 | #[derive(Debug, Deserialize, PartialEq)] 843 | enum Ops { 844 | Exit(), 845 | Square(i32), 846 | Add(i64, i64), 847 | } 848 | assert_eq!(from_str(r#"{"Exit":[]}"#), Ok(Ops::Exit())); 849 | assert_eq!( 850 | serde_json::from_str::(r#"{"Exit":[]}"#).unwrap(), 851 | Ops::Exit() 852 | ); 853 | assert_eq!(from_str(r#"{"Square":1}"#), Ok(Ops::Square(1))); 854 | assert_eq!( 855 | serde_json::from_str::(r#"{"Square":1}"#).unwrap(), 856 | Ops::Square(1) 857 | ); 858 | assert_eq!(from_str(r#"{"Add":[2,3]}"#), Ok(Ops::Add(2, 3))); 859 | assert_eq!( 860 | serde_json::from_str::(r#"{"Add":[2,3]}"#).unwrap(), 861 | Ops::Add(2, 3) 862 | ); 863 | } 864 | 865 | #[test] 866 | fn bool() { 867 | assert_eq!(from_str("true"), Ok(true)); 868 | assert_eq!(from_str(" true"), Ok(true)); 869 | assert_eq!(from_str("true "), Ok(true)); 870 | 871 | assert_eq!(from_str("false"), Ok(false)); 872 | assert_eq!(from_str(" false"), Ok(false)); 873 | assert_eq!(from_str("false "), Ok(false)); 874 | 875 | // errors 876 | assert!(from_str::("true false").is_err()); 877 | assert!(from_str::("tru").is_err()); 878 | } 879 | 880 | #[test] 881 | fn enum_clike() { 882 | assert_eq!(from_str(r#" "boolean" "#), Ok(Type::Boolean)); 883 | assert_eq!(from_str(r#" "number" "#), Ok(Type::Number)); 884 | assert_eq!(from_str(r#" "thing" "#), Ok(Type::Thing)); 885 | } 886 | 887 | #[test] 888 | fn string() { 889 | assert_eq!(from_str(r#" "hello" "#), Ok("hello".to_string())); 890 | assert_eq!(from_str(r#" "" "#), Ok("".to_string())); 891 | assert_eq!(from_str(r#" " " "#), Ok(" ".to_string())); 892 | assert_eq!(from_str(r#" "👏" "#), Ok("👏".to_string())); 893 | 894 | // Unescapes things 895 | assert_eq!(from_str(r#" "hel\tlo" "#), Ok("hel\tlo".to_string())); 896 | assert_eq!(from_str(r#" "hel\\lo" "#), Ok("hel\\lo".to_string())); 897 | 898 | // escaped " in the string content 899 | assert_eq!(from_str(r#" "foo\"bar" "#), Ok(r#"foo"bar"#.to_string())); 900 | assert_eq!(from_str(r#" "foo\\\"ba" "#), Ok(r#"foo\"ba"#.to_string())); 901 | assert_eq!(from_str(r#" "foo\"\"ba" "#), Ok(r#"foo""ba"#.to_string())); 902 | assert_eq!(from_str(r#" "\"bar" "#), Ok(r#""bar"#.to_string())); 903 | assert_eq!(from_str(r#" "foo\"" "#), Ok(r#"foo""#.to_string())); 904 | assert_eq!(from_str(r#" "\"" "#), Ok(r#"""#.to_string())); 905 | 906 | // non-escaped " preceded by backslashes 907 | assert_eq!(from_str(r#" "fooooo\\" "#), Ok(r#"fooooo\"#.to_string())); 908 | assert_eq!(from_str(r#" "fooo\\\\" "#), Ok(r#"fooo\\"#.to_string())); 909 | assert_eq!(from_str(r#" "fo\\\\\\" "#), Ok(r#"fo\\\"#.to_string())); 910 | assert_eq!(from_str(r#" "\\\\\\\\" "#), Ok(r#"\\\\"#.to_string())); 911 | } 912 | 913 | #[test] 914 | fn struct_bool() { 915 | #[derive(Debug, Deserialize, PartialEq)] 916 | struct Led { 917 | led: bool, 918 | } 919 | 920 | assert_eq!(from_str(r#"{ "led": true }"#), Ok(Led { led: true })); 921 | assert_eq!(from_str(r#"{ "led": false }"#), Ok(Led { led: false })); 922 | } 923 | 924 | #[test] 925 | fn struct_i8() { 926 | #[derive(Debug, Deserialize, PartialEq)] 927 | struct Temperature { 928 | temperature: i8, 929 | } 930 | 931 | assert_eq!( 932 | from_str(r#"{ "temperature": -17 }"#), 933 | Ok(Temperature { temperature: -17 }) 934 | ); 935 | 936 | assert_eq!( 937 | from_str(r#"{ "temperature": -0 }"#), 938 | Ok(Temperature { temperature: -0 }) 939 | ); 940 | 941 | assert_eq!( 942 | from_str(r#"{ "temperature": 0 }"#), 943 | Ok(Temperature { temperature: 0 }) 944 | ); 945 | 946 | // out of range 947 | assert!(from_str::(r#"{ "temperature": 128 }"#).is_err()); 948 | assert!(from_str::(r#"{ "temperature": -129 }"#).is_err()); 949 | } 950 | 951 | #[test] 952 | fn struct_option() { 953 | #[derive(Debug, Deserialize, PartialEq)] 954 | struct Property { 955 | description: Option, 956 | } 957 | 958 | assert_eq!( 959 | from_str(r#"{ "description": "An ambient temperature sensor" }"#), 960 | Ok(Property { 961 | description: Some("An ambient temperature sensor".to_string()), 962 | }) 963 | ); 964 | 965 | assert_eq!( 966 | from_str(r#"{ "description": null }"#), 967 | Ok(Property { description: None }) 968 | ); 969 | 970 | assert_eq!(from_str(r#"{}"#), Ok(Property { description: None })); 971 | } 972 | 973 | #[test] 974 | fn struct_u8() { 975 | #[derive(Debug, Deserialize, PartialEq)] 976 | struct Temperature { 977 | temperature: u8, 978 | } 979 | 980 | assert_eq!( 981 | from_str(r#"{ "temperature": 20 }"#), 982 | Ok(Temperature { temperature: 20 }) 983 | ); 984 | 985 | assert_eq!( 986 | from_str(r#"{ "temperature": 0 }"#), 987 | Ok(Temperature { temperature: 0 }) 988 | ); 989 | 990 | // out of range 991 | assert!(from_str::(r#"{ "temperature": 256 }"#).is_err()); 992 | assert!(from_str::(r#"{ "temperature": -1 }"#).is_err()); 993 | } 994 | 995 | #[test] 996 | fn struct_tuple() { 997 | #[derive(Debug, Deserialize, PartialEq)] 998 | struct Xy(i8, i8); 999 | 1000 | assert_eq!(from_str(r#"[10, 20]"#), Ok(Xy(10, 20))); 1001 | assert_eq!(from_str(r#"[10, -20]"#), Ok(Xy(10, -20))); 1002 | 1003 | // wrong number of args 1004 | match from_str::(r#"[10]"#) { 1005 | Err(super::Error::Custom(_)) => {} 1006 | _ => panic!("expect custom error"), 1007 | } 1008 | assert_eq!( 1009 | from_str::(r#"[10, 20, 30]"#), 1010 | Err(crate::de::Error::TrailingCharacters) 1011 | ); 1012 | } 1013 | 1014 | #[test] 1015 | fn struct_empty() { 1016 | #[derive(Debug, Deserialize, PartialEq)] 1017 | struct Empty {} 1018 | 1019 | assert_eq!(from_str(r#"{}"#), Ok(Empty {})); 1020 | assert_eq!(serde_json::from_str::(r#"{}"#).unwrap(), Empty {}); 1021 | } 1022 | 1023 | #[test] 1024 | fn struct_nothing() { 1025 | #[derive(Debug, Deserialize, PartialEq)] 1026 | struct Nothing; 1027 | 1028 | assert_eq!(from_str(r#"null"#), Ok(Nothing)); 1029 | assert_eq!(serde_json::from_str::(r#"null"#).unwrap(), Nothing); 1030 | } 1031 | 1032 | #[test] 1033 | fn struct_with_flatten() { 1034 | #[derive(Serialize, Deserialize, Debug, PartialEq, Eq)] 1035 | struct Pagination { 1036 | limit: u64, 1037 | offset: u64, 1038 | total: u64, 1039 | } 1040 | 1041 | #[derive(Serialize, Deserialize, Debug, PartialEq, Eq)] 1042 | struct Users { 1043 | users: Vec, 1044 | 1045 | #[serde(flatten)] 1046 | pagination: Pagination, 1047 | } 1048 | 1049 | let expected = Users { 1050 | users: vec!["joe".to_string(), "alice".to_string()], 1051 | pagination: Pagination { 1052 | offset: 100, 1053 | limit: 20, 1054 | total: 102, 1055 | }, 1056 | }; 1057 | 1058 | assert_eq!( 1059 | from_str::(r#"{"users":["joe","alice"],"limit":20,"offset":100,"total":102}"#) 1060 | .unwrap(), 1061 | expected, 1062 | ); 1063 | } 1064 | 1065 | #[test] 1066 | fn ignoring_extra_fields() { 1067 | #[derive(Debug, Deserialize, PartialEq)] 1068 | struct Temperature { 1069 | temperature: u8, 1070 | } 1071 | 1072 | assert_eq!( 1073 | from_str(r#"{ "temperature": 20, "high": 80, "low": -10, "updated": true }"#), 1074 | Ok(Temperature { temperature: 20 }) 1075 | ); 1076 | 1077 | assert_eq!( 1078 | from_str(r#"{ "temperature": 20, "conditions": "windy", "forecast": "cloudy" }"#), 1079 | Ok(Temperature { temperature: 20 }) 1080 | ); 1081 | 1082 | assert_eq!( 1083 | from_str(r#"{ "temperature": 20, "hourly_conditions": ["windy", "rainy"] }"#), 1084 | Ok(Temperature { temperature: 20 }) 1085 | ); 1086 | 1087 | assert_eq!( 1088 | from_str( 1089 | r#"{ "temperature": 20, "source": { "station": "dock", "sensors": ["front", "back"] } }"# 1090 | ), 1091 | Ok(Temperature { temperature: 20 }) 1092 | ); 1093 | 1094 | assert_eq!( 1095 | from_str(r#"{ "temperature": 20, "invalid": this-is-ignored }"#), 1096 | Ok(Temperature { temperature: 20 }) 1097 | ); 1098 | 1099 | assert_eq!( 1100 | from_str::(r#"{ "temperature": 20, "broken": }"#), 1101 | Err(crate::de::Error::ExpectedSomeValue) 1102 | ); 1103 | 1104 | assert_eq!( 1105 | from_str::(r#"{ "temperature": 20, "broken": [ }"#), 1106 | Err(crate::de::Error::ExpectedSomeValue) 1107 | ); 1108 | 1109 | assert_eq!( 1110 | from_str::(r#"{ "temperature": 20, "broken": ] }"#), 1111 | Err(crate::de::Error::ExpectedSomeValue) 1112 | ); 1113 | } 1114 | 1115 | #[test] 1116 | fn newtypes() { 1117 | #[derive(Deserialize, Debug, PartialEq)] 1118 | struct Address(String); 1119 | 1120 | #[derive(Deserialize, Debug, PartialEq)] 1121 | struct CommentId(u32); 1122 | 1123 | #[derive(Deserialize, Debug, PartialEq)] 1124 | struct NewtypeDemo { 1125 | address: Address, 1126 | comment: CommentId, 1127 | } 1128 | 1129 | let element: Address = from_str(r#""johnny""#).unwrap(); 1130 | assert_eq!(element, Address("johnny".to_string())); 1131 | 1132 | let element: CommentId = from_str(r#"5464813"#).unwrap(); 1133 | assert_eq!(element, CommentId(5464813)); 1134 | 1135 | let element: NewtypeDemo = from_str(r#"{"address": "johnny", "comment": 9897}"#).unwrap(); 1136 | assert_eq!( 1137 | element, 1138 | NewtypeDemo { 1139 | address: Address("johnny".to_string()), 1140 | comment: CommentId(9897), 1141 | } 1142 | ); 1143 | } 1144 | 1145 | #[test] 1146 | fn numbered_key_maps() { 1147 | use alloc::collections::BTreeMap; 1148 | 1149 | // u8 1150 | let mut ranking: BTreeMap = BTreeMap::new(); 1151 | ranking.insert(1, "Elon".to_string()); 1152 | ranking.insert(2, "Bazos".to_string()); 1153 | assert_eq!( 1154 | from_str::>(r#"{"1": "Elon", "2": "Bazos"}"#).unwrap(), 1155 | ranking 1156 | ); 1157 | 1158 | // u16 1159 | let mut ranking: BTreeMap = BTreeMap::new(); 1160 | ranking.insert(1, "Elon".to_string()); 1161 | ranking.insert(2, "Bazos".to_string()); 1162 | assert_eq!( 1163 | from_str::>(r#"{"1": "Elon", "2": "Bazos"}"#).unwrap(), 1164 | ranking 1165 | ); 1166 | 1167 | // u32 1168 | let mut ranking: BTreeMap = BTreeMap::new(); 1169 | ranking.insert(1, "Elon".to_string()); 1170 | ranking.insert(2, "Bazos".to_string()); 1171 | assert_eq!( 1172 | from_str::>(r#"{"1": "Elon", "2": "Bazos"}"#).unwrap(), 1173 | ranking 1174 | ); 1175 | 1176 | // u64 1177 | let mut ranking: BTreeMap = BTreeMap::new(); 1178 | ranking.insert(1, "Elon".to_string()); 1179 | ranking.insert(2, "Bazos".to_string()); 1180 | assert_eq!( 1181 | from_str::>(r#"{"1": "Elon", "2": "Bazos"}"#).unwrap(), 1182 | ranking 1183 | ); 1184 | 1185 | // u128 1186 | let mut ranking: BTreeMap = BTreeMap::new(); 1187 | ranking.insert(1, "Elon".to_string()); 1188 | ranking.insert(2, "Bazos".to_string()); 1189 | assert_eq!( 1190 | from_str::>(r#"{"1": "Elon", "2": "Bazos"}"#).unwrap(), 1191 | ranking 1192 | ); 1193 | 1194 | // i8 1195 | let mut ranking: BTreeMap = BTreeMap::new(); 1196 | ranking.insert(1, "Elon".to_string()); 1197 | ranking.insert(2, "Bazos".to_string()); 1198 | assert_eq!( 1199 | from_str::>(r#"{"1": "Elon", "2": "Bazos"}"#).unwrap(), 1200 | ranking 1201 | ); 1202 | 1203 | // i16 1204 | let mut ranking: BTreeMap = BTreeMap::new(); 1205 | ranking.insert(1, "Elon".to_string()); 1206 | ranking.insert(2, "Bazos".to_string()); 1207 | assert_eq!( 1208 | from_str::>(r#"{"1": "Elon", "2": "Bazos"}"#).unwrap(), 1209 | ranking 1210 | ); 1211 | 1212 | // i32 1213 | let mut ranking: BTreeMap = BTreeMap::new(); 1214 | ranking.insert(1, "Elon".to_string()); 1215 | ranking.insert(2, "Bazos".to_string()); 1216 | assert_eq!( 1217 | from_str::>(r#"{"1": "Elon", "2": "Bazos"}"#).unwrap(), 1218 | ranking 1219 | ); 1220 | 1221 | // i64 1222 | let mut ranking: BTreeMap = BTreeMap::new(); 1223 | ranking.insert(1, "Elon".to_string()); 1224 | ranking.insert(2, "Bazos".to_string()); 1225 | assert_eq!( 1226 | from_str::>(r#"{"1": "Elon", "2": "Bazos"}"#).unwrap(), 1227 | ranking 1228 | ); 1229 | 1230 | // i128 1231 | let mut ranking: BTreeMap = BTreeMap::new(); 1232 | ranking.insert(1, "Elon".to_string()); 1233 | ranking.insert(2, "Bazos".to_string()); 1234 | assert_eq!( 1235 | from_str::>(r#"{"1": "Elon", "2": "Bazos"}"#).unwrap(), 1236 | ranking 1237 | ); 1238 | } 1239 | 1240 | #[test] 1241 | fn deserialize_optional_vector() { 1242 | #[derive(Debug, Deserialize, PartialEq, Eq)] 1243 | pub struct Response { 1244 | pub log: Option, 1245 | pub messages: Vec, 1246 | } 1247 | 1248 | #[derive(Debug, Deserialize, PartialEq, Eq, serde_derive::Serialize)] 1249 | pub struct Msg { 1250 | pub name: String, 1251 | } 1252 | 1253 | #[derive(Debug, Deserialize, PartialEq, Eq)] 1254 | pub struct OptIn { 1255 | pub name: Option, 1256 | } 1257 | 1258 | let m: Msg = from_str( 1259 | r#"{ 1260 | "name": "one" 1261 | }"#, 1262 | ) 1263 | .expect("simple"); 1264 | assert_eq!( 1265 | m, 1266 | Msg { 1267 | name: "one".to_string() 1268 | } 1269 | ); 1270 | 1271 | let o: OptIn = from_str( 1272 | r#"{ 1273 | "name": "two" 1274 | }"#, 1275 | ) 1276 | .expect("opt"); 1277 | assert_eq!( 1278 | o, 1279 | OptIn { 1280 | name: Some("two".to_string()) 1281 | } 1282 | ); 1283 | 1284 | let res: Response = from_str( 1285 | r#"{ 1286 | "log": "my log", 1287 | "messages": [{"name": "one"}] 1288 | }"#, 1289 | ) 1290 | .expect("fud"); 1291 | assert_eq!( 1292 | res, 1293 | Response { 1294 | log: Some("my log".to_string()), 1295 | messages: vec![Msg { 1296 | name: "one".to_string() 1297 | }], 1298 | } 1299 | ); 1300 | 1301 | let res: Response = from_str(r#"{"log": null,"messages": []}"#).expect("fud"); 1302 | assert_eq!( 1303 | res, 1304 | Response { 1305 | log: None, 1306 | messages: Vec::new() 1307 | } 1308 | ); 1309 | } 1310 | 1311 | #[test] 1312 | fn deserialize_embedded_enum() { 1313 | #[derive(Debug, Deserialize, PartialEq, Eq)] 1314 | #[serde(rename_all = "lowercase")] 1315 | pub enum MyResult { 1316 | Ok(Response), 1317 | Err(String), 1318 | } 1319 | 1320 | #[derive(Debug, Deserialize, PartialEq, Eq)] 1321 | pub struct Response { 1322 | pub log: Option, 1323 | pub messages: Vec, 1324 | } 1325 | 1326 | #[derive(Debug, Deserialize, PartialEq, Eq)] 1327 | pub struct Msg { 1328 | pub name: String, 1329 | pub amount: Option, 1330 | } 1331 | 1332 | let res: MyResult = from_str( 1333 | r#"{ 1334 | "ok": { 1335 | "log": "hello", 1336 | "messages": [{ 1337 | "name": "fred", 1338 | "amount": "15" 1339 | }] 1340 | } 1341 | }"#, 1342 | ) 1343 | .expect("goo"); 1344 | assert_eq!( 1345 | res, 1346 | MyResult::Ok(Response { 1347 | log: Some("hello".to_string()), 1348 | messages: vec![Msg { 1349 | name: "fred".to_string(), 1350 | amount: Some("15".to_string()) 1351 | }] 1352 | }) 1353 | ); 1354 | 1355 | let res: MyResult = from_str( 1356 | r#"{ 1357 | "ok": { 1358 | "log": "hello", 1359 | "messages": [] 1360 | } 1361 | }"#, 1362 | ) 1363 | .expect("goo"); 1364 | assert_eq!( 1365 | res, 1366 | MyResult::Ok(Response { 1367 | log: Some("hello".to_string()), 1368 | messages: Vec::new() 1369 | }) 1370 | ); 1371 | 1372 | let res: MyResult = from_str( 1373 | r#"{ 1374 | "ok": { 1375 | "log": null, 1376 | "messages": [] 1377 | } 1378 | }"#, 1379 | ) 1380 | .expect("goo"); 1381 | assert_eq!( 1382 | res, 1383 | MyResult::Ok(Response { 1384 | log: None, 1385 | messages: Vec::new() 1386 | }) 1387 | ); 1388 | } 1389 | 1390 | // See https://iot.mozilla.org/wot/#thing-resource 1391 | #[test] 1392 | fn wot() { 1393 | #[derive(Debug, Deserialize, PartialEq)] 1394 | struct Thing { 1395 | properties: Properties, 1396 | #[serde(rename = "type")] 1397 | ty: Type, 1398 | } 1399 | 1400 | #[derive(Debug, Deserialize, PartialEq)] 1401 | struct Properties { 1402 | temperature: Property, 1403 | humidity: Property, 1404 | led: Property, 1405 | } 1406 | 1407 | #[derive(Debug, Deserialize, PartialEq)] 1408 | struct Property { 1409 | #[serde(rename = "type")] 1410 | ty: Type, 1411 | unit: Option, 1412 | description: Option, 1413 | href: String, 1414 | } 1415 | 1416 | assert_eq!( 1417 | from_str::( 1418 | r#" 1419 | { 1420 | "type": "thing", 1421 | "properties": { 1422 | "temperature": { 1423 | "type": "number", 1424 | "unit": "celsius", 1425 | "description": "An ambient temperature sensor", 1426 | "href": "/properties/temperature" 1427 | }, 1428 | "humidity": { 1429 | "type": "number", 1430 | "unit": "percent", 1431 | "href": "/properties/humidity" 1432 | }, 1433 | "led": { 1434 | "type": "boolean", 1435 | "unit": null, 1436 | "description": "A red LED", 1437 | "href": "/properties/led" 1438 | } 1439 | } 1440 | } 1441 | "# 1442 | ), 1443 | Ok(Thing { 1444 | properties: Properties { 1445 | temperature: Property { 1446 | ty: Type::Number, 1447 | unit: Some("celsius".to_string()), 1448 | description: Some("An ambient temperature sensor".to_string()), 1449 | href: "/properties/temperature".to_string(), 1450 | }, 1451 | humidity: Property { 1452 | ty: Type::Number, 1453 | unit: Some("percent".to_string()), 1454 | description: None, 1455 | href: "/properties/humidity".to_string(), 1456 | }, 1457 | led: Property { 1458 | ty: Type::Boolean, 1459 | unit: None, 1460 | description: Some("A red LED".to_string()), 1461 | href: "/properties/led".to_string(), 1462 | }, 1463 | }, 1464 | ty: Type::Thing, 1465 | }) 1466 | ) 1467 | } 1468 | } 1469 | -------------------------------------------------------------------------------- /src/de/seq.rs: -------------------------------------------------------------------------------- 1 | use serde::de; 2 | 3 | use crate::de::{Deserializer, Error, Result}; 4 | 5 | pub(crate) struct SeqAccess<'a, 'b> { 6 | first: bool, 7 | de: &'a mut Deserializer<'b>, 8 | } 9 | 10 | impl<'a, 'b> SeqAccess<'a, 'b> { 11 | pub fn new(de: &'a mut Deserializer<'b>) -> Self { 12 | SeqAccess { de, first: true } 13 | } 14 | } 15 | 16 | impl<'a, 'de> de::SeqAccess<'de> for SeqAccess<'a, 'de> { 17 | type Error = Error; 18 | 19 | fn next_element_seed(&mut self, seed: T) -> Result> 20 | where 21 | T: de::DeserializeSeed<'de>, 22 | { 23 | let peek = match self 24 | .de 25 | .parse_whitespace() 26 | .ok_or(Error::EofWhileParsingList)? 27 | { 28 | b']' => return Ok(None), 29 | b',' => { 30 | self.de.eat_char(); 31 | self.de 32 | .parse_whitespace() 33 | .ok_or(Error::EofWhileParsingValue)? 34 | } 35 | c => { 36 | if self.first { 37 | self.first = false; 38 | c 39 | } else { 40 | return Err(Error::ExpectedListCommaOrEnd); 41 | } 42 | } 43 | }; 44 | 45 | if peek == b']' { 46 | Err(Error::TrailingComma) 47 | } else { 48 | Ok(Some(seed.deserialize(&mut *self.de)?)) 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/de/unescape.rs: -------------------------------------------------------------------------------- 1 | use alloc::string::String; 2 | use alloc::vec::Vec; 3 | use core::convert::TryFrom; 4 | 5 | use super::errors::{Error, Result}; 6 | 7 | // https://de.wikipedia.org/wiki/American_Standard_Code_for_Information_Interchange#ASCII-Tabelle 8 | static BACKSPACE: u8 = 0x08; // BS 9 | static FORMFEED: u8 = 0x0C; // FF 10 | static LINEFEED: u8 = 0x0A; // LF 11 | static CARRIAGE_RETURN: u8 = 0x0D; // CR 12 | static HORIZONTAL_TAB: u8 = 0x09; // HT 13 | 14 | static SURROGARES_FIRST: u16 = 0xD800; 15 | static SURROGARES_HIGH_LAST: u16 = 0xDBFF; 16 | static SURROGARES_LOW_FIRST: u16 = 0xDC00; 17 | static SURROGARES_LAST: u16 = 0xDFFF; 18 | 19 | pub(crate) fn unescape(source: &[u8]) -> Result { 20 | let mut out: Vec = Vec::with_capacity(source.len()); 21 | 22 | let mut encoding_tmp = [0u8; 4]; 23 | let mut in_escape = false; 24 | let mut in_unicode = false; 25 | // Temporary storage of the four hex characters of \uACDC 26 | let mut unicode_tmp = [0u8; 4]; 27 | // Position in `unicode_tmp` where the next insertion happens 28 | let mut unicode_tmp_pos: usize = 0; 29 | let mut high_surrogate: Option = None; 30 | 31 | for byte in source { 32 | if *byte <= 0x1F { 33 | return Err(Error::ControlCharacterInString); 34 | } 35 | 36 | if in_unicode { 37 | match byte { 38 | b'0'..=b'9' | b'a'..=b'f' | b'A'..=b'F' => { 39 | unicode_tmp[unicode_tmp_pos] = *byte; 40 | unicode_tmp_pos += 1; 41 | if unicode_tmp_pos == 4 { 42 | let codepoint = hex_decode(unicode_tmp); 43 | 44 | if codepoint >= SURROGARES_FIRST && codepoint <= SURROGARES_LAST { 45 | if let Some(high) = high_surrogate { 46 | if codepoint < SURROGARES_LOW_FIRST { 47 | return Err(Error::ExpectedLowSurrogate); 48 | } 49 | let low = codepoint; 50 | 51 | // https://en.wikipedia.org/wiki/Universal_Character_Set_characters#Surrogates 52 | let combined = 0x1_0000 53 | + (((high - 0xD800) as u32) << 10 | (low - 0xDC00) as u32); 54 | let encoded = match char::try_from(combined) { 55 | Ok(c) => c.encode_utf8(&mut encoding_tmp as &mut [u8]), 56 | Err(_) => return Err(Error::InvalidUnicodeCodePoint), 57 | }; 58 | out.extend_from_slice(encoded.as_bytes()); 59 | 60 | high_surrogate = None; 61 | } else { 62 | if codepoint > SURROGARES_HIGH_LAST { 63 | return Err(Error::ExpectedHighSurrogate); 64 | } 65 | high_surrogate = Some(codepoint); 66 | } 67 | } else { 68 | let encoded = match char::try_from(codepoint as u32) { 69 | Ok(c) => c.encode_utf8(&mut encoding_tmp as &mut [u8]), 70 | Err(_) => return Err(Error::InvalidEscape), 71 | }; 72 | out.extend_from_slice(encoded.as_bytes()); 73 | } 74 | 75 | unicode_tmp_pos = 0; 76 | in_unicode = false; 77 | in_escape = false; 78 | } 79 | } 80 | _ => return Err(Error::InvalidEscape), 81 | } 82 | } else if in_escape { 83 | match byte { 84 | b'"' | b'/' | b'\\' => { 85 | out.push(*byte); 86 | in_escape = false; 87 | } 88 | b'b' => { 89 | out.push(BACKSPACE); 90 | in_escape = false; 91 | } 92 | b'f' => { 93 | out.push(FORMFEED); 94 | in_escape = false; 95 | } 96 | b'n' => { 97 | out.push(LINEFEED); 98 | in_escape = false; 99 | } 100 | b'r' => { 101 | out.push(CARRIAGE_RETURN); 102 | in_escape = false; 103 | } 104 | b't' => { 105 | out.push(HORIZONTAL_TAB); 106 | in_escape = false; 107 | } 108 | b'u' => { 109 | in_unicode = true; 110 | } 111 | _ => return Err(Error::InvalidEscape), 112 | } 113 | } else { 114 | // Default case, not in escape sequence 115 | 116 | if *byte == b'\\' { 117 | in_escape = true; 118 | } else { 119 | if high_surrogate.is_some() { 120 | return Err(Error::LoneSurrogateFound); 121 | } 122 | 123 | out.push(*byte); 124 | } 125 | } 126 | } 127 | 128 | if in_escape { 129 | return Err(Error::InvalidEscape); 130 | } 131 | 132 | if high_surrogate.is_some() { 133 | return Err(Error::LoneSurrogateFound); 134 | } 135 | 136 | String::from_utf8(out).map_err(|_| Error::InvalidUnicodeCodePoint) 137 | } 138 | 139 | /// Returns a 16 bit value between 0x0000 and 0xFFFF, i.e. a codepoint 140 | /// in the Basic Multilingual Plane. 141 | fn hex_decode(a: [u8; 4]) -> u16 { 142 | (hex_decode_4bit(a[0]) as u16) << 12 143 | | (hex_decode_4bit(a[1]) as u16) << 8 144 | | (hex_decode_4bit(a[2]) as u16) << 4 145 | | (hex_decode_4bit(a[3]) as u16) 146 | } 147 | 148 | /// Decodes a single hex character into its numeric value, i.e. maps 149 | /// ASCII '0'-'9' to 0-9, 'A'-'F' to 10-15 and 'a'-'f' to 10-15. 150 | fn hex_decode_4bit(x: u8) -> u8 { 151 | match x { 152 | b'0'..=b'9' => x - 0x30, 153 | b'A'..=b'F' => x - 0x41 + 10, 154 | b'a'..=b'f' => x - 0x61 + 10, 155 | _ => panic!("Non-hex ASCII character found"), 156 | } 157 | } 158 | 159 | #[cfg(test)] 160 | mod tests { 161 | use super::*; 162 | 163 | /// A testing wrapper around unescape 164 | fn ue(source: &[u8]) -> String { 165 | unescape(source).unwrap() 166 | } 167 | 168 | /// A testing wrapper around unescape, expecting error 169 | fn uee(source: &[u8]) -> Error { 170 | unescape(source).unwrap_err() 171 | } 172 | 173 | #[test] 174 | fn unescape_works() { 175 | // Unchanged because no unescaping happens 176 | assert_eq!(ue(b""), ""); 177 | assert_eq!(ue(b"a"), "a"); 178 | assert_eq!(ue(b"ab"), "ab"); 179 | assert_eq!(ue(b"abc"), "abc"); 180 | assert_eq!(ue(b"a/c"), "a/c"); 181 | assert_eq!(ue(b"\x20"), " "); // first non-control character 182 | assert_eq!(ue(b"\xF0\x9F\x91\x8F"), "👏"); // U+1F44F 183 | 184 | // even number of backslashes 185 | assert_eq!(ue(br#"\\"#), "\\"); 186 | assert_eq!(ue(br#"\\\\"#), "\\\\"); 187 | assert_eq!(ue(br#"\\\\\\"#), "\\\\\\"); 188 | assert_eq!(ue(br#"\\\\\\\\"#), "\\\\\\\\"); 189 | 190 | // The 8 short escape sequences \", \\, \/, \b, \f, \n, \r, \t (alone, start, end, middle) 191 | assert_eq!(ue(br#"\""#), "\""); 192 | assert_eq!(ue(br#"\\"#), "\\"); 193 | assert_eq!(ue(br#"\/"#), "/"); 194 | assert_eq!(ue(br#"\b"#), "\x08"); 195 | assert_eq!(ue(br#"\f"#), "\x0C"); 196 | assert_eq!(ue(br#"\n"#), "\n"); 197 | assert_eq!(ue(br#"\r"#), "\r"); 198 | assert_eq!(ue(br#"\t"#), "\t"); 199 | assert_eq!(ue(br#"\"abc"#), "\"abc"); 200 | assert_eq!(ue(br#"\\abc"#), "\\abc"); 201 | assert_eq!(ue(br#"\/abc"#), "/abc"); 202 | assert_eq!(ue(br#"\babc"#), "\x08abc"); 203 | assert_eq!(ue(br#"\fabc"#), "\x0Cabc"); 204 | assert_eq!(ue(br#"\nabc"#), "\nabc"); 205 | assert_eq!(ue(br#"\rabc"#), "\rabc"); 206 | assert_eq!(ue(br#"\tabc"#), "\tabc"); 207 | assert_eq!(ue(br#"abc\""#), "abc\""); 208 | assert_eq!(ue(br#"abc\\"#), "abc\\"); 209 | assert_eq!(ue(br#"abc\/"#), "abc/"); 210 | assert_eq!(ue(br#"abc\b"#), "abc\x08"); 211 | assert_eq!(ue(br#"abc\f"#), "abc\x0C"); 212 | assert_eq!(ue(br#"abc\n"#), "abc\n"); 213 | assert_eq!(ue(br#"abc\r"#), "abc\r"); 214 | assert_eq!(ue(br#"abc\t"#), "abc\t"); 215 | assert_eq!(ue(br#"xy\"abc"#), "xy\"abc"); 216 | assert_eq!(ue(br#"xy\\abc"#), "xy\\abc"); 217 | assert_eq!(ue(br#"xy\/abc"#), "xy/abc"); 218 | assert_eq!(ue(br#"xy\babc"#), "xy\x08abc"); 219 | assert_eq!(ue(br#"xy\fabc"#), "xy\x0Cabc"); 220 | assert_eq!(ue(br#"xy\nabc"#), "xy\nabc"); 221 | assert_eq!(ue(br#"xy\rabc"#), "xy\rabc"); 222 | assert_eq!(ue(br#"xy\tabc"#), "xy\tabc"); 223 | 224 | // Short escape sequences mixed 225 | assert_eq!(ue(br#" \" \" \" "#), " \" \" \" "); 226 | assert_eq!(ue(br#" \t \n \r "#), " \t \n \r "); 227 | assert_eq!(ue(br#" \"\"\" "#), " \"\"\" "); 228 | assert_eq!(ue(br#" \t\n\r "#), " \t\n\r "); 229 | 230 | // Unicode 231 | assert_eq!(ue(br#" \u0001 "#), " \u{0001} "); 232 | assert_eq!(ue(br#" \u0010 "#), " \u{0010} "); 233 | assert_eq!(ue(br#" \u0100 "#), " \u{0100} "); 234 | assert_eq!(ue(br#" \u1000 "#), " \u{1000} "); 235 | assert_eq!(ue(br#" \uABCD "#), " \u{abcd} "); 236 | assert_eq!(ue(br#" \uabcd "#), " \u{abcd} "); 237 | assert_eq!(ue(br#" \uAbCd "#), " \u{abcd} "); 238 | assert_eq!(ue(br#" \uABCDefg "#), " \u{abcd}efg "); 239 | assert_eq!(ue(br#" \uabcdefg "#), " \u{abcd}efg "); 240 | assert_eq!(ue(br#" \uAbCdefg "#), " \u{abcd}efg "); 241 | } 242 | 243 | #[test] 244 | fn unescape_fails_for_control_characters() { 245 | assert_eq!(unescape(b" \x00 "), Err(Error::ControlCharacterInString)); 246 | assert_eq!(unescape(b" \x01 "), Err(Error::ControlCharacterInString)); 247 | assert_eq!(unescape(b" \x02 "), Err(Error::ControlCharacterInString)); 248 | assert_eq!(unescape(b" \x03 "), Err(Error::ControlCharacterInString)); 249 | assert_eq!(unescape(b" \x04 "), Err(Error::ControlCharacterInString)); 250 | assert_eq!(unescape(b" \x05 "), Err(Error::ControlCharacterInString)); 251 | assert_eq!(unescape(b" \x06 "), Err(Error::ControlCharacterInString)); 252 | assert_eq!(unescape(b" \x07 "), Err(Error::ControlCharacterInString)); 253 | assert_eq!(unescape(b" \x08 "), Err(Error::ControlCharacterInString)); 254 | assert_eq!(unescape(b" \x09 "), Err(Error::ControlCharacterInString)); 255 | assert_eq!(unescape(b" \x0a "), Err(Error::ControlCharacterInString)); 256 | assert_eq!(unescape(b" \x0b "), Err(Error::ControlCharacterInString)); 257 | assert_eq!(unescape(b" \x0c "), Err(Error::ControlCharacterInString)); 258 | assert_eq!(unescape(b" \x0d "), Err(Error::ControlCharacterInString)); 259 | assert_eq!(unescape(b" \x0e "), Err(Error::ControlCharacterInString)); 260 | assert_eq!(unescape(b" \x0f "), Err(Error::ControlCharacterInString)); 261 | assert_eq!(unescape(b" \x10 "), Err(Error::ControlCharacterInString)); 262 | assert_eq!(unescape(b" \x11 "), Err(Error::ControlCharacterInString)); 263 | assert_eq!(unescape(b" \x12 "), Err(Error::ControlCharacterInString)); 264 | assert_eq!(unescape(b" \x13 "), Err(Error::ControlCharacterInString)); 265 | assert_eq!(unescape(b" \x14 "), Err(Error::ControlCharacterInString)); 266 | assert_eq!(unescape(b" \x15 "), Err(Error::ControlCharacterInString)); 267 | assert_eq!(unescape(b" \x16 "), Err(Error::ControlCharacterInString)); 268 | assert_eq!(unescape(b" \x17 "), Err(Error::ControlCharacterInString)); 269 | assert_eq!(unescape(b" \x18 "), Err(Error::ControlCharacterInString)); 270 | assert_eq!(unescape(b" \x19 "), Err(Error::ControlCharacterInString)); 271 | assert_eq!(unescape(b" \x1a "), Err(Error::ControlCharacterInString)); 272 | assert_eq!(unescape(b" \x1b "), Err(Error::ControlCharacterInString)); 273 | assert_eq!(unescape(b" \x1c "), Err(Error::ControlCharacterInString)); 274 | assert_eq!(unescape(b" \x1d "), Err(Error::ControlCharacterInString)); 275 | assert_eq!(unescape(b" \x1e "), Err(Error::ControlCharacterInString)); 276 | assert_eq!(unescape(b" \x1f "), Err(Error::ControlCharacterInString)); 277 | } 278 | 279 | #[test] 280 | fn unescape_fails_for_invalid_escape_sequence() { 281 | assert_eq!(unescape(br#" \ "#), Err(Error::InvalidEscape)); 282 | assert_eq!(unescape(br#" \a "#), Err(Error::InvalidEscape)); 283 | assert_eq!(unescape(br#" \N "#), Err(Error::InvalidEscape)); 284 | assert_eq!(unescape(br#" \- "#), Err(Error::InvalidEscape)); 285 | assert_eq!(unescape(br#" \' "#), Err(Error::InvalidEscape)); 286 | assert_eq!(unescape(br#" \x "#), Err(Error::InvalidEscape)); 287 | assert_eq!(unescape(br#" \x08 "#), Err(Error::InvalidEscape)); // valid in Rust and ES6 but not JSON 288 | 289 | // unicode 290 | assert_eq!(unescape(br#" \u{7A} "#), Err(Error::InvalidEscape)); // valid in ES6 but not JSON 291 | assert_eq!(unescape(br#" \uAAA "#), Err(Error::InvalidEscape)); // too short 292 | assert_eq!(unescape(br#" \uAA "#), Err(Error::InvalidEscape)); // too short 293 | assert_eq!(unescape(br#" \uA "#), Err(Error::InvalidEscape)); // too short 294 | assert_eq!(unescape(br#" \u "#), Err(Error::InvalidEscape)); // too short 295 | assert_eq!(unescape(br#" \u123. "#), Err(Error::InvalidEscape)); // non-hex char 296 | assert_eq!(unescape(br#" \u123g "#), Err(Error::InvalidEscape)); // non-hex char 297 | assert_eq!(unescape(br#" \u123\9 "#), Err(Error::InvalidEscape)); // non-hex char 298 | 299 | // unfinished escape sequences 300 | assert_eq!(unescape(br#" \u123"#), Err(Error::InvalidEscape)); 301 | assert_eq!(unescape(br#" \u12"#), Err(Error::InvalidEscape)); 302 | assert_eq!(unescape(br#" \u1"#), Err(Error::InvalidEscape)); 303 | assert_eq!(unescape(br#" \u"#), Err(Error::InvalidEscape)); 304 | assert_eq!(unescape(br#" \"#), Err(Error::InvalidEscape)); 305 | } 306 | 307 | #[test] 308 | fn unescape_works_for_surrogate_pairs() { 309 | assert_eq!(ue(br#" \uD83D\uDC4F "#), " \u{1F44F} "); 310 | assert_eq!(ue(br#" \uD83D\uDC4F\uD83D\uDC4F "#), " 👏👏 "); 311 | 312 | assert_eq!(ue(br#" \uD83E\uDD7A "#), " \u{1F97A} "); 313 | assert_eq!(ue(br#" \uD83E\uDD7A\uD83D\uDC4F "#), " 🥺👏 "); 314 | } 315 | 316 | #[test] 317 | fn unescape_fails_for_broken_surrogates() { 318 | assert_eq!(uee(br#" \uDEAD "#), Error::ExpectedHighSurrogate); 319 | assert_eq!(uee(br#" \uDC4F\uD83D "#), Error::ExpectedHighSurrogate); // Clapping hands reversed 320 | 321 | assert_eq!(uee(br#" \uD800\uD800 "#), Error::ExpectedLowSurrogate); 322 | } 323 | 324 | #[test] 325 | fn unescape_fails_for_lone_surrogates() { 326 | assert_eq!(uee(br#" \uD83Dabc "#), Error::LoneSurrogateFound); 327 | assert_eq!(uee(br#" \uD83D"#), Error::LoneSurrogateFound); 328 | 329 | // high surrogate followed by non-surrogate 330 | assert_eq!(uee(br#" \uD800\u0001 "#), Error::LoneSurrogateFound); 331 | assert_eq!(uee(br#" \uD800\uD799 "#), Error::LoneSurrogateFound); 332 | assert_eq!(uee(br#" \uD800\uE000 "#), Error::LoneSurrogateFound); 333 | } 334 | 335 | #[test] 336 | fn hex_decode_works() { 337 | assert_eq!(hex_decode([b'0', b'0', b'0', b'0']), 0x0000); 338 | assert_eq!(hex_decode([b'0', b'0', b'0', b'1']), 0x0001); 339 | assert_eq!(hex_decode([b'0', b'0', b'1', b'0']), 0x0010); 340 | assert_eq!(hex_decode([b'0', b'1', b'0', b'0']), 0x0100); 341 | assert_eq!(hex_decode([b'1', b'0', b'0', b'0']), 0x1000); 342 | assert_eq!(hex_decode([b'1', b'1', b'1', b'1']), 0x1111); 343 | assert_eq!(hex_decode([b'1', b'1', b'1', b'0']), 0x1110); 344 | assert_eq!(hex_decode([b'1', b'1', b'0', b'1']), 0x1101); 345 | assert_eq!(hex_decode([b'1', b'0', b'1', b'1']), 0x1011); 346 | assert_eq!(hex_decode([b'0', b'1', b'1', b'1']), 0x0111); 347 | 348 | assert_eq!(hex_decode([b'2', b'3', b'4', b'5']), 0x2345); 349 | assert_eq!(hex_decode([b'6', b'7', b'8', b'9']), 0x6789); 350 | assert_eq!(hex_decode([b'a', b'b', b'c', b'd']), 0xabcd); 351 | assert_eq!(hex_decode([b'e', b'f', b'A', b'B']), 0xefab); 352 | assert_eq!(hex_decode([b'C', b'D', b'E', b'F']), 0xcdef); 353 | } 354 | } 355 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | //! [`serde-json`] for `wasm` programs 2 | //! 3 | //! [`serde-json`]: https://crates.io/crates/serde_json 4 | //! 5 | //! This version of [`serde-json`] is aimed at applications that run on resource constrained 6 | //! devices. 7 | //! 8 | //! # Current features 9 | //! 10 | //! - The error type is a simple C like enum (less overhead, smaller memory footprint) 11 | //! - (De)serialization doesn't require memory allocations 12 | //! - Deserialization of integers doesn't go through `u64`; instead the string is directly parsed 13 | //! into the requested integer type. This avoids pulling in KBs of compiler intrinsics when 14 | //! targeting a non 64-bit architecture. 15 | //! - Supports deserialization of: 16 | //! - `bool` 17 | //! - Integers 18 | //! - `str` (This is a zero copy operation.) (\*) 19 | //! - `Option` 20 | //! - Arrays 21 | //! - Tuples 22 | //! - Structs 23 | //! - C like enums 24 | //! - Supports serialization (compact format only) of: 25 | //! - `bool` 26 | //! - Integers 27 | //! - `str` 28 | //! - `Option` 29 | //! - Arrays 30 | //! - Tuples 31 | //! - Structs 32 | //! - C like enums 33 | //! 34 | //! (\*) Deserialization of strings ignores escaped sequences. Escaped sequences might be supported 35 | //! in the future using a different Serializer as this operation is not zero copy. 36 | //! 37 | //! # Planned features 38 | //! 39 | //! - (De)serialization from / into IO objects once `core::io::{Read,Write}` becomes a thing. 40 | //! 41 | //! # Non-features 42 | //! 43 | //! This is explicitly out of scope 44 | //! 45 | //! - Anything that involves dynamic memory allocation 46 | //! - Like the dynamic [`Value`](https://docs.rs/serde_json/1.0.11/serde_json/enum.Value.html) 47 | //! type 48 | //! 49 | //! # MSRV 50 | //! 51 | //! This crate is guaranteed to compile on stable Rust 1.31.0 and up. It *might* compile with older 52 | //! versions but that may change in any new patch release. 53 | 54 | #![deny(missing_docs)] 55 | #![deny(rust_2018_compatibility)] 56 | #![deny(rust_2018_idioms)] 57 | // Note: Even though we declare the crate as `no_std`, by default `std` feature 58 | // is enabled which enables serde’s `std` feature which makes our dependency 59 | // non-`no_std`. This `no_std` declaration only makes sure that our code 60 | // doesn’t depend on `std` directly (except for tests). 61 | #![no_std] 62 | 63 | extern crate alloc; 64 | #[cfg(test)] 65 | extern crate std; 66 | 67 | pub mod de; 68 | pub mod ser; 69 | 70 | #[doc(inline)] 71 | pub use self::de::{from_slice, from_str}; 72 | #[doc(inline)] 73 | pub use self::ser::{to_string, to_vec}; 74 | 75 | #[cfg(test)] 76 | mod test { 77 | use alloc::borrow::ToOwned; 78 | use alloc::collections::BTreeMap; 79 | use alloc::string::{String, ToString}; 80 | use alloc::vec; 81 | use alloc::vec::Vec; 82 | 83 | use super::*; 84 | use serde_derive::{Deserialize, Serialize}; 85 | 86 | #[derive(Debug, Deserialize, Serialize, PartialEq)] 87 | struct Address(String); 88 | 89 | #[derive(Debug, Deserialize, Serialize, PartialEq)] 90 | struct CommentId(u32); 91 | 92 | #[derive(Debug, Deserialize, Serialize, PartialEq)] 93 | enum Model { 94 | Comment, 95 | Post { category: String, author: Address }, 96 | } 97 | 98 | #[derive(Debug, Deserialize, Serialize, PartialEq)] 99 | struct Stats { 100 | views: u64, 101 | score: i64, 102 | } 103 | 104 | #[derive(Debug, Deserialize, Serialize, PartialEq)] 105 | struct Item { 106 | model: Model, 107 | title: String, 108 | content: Option, 109 | list: Vec, 110 | published: bool, 111 | comments: Vec, 112 | stats: Stats, 113 | balances: BTreeMap, 114 | } 115 | 116 | #[test] 117 | fn can_serde() { 118 | let min = Item { 119 | model: Model::Comment, 120 | title: String::new(), 121 | content: None, 122 | list: vec![], 123 | published: false, 124 | comments: vec![], 125 | stats: Stats { views: 0, score: 0 }, 126 | balances: BTreeMap::new(), 127 | }; 128 | let mut balances: BTreeMap = BTreeMap::new(); 129 | balances.insert("chareen".into(), 347); 130 | let max = Item { 131 | model: Model::Post { 132 | category: "fun".to_string(), 133 | author: Address("sunnyboy85".to_string()), 134 | }, 135 | title: "Nice message".to_string(), 136 | content: Some("Happy \"blogging\" 👏\n\n\tCheers, I'm out\0\0\0".to_string()), 137 | list: vec![0, 1, 2, 3, 42, 154841, u32::MAX], 138 | published: true, 139 | comments: vec![CommentId(2), CommentId(700)], 140 | stats: Stats { 141 | views: u64::MAX, 142 | score: i64::MIN, 143 | }, 144 | balances, 145 | }; 146 | 147 | // binary 148 | assert_eq!(from_slice::(&to_vec(&min).unwrap()).unwrap(), min); 149 | assert_eq!(from_slice::(&to_vec(&max).unwrap()).unwrap(), max); 150 | 151 | // string 152 | assert_eq!(from_str::(&to_string(&min).unwrap()).unwrap(), min); 153 | assert_eq!(from_str::(&to_string(&max).unwrap()).unwrap(), max); 154 | } 155 | 156 | #[test] 157 | fn untagged() { 158 | #[derive(Debug, Deserialize, Serialize, PartialEq)] 159 | #[serde(untagged)] 160 | enum UntaggedEnum { 161 | S(String), 162 | I(i64), 163 | } 164 | 165 | let s = UntaggedEnum::S("Some string".to_owned()); 166 | let i = UntaggedEnum::I(32); 167 | 168 | assert_eq!(from_slice::(&to_vec(&s).unwrap()).unwrap(), s); 169 | assert_eq!(from_slice::(&to_vec(&i).unwrap()).unwrap(), i); 170 | 171 | assert_eq!( 172 | from_str::(&to_string(&s).unwrap()).unwrap(), 173 | s 174 | ); 175 | assert_eq!( 176 | from_str::(&to_string(&i).unwrap()).unwrap(), 177 | i 178 | ); 179 | } 180 | 181 | #[test] 182 | fn untagged_structures() { 183 | #[derive(Debug, Deserialize, Serialize, PartialEq)] 184 | #[serde(untagged)] 185 | enum ModelOrItem { 186 | Model(Model), 187 | Item(Item), 188 | } 189 | 190 | let model = ModelOrItem::Model(Model::Post { 191 | category: "Rust".to_owned(), 192 | author: Address("no-reply@domain.com".to_owned()), 193 | }); 194 | 195 | let mut balances: BTreeMap = BTreeMap::new(); 196 | balances.insert("chareen".into(), 347); 197 | 198 | let item = ModelOrItem::Item(Item { 199 | model: Model::Comment, 200 | title: "Title".to_owned(), 201 | content: None, 202 | list: vec![13, 14], 203 | published: true, 204 | comments: vec![], 205 | stats: Stats { 206 | views: 110, 207 | score: 12, 208 | }, 209 | balances, 210 | }); 211 | 212 | assert_eq!( 213 | from_slice::(&to_vec(&model).unwrap()).unwrap(), 214 | model 215 | ); 216 | assert_eq!( 217 | from_slice::(&to_vec(&item).unwrap()).unwrap(), 218 | item 219 | ); 220 | 221 | assert_eq!( 222 | from_str::(&to_string(&model).unwrap()).unwrap(), 223 | model 224 | ); 225 | assert_eq!( 226 | from_str::(&to_string(&item).unwrap()).unwrap(), 227 | item 228 | ); 229 | } 230 | 231 | #[test] 232 | fn no_stack_overflow() { 233 | const AMOUNT: usize = 2000; 234 | let mut json = String::from(r#"{"":"#); 235 | 236 | #[derive(Debug, Deserialize, Serialize)] 237 | pub struct Person { 238 | name: String, 239 | age: u8, 240 | phones: Vec, 241 | } 242 | 243 | for _ in 0..AMOUNT { 244 | json.push('['); 245 | } 246 | for _ in 0..AMOUNT { 247 | json.push(']'); 248 | } 249 | 250 | json.push_str(r#"] }[[[[[[[[[[[[[[[[[[[[[ ""","age":35,"phones":["#); 251 | 252 | let err = from_str::(&json).unwrap_err(); 253 | assert_eq!(err, crate::de::Error::RecursionLimitExceeded); 254 | } 255 | } 256 | -------------------------------------------------------------------------------- /src/ser/map.rs: -------------------------------------------------------------------------------- 1 | use serde::{ser, Serialize}; 2 | 3 | use crate::ser::{Error, Result, Serializer}; 4 | 5 | use super::{seq::SerializeSeq, struct_::SerializeStruct, Unreachable}; 6 | 7 | pub struct SerializeMap<'a> { 8 | ser: &'a mut Serializer, 9 | first: bool, 10 | } 11 | 12 | impl<'a> SerializeMap<'a> { 13 | pub(crate) fn new(ser: &'a mut Serializer) -> Self { 14 | SerializeMap { ser, first: true } 15 | } 16 | } 17 | 18 | impl<'a> ser::SerializeMap for SerializeMap<'a> { 19 | type Ok = (); 20 | type Error = Error; 21 | 22 | fn end(self) -> Result { 23 | self.ser.buf.push(b'}'); 24 | Ok(()) 25 | } 26 | 27 | fn serialize_key(&mut self, key: &T) -> Result<()> 28 | where 29 | T: ser::Serialize, 30 | { 31 | if !self.first { 32 | self.ser.buf.push(b','); 33 | } 34 | self.first = false; 35 | // Use key serializer to unsure key type validity. 36 | key.serialize(MapKeySerializer { ser: self.ser })?; 37 | self.ser.buf.extend_from_slice(b":"); 38 | Ok(()) 39 | } 40 | 41 | fn serialize_value(&mut self, value: &T) -> Result<()> 42 | where 43 | T: ser::Serialize, 44 | { 45 | value.serialize(&mut *self.ser)?; 46 | Ok(()) 47 | } 48 | } 49 | 50 | /// Wrapper around Serializer that only allows serialization of valid JSON key types (strings). 51 | struct MapKeySerializer<'a> { 52 | ser: &'a mut Serializer, 53 | } 54 | 55 | pub(crate) fn key_must_be_a_string() -> Error { 56 | Error::Custom("JSON object key is required to be a string type.".into()) 57 | } 58 | 59 | macro_rules! serialize_unsigned_key { 60 | ($self:ident, $N:expr, $v:expr) => {{ 61 | let ser = $self.ser; 62 | ser.buf.push(b'"'); 63 | let res: Result = super::serialize_unsigned!(ser, $N, $v); 64 | res?; 65 | ser.buf.push(b'"'); 66 | Ok(()) 67 | }}; 68 | } 69 | 70 | macro_rules! serialize_signed_key { 71 | ($self:ident, $N:expr, $v:expr, $ixx:ident, $uxx:ident) => {{ 72 | let ser = $self.ser; 73 | ser.buf.push(b'"'); 74 | let res: Result = super::serialize_signed!(ser, $N, $v, $ixx, $uxx); 75 | res?; 76 | ser.buf.push(b'"'); 77 | Ok(()) 78 | }}; 79 | } 80 | 81 | impl<'a> ser::Serializer for MapKeySerializer<'a> { 82 | type Ok = (); 83 | type Error = Error; 84 | type SerializeSeq = SerializeSeq<'a>; 85 | type SerializeTuple = SerializeSeq<'a>; 86 | type SerializeTupleStruct = Unreachable; 87 | type SerializeTupleVariant = SerializeSeq<'a>; 88 | type SerializeMap = SerializeMap<'a>; 89 | type SerializeStruct = SerializeStruct<'a>; 90 | type SerializeStructVariant = SerializeStruct<'a>; 91 | 92 | fn serialize_bool(self, _value: bool) -> Result<()> { 93 | Err(key_must_be_a_string()) 94 | } 95 | #[inline] 96 | fn serialize_str(self, value: &str) -> Result<()> { 97 | self.ser.serialize_str(value) 98 | } 99 | 100 | #[inline] 101 | fn serialize_unit_variant( 102 | self, 103 | _name: &'static str, 104 | _variant_index: u32, 105 | variant: &'static str, 106 | ) -> Result<()> { 107 | self.ser.serialize_str(variant) 108 | } 109 | 110 | #[inline] 111 | fn serialize_newtype_struct(self, _name: &'static str, value: &T) -> Result<()> 112 | where 113 | T: ?Sized + Serialize, 114 | { 115 | value.serialize(self) 116 | } 117 | 118 | fn serialize_i8(self, value: i8) -> Result<()> { 119 | serialize_signed_key!(self, 4, value, i8, u8) 120 | } 121 | 122 | fn serialize_i16(self, value: i16) -> Result<()> { 123 | serialize_signed_key!(self, 6, value, i16, u16) 124 | } 125 | 126 | fn serialize_i32(self, value: i32) -> Result<()> { 127 | serialize_signed_key!(self, 11, value, i32, u32) 128 | } 129 | 130 | fn serialize_i64(self, value: i64) -> Result<()> { 131 | serialize_signed_key!(self, 20, value, i64, u64) 132 | } 133 | 134 | fn serialize_i128(self, value: i128) -> Result<()> { 135 | serialize_signed_key!(self, 40, value, i128, u128) 136 | } 137 | 138 | fn serialize_u8(self, value: u8) -> Result<()> { 139 | serialize_unsigned_key!(self, 3, value) 140 | } 141 | 142 | fn serialize_u16(self, value: u16) -> Result<()> { 143 | serialize_unsigned_key!(self, 5, value) 144 | } 145 | 146 | fn serialize_u32(self, value: u32) -> Result<()> { 147 | serialize_unsigned_key!(self, 10, value) 148 | } 149 | 150 | fn serialize_u64(self, value: u64) -> Result<()> { 151 | serialize_unsigned_key!(self, 20, value) 152 | } 153 | 154 | fn serialize_u128(self, value: u128) -> Result<()> { 155 | serialize_unsigned_key!(self, 39, value) 156 | } 157 | 158 | fn serialize_f32(self, _value: f32) -> Result<()> { 159 | Err(key_must_be_a_string()) 160 | } 161 | 162 | fn serialize_f64(self, _value: f64) -> Result<()> { 163 | Err(key_must_be_a_string()) 164 | } 165 | 166 | fn serialize_char(self, value: char) -> Result<()> { 167 | let mut buf = [0u8; 4]; 168 | self.ser.serialize_str(value.encode_utf8(&mut buf)) 169 | } 170 | 171 | fn serialize_bytes(self, _value: &[u8]) -> Result<()> { 172 | Err(key_must_be_a_string()) 173 | } 174 | 175 | fn serialize_unit(self) -> Result<()> { 176 | Err(key_must_be_a_string()) 177 | } 178 | 179 | fn serialize_unit_struct(self, _name: &'static str) -> Result<()> { 180 | Err(key_must_be_a_string()) 181 | } 182 | 183 | fn serialize_newtype_variant( 184 | self, 185 | _name: &'static str, 186 | _variant_index: u32, 187 | _variant: &'static str, 188 | _value: &T, 189 | ) -> Result<()> 190 | where 191 | T: ?Sized + Serialize, 192 | { 193 | Err(key_must_be_a_string()) 194 | } 195 | 196 | fn serialize_none(self) -> Result<()> { 197 | Err(key_must_be_a_string()) 198 | } 199 | 200 | fn serialize_some(self, _value: &T) -> Result<()> 201 | where 202 | T: ?Sized + Serialize, 203 | { 204 | Err(key_must_be_a_string()) 205 | } 206 | 207 | fn serialize_seq(self, _len: Option) -> Result { 208 | Err(key_must_be_a_string()) 209 | } 210 | 211 | fn serialize_tuple(self, _len: usize) -> Result { 212 | Err(key_must_be_a_string()) 213 | } 214 | 215 | fn serialize_tuple_struct( 216 | self, 217 | _name: &'static str, 218 | _len: usize, 219 | ) -> Result { 220 | Err(key_must_be_a_string()) 221 | } 222 | 223 | fn serialize_tuple_variant( 224 | self, 225 | _name: &'static str, 226 | _variant_index: u32, 227 | _variant: &'static str, 228 | _len: usize, 229 | ) -> Result { 230 | Err(key_must_be_a_string()) 231 | } 232 | 233 | fn serialize_map(self, _len: Option) -> Result { 234 | Err(key_must_be_a_string()) 235 | } 236 | 237 | fn serialize_struct(self, _name: &'static str, _len: usize) -> Result { 238 | Err(key_must_be_a_string()) 239 | } 240 | 241 | fn serialize_struct_variant( 242 | self, 243 | _name: &'static str, 244 | _variant_index: u32, 245 | _variant: &'static str, 246 | _len: usize, 247 | ) -> Result { 248 | Err(key_must_be_a_string()) 249 | } 250 | 251 | fn collect_str(self, _value: &T) -> Result<()> 252 | where 253 | T: ?Sized + core::fmt::Display, 254 | { 255 | unreachable!() 256 | } 257 | } 258 | -------------------------------------------------------------------------------- /src/ser/mod.rs: -------------------------------------------------------------------------------- 1 | //! Serialize a Rust data structure into JSON data 2 | 3 | use alloc::string::{String, ToString}; 4 | use alloc::vec::Vec; 5 | 6 | use serde::ser; 7 | 8 | use self::map::SerializeMap; 9 | use self::seq::SerializeSeq; 10 | use self::struct_::SerializeStruct; 11 | 12 | mod map; 13 | mod seq; 14 | mod struct_; 15 | 16 | /// Serialization result 17 | pub type Result = ::core::result::Result; 18 | 19 | /// This type represents all possible errors that can occur when serializing JSON data 20 | /// 21 | /// It implements [`std::error::Error`] trait so long as either `std` or 22 | /// `unstable` features are enabled. `std` is enabled by default and disabling 23 | /// it makes the crate `no_std`. `unstable` makes it necessary to build code 24 | /// with nightly compiler. 25 | #[derive(Debug)] 26 | #[non_exhaustive] 27 | pub enum Error { 28 | /// Buffer is full 29 | BufferFull, 30 | 31 | /// Custom error message from serde 32 | Custom(String), 33 | } 34 | 35 | impl From<()> for Error { 36 | fn from(_: ()) -> Error { 37 | Error::BufferFull 38 | } 39 | } 40 | 41 | impl From for Error { 42 | fn from(_: u8) -> Error { 43 | Error::BufferFull 44 | } 45 | } 46 | 47 | impl ser::StdError for Error {} 48 | 49 | impl core::fmt::Display for Error { 50 | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { 51 | match self { 52 | Error::BufferFull => write!(f, "Buffer is full"), 53 | Error::Custom(msg) => write!(f, "{}", &msg), 54 | } 55 | } 56 | } 57 | 58 | /// Serializer implements serde::ser::Serializer and allows us to serialize a 59 | /// serde struct into JSON 60 | pub struct Serializer { 61 | buf: Vec, 62 | } 63 | 64 | /// Number of bytes reserved by default for the output JSON 65 | static INITIAL_CAPACITY: usize = 1024; 66 | 67 | impl Serializer { 68 | fn new() -> Self { 69 | Serializer { 70 | buf: Vec::with_capacity(INITIAL_CAPACITY), 71 | } 72 | } 73 | } 74 | 75 | // NOTE(serialize_*signed) This is basically the numtoa implementation minus the lookup tables, 76 | // which take 200+ bytes of ROM / Flash 77 | macro_rules! serialize_unsigned { 78 | ($self:ident, $N:expr, $v:expr) => {{ 79 | let mut buf = [0u8; $N]; 80 | 81 | let mut v = $v; 82 | let mut i = $N - 1; 83 | loop { 84 | buf[i] = (v % 10) as u8 + b'0'; 85 | v /= 10; 86 | 87 | if v == 0 { 88 | break; 89 | } else { 90 | i -= 1; 91 | } 92 | } 93 | 94 | $self.buf.extend_from_slice(&buf[i..]); 95 | Ok(()) 96 | }}; 97 | } 98 | // Export for use in map 99 | pub(crate) use serialize_unsigned; 100 | 101 | macro_rules! serialize_signed { 102 | ($self:ident, $N:expr, $v:expr, $ixx:ident, $uxx:ident) => {{ 103 | let v = $v; 104 | let (signed, mut v) = if v == $ixx::min_value() { 105 | (true, $ixx::max_value() as $uxx + 1) 106 | } else if v < 0 { 107 | (true, -v as $uxx) 108 | } else { 109 | (false, v as $uxx) 110 | }; 111 | 112 | let mut buf = [0u8; $N]; 113 | let mut i = $N - 1; 114 | loop { 115 | buf[i] = (v % 10) as u8 + b'0'; 116 | v /= 10; 117 | 118 | i -= 1; 119 | 120 | if v == 0 { 121 | break; 122 | } 123 | } 124 | 125 | if signed { 126 | buf[i] = b'-'; 127 | } else { 128 | i += 1; 129 | } 130 | $self.buf.extend_from_slice(&buf[i..]); 131 | Ok(()) 132 | }}; 133 | } 134 | // Export for use in map 135 | pub(crate) use serialize_signed; 136 | 137 | /// Upper-case hex for value in 0..16, encoded as ASCII bytes 138 | fn hex_4bit(c: u8) -> u8 { 139 | if c <= 9 { 140 | 0x30 + c 141 | } else { 142 | 0x41 + (c - 10) 143 | } 144 | } 145 | 146 | /// Upper-case hex for value in 0..256, encoded as ASCII bytes 147 | fn hex(c: u8) -> (u8, u8) { 148 | (hex_4bit(c >> 4), hex_4bit(c & 0x0F)) 149 | } 150 | 151 | impl<'a> ser::Serializer for &'a mut Serializer { 152 | type Ok = (); 153 | type Error = Error; 154 | type SerializeSeq = SerializeSeq<'a>; 155 | type SerializeTuple = SerializeSeq<'a>; 156 | type SerializeTupleStruct = Unreachable; 157 | type SerializeTupleVariant = SerializeSeq<'a>; 158 | type SerializeMap = SerializeMap<'a>; 159 | type SerializeStruct = SerializeStruct<'a>; 160 | type SerializeStructVariant = SerializeStruct<'a>; 161 | 162 | fn serialize_bool(self, v: bool) -> Result { 163 | if v { 164 | self.buf.extend_from_slice(b"true"); 165 | } else { 166 | self.buf.extend_from_slice(b"false"); 167 | } 168 | Ok(()) 169 | } 170 | 171 | fn serialize_i8(self, v: i8) -> Result { 172 | // -128 173 | serialize_signed!(self, 4, v, i8, u8) 174 | } 175 | 176 | fn serialize_i16(self, v: i16) -> Result { 177 | // -32768 178 | serialize_signed!(self, 6, v, i16, u16) 179 | } 180 | 181 | fn serialize_i32(self, v: i32) -> Result { 182 | // -2147483648 183 | serialize_signed!(self, 11, v, i32, u32) 184 | } 185 | 186 | fn serialize_i64(self, v: i64) -> Result { 187 | // -9223372036854775808 188 | serialize_signed!(self, 20, v, i64, u64) 189 | } 190 | 191 | fn serialize_i128(self, v: i128) -> Result { 192 | // -170141183460469231731687303715884105728 193 | serialize_signed!(self, 40, v, i128, u128) 194 | } 195 | 196 | fn serialize_u8(self, v: u8) -> Result { 197 | // 255 198 | serialize_unsigned!(self, 3, v) 199 | } 200 | 201 | fn serialize_u16(self, v: u16) -> Result { 202 | // 65535 203 | serialize_unsigned!(self, 5, v) 204 | } 205 | 206 | fn serialize_u32(self, v: u32) -> Result { 207 | // 4294967295 208 | serialize_unsigned!(self, 10, v) 209 | } 210 | 211 | fn serialize_u64(self, v: u64) -> Result { 212 | // 18446744073709551615 213 | serialize_unsigned!(self, 20, v) 214 | } 215 | 216 | fn serialize_u128(self, v: u128) -> Result { 217 | // 340282366920938463463374607431768211455 218 | serialize_unsigned!(self, 39, v) 219 | } 220 | 221 | fn serialize_f32(self, _v: f32) -> Result { 222 | unreachable!() 223 | } 224 | 225 | fn serialize_f64(self, _v: f64) -> Result { 226 | unreachable!() 227 | } 228 | 229 | fn serialize_char(self, _v: char) -> Result { 230 | unreachable!() 231 | } 232 | 233 | fn serialize_str(self, v: &str) -> Result { 234 | self.buf.push(b'"'); 235 | 236 | // Do escaping according to "6. MUST represent all strings (including object member names) in 237 | // their minimal-length UTF-8 encoding": https://gibson042.github.io/canonicaljson-spec/ 238 | // 239 | // We don't need to escape lone surrogates because surrogate pairs do not exist in valid UTF-8, 240 | // even if they can exist in JSON or JavaScript strings (UCS-2 based). As a result, lone surrogates 241 | // cannot exist in a Rust String. If they do, the bug is in the String constructor. 242 | // An excellent explanation is available at https://www.youtube.com/watch?v=HhIEDWmQS3w 243 | 244 | // Temporary storage for encoded a single char. 245 | // A char is up to 4 bytes long when encoded to UTF-8. 246 | let mut encoding_tmp = [0u8; 4]; 247 | 248 | for c in v.chars() { 249 | match c { 250 | '\\' => { 251 | self.buf.push(b'\\'); 252 | self.buf.push(b'\\'); 253 | } 254 | '"' => { 255 | self.buf.push(b'\\'); 256 | self.buf.push(b'"'); 257 | } 258 | '\u{0008}' => { 259 | self.buf.push(b'\\'); 260 | self.buf.push(b'b'); 261 | } 262 | '\u{0009}' => { 263 | self.buf.push(b'\\'); 264 | self.buf.push(b't'); 265 | } 266 | '\u{000A}' => { 267 | self.buf.push(b'\\'); 268 | self.buf.push(b'n'); 269 | } 270 | '\u{000C}' => { 271 | self.buf.push(b'\\'); 272 | self.buf.push(b'f'); 273 | } 274 | '\u{000D}' => { 275 | self.buf.push(b'\\'); 276 | self.buf.push(b'r'); 277 | } 278 | '\u{0000}'..='\u{001F}' => { 279 | self.buf.push(b'\\'); 280 | self.buf.push(b'u'); 281 | self.buf.push(b'0'); 282 | self.buf.push(b'0'); 283 | let (hex1, hex2) = hex(c as u8); 284 | self.buf.push(hex1); 285 | self.buf.push(hex2); 286 | } 287 | _ => { 288 | if c.len_utf8() == 1 { 289 | self.buf.push(c as u8); 290 | } else { 291 | let encoded = c.encode_utf8(&mut encoding_tmp as &mut [u8]); 292 | self.buf.extend_from_slice(encoded.as_bytes()); 293 | } 294 | } 295 | } 296 | } 297 | 298 | self.buf.push(b'"'); 299 | Ok(()) 300 | } 301 | 302 | fn serialize_bytes(self, _v: &[u8]) -> Result { 303 | unreachable!() 304 | } 305 | 306 | fn serialize_none(self) -> Result { 307 | self.buf.extend_from_slice(b"null"); 308 | Ok(()) 309 | } 310 | 311 | fn serialize_some(self, value: &T) -> Result 312 | where 313 | T: ser::Serialize, 314 | { 315 | value.serialize(self) 316 | } 317 | 318 | fn serialize_unit(self) -> Result { 319 | // The unit type is a zero element tuple, so the consistent way to serialize this would be "[]". 320 | // However, for compatibility with serde_json we serialize to "null". 321 | self.buf.extend_from_slice(b"null"); 322 | Ok(()) 323 | } 324 | 325 | fn serialize_unit_struct(self, _name: &'static str) -> Result { 326 | // Unit struct is serialized to (serde_json compatible) "null" 327 | self.buf.extend_from_slice(b"null"); 328 | Ok(()) 329 | } 330 | 331 | fn serialize_unit_variant( 332 | self, 333 | _name: &'static str, 334 | _variant_index: u32, 335 | variant: &'static str, 336 | ) -> Result { 337 | self.serialize_str(variant) 338 | } 339 | 340 | fn serialize_newtype_struct(self, _name: &'static str, value: &T) -> Result 341 | where 342 | T: ser::Serialize, 343 | { 344 | value.serialize(&mut *self) 345 | } 346 | 347 | fn serialize_newtype_variant( 348 | self, 349 | _name: &'static str, 350 | _variant_index: u32, 351 | variant: &'static str, 352 | value: &T, 353 | ) -> Result 354 | where 355 | T: ser::Serialize, 356 | { 357 | self.buf.push(b'{'); 358 | self.serialize_str(variant)?; 359 | self.buf.push(b':'); 360 | value.serialize(&mut *self)?; 361 | self.buf.push(b'}'); 362 | Ok(()) 363 | } 364 | 365 | fn serialize_seq(self, _len: Option) -> Result { 366 | self.buf.push(b'['); 367 | 368 | Ok(SerializeSeq::new(self)) 369 | } 370 | 371 | fn serialize_tuple(self, _len: usize) -> Result { 372 | self.serialize_seq(Some(_len)) 373 | } 374 | 375 | fn serialize_tuple_struct( 376 | self, 377 | _name: &'static str, 378 | _len: usize, 379 | ) -> Result { 380 | unreachable!() 381 | } 382 | 383 | fn serialize_tuple_variant( 384 | self, 385 | _name: &'static str, 386 | _variant_index: u32, 387 | variant: &'static str, 388 | len: usize, 389 | ) -> Result { 390 | self.buf.push(b'{'); 391 | self.serialize_str(variant)?; 392 | self.buf.push(b':'); 393 | self.serialize_tuple(len) 394 | } 395 | 396 | fn serialize_map(self, _len: Option) -> Result { 397 | self.buf.push(b'{'); 398 | Ok(SerializeMap::new(self)) 399 | } 400 | 401 | fn serialize_struct(self, _name: &'static str, _len: usize) -> Result { 402 | self.buf.push(b'{'); 403 | 404 | Ok(SerializeStruct::new(self)) 405 | } 406 | 407 | fn serialize_struct_variant( 408 | self, 409 | name: &'static str, 410 | _variant_index: u32, 411 | variant: &'static str, 412 | len: usize, 413 | ) -> Result { 414 | self.buf.push(b'{'); 415 | self.serialize_str(variant)?; 416 | self.buf.push(b':'); 417 | self.serialize_struct(name, len) 418 | } 419 | } 420 | 421 | /// Serializes the given data structure as a string of JSON text 422 | pub fn to_string(value: &T) -> Result 423 | where 424 | T: ser::Serialize + ?Sized, 425 | { 426 | let mut ser = Serializer::new(); 427 | value.serialize(&mut ser)?; 428 | Ok(unsafe { String::from_utf8_unchecked(ser.buf) }) 429 | } 430 | 431 | /// Serializes the given data structure as a JSON byte vector 432 | pub fn to_vec(value: &T) -> Result> 433 | where 434 | T: ser::Serialize + ?Sized, 435 | { 436 | let mut ser = Serializer::new(); 437 | value.serialize(&mut ser)?; 438 | Ok(ser.buf) 439 | } 440 | 441 | impl ser::Error for Error { 442 | fn custom(msg: T) -> Self { 443 | Error::Custom(msg.to_string()) 444 | } 445 | } 446 | 447 | /// Unreachable is a placeholder for features that are not supported 448 | /// (and should be unreachable, unless you use unsupported serde flags) 449 | pub enum Unreachable {} 450 | 451 | impl ser::SerializeTupleStruct for Unreachable { 452 | type Ok = (); 453 | type Error = Error; 454 | 455 | fn serialize_field(&mut self, _value: &T) -> Result<()> { 456 | unreachable!() 457 | } 458 | 459 | fn end(self) -> Result { 460 | unreachable!() 461 | } 462 | } 463 | 464 | impl ser::SerializeTupleVariant for Unreachable { 465 | type Ok = (); 466 | type Error = Error; 467 | 468 | fn serialize_field(&mut self, _value: &T) -> Result<()> { 469 | unreachable!() 470 | } 471 | 472 | fn end(self) -> Result { 473 | unreachable!() 474 | } 475 | } 476 | 477 | impl ser::SerializeMap for Unreachable { 478 | type Ok = (); 479 | type Error = Error; 480 | 481 | fn serialize_key(&mut self, _key: &T) -> Result<()> 482 | where 483 | T: ser::Serialize, 484 | { 485 | unreachable!() 486 | } 487 | 488 | fn serialize_value(&mut self, _value: &T) -> Result<()> 489 | where 490 | T: ser::Serialize, 491 | { 492 | unreachable!() 493 | } 494 | 495 | fn end(self) -> Result { 496 | unreachable!() 497 | } 498 | } 499 | 500 | impl ser::SerializeStructVariant for Unreachable { 501 | type Ok = (); 502 | type Error = Error; 503 | 504 | fn serialize_field(&mut self, _key: &'static str, _value: &T) -> Result<()> 505 | where 506 | T: ser::Serialize, 507 | { 508 | unreachable!() 509 | } 510 | 511 | fn end(self) -> Result { 512 | unreachable!() 513 | } 514 | } 515 | 516 | #[cfg(test)] 517 | mod tests { 518 | use super::to_string; 519 | 520 | use alloc::collections::BTreeMap; 521 | use alloc::string::{String, ToString}; 522 | use alloc::vec; 523 | use alloc::vec::Vec; 524 | use std::collections::HashMap; 525 | 526 | use serde::{Serialize, Serializer}; 527 | use serde_derive::{Deserialize, Serialize}; 528 | 529 | #[macro_export] 530 | macro_rules! assert_serde_json_serialize_eq { 531 | ($target:expr,) => { 532 | assert_serde_json_serialize_eq!($target); 533 | }; 534 | ($target:expr) => { 535 | assert_eq!( 536 | crate::to_string($target).unwrap(), 537 | ::serde_json::to_string($target).unwrap(), 538 | "Serialization does not match serde_json" 539 | ); 540 | }; 541 | } 542 | 543 | #[test] 544 | fn bool() { 545 | assert_eq!(to_string(&true).unwrap(), "true"); 546 | assert_eq!(to_string(&false).unwrap(), "false"); 547 | } 548 | 549 | #[test] 550 | fn number() { 551 | assert_eq!(to_string::(&0).unwrap(), "0"); 552 | assert_eq!(to_string::(&1).unwrap(), "1"); 553 | assert_eq!(to_string::(&u8::MAX).unwrap(), "255"); 554 | 555 | assert_eq!(to_string::(&0).unwrap(), "0"); 556 | assert_eq!(to_string::(&1).unwrap(), "1"); 557 | assert_eq!(to_string::(&127).unwrap(), "127"); 558 | assert_eq!(to_string::(&-1).unwrap(), "-1"); 559 | assert_eq!(to_string::(&i8::MIN).unwrap(), "-128"); 560 | 561 | assert_eq!(to_string::(&0).unwrap(), "0"); 562 | assert_eq!(to_string::(&1).unwrap(), "1"); 563 | assert_eq!(to_string::(&550).unwrap(), "550"); 564 | assert_eq!(to_string::(&u16::MAX).unwrap(), "65535"); 565 | 566 | assert_eq!(to_string::(&0).unwrap(), "0"); 567 | assert_eq!(to_string::(&1).unwrap(), "1"); 568 | assert_eq!(to_string::(&550).unwrap(), "550"); 569 | assert_eq!(to_string::(&i16::MAX).unwrap(), "32767"); 570 | assert_eq!(to_string::(&-1).unwrap(), "-1"); 571 | assert_eq!(to_string::(&i16::MIN).unwrap(), "-32768"); 572 | 573 | assert_eq!(to_string::(&0).unwrap(), "0"); 574 | assert_eq!(to_string::(&1).unwrap(), "1"); 575 | assert_eq!(to_string::(&456789).unwrap(), "456789"); 576 | assert_eq!(to_string::(&u32::MAX).unwrap(), "4294967295"); 577 | 578 | assert_eq!(to_string::(&0).unwrap(), "0"); 579 | assert_eq!(to_string::(&1).unwrap(), "1"); 580 | assert_eq!(to_string::(&456789).unwrap(), "456789"); 581 | assert_eq!(to_string::(&i32::MAX).unwrap(), "2147483647"); 582 | assert_eq!(to_string::(&-1).unwrap(), "-1"); 583 | assert_eq!(to_string::(&i32::MIN).unwrap(), "-2147483648"); 584 | 585 | assert_eq!(to_string::(&0).unwrap(), "0"); 586 | assert_eq!(to_string::(&1).unwrap(), "1"); 587 | assert_eq!(to_string::(&456789).unwrap(), "456789"); 588 | assert_eq!(to_string::(&4294967295).unwrap(), "4294967295"); 589 | assert_eq!(to_string::(&4294967296).unwrap(), "4294967296"); 590 | assert_eq!( 591 | to_string::(&9007199254740991).unwrap(), 592 | "9007199254740991" 593 | ); // Number.MAX_SAFE_INTEGER 594 | assert_eq!( 595 | to_string::(&9007199254740992).unwrap(), 596 | "9007199254740992" 597 | ); // Number.MAX_SAFE_INTEGER+1 598 | assert_eq!(to_string::(&u64::MAX).unwrap(), "18446744073709551615"); 599 | 600 | assert_eq!(to_string::(&0).unwrap(), "0"); 601 | assert_eq!(to_string::(&1).unwrap(), "1"); 602 | assert_eq!(to_string::(&456789).unwrap(), "456789"); 603 | assert_eq!(to_string::(&4294967295).unwrap(), "4294967295"); 604 | assert_eq!(to_string::(&4294967296).unwrap(), "4294967296"); 605 | assert_eq!( 606 | to_string::(&9007199254740991).unwrap(), 607 | "9007199254740991" 608 | ); // Number.MAX_SAFE_INTEGER 609 | assert_eq!( 610 | to_string::(&9007199254740992).unwrap(), 611 | "9007199254740992" 612 | ); // Number.MAX_SAFE_INTEGER+1 613 | assert_eq!(to_string::(&i64::MAX).unwrap(), "9223372036854775807"); 614 | assert_eq!(to_string::(&-1).unwrap(), "-1"); 615 | assert_eq!(to_string::(&i64::MIN).unwrap(), "-9223372036854775808"); 616 | 617 | assert_eq!(to_string::(&0).unwrap(), r#"0"#); 618 | assert_eq!(to_string::(&1).unwrap(), r#"1"#); 619 | assert_eq!(to_string::(&456789).unwrap(), r#"456789"#); 620 | assert_eq!(to_string::(&4294967295).unwrap(), r#"4294967295"#); 621 | assert_eq!(to_string::(&4294967296).unwrap(), r#"4294967296"#); 622 | assert_eq!( 623 | to_string::(&9007199254740991).unwrap(), 624 | r#"9007199254740991"# 625 | ); // Number.MAX_SAFE_INTEGER 626 | assert_eq!( 627 | to_string::(&9007199254740992).unwrap(), 628 | r#"9007199254740992"# 629 | ); // Number.MAX_SAFE_INTEGER+1 630 | assert_eq!( 631 | to_string::(&9223372036854775807).unwrap(), 632 | r#"9223372036854775807"# 633 | ); 634 | assert_eq!( 635 | to_string::(&9223372036854775808).unwrap(), 636 | r#"9223372036854775808"# 637 | ); 638 | assert_eq!( 639 | to_string::(&u128::MAX).unwrap(), 640 | r#"340282366920938463463374607431768211455"# 641 | ); 642 | assert_serde_json_serialize_eq!(&u128::MAX); 643 | 644 | assert_eq!(to_string::(&0).unwrap(), r#"0"#); 645 | assert_eq!(to_string::(&1).unwrap(), r#"1"#); 646 | assert_eq!(to_string::(&456789).unwrap(), r#"456789"#); 647 | assert_eq!(to_string::(&4294967295).unwrap(), r#"4294967295"#); 648 | assert_eq!(to_string::(&4294967296).unwrap(), r#"4294967296"#); 649 | assert_eq!( 650 | to_string::(&9007199254740991).unwrap(), 651 | r#"9007199254740991"# 652 | ); // Number.MAX_SAFE_INTEGER 653 | assert_eq!( 654 | to_string::(&9007199254740992).unwrap(), 655 | r#"9007199254740992"# 656 | ); // Number.MAX_SAFE_INTEGER+1 657 | assert_eq!( 658 | to_string::(&9223372036854775807).unwrap(), 659 | r#"9223372036854775807"# 660 | ); 661 | assert_eq!( 662 | to_string::(&9223372036854775808).unwrap(), 663 | r#"9223372036854775808"# 664 | ); 665 | assert_eq!( 666 | to_string::(&i128::MAX).unwrap(), 667 | r#"170141183460469231731687303715884105727"# 668 | ); 669 | assert_eq!(to_string::(&-1).unwrap(), r#"-1"#); 670 | assert_eq!( 671 | to_string::(&i128::MIN).unwrap(), 672 | r#"-170141183460469231731687303715884105728"# 673 | ); 674 | assert_serde_json_serialize_eq!(&i128::MIN); 675 | } 676 | 677 | #[test] 678 | fn array() { 679 | assert_eq!(to_string::<[u8]>(&[]).unwrap(), "[]"); 680 | assert_eq!(to_string(&[0, 1, 2]).unwrap(), "[0,1,2]"); 681 | } 682 | 683 | #[test] 684 | fn tuple() { 685 | type Pair = (i64, i64); 686 | type Wrapped = (i64,); // Comma differentiates one element tuple from a primary type surrounded by parentheses 687 | type Unit = (); 688 | 689 | let pair: Pair = (1, 2); 690 | assert_eq!(to_string(&pair).unwrap(), "[1,2]"); 691 | assert_serde_json_serialize_eq!(&pair); 692 | 693 | let wrapped: Wrapped = (5,); 694 | assert_eq!(to_string(&wrapped).unwrap(), "[5]"); 695 | assert_serde_json_serialize_eq!(&wrapped); 696 | 697 | #[allow(clippy::let_unit_value)] 698 | let unit: Unit = (); 699 | assert_eq!(to_string(&unit).unwrap(), "null"); 700 | assert_serde_json_serialize_eq!(&unit); 701 | 702 | type BigPair = (u128, u128); 703 | 704 | let pair: BigPair = (u128::MAX, u128::MAX); 705 | 706 | assert_eq!( 707 | to_string(&pair).unwrap(), 708 | r#"[340282366920938463463374607431768211455,340282366920938463463374607431768211455]"# 709 | ); 710 | assert_serde_json_serialize_eq!(&pair); 711 | } 712 | 713 | #[test] 714 | fn enum_variants_unit_like() { 715 | #[allow(dead_code)] 716 | #[derive(Serialize)] 717 | enum Op { 718 | Enter, 719 | Exit, 720 | } 721 | assert_eq!(to_string(&Op::Exit).unwrap(), r#""Exit""#); 722 | assert_serde_json_serialize_eq!(&Op::Exit); 723 | 724 | // Numeric values are ignored 🤷 725 | #[derive(Serialize)] 726 | enum Order { 727 | Unordered = 1, 728 | Ordered = 42, 729 | } 730 | assert_eq!(to_string(&Order::Unordered).unwrap(), r#""Unordered""#); 731 | assert_serde_json_serialize_eq!(&Order::Unordered); 732 | 733 | assert_eq!(to_string(&Order::Ordered).unwrap(), r#""Ordered""#); 734 | assert_serde_json_serialize_eq!(&Order::Ordered); 735 | } 736 | 737 | #[test] 738 | fn enum_variants_tuple_like_structs() { 739 | #[derive(Serialize)] 740 | enum Op { 741 | Exit(), 742 | Square(i32), 743 | Add(i64, i64), 744 | } 745 | assert_eq!(to_string(&Op::Exit()).unwrap(), r#"{"Exit":[]}"#); 746 | assert_serde_json_serialize_eq!(&Op::Exit()); 747 | 748 | assert_eq!(to_string(&Op::Square(2)).unwrap(), r#"{"Square":2}"#); 749 | assert_serde_json_serialize_eq!(&Op::Square(2)); 750 | 751 | assert_eq!(to_string(&Op::Add(3, 4)).unwrap(), r#"{"Add":[3,4]}"#); 752 | assert_serde_json_serialize_eq!(&Op::Add(3, 4)); 753 | } 754 | 755 | #[test] 756 | fn enum_variants_c_like_structs() { 757 | #[derive(Serialize)] 758 | enum Op { 759 | Exit {}, 760 | Square { input: i32 }, 761 | Add { a: i64, b: i64 }, 762 | } 763 | assert_eq!(to_string(&Op::Exit {}).unwrap(), r#"{"Exit":{}}"#); 764 | assert_serde_json_serialize_eq!(&Op::Exit {}); 765 | 766 | assert_eq!( 767 | to_string(&Op::Square { input: 2 }).unwrap(), 768 | r#"{"Square":{"input":2}}"# 769 | ); 770 | assert_serde_json_serialize_eq!(&Op::Square { input: 2 }); 771 | 772 | assert_eq!( 773 | to_string(&Op::Add { a: 3, b: 4 }).unwrap(), 774 | r#"{"Add":{"a":3,"b":4}}"# 775 | ); 776 | assert_serde_json_serialize_eq!(&Op::Add { a: 3, b: 4 }); 777 | } 778 | 779 | #[test] 780 | fn enum_mixed() { 781 | #[derive(Serialize)] 782 | enum Animal { 783 | Ant, 784 | #[serde(rename = "kitty")] 785 | Cat, 786 | Dog(), 787 | Horse {}, 788 | Zebra { 789 | height: u32, 790 | }, 791 | } 792 | assert_eq!(to_string(&Animal::Ant).unwrap(), r#""Ant""#); 793 | assert_eq!(to_string(&Animal::Cat).unwrap(), r#""kitty""#); 794 | assert_eq!(to_string(&Animal::Dog()).unwrap(), r#"{"Dog":[]}"#); 795 | assert_eq!(to_string(&Animal::Horse {}).unwrap(), r#"{"Horse":{}}"#); 796 | assert_eq!( 797 | to_string(&Animal::Zebra { height: 273 }).unwrap(), 798 | r#"{"Zebra":{"height":273}}"# 799 | ); 800 | } 801 | 802 | #[test] 803 | fn str() { 804 | assert_eq!(to_string("hello").unwrap(), r#""hello""#); 805 | assert_eq!(to_string("").unwrap(), r#""""#); 806 | 807 | // Characters unescaped if possible 808 | assert_eq!(to_string("ä").unwrap(), r#""ä""#); 809 | assert_eq!(to_string("৬").unwrap(), r#""৬""#); 810 | assert_eq!(to_string("\u{A0}").unwrap(), r#"" ""#); // non-breaking space 811 | assert_eq!(to_string("ℝ").unwrap(), r#""ℝ""#); // 3 byte character 812 | assert_eq!(to_string("💣").unwrap(), r#""💣""#); // 4 byte character 813 | 814 | // " and \ must be escaped 815 | assert_eq!(to_string("foo\"bar").unwrap(), r#""foo\"bar""#); 816 | assert_eq!(to_string("foo\\bar").unwrap(), r#""foo\\bar""#); 817 | 818 | // \b, \t, \n, \f, \r must be escaped in their two-character escaping 819 | assert_eq!(to_string(" \u{0008} ").unwrap(), r#"" \b ""#); 820 | assert_eq!(to_string(" \u{0009} ").unwrap(), r#"" \t ""#); 821 | assert_eq!(to_string(" \u{000A} ").unwrap(), r#"" \n ""#); 822 | assert_eq!(to_string(" \u{000C} ").unwrap(), r#"" \f ""#); 823 | assert_eq!(to_string(" \u{000D} ").unwrap(), r#"" \r ""#); 824 | 825 | // U+0000 through U+001F is escaped using six-character \u00xx uppercase hexadecimal escape sequences 826 | assert_eq!(to_string(" \u{0000} ").unwrap(), r#"" \u0000 ""#); 827 | assert_eq!(to_string(" \u{0001} ").unwrap(), r#"" \u0001 ""#); 828 | assert_eq!(to_string(" \u{0007} ").unwrap(), r#"" \u0007 ""#); 829 | assert_eq!(to_string(" \u{000e} ").unwrap(), r#"" \u000E ""#); 830 | assert_eq!(to_string(" \u{001D} ").unwrap(), r#"" \u001D ""#); 831 | assert_eq!(to_string(" \u{001f} ").unwrap(), r#"" \u001F ""#); 832 | } 833 | 834 | #[test] 835 | fn collect_str_can_be_used_in_custom_seralize_impl() { 836 | struct SpecialType { 837 | count: u32, 838 | on: bool, 839 | } 840 | 841 | impl Serialize for SpecialType { 842 | // A custom Serialize implementation for SpecialType. SpecialType is giving us the chance to use 843 | // an efficient collect_str implementation that is better than allocating the String and running 844 | // serialize_str on it. 845 | fn serialize(&self, serializer: S) -> Result 846 | where 847 | S: Serializer, 848 | { 849 | serializer.collect_str(&format_args!("{}-{}", self.count, self.on)) 850 | } 851 | } 852 | 853 | let value = SpecialType { 854 | count: 123, 855 | on: false, 856 | }; 857 | assert_eq!(to_string(&value).unwrap(), r#""123-false""#); 858 | } 859 | 860 | #[test] 861 | fn newtype() { 862 | #[derive(Serialize)] 863 | struct Address(String); 864 | #[derive(Serialize)] 865 | struct CommentId(u32); 866 | 867 | // string 868 | assert_eq!( 869 | to_string(&Address("home".to_string())).unwrap(), 870 | r#""home""# 871 | ); 872 | assert_serde_json_serialize_eq!(&Address("home".to_string())); 873 | 874 | // number 875 | assert_eq!(to_string(&CommentId(42)).unwrap(), r#"42"#); 876 | assert_serde_json_serialize_eq!(&CommentId(42)); 877 | } 878 | 879 | #[test] 880 | fn struct_bool() { 881 | #[derive(Serialize)] 882 | struct Led { 883 | led: bool, 884 | } 885 | 886 | assert_eq!(to_string(&Led { led: true }).unwrap(), r#"{"led":true}"#); 887 | assert_serde_json_serialize_eq!(&Led { led: true }); 888 | } 889 | 890 | #[test] 891 | fn struct_i8() { 892 | #[derive(Serialize)] 893 | struct Temperature { 894 | temperature: i8, 895 | } 896 | 897 | assert_eq!( 898 | to_string(&Temperature { temperature: 127 }).unwrap(), 899 | r#"{"temperature":127}"# 900 | ); 901 | assert_eq!( 902 | to_string(&Temperature { temperature: 20 }).unwrap(), 903 | r#"{"temperature":20}"# 904 | ); 905 | assert_eq!( 906 | to_string(&Temperature { temperature: -17 }).unwrap(), 907 | r#"{"temperature":-17}"# 908 | ); 909 | assert_eq!( 910 | to_string(&Temperature { temperature: -128 }).unwrap(), 911 | r#"{"temperature":-128}"# 912 | ); 913 | assert_serde_json_serialize_eq!(&Temperature { temperature: -128 }); 914 | } 915 | 916 | #[test] 917 | fn struct_option() { 918 | #[derive(Serialize)] 919 | struct Property<'a> { 920 | description: Option<&'a str>, 921 | } 922 | 923 | assert_eq!( 924 | to_string(&Property { 925 | description: Some("An ambient temperature sensor"), 926 | }) 927 | .unwrap(), 928 | r#"{"description":"An ambient temperature sensor"}"# 929 | ); 930 | assert_serde_json_serialize_eq!(&Property { 931 | description: Some("An ambient temperature sensor"), 932 | }); 933 | 934 | assert_eq!( 935 | to_string(&Property { description: None }).unwrap(), 936 | r#"{"description":null}"# 937 | ); 938 | assert_serde_json_serialize_eq!(&Property { description: None }); 939 | } 940 | 941 | #[test] 942 | fn struct_u8() { 943 | #[derive(Serialize)] 944 | struct Temperature { 945 | temperature: u8, 946 | } 947 | 948 | assert_eq!( 949 | to_string(&Temperature { temperature: 20 }).unwrap(), 950 | r#"{"temperature":20}"# 951 | ); 952 | assert_serde_json_serialize_eq!(&Temperature { temperature: 20 }); 953 | } 954 | 955 | #[test] 956 | fn struct_() { 957 | #[derive(Serialize)] 958 | struct Nothing; 959 | 960 | assert_eq!(to_string(&Nothing).unwrap(), r#"null"#); 961 | assert_serde_json_serialize_eq!(&Nothing); 962 | 963 | #[derive(Serialize)] 964 | struct Empty {} 965 | 966 | assert_eq!(to_string(&Empty {}).unwrap(), r#"{}"#); 967 | assert_serde_json_serialize_eq!(&Empty {}); 968 | 969 | #[derive(Serialize)] 970 | struct Tuple { 971 | a: bool, 972 | b: bool, 973 | } 974 | 975 | assert_eq!( 976 | to_string(&Tuple { a: true, b: false }).unwrap(), 977 | r#"{"a":true,"b":false}"# 978 | ); 979 | assert_serde_json_serialize_eq!(&Tuple { a: true, b: false }); 980 | } 981 | 982 | #[test] 983 | fn struct_with_flatten() { 984 | #[derive(Serialize, Deserialize, Debug, PartialEq, Eq)] 985 | struct Pagination { 986 | limit: u64, 987 | offset: u64, 988 | total: u64, 989 | } 990 | 991 | #[derive(Serialize, Deserialize, Debug, PartialEq, Eq)] 992 | struct Users { 993 | users: Vec, 994 | 995 | #[serde(flatten)] 996 | pagination: Pagination, 997 | } 998 | 999 | let users = Users { 1000 | users: vec!["joe".into(), "alice".into()], 1001 | pagination: Pagination { 1002 | offset: 100, 1003 | limit: 20, 1004 | total: 102, 1005 | }, 1006 | }; 1007 | 1008 | assert_eq!( 1009 | to_string(&users).unwrap(), 1010 | r#"{"users":["joe","alice"],"limit":20,"offset":100,"total":102}"# 1011 | ); 1012 | assert_serde_json_serialize_eq!(&users); 1013 | } 1014 | 1015 | #[test] 1016 | fn btree_map() { 1017 | // empty map 1018 | let empty = BTreeMap::<(), ()>::new(); 1019 | assert_eq!(to_string(&empty).unwrap(), r#"{}"#); 1020 | assert_serde_json_serialize_eq!(&empty); 1021 | 1022 | // One element with unit type 1023 | let mut map = BTreeMap::<&str, ()>::new(); 1024 | map.insert("set_element", ()); 1025 | assert_eq!(to_string(&map).unwrap(), r#"{"set_element":null}"#); 1026 | assert_serde_json_serialize_eq!(&map); 1027 | 1028 | let mut two_values = BTreeMap::new(); 1029 | two_values.insert("my_name", "joseph"); 1030 | two_values.insert("her_name", "aline"); 1031 | assert_eq!( 1032 | to_string(&two_values).unwrap(), 1033 | r#"{"her_name":"aline","my_name":"joseph"}"# 1034 | ); 1035 | assert_serde_json_serialize_eq!(&two_values); 1036 | 1037 | let mut nested_map = BTreeMap::new(); 1038 | nested_map.insert("two_entries", two_values.clone()); 1039 | 1040 | two_values.remove("my_name"); 1041 | nested_map.insert("one_entry", two_values); 1042 | assert_eq!( 1043 | to_string(&nested_map).unwrap(), 1044 | r#"{"one_entry":{"her_name":"aline"},"two_entries":{"her_name":"aline","my_name":"joseph"}}"# 1045 | ); 1046 | assert_serde_json_serialize_eq!(&nested_map); 1047 | } 1048 | 1049 | #[test] 1050 | fn hash_map() { 1051 | // empty map 1052 | let empty = HashMap::<(), ()>::new(); 1053 | assert_eq!(to_string(&empty).unwrap(), r#"{}"#); 1054 | assert_serde_json_serialize_eq!(&empty); 1055 | 1056 | // One element 1057 | let mut map = HashMap::new(); 1058 | map.insert("my_age", 28); 1059 | assert_eq!(to_string(&map).unwrap(), r#"{"my_age":28}"#); 1060 | assert_serde_json_serialize_eq!(&map); 1061 | 1062 | #[derive(Debug, Serialize, PartialEq, Eq, Hash)] 1063 | pub struct NewType(String); 1064 | 1065 | // New type wrappers around String types work as keys 1066 | let mut map = HashMap::new(); 1067 | map.insert(NewType(String::from("my_age")), 44); 1068 | assert_eq!(to_string(&map).unwrap(), r#"{"my_age":44}"#); 1069 | assert_serde_json_serialize_eq!(&map); 1070 | 1071 | #[derive(Debug, Serialize, PartialEq, Eq, Hash)] 1072 | #[serde(rename_all = "lowercase")] 1073 | pub enum MyResult { 1074 | Err, 1075 | } 1076 | 1077 | // Unit variants are also valid keys 1078 | let mut map = HashMap::new(); 1079 | map.insert(MyResult::Err, 404); 1080 | assert_eq!(to_string(&map).unwrap(), r#"{"err":404}"#); 1081 | assert_serde_json_serialize_eq!(&map); 1082 | 1083 | // HashMap does not have deterministic iteration order (except in the Wasm target). 1084 | // So the two element map is serialized as one of two options. 1085 | let mut two_values = HashMap::new(); 1086 | two_values.insert("my_name", "joseph"); 1087 | two_values.insert("her_name", "aline"); 1088 | let serialized = to_string(&two_values).unwrap(); 1089 | assert!( 1090 | serialized == r#"{"her_name":"aline","my_name":"joseph"}"# 1091 | || serialized == r#"{"my_name":"joseph","her_name":"aline"}"# 1092 | ); 1093 | assert_serde_json_serialize_eq!(&two_values); 1094 | } 1095 | 1096 | #[test] 1097 | fn number_key() { 1098 | // i8 key 1099 | let mut map = HashMap::new(); 1100 | map.insert(10i8, "my_age"); 1101 | assert_eq!(to_string(&map).unwrap(), r#"{"10":"my_age"}"#); 1102 | assert_serde_json_serialize_eq!(&map); 1103 | 1104 | // i16 key 1105 | let mut map = HashMap::new(); 1106 | map.insert(10i16, "my_age"); 1107 | assert_eq!(to_string(&map).unwrap(), r#"{"10":"my_age"}"#); 1108 | assert_serde_json_serialize_eq!(&map); 1109 | 1110 | // i32 key 1111 | let mut map = HashMap::new(); 1112 | map.insert(10i32, "my_age"); 1113 | assert_eq!(to_string(&map).unwrap(), r#"{"10":"my_age"}"#); 1114 | assert_serde_json_serialize_eq!(&map); 1115 | 1116 | // i64 key 1117 | let mut map = HashMap::new(); 1118 | map.insert(10i64, "my_age"); 1119 | assert_eq!(to_string(&map).unwrap(), r#"{"10":"my_age"}"#); 1120 | 1121 | // i128 key 1122 | let mut map = HashMap::new(); 1123 | map.insert(10i128, "my_age"); 1124 | assert_eq!(to_string(&map).unwrap(), r#"{"10":"my_age"}"#); 1125 | assert_serde_json_serialize_eq!(&map); 1126 | 1127 | // u8 key 1128 | let mut map = HashMap::new(); 1129 | map.insert(10u8, "my_age"); 1130 | assert_eq!(to_string(&map).unwrap(), r#"{"10":"my_age"}"#); 1131 | assert_serde_json_serialize_eq!(&map); 1132 | 1133 | // u16 key 1134 | let mut map = HashMap::new(); 1135 | map.insert(10u16, "my_age"); 1136 | assert_eq!(to_string(&map).unwrap(), r#"{"10":"my_age"}"#); 1137 | 1138 | // u32 key 1139 | let mut map = HashMap::new(); 1140 | map.insert(10u32, "my_age"); 1141 | assert_eq!(to_string(&map).unwrap(), r#"{"10":"my_age"}"#); 1142 | assert_serde_json_serialize_eq!(&map); 1143 | 1144 | // u64 key 1145 | let mut map = HashMap::new(); 1146 | map.insert(10u64, "my_age"); 1147 | assert_eq!(to_string(&map).unwrap(), r#"{"10":"my_age"}"#); 1148 | assert_serde_json_serialize_eq!(&map); 1149 | 1150 | // u128 key 1151 | let mut map = HashMap::new(); 1152 | map.insert(10u128, "my_age"); 1153 | assert_eq!(to_string(&map).unwrap(), r#"{"10":"my_age"}"#); 1154 | assert_serde_json_serialize_eq!(&map); 1155 | } 1156 | 1157 | #[test] 1158 | fn invalid_json_key() { 1159 | use crate::ser::map::key_must_be_a_string; 1160 | 1161 | #[derive(Debug, Serialize, PartialEq, Eq, Hash)] 1162 | #[serde(rename_all = "lowercase")] 1163 | pub enum MyResult { 1164 | Unit(()), 1165 | Ok(Response), 1166 | } 1167 | #[derive(Debug, Serialize, PartialEq, Eq, Hash)] 1168 | pub struct Response { 1169 | pub log: Option, 1170 | pub count: i64, 1171 | pub list: Vec, 1172 | } 1173 | 1174 | // unit enum 1175 | let mut map = HashMap::new(); 1176 | map.insert(MyResult::Unit(()), "my_age"); 1177 | assert_eq!( 1178 | to_string(&map).unwrap_err().to_string(), 1179 | key_must_be_a_string().to_string() 1180 | ); 1181 | 1182 | // struct enum 1183 | let mut map = HashMap::new(); 1184 | map.insert( 1185 | MyResult::Ok(Response { 1186 | log: None, 1187 | count: 1, 1188 | list: vec![6], 1189 | }), 1190 | "my_age", 1191 | ); 1192 | assert_eq!( 1193 | to_string(&map).unwrap_err().to_string(), 1194 | key_must_be_a_string().to_string() 1195 | ); 1196 | 1197 | // Struct 1198 | let mut map = HashMap::new(); 1199 | map.insert( 1200 | Response { 1201 | log: None, 1202 | count: 1, 1203 | list: vec![6], 1204 | }, 1205 | "my_age", 1206 | ); 1207 | assert_eq!( 1208 | to_string(&map).unwrap_err().to_string(), 1209 | key_must_be_a_string().to_string() 1210 | ); 1211 | } 1212 | 1213 | #[test] 1214 | fn serialize_embedded_enum() { 1215 | use serde_derive::Deserialize; 1216 | 1217 | #[derive(Debug, Deserialize, Serialize, PartialEq, Eq)] 1218 | #[serde(rename_all = "lowercase")] 1219 | pub enum MyResult { 1220 | Unit(()), 1221 | Ok(Response), 1222 | Err(String), 1223 | } 1224 | 1225 | #[derive(Debug, Deserialize, Serialize, PartialEq, Eq)] 1226 | pub struct Response { 1227 | pub log: Option, 1228 | pub count: i64, 1229 | pub list: Vec, 1230 | } 1231 | 1232 | let err_input = MyResult::Err("some error".to_string()); 1233 | let json = to_string(&err_input).expect("encode err enum"); 1234 | assert_eq!(json, r#"{"err":"some error"}"#); 1235 | let loaded = crate::from_str(&json).expect("re-load err enum"); 1236 | assert_eq!(err_input, loaded); 1237 | assert_serde_json_serialize_eq!(&err_input); 1238 | 1239 | let unit = MyResult::Unit(()); 1240 | let json = to_string(&unit).expect("encode unit enum"); 1241 | assert_eq!(json, r#"{"unit":null}"#); 1242 | let loaded = crate::from_str(&json).expect("re-load unit enum"); 1243 | assert_eq!(unit, loaded); 1244 | assert_serde_json_serialize_eq!(&unit); 1245 | 1246 | let empty_list = MyResult::Ok(Response { 1247 | log: Some("log message".to_string()), 1248 | count: 137, 1249 | list: Vec::new(), 1250 | }); 1251 | let json = to_string(&empty_list).expect("encode ok enum"); 1252 | assert_eq!( 1253 | json, 1254 | r#"{"ok":{"log":"log message","count":137,"list":[]}}"# 1255 | ); 1256 | let loaded = crate::from_str(&json).expect("re-load ok enum"); 1257 | assert_eq!(empty_list, loaded); 1258 | assert_serde_json_serialize_eq!(&empty_list); 1259 | 1260 | let full_list = MyResult::Ok(Response { 1261 | log: None, 1262 | count: 137, 1263 | list: vec![18u32, 34, 12], 1264 | }); 1265 | let json = to_string(&full_list).expect("encode ok enum"); 1266 | assert_eq!(json, r#"{"ok":{"log":null,"count":137,"list":[18,34,12]}}"#); 1267 | let loaded = crate::from_str(&json).expect("re-load ok enum"); 1268 | assert_eq!(full_list, loaded); 1269 | assert_serde_json_serialize_eq!(&full_list); 1270 | } 1271 | } 1272 | -------------------------------------------------------------------------------- /src/ser/seq.rs: -------------------------------------------------------------------------------- 1 | use serde::ser; 2 | 3 | use crate::ser::{Error, Result, Serializer}; 4 | 5 | pub struct SerializeSeq<'a> { 6 | ser: &'a mut Serializer, 7 | first: bool, 8 | } 9 | 10 | impl<'a> SerializeSeq<'a> { 11 | pub(crate) fn new(ser: &'a mut Serializer) -> Self { 12 | SerializeSeq { ser, first: true } 13 | } 14 | } 15 | 16 | impl<'a> ser::SerializeSeq for SerializeSeq<'a> { 17 | type Ok = (); 18 | type Error = Error; 19 | 20 | fn serialize_element(&mut self, value: &T) -> Result<()> 21 | where 22 | T: ser::Serialize, 23 | { 24 | if !self.first { 25 | self.ser.buf.push(b','); 26 | } 27 | self.first = false; 28 | 29 | value.serialize(&mut *self.ser)?; 30 | Ok(()) 31 | } 32 | 33 | fn end(self) -> Result { 34 | self.ser.buf.push(b']'); 35 | Ok(()) 36 | } 37 | } 38 | 39 | impl<'a> ser::SerializeTuple for SerializeSeq<'a> { 40 | type Ok = (); 41 | type Error = Error; 42 | 43 | fn serialize_element(&mut self, value: &T) -> Result<()> 44 | where 45 | T: ser::Serialize, 46 | { 47 | ser::SerializeSeq::serialize_element(self, value) 48 | } 49 | 50 | fn end(self) -> Result { 51 | ser::SerializeSeq::end(self) 52 | } 53 | } 54 | 55 | impl<'a> ser::SerializeTupleVariant for SerializeSeq<'a> { 56 | type Ok = (); 57 | type Error = Error; 58 | 59 | fn serialize_field(&mut self, value: &T) -> Result<()> 60 | where 61 | T: ser::Serialize, 62 | { 63 | ser::SerializeSeq::serialize_element(self, value) 64 | } 65 | 66 | fn end(self) -> Result { 67 | // close sequence 68 | self.ser.buf.push(b']'); 69 | // close surrounding enum 70 | self.ser.buf.push(b'}'); 71 | Ok(()) 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/ser/struct_.rs: -------------------------------------------------------------------------------- 1 | use serde::ser; 2 | 3 | use crate::ser::{Error, Result, Serializer}; 4 | 5 | pub struct SerializeStruct<'a> { 6 | ser: &'a mut Serializer, 7 | first: bool, 8 | } 9 | 10 | impl<'a> SerializeStruct<'a> { 11 | pub(crate) fn new(ser: &'a mut Serializer) -> Self { 12 | SerializeStruct { ser, first: true } 13 | } 14 | } 15 | 16 | impl<'a> ser::SerializeStruct for SerializeStruct<'a> { 17 | type Ok = (); 18 | type Error = Error; 19 | 20 | fn serialize_field(&mut self, key: &'static str, value: &T) -> Result<()> 21 | where 22 | T: ser::Serialize, 23 | { 24 | if !self.first { 25 | self.ser.buf.push(b','); 26 | } 27 | self.first = false; 28 | 29 | self.ser.buf.push(b'"'); 30 | self.ser.buf.extend_from_slice(key.as_bytes()); 31 | self.ser.buf.extend_from_slice(b"\":"); 32 | 33 | value.serialize(&mut *self.ser)?; 34 | 35 | Ok(()) 36 | } 37 | 38 | fn end(self) -> Result { 39 | self.ser.buf.push(b'}'); 40 | Ok(()) 41 | } 42 | } 43 | 44 | impl<'a> ser::SerializeStructVariant for SerializeStruct<'a> { 45 | type Ok = (); 46 | type Error = Error; 47 | 48 | fn serialize_field(&mut self, key: &'static str, value: &T) -> Result<()> 49 | where 50 | T: ser::Serialize, 51 | { 52 | if !self.first { 53 | self.ser.buf.push(b','); 54 | } 55 | self.first = false; 56 | 57 | self.ser.buf.push(b'"'); 58 | self.ser.buf.extend_from_slice(key.as_bytes()); 59 | self.ser.buf.extend_from_slice(b"\":"); 60 | 61 | value.serialize(&mut *self.ser)?; 62 | 63 | Ok(()) 64 | } 65 | 66 | fn end(self) -> Result { 67 | // close struct 68 | self.ser.buf.push(b'}'); 69 | // close surrounding enum 70 | self.ser.buf.push(b'}'); 71 | Ok(()) 72 | } 73 | } 74 | --------------------------------------------------------------------------------