diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
commit | 36d22d82aa202bb199967e9512281e9a53db42c9 (patch) | |
tree | 105e8c98ddea1c1e4784a60a5a6410fa416be2de /third_party/rust/serde_cbor | |
parent | Initial commit. (diff) | |
download | firefox-esr-upstream.tar.xz firefox-esr-upstream.zip |
Adding upstream version 115.7.0esr.upstream/115.7.0esrupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/rust/serde_cbor')
30 files changed, 6905 insertions, 0 deletions
diff --git a/third_party/rust/serde_cbor/.cargo-checksum.json b/third_party/rust/serde_cbor/.cargo-checksum.json new file mode 100644 index 0000000000..03e08b7b06 --- /dev/null +++ b/third_party/rust/serde_cbor/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"CONTRIBUTING.md":"bcbbc1fd8aefd2af15d432b551ddc32b0b832c1ad669eeedfaffb2092448c080","Cargo.lock":"b900f78562d5ae2ffffc0e8f739328df268f0fb80696018eb5df8e5e633b733e","Cargo.toml":"522e55ca99d851f9a3e7361f090451fc87c6097320c77bd574a80df27c183078","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"e03e58ea9205f51989b7a50f450051b24e6516cc1f0b920222dcda992072be99","README.md":"abb494d9608a40bac62da0bbd4680c0f03d960922d92261fb6492a1ee448d5c6","examples/readme.rs":"2e356830c62e84605d6b7efa07a0266ad96ed960fde09d4ae241c642ff662ab2","examples/tags.rs":"a1e1e4de8a5b09c54f96a56b8d7dc749fff9c73facb1dcad05540bc83f34dbd2","examples/tux.cbor":"3251bceb0a182543de2129cd920b2af597c481513a0624887a7daeb468c530f8","src/de.rs":"433d2e10bf1be80f881dfd5355a0df1a1c6b1e09a2d36c4d6f39894b13b42e0b","src/error.rs":"9247283d47617626c90a0d32bba40b54a18c6bb0ecce37057d7423ff9158d223","src/lib.rs":"efe97da47a332789d29eb4480a65ae00b4ccd9e6ba22d2b2c945cbeb97edf2b5","src/read.rs":"001754714cf10e9691e3284bf8170348346858be8e5d72ee845853b928588c7c","src/ser.rs":"0b7cb6162e104bfea55f6bffa591d19876236a798134fec8dbabb1c2d4a22363","src/tags.rs":"8d83efd96daca49ac51f24d41b986f4247fcd2a011855ffc99e9388834bd31a3","src/value/de.rs":"986784dcf015464b01f669949f823ba0e29b7414f6d56cad3311cee036d1a954","src/value/mod.rs":"0afa696a6ed01f97380f84e4e219090393bc8cc52cd9c11f4db3eb5b1fb85e7f","src/value/ser.rs":"f5d505125ae496c99d611c24cb0905199b3b66b949ae18bb48863317b686f301","src/write.rs":"6bcc413fe531799cd979d954615e73dd87e185082858a63c5aef73f0fbe08806","tests/bennofs.rs":"2211b234f442e909659f0610fcb20e7cf746bc6c648fe258e5300ebcd6a4251f","tests/canonical.rs":"37fcbe3a1956c72e4aef808acb2e194f09ae8aaa752c6a94cf6d06731c19948d","tests/crash.cbor":"8aeb60947fc5d43e80f3c884fc6cb37c9021cc691492d055a14e55c69b366d1f","tests/de.rs":"545cf5f5bd1ab0b3b4c05c4985baf40ad419dc1568f28549d17eacf5efc7beb7","tests/enum.rs":"699886e517546396979c9843b6d1c513b4370af81e2b0d3bcf0727435c5c0a8a","tests/kietaub.cbor":"98146fa75d5970eea896baa19b5aeda31695d6ceeed4b23aa67fc13142123a9a","tests/ser.rs":"7eadf27fb58b8bd498f0be8e1670d76de36e3f21b565daeb8ec9cf30140c068e","tests/std_types.rs":"549e357ad5062eb8ae298df3bbbd0e8ee87ee0434f8c67dc53642ff2b2171e40","tests/tags.rs":"e847b9ab49f47a81a09e34d4af3bd25bb546e408915f033dc06b03b275f68065","tests/value.rs":"540469dccb6c6f3542b75934707203dff93132a7e160de798a21f16caf16075e"},"package":"2bef2ebfde456fb76bbcf9f59315333decc4fda0b2b44b420243c11e0f5ec1f5"}
\ No newline at end of file diff --git a/third_party/rust/serde_cbor/CONTRIBUTING.md b/third_party/rust/serde_cbor/CONTRIBUTING.md new file mode 100644 index 0000000000..1489ade658 --- /dev/null +++ b/third_party/rust/serde_cbor/CONTRIBUTING.md @@ -0,0 +1,29 @@ +# Contributing to Serde CBOR +Thanks for your interest! +There are many ways to help: + +* write an issue about a problem you encountered +* submit a pull request +* add documentation and examples + +## Pull Requests + +Code should be easy to understand and documented. +For new features and fixed bugs please add a test to one of the files in `test/`. +The tests are run on Travis CI to catch regressions early. +Format your code with `cargo fmt` before committing. +Currently Serde CBOR does not contain `unsafe` code and I would like to keep it this way. + +## Making a Release + +* [ ] Make sure the crate compiles and all tests pass. +* [ ] (Optional) Test that the fuzzer works and fuzz the crate for some time. +* [ ] Write a list with all changes made since the last release +* [ ] Increment the version number in `Cargo.toml` and the `README.md`. Bugfixes increase the patch version while new features or an increased minimum Rust version require a new minor version. +* [ ] Check that the file `examples/readme.rs` and the example from the `README.md` match. +* [ ] Commit the changes. +* [ ] Add a git tag with the new version number: + `git tag "v42.0.2"` +* [ ] Push the changes: `git push --tags` +* [ ] Run `cargo publish` +* [ ] Add a new release to GitHub with a list of changes.
\ No newline at end of file diff --git a/third_party/rust/serde_cbor/Cargo.lock b/third_party/rust/serde_cbor/Cargo.lock new file mode 100644 index 0000000000..b91ed7cd52 --- /dev/null +++ b/third_party/rust/serde_cbor/Cargo.lock @@ -0,0 +1,68 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "half" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ff54597ea139063f4225f1ec47011b03c9de4a486957ff3fc506881dac951d0" + +[[package]] +name = "proc-macro2" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0319972dcae462681daf4da1adeeaa066e3ebd29c69be96c6abb1259d2ee2bcc" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "quote" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "serde" +version = "1.0.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "414115f25f818d7dfccec8ee535d76949ae78584fc4f79a6f45a904bf8ab4449" + +[[package]] +name = "serde_cbor" +version = "0.11.2" +dependencies = [ + "half", + "serde", + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "128f9e303a5a29922045a830221b8f78ec74a5f544944f3d5984f8ec3895ef64" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "syn" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e4ff033220a41d1a57d8125eab57bf5263783dfdcc18688b1dacc6ce9651ef8" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "unicode-xid" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" diff --git a/third_party/rust/serde_cbor/Cargo.toml b/third_party/rust/serde_cbor/Cargo.toml new file mode 100644 index 0000000000..2960dbe95d --- /dev/null +++ b/third_party/rust/serde_cbor/Cargo.toml @@ -0,0 +1,44 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +edition = "2018" +name = "serde_cbor" +version = "0.11.2" +authors = ["Pyfisch <pyfisch@posteo.org>", "Steven Fackler <sfackler@gmail.com>"] +description = "CBOR support for serde." +readme = "README.md" +keywords = ["serde", "cbor", "serialization", "no_std"] +categories = ["encoding"] +license = "MIT/Apache-2.0" +repository = "https://github.com/pyfisch/cbor" +[dependencies.half] +version = "1.2.0" + +[dependencies.serde] +version = "1.0.14" +default-features = false +[dev-dependencies.serde_derive] +version = "1.0.14" +default-features = false + +[features] +alloc = ["serde/alloc"] +default = ["std"] +std = ["serde/std"] +tags = [] +unsealed_read_write = [] +[badges.maintenance] +status = "as-is" + +[badges.travis-ci] +repository = "pyfisch/cbor" diff --git a/third_party/rust/serde_cbor/LICENSE-APACHE b/third_party/rust/serde_cbor/LICENSE-APACHE new file mode 100644 index 0000000000..16fe87b06e --- /dev/null +++ b/third_party/rust/serde_cbor/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/third_party/rust/serde_cbor/LICENSE-MIT b/third_party/rust/serde_cbor/LICENSE-MIT new file mode 100644 index 0000000000..b1b75fa62c --- /dev/null +++ b/third_party/rust/serde_cbor/LICENSE-MIT @@ -0,0 +1,19 @@ +Copyright (c) 2015 Pyfisch + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/third_party/rust/serde_cbor/README.md b/third_party/rust/serde_cbor/README.md new file mode 100644 index 0000000000..b49e8adbc3 --- /dev/null +++ b/third_party/rust/serde_cbor/README.md @@ -0,0 +1,97 @@ +# Serde CBOR +[![Build Status](https://travis-ci.org/pyfisch/cbor.svg?branch=master)](https://travis-ci.org/pyfisch/cbor) +[![Crates.io](https://img.shields.io/crates/v/serde_cbor.svg)](https://crates.io/crates/serde_cbor) +[![Documentation](https://docs.rs/serde_cbor/badge.svg)](https://docs.rs/serde_cbor) + +## PROJECT IS ARCHIVED + +After almost 6 years it is time to retire this crate. +This implementation of CBOR for serde is used in hundreds of projects with widely differing needs. +Besides the standard features it contains code for no-std environments, a packed encoding and CBOR tags. +However while these features are useful to many people they sometimes interact poorly with each others and with optional features of serde itself. +Because I don't use the crate myself and because of the potential for new errors I have been reluctant to accept any changes or additional features for the crate. +Since this situation is unlikely to change anytime soon and no one else stepped up to maintain this crate I am archiving the repository today. +If the crate works for you there is no need to switch to another implementation. +However if you encounter problems or for new projects I recommend you take a look at these crates: + +* [ciborium](https://crates.io/crates/ciborium) +* [minicbor](https://crates.io/crates/minicbor) + +~~ Pyfisch, August 2021 + + + +This crate implements the Concise Binary Object Representation from [RFC 7049]. +It builds on [Serde], the generic serialization framework for Rust. +CBOR provides a binary encoding for a superset +of the JSON data model that is small and very fast to parse. + +[RFC 7049]: https://tools.ietf.org/html/rfc7049 +[Serde]: https://github.com/serde-rs/serde + +## Usage + +Serde CBOR supports Rust 1.40 and up. Add this to your `Cargo.toml`: +```toml +[dependencies] +serde_cbor = "0.11.2" +``` + +Storing and loading Rust types is easy and requires only +minimal modifications to the program code. + +```rust +use serde_derive::{Deserialize, Serialize}; +use std::error::Error; +use std::fs::File; + +// Types annotated with `Serialize` can be stored as CBOR. +// To be able to load them again add `Deserialize`. +#[derive(Debug, Serialize, Deserialize)] +struct Mascot { + name: String, + species: String, + year_of_birth: u32, +} + +fn main() -> Result<(), Box<dyn Error>> { + let ferris = Mascot { + name: "Ferris".to_owned(), + species: "crab".to_owned(), + year_of_birth: 2015, + }; + + let ferris_file = File::create("examples/ferris.cbor")?; + // Write Ferris to the given file. + // Instead of a file you can use any type that implements `io::Write` + // like a HTTP body, database connection etc. + serde_cbor::to_writer(ferris_file, &ferris)?; + + let tux_file = File::open("examples/tux.cbor")?; + // Load Tux from a file. + // Serde CBOR performs roundtrip serialization meaning that + // the data will not change in any way. + let tux: Mascot = serde_cbor::from_reader(tux_file)?; + + println!("{:?}", tux); + // prints: Mascot { name: "Tux", species: "penguin", year_of_birth: 1996 } + + Ok(()) +} +``` + +There are a lot of options available to customize the format. +To operate on untyped CBOR values have a look at the `Value` type. + +## License +Licensed under either of + + * Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) + * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) + +at your option. + +### Contribution +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any +additional terms or conditions. diff --git a/third_party/rust/serde_cbor/examples/readme.rs b/third_party/rust/serde_cbor/examples/readme.rs new file mode 100644 index 0000000000..7689394b79 --- /dev/null +++ b/third_party/rust/serde_cbor/examples/readme.rs @@ -0,0 +1,39 @@ +// NOTE: This file should be kept in sync with README.md + +use serde_derive::{Deserialize, Serialize}; +use std::error::Error; +use std::fs::File; + +// Types annotated with `Serialize` can be stored as CBOR. +// To be able to load them again add `Deserialize`. +#[derive(Debug, Serialize, Deserialize)] +struct Mascot { + name: String, + species: String, + year_of_birth: u32, +} + +fn main() -> Result<(), Box<dyn Error>> { + let ferris = Mascot { + name: "Ferris".to_owned(), + species: "crab".to_owned(), + year_of_birth: 2015, + }; + + let ferris_file = File::create("examples/ferris.cbor")?; + // Write Ferris to the given file. + // Instead of a file you can use any type that implements `io::Write` + // like a HTTP body, database connection etc. + serde_cbor::to_writer(ferris_file, &ferris)?; + + let tux_file = File::open("examples/tux.cbor")?; + // Load Tux from a file. + // Serde CBOR performs roundtrip serialization meaning that + // the data will not change in any way. + let tux: Mascot = serde_cbor::from_reader(tux_file)?; + + println!("{:?}", tux); + // prints: Mascot { name: "Tux", species: "penguin", year_of_birth: 1996 } + + Ok(()) +} diff --git a/third_party/rust/serde_cbor/examples/tags.rs b/third_party/rust/serde_cbor/examples/tags.rs new file mode 100644 index 0000000000..9281b9b845 --- /dev/null +++ b/third_party/rust/serde_cbor/examples/tags.rs @@ -0,0 +1,84 @@ +use serde::de::{Deserialize, Deserializer}; +use serde::ser::{Serialize, Serializer}; +use serde_cbor::tags::Tagged; +use serde_cbor::Value; +use serde_derive::{Deserialize, Serialize}; +use std::error::Error; + +/// https://tools.ietf.org/html/rfc7049#section-2.4.1 +#[derive(Debug, PartialEq)] +struct Date(String); + +impl Serialize for Date { + fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> { + Tagged::new(Some(0), &self.0).serialize(s) + } +} + +impl<'de> Deserialize<'de> for Date { + fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> { + let tagged = Tagged::<String>::deserialize(deserializer)?; + match tagged.tag { + Some(0) | None => Ok(Date(tagged.value)), + Some(_) => Err(serde::de::Error::custom("unexpected tag")), + } + } +} + +/// https://tools.ietf.org/html/rfc7049#section-2.4.4.3 +#[derive(Debug, PartialEq)] +struct Uri(String); + +impl Serialize for Uri { + fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> { + Tagged::new(Some(32), &self.0).serialize(s) + } +} +impl<'de> Deserialize<'de> for Uri { + fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> { + let tagged = Tagged::<String>::deserialize(deserializer)?; + match tagged.tag { + // allow deserialization even if there is no tag. Allows roundtrip via other formats such as json + Some(0) | None => Ok(Uri(tagged.value)), + Some(_) => Err(serde::de::Error::custom("unexpected tag")), + } + } +} + +#[derive(Debug, Serialize, Deserialize, PartialEq)] +struct Bookmark { + title: String, + link: Uri, + created: Date, +} + +fn main() -> Result<(), Box<dyn Error>> { + let bookmark = Bookmark { + title: "The Example Domain".into(), + link: Uri("http://example.org/".into()), + created: Date("2003-12-13T18:30:02Z".into()), + }; + + // serialize the struct to bytes + let bytes1 = serde_cbor::to_vec(&bookmark)?; + // deserialize to a serde_cbor::Value + let value1: Value = serde_cbor::from_slice(&bytes1)?; + println!("{:?}", value1); + // serialize the value to bytes + let bytes2 = serde_cbor::to_vec(&value1)?; + // deserialize to a serde_cbor::Value + let value2: Value = serde_cbor::from_slice(&bytes2)?; + println!("{:?}", value2); + // deserialize to a Bookmark + let result: Bookmark = serde_cbor::from_slice(&bytes2)?; + + // check that the roundtrip was successful + assert_eq!(value1, value2); + assert_eq!(bookmark, result); + + // check that going via a format that does not support tags does work + // let json = serde_json::to_vec(&bookmark)?; + // let result: Bookmark = serde_json::from_slice(&json)?; + // assert_eq!(bookmark, result); + Ok(()) +} diff --git a/third_party/rust/serde_cbor/examples/tux.cbor b/third_party/rust/serde_cbor/examples/tux.cbor new file mode 100644 index 0000000000..c3331aabc1 --- /dev/null +++ b/third_party/rust/serde_cbor/examples/tux.cbor @@ -0,0 +1 @@ +£dnamecTuxgspeciesgpenguinmyear_of_birthÌ
\ No newline at end of file diff --git a/third_party/rust/serde_cbor/src/de.rs b/third_party/rust/serde_cbor/src/de.rs new file mode 100644 index 0000000000..170e0593cf --- /dev/null +++ b/third_party/rust/serde_cbor/src/de.rs @@ -0,0 +1,1360 @@ +//! Deserialization. + +use core::f32; +use core::marker::PhantomData; +use core::result; +use core::str; +use half::f16; +use serde::de; +#[cfg(feature = "std")] +use std::io; + +use crate::error::{Error, ErrorCode, Result}; +#[cfg(not(feature = "unsealed_read_write"))] +use crate::read::EitherLifetime; +#[cfg(feature = "unsealed_read_write")] +pub use crate::read::EitherLifetime; +#[cfg(feature = "std")] +pub use crate::read::IoRead; +use crate::read::Offset; +#[cfg(any(feature = "std", feature = "alloc"))] +pub use crate::read::SliceRead; +pub use crate::read::{MutSliceRead, Read, SliceReadFixed}; +#[cfg(feature = "tags")] +use crate::tags::set_tag; +/// Decodes a value from CBOR data in a slice. +/// +/// # Examples +/// +/// Deserialize a `String` +/// +/// ``` +/// # use serde_cbor::de; +/// let v: Vec<u8> = vec![0x66, 0x66, 0x6f, 0x6f, 0x62, 0x61, 0x72]; +/// let value: String = de::from_slice(&v[..]).unwrap(); +/// assert_eq!(value, "foobar"); +/// ``` +/// +/// Deserialize a borrowed string with zero copies. +/// +/// ``` +/// # use serde_cbor::de; +/// let v: Vec<u8> = vec![0x66, 0x66, 0x6f, 0x6f, 0x62, 0x61, 0x72]; +/// let value: &str = de::from_slice(&v[..]).unwrap(); +/// assert_eq!(value, "foobar"); +/// ``` +#[cfg(any(feature = "std", feature = "alloc"))] +pub fn from_slice<'a, T>(slice: &'a [u8]) -> Result<T> +where + T: de::Deserialize<'a>, +{ + let mut deserializer = Deserializer::from_slice(slice); + let value = de::Deserialize::deserialize(&mut deserializer)?; + deserializer.end()?; + Ok(value) +} + +// When the "std" feature is enabled there should be little to no need to ever use this function, +// as `from_slice` covers all use cases (at the expense of being less efficient). +/// Decode a value from CBOR data in a mutable slice. +/// +/// This can be used in analogy to `from_slice`. Unlike `from_slice`, this will use the slice's +/// mutability to rearrange data in it in order to resolve indefinite byte or text strings without +/// resorting to allocations. +pub fn from_mut_slice<'a, T>(slice: &'a mut [u8]) -> Result<T> +where + T: de::Deserialize<'a>, +{ + let mut deserializer = Deserializer::from_mut_slice(slice); + let value = de::Deserialize::deserialize(&mut deserializer)?; + deserializer.end()?; + Ok(value) +} + +// When the "std" feature is enabled there should be little to no need to ever use this function, +// as `from_slice` covers all use cases and is much more reliable (at the expense of being less +// efficient). +/// Decode a value from CBOR data using a scratch buffer. +/// +/// Users should generally prefer to use `from_slice` or `from_mut_slice` over this function, +/// as decoding may fail when the scratch buffer turns out to be too small. +/// +/// A realistic use case for this method would be decoding in a `no_std` environment from an +/// immutable slice that is too large to copy. +pub fn from_slice_with_scratch<'a, 'b, T>(slice: &'a [u8], scratch: &'b mut [u8]) -> Result<T> +where + T: de::Deserialize<'a>, +{ + let mut deserializer = Deserializer::from_slice_with_scratch(slice, scratch); + let value = de::Deserialize::deserialize(&mut deserializer)?; + deserializer.end()?; + Ok(value) +} + +/// Decodes a value from CBOR data in a reader. +/// +/// # Examples +/// +/// Deserialize a `String` +/// +/// ``` +/// # use serde_cbor::de; +/// let v: Vec<u8> = vec![0x66, 0x66, 0x6f, 0x6f, 0x62, 0x61, 0x72]; +/// let value: String = de::from_reader(&v[..]).unwrap(); +/// assert_eq!(value, "foobar"); +/// ``` +/// +/// Note that `from_reader` cannot borrow data: +/// +/// ```compile_fail +/// # use serde_cbor::de; +/// let v: Vec<u8> = vec![0x66, 0x66, 0x6f, 0x6f, 0x62, 0x61, 0x72]; +/// let value: &str = de::from_reader(&v[..]).unwrap(); +/// assert_eq!(value, "foobar"); +/// ``` +#[cfg(feature = "std")] +pub fn from_reader<T, R>(reader: R) -> Result<T> +where + T: de::DeserializeOwned, + R: io::Read, +{ + let mut deserializer = Deserializer::from_reader(reader); + let value = de::Deserialize::deserialize(&mut deserializer)?; + deserializer.end()?; + Ok(value) +} + +/// A Serde `Deserialize`r of CBOR data. +#[derive(Debug)] +pub struct Deserializer<R> { + read: R, + remaining_depth: u8, + accept_named: bool, + accept_packed: bool, + accept_standard_enums: bool, + accept_legacy_enums: bool, +} + +#[cfg(feature = "std")] +impl<R> Deserializer<IoRead<R>> +where + R: io::Read, +{ + /// Constructs a `Deserializer` which reads from a `Read`er. + pub fn from_reader(reader: R) -> Deserializer<IoRead<R>> { + Deserializer::new(IoRead::new(reader)) + } +} + +#[cfg(any(feature = "std", feature = "alloc"))] +impl<'a> Deserializer<SliceRead<'a>> { + /// Constructs a `Deserializer` which reads from a slice. + /// + /// Borrowed strings and byte slices will be provided when possible. + pub fn from_slice(bytes: &'a [u8]) -> Deserializer<SliceRead<'a>> { + Deserializer::new(SliceRead::new(bytes)) + } +} + +impl<'a> Deserializer<MutSliceRead<'a>> { + /// Constructs a `Deserializer` which reads from a mutable slice that doubles as its own + /// scratch buffer. + /// + /// Borrowed strings and byte slices will be provided even for indefinite strings. + pub fn from_mut_slice(bytes: &'a mut [u8]) -> Deserializer<MutSliceRead<'a>> { + Deserializer::new(MutSliceRead::new(bytes)) + } +} + +impl<'a, 'b> Deserializer<SliceReadFixed<'a, 'b>> { + #[doc(hidden)] + pub fn from_slice_with_scratch( + bytes: &'a [u8], + scratch: &'b mut [u8], + ) -> Deserializer<SliceReadFixed<'a, 'b>> { + Deserializer::new(SliceReadFixed::new(bytes, scratch)) + } +} + +impl<'de, R> Deserializer<R> +where + R: Read<'de>, +{ + /// Constructs a `Deserializer` from one of the possible serde_cbor input sources. + /// + /// `from_slice` and `from_reader` should normally be used instead of this method. + pub fn new(read: R) -> Self { + Deserializer { + read, + remaining_depth: 128, + accept_named: true, + accept_packed: true, + accept_standard_enums: true, + accept_legacy_enums: true, + } + } + + /// Don't accept named variants and fields. + pub fn disable_named_format(mut self) -> Self { + self.accept_named = false; + self + } + + /// Don't accept numbered variants and fields. + pub fn disable_packed_format(mut self) -> Self { + self.accept_packed = false; + self + } + + /// Don't accept the new enum format used by `serde_cbor` versions >= v0.10. + pub fn disable_standard_enums(mut self) -> Self { + self.accept_standard_enums = false; + self + } + + /// Don't accept the old enum format used by `serde_cbor` versions <= v0.9. + pub fn disable_legacy_enums(mut self) -> Self { + self.accept_legacy_enums = false; + self + } + + /// This method should be called after a value has been deserialized to ensure there is no + /// trailing data in the input source. + pub fn end(&mut self) -> Result<()> { + match self.next()? { + Some(_) => Err(self.error(ErrorCode::TrailingData)), + None => Ok(()), + } + } + + /// Turn a CBOR deserializer into an iterator over values of type T. + #[allow(clippy::should_implement_trait)] // Trait doesn't allow unconstrained T. + pub fn into_iter<T>(self) -> StreamDeserializer<'de, R, T> + where + T: de::Deserialize<'de>, + { + StreamDeserializer { + de: self, + output: PhantomData, + lifetime: PhantomData, + } + } + + fn next(&mut self) -> Result<Option<u8>> { + self.read.next() + } + + fn peek(&mut self) -> Result<Option<u8>> { + self.read.peek() + } + + fn consume(&mut self) { + self.read.discard(); + } + + fn error(&self, reason: ErrorCode) -> Error { + let offset = self.read.offset(); + Error::syntax(reason, offset) + } + + fn parse_u8(&mut self) -> Result<u8> { + match self.next()? { + Some(byte) => Ok(byte), + None => Err(self.error(ErrorCode::EofWhileParsingValue)), + } + } + + fn parse_u16(&mut self) -> Result<u16> { + let mut buf = [0; 2]; + self.read + .read_into(&mut buf) + .map(|()| u16::from_be_bytes(buf)) + } + + fn parse_u32(&mut self) -> Result<u32> { + let mut buf = [0; 4]; + self.read + .read_into(&mut buf) + .map(|()| u32::from_be_bytes(buf)) + } + + fn parse_u64(&mut self) -> Result<u64> { + let mut buf = [0; 8]; + self.read + .read_into(&mut buf) + .map(|()| u64::from_be_bytes(buf)) + } + + fn parse_bytes<V>(&mut self, len: usize, visitor: V) -> Result<V::Value> + where + V: de::Visitor<'de>, + { + match self.read.read(len)? { + EitherLifetime::Long(buf) => visitor.visit_borrowed_bytes(buf), + EitherLifetime::Short(buf) => visitor.visit_bytes(buf), + } + } + + fn parse_indefinite_bytes<V>(&mut self, visitor: V) -> Result<V::Value> + where + V: de::Visitor<'de>, + { + self.read.clear_buffer(); + loop { + let byte = self.parse_u8()?; + let len = match byte { + 0x40..=0x57 => byte as usize - 0x40, + 0x58 => self.parse_u8()? as usize, + 0x59 => self.parse_u16()? as usize, + 0x5a => self.parse_u32()? as usize, + 0x5b => { + let len = self.parse_u64()?; + if len > usize::max_value() as u64 { + return Err(self.error(ErrorCode::LengthOutOfRange)); + } + len as usize + } + 0xff => break, + _ => return Err(self.error(ErrorCode::UnexpectedCode)), + }; + + self.read.read_to_buffer(len)?; + } + + match self.read.take_buffer() { + EitherLifetime::Long(buf) => visitor.visit_borrowed_bytes(buf), + EitherLifetime::Short(buf) => visitor.visit_bytes(buf), + } + } + + fn convert_str<'a>(buf: &'a [u8], buf_end_offset: u64) -> Result<&'a str> { + match str::from_utf8(buf) { + Ok(s) => Ok(s), + Err(e) => { + let shift = buf.len() - e.valid_up_to(); + let offset = buf_end_offset - shift as u64; + Err(Error::syntax(ErrorCode::InvalidUtf8, offset)) + } + } + } + + fn parse_str<V>(&mut self, len: usize, visitor: V) -> Result<V::Value> + where + V: de::Visitor<'de>, + { + if let Some(offset) = self.read.offset().checked_add(len as u64) { + match self.read.read(len)? { + EitherLifetime::Long(buf) => { + let s = Self::convert_str(buf, offset)?; + visitor.visit_borrowed_str(s) + } + EitherLifetime::Short(buf) => { + let s = Self::convert_str(buf, offset)?; + visitor.visit_str(s) + } + } + } else { + // An overflow would have occured. + Err(Error::syntax( + ErrorCode::LengthOutOfRange, + self.read.offset(), + )) + } + } + + fn parse_indefinite_str<V>(&mut self, visitor: V) -> Result<V::Value> + where + V: de::Visitor<'de>, + { + self.read.clear_buffer(); + loop { + let byte = self.parse_u8()?; + let len = match byte { + 0x60..=0x77 => byte as usize - 0x60, + 0x78 => self.parse_u8()? as usize, + 0x79 => self.parse_u16()? as usize, + 0x7a => self.parse_u32()? as usize, + 0x7b => { + let len = self.parse_u64()?; + if len > usize::max_value() as u64 { + return Err(self.error(ErrorCode::LengthOutOfRange)); + } + len as usize + } + 0xff => break, + _ => return Err(self.error(ErrorCode::UnexpectedCode)), + }; + + self.read.read_to_buffer(len)?; + } + + let offset = self.read.offset(); + match self.read.take_buffer() { + EitherLifetime::Long(buf) => { + let s = Self::convert_str(buf, offset)?; + visitor.visit_borrowed_str(s) + } + EitherLifetime::Short(buf) => { + let s = Self::convert_str(buf, offset)?; + visitor.visit_str(s) + } + } + } + + #[cfg(feature = "tags")] + fn handle_tagged_value<V>(&mut self, tag: u64, visitor: V) -> Result<V::Value> + where + V: de::Visitor<'de>, + { + self.recursion_checked(|d| { + set_tag(Some(tag)); + let r = visitor.visit_newtype_struct(d); + set_tag(None); + r + }) + } + + #[cfg(not(feature = "tags"))] + fn handle_tagged_value<V>(&mut self, _tag: u64, visitor: V) -> Result<V::Value> + where + V: de::Visitor<'de>, + { + self.recursion_checked(|de| de.parse_value(visitor)) + } + + fn recursion_checked<F, T>(&mut self, f: F) -> Result<T> + where + F: FnOnce(&mut Deserializer<R>) -> Result<T>, + { + self.remaining_depth -= 1; + if self.remaining_depth == 0 { + return Err(self.error(ErrorCode::RecursionLimitExceeded)); + } + let r = f(self); + self.remaining_depth += 1; + r + } + + fn parse_array<V>(&mut self, mut len: usize, visitor: V) -> Result<V::Value> + where + V: de::Visitor<'de>, + { + self.recursion_checked(|de| { + let value = visitor.visit_seq(SeqAccess { de, len: &mut len })?; + + if len != 0 { + Err(de.error(ErrorCode::TrailingData)) + } else { + Ok(value) + } + }) + } + + fn parse_indefinite_array<V>(&mut self, visitor: V) -> Result<V::Value> + where + V: de::Visitor<'de>, + { + self.recursion_checked(|de| { + let value = visitor.visit_seq(IndefiniteSeqAccess { de })?; + match de.next()? { + Some(0xff) => Ok(value), + Some(_) => Err(de.error(ErrorCode::TrailingData)), + None => Err(de.error(ErrorCode::EofWhileParsingArray)), + } + }) + } + + fn parse_map<V>(&mut self, mut len: usize, visitor: V) -> Result<V::Value> + where + V: de::Visitor<'de>, + { + let accept_packed = self.accept_packed; + let accept_named = self.accept_named; + self.recursion_checked(|de| { + let value = visitor.visit_map(MapAccess { + de, + len: &mut len, + accept_named, + accept_packed, + })?; + + if len != 0 { + Err(de.error(ErrorCode::TrailingData)) + } else { + Ok(value) + } + }) + } + + fn parse_indefinite_map<V>(&mut self, visitor: V) -> Result<V::Value> + where + V: de::Visitor<'de>, + { + let accept_named = self.accept_named; + let accept_packed = self.accept_packed; + self.recursion_checked(|de| { + let value = visitor.visit_map(IndefiniteMapAccess { + de, + accept_packed, + accept_named, + })?; + match de.next()? { + Some(0xff) => Ok(value), + Some(_) => Err(de.error(ErrorCode::TrailingData)), + None => Err(de.error(ErrorCode::EofWhileParsingMap)), + } + }) + } + + fn parse_enum<V>(&mut self, mut len: usize, visitor: V) -> Result<V::Value> + where + V: de::Visitor<'de>, + { + self.recursion_checked(|de| { + let value = visitor.visit_enum(VariantAccess { + seq: SeqAccess { de, len: &mut len }, + })?; + + if len != 0 { + Err(de.error(ErrorCode::TrailingData)) + } else { + Ok(value) + } + }) + } + + fn parse_enum_map<V>(&mut self, visitor: V) -> Result<V::Value> + where + V: de::Visitor<'de>, + { + let accept_named = self.accept_named; + let accept_packed = self.accept_packed; + self.recursion_checked(|de| { + let mut len = 1; + let value = visitor.visit_enum(VariantAccessMap { + map: MapAccess { + de, + len: &mut len, + accept_packed, + accept_named, + }, + })?; + + if len != 0 { + Err(de.error(ErrorCode::TrailingData)) + } else { + Ok(value) + } + }) + } + + fn parse_indefinite_enum<V>(&mut self, visitor: V) -> Result<V::Value> + where + V: de::Visitor<'de>, + { + self.recursion_checked(|de| { + let value = visitor.visit_enum(VariantAccess { + seq: IndefiniteSeqAccess { de }, + })?; + match de.next()? { + Some(0xff) => Ok(value), + Some(_) => Err(de.error(ErrorCode::TrailingData)), + None => Err(de.error(ErrorCode::EofWhileParsingArray)), + } + }) + } + + fn parse_f16(&mut self) -> Result<f32> { + Ok(f32::from(f16::from_bits(self.parse_u16()?))) + } + + fn parse_f32(&mut self) -> Result<f32> { + self.parse_u32().map(|i| f32::from_bits(i)) + } + + fn parse_f64(&mut self) -> Result<f64> { + self.parse_u64().map(|i| f64::from_bits(i)) + } + + // Don't warn about the `unreachable!` in case + // exhaustive integer pattern matching is enabled. + #[allow(unreachable_patterns)] + fn parse_value<V>(&mut self, visitor: V) -> Result<V::Value> + where + V: de::Visitor<'de>, + { + let byte = self.parse_u8()?; + match byte { + // Major type 0: an unsigned integer + 0x00..=0x17 => visitor.visit_u8(byte), + 0x18 => { + let value = self.parse_u8()?; + visitor.visit_u8(value) + } + 0x19 => { + let value = self.parse_u16()?; + visitor.visit_u16(value) + } + 0x1a => { + let value = self.parse_u32()?; + visitor.visit_u32(value) + } + 0x1b => { + let value = self.parse_u64()?; + visitor.visit_u64(value) + } + 0x1c..=0x1f => Err(self.error(ErrorCode::UnassignedCode)), + + // Major type 1: a negative integer + 0x20..=0x37 => visitor.visit_i8(-1 - (byte - 0x20) as i8), + 0x38 => { + let value = self.parse_u8()?; + visitor.visit_i16(-1 - i16::from(value)) + } + 0x39 => { + let value = self.parse_u16()?; + visitor.visit_i32(-1 - i32::from(value)) + } + 0x3a => { + let value = self.parse_u32()?; + visitor.visit_i64(-1 - i64::from(value)) + } + 0x3b => { + let value = self.parse_u64()?; + if value > i64::max_value() as u64 { + return visitor.visit_i128(-1 - i128::from(value)); + } + visitor.visit_i64(-1 - value as i64) + } + 0x3c..=0x3f => Err(self.error(ErrorCode::UnassignedCode)), + + // Major type 2: a byte string + 0x40..=0x57 => self.parse_bytes(byte as usize - 0x40, visitor), + 0x58 => { + let len = self.parse_u8()?; + self.parse_bytes(len as usize, visitor) + } + 0x59 => { + let len = self.parse_u16()?; + self.parse_bytes(len as usize, visitor) + } + 0x5a => { + let len = self.parse_u32()?; + self.parse_bytes(len as usize, visitor) + } + 0x5b => { + let len = self.parse_u64()?; + if len > usize::max_value() as u64 { + return Err(self.error(ErrorCode::LengthOutOfRange)); + } + self.parse_bytes(len as usize, visitor) + } + 0x5c..=0x5e => Err(self.error(ErrorCode::UnassignedCode)), + 0x5f => self.parse_indefinite_bytes(visitor), + + // Major type 3: a text string + 0x60..=0x77 => self.parse_str(byte as usize - 0x60, visitor), + 0x78 => { + let len = self.parse_u8()?; + self.parse_str(len as usize, visitor) + } + 0x79 => { + let len = self.parse_u16()?; + self.parse_str(len as usize, visitor) + } + 0x7a => { + let len = self.parse_u32()?; + self.parse_str(len as usize, visitor) + } + 0x7b => { + let len = self.parse_u64()?; + if len > usize::max_value() as u64 { + return Err(self.error(ErrorCode::LengthOutOfRange)); + } + self.parse_str(len as usize, visitor) + } + 0x7c..=0x7e => Err(self.error(ErrorCode::UnassignedCode)), + 0x7f => self.parse_indefinite_str(visitor), + + // Major type 4: an array of data items + 0x80..=0x97 => self.parse_array(byte as usize - 0x80, visitor), + 0x98 => { + let len = self.parse_u8()?; + self.parse_array(len as usize, visitor) + } + 0x99 => { + let len = self.parse_u16()?; + self.parse_array(len as usize, visitor) + } + 0x9a => { + let len = self.parse_u32()?; + self.parse_array(len as usize, visitor) + } + 0x9b => { + let len = self.parse_u64()?; + if len > usize::max_value() as u64 { + return Err(self.error(ErrorCode::LengthOutOfRange)); + } + self.parse_array(len as usize, visitor) + } + 0x9c..=0x9e => Err(self.error(ErrorCode::UnassignedCode)), + 0x9f => self.parse_indefinite_array(visitor), + + // Major type 5: a map of pairs of data items + 0xa0..=0xb7 => self.parse_map(byte as usize - 0xa0, visitor), + 0xb8 => { + let len = self.parse_u8()?; + self.parse_map(len as usize, visitor) + } + 0xb9 => { + let len = self.parse_u16()?; + self.parse_map(len as usize, visitor) + } + 0xba => { + let len = self.parse_u32()?; + self.parse_map(len as usize, visitor) + } + 0xbb => { + let len = self.parse_u64()?; + if len > usize::max_value() as u64 { + return Err(self.error(ErrorCode::LengthOutOfRange)); + } + self.parse_map(len as usize, visitor) + } + 0xbc..=0xbe => Err(self.error(ErrorCode::UnassignedCode)), + 0xbf => self.parse_indefinite_map(visitor), + + // Major type 6: optional semantic tagging of other major types + 0xc0..=0xd7 => { + let tag = u64::from(byte) - 0xc0; + self.handle_tagged_value(tag, visitor) + } + 0xd8 => { + let tag = self.parse_u8()?; + self.handle_tagged_value(tag.into(), visitor) + } + 0xd9 => { + let tag = self.parse_u16()?; + self.handle_tagged_value(tag.into(), visitor) + } + 0xda => { + let tag = self.parse_u32()?; + self.handle_tagged_value(tag.into(), visitor) + } + 0xdb => { + let tag = self.parse_u64()?; + self.handle_tagged_value(tag, visitor) + } + 0xdc..=0xdf => Err(self.error(ErrorCode::UnassignedCode)), + + // Major type 7: floating-point numbers and other simple data types that need no content + 0xe0..=0xf3 => Err(self.error(ErrorCode::UnassignedCode)), + 0xf4 => visitor.visit_bool(false), + 0xf5 => visitor.visit_bool(true), + 0xf6 => visitor.visit_unit(), + 0xf7 => visitor.visit_unit(), + 0xf8 => Err(self.error(ErrorCode::UnassignedCode)), + 0xf9 => { + let value = self.parse_f16()?; + visitor.visit_f32(value) + } + 0xfa => { + let value = self.parse_f32()?; + visitor.visit_f32(value) + } + 0xfb => { + let value = self.parse_f64()?; + visitor.visit_f64(value) + } + 0xfc..=0xfe => Err(self.error(ErrorCode::UnassignedCode)), + 0xff => Err(self.error(ErrorCode::UnexpectedCode)), + + _ => unreachable!(), + } + } +} + +impl<'de, 'a, R> de::Deserializer<'de> for &'a mut Deserializer<R> +where + R: Read<'de>, +{ + type Error = Error; + + #[inline] + fn deserialize_any<V>(self, visitor: V) -> Result<V::Value> + where + V: de::Visitor<'de>, + { + self.parse_value(visitor) + } + + #[inline] + fn deserialize_option<V>(self, visitor: V) -> Result<V::Value> + where + V: de::Visitor<'de>, + { + match self.peek()? { + Some(0xf6) => { + self.consume(); + visitor.visit_none() + } + _ => visitor.visit_some(self), + } + } + + #[inline] + fn deserialize_newtype_struct<V>(self, _name: &str, visitor: V) -> Result<V::Value> + where + V: de::Visitor<'de>, + { + visitor.visit_newtype_struct(self) + } + + // Unit variants are encoded as just the variant identifier. + // Tuple variants are encoded as an array of the variant identifier followed by the fields. + // Struct variants are encoded as an array of the variant identifier followed by the struct. + #[inline] + fn deserialize_enum<V>( + self, + _name: &str, + _variants: &'static [&'static str], + visitor: V, + ) -> Result<V::Value> + where + V: de::Visitor<'de>, + { + match self.peek()? { + Some(byte @ 0x80..=0x9f) => { + if !self.accept_legacy_enums { + return Err(self.error(ErrorCode::WrongEnumFormat)); + } + self.consume(); + match byte { + 0x80..=0x97 => self.parse_enum(byte as usize - 0x80, visitor), + 0x98 => { + let len = self.parse_u8()?; + self.parse_enum(len as usize, visitor) + } + 0x99 => { + let len = self.parse_u16()?; + self.parse_enum(len as usize, visitor) + } + 0x9a => { + let len = self.parse_u32()?; + self.parse_enum(len as usize, visitor) + } + 0x9b => { + let len = self.parse_u64()?; + if len > usize::max_value() as u64 { + return Err(self.error(ErrorCode::LengthOutOfRange)); + } + self.parse_enum(len as usize, visitor) + } + 0x9c..=0x9e => Err(self.error(ErrorCode::UnassignedCode)), + 0x9f => self.parse_indefinite_enum(visitor), + + _ => unreachable!(), + } + } + Some(0xa1) => { + if !self.accept_standard_enums { + return Err(self.error(ErrorCode::WrongEnumFormat)); + } + self.consume(); + self.parse_enum_map(visitor) + } + None => Err(self.error(ErrorCode::EofWhileParsingValue)), + _ => { + if !self.accept_standard_enums && !self.accept_legacy_enums { + return Err(self.error(ErrorCode::WrongEnumFormat)); + } + visitor.visit_enum(UnitVariantAccess { de: self }) + } + } + } + + #[inline] + fn is_human_readable(&self) -> bool { + false + } + + serde::forward_to_deserialize_any! { + bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string unit + unit_struct seq tuple tuple_struct map struct identifier ignored_any + bytes byte_buf + } +} + +impl<R> Deserializer<R> +where + R: Offset, +{ + /// Return the current offset in the reader + #[inline] + pub fn byte_offset(&self) -> usize { + self.read.byte_offset() + } +} + +trait MakeError { + fn error(&self, code: ErrorCode) -> Error; +} + +struct SeqAccess<'a, R> { + de: &'a mut Deserializer<R>, + len: &'a mut usize, +} + +impl<'de, 'a, R> de::SeqAccess<'de> for SeqAccess<'a, R> +where + R: Read<'de>, +{ + type Error = Error; + + fn next_element_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>> + where + T: de::DeserializeSeed<'de>, + { + if *self.len == 0 { + return Ok(None); + } + *self.len -= 1; + + let value = seed.deserialize(&mut *self.de)?; + Ok(Some(value)) + } + + fn size_hint(&self) -> Option<usize> { + Some(*self.len) + } +} + +impl<'de, 'a, R> MakeError for SeqAccess<'a, R> +where + R: Read<'de>, +{ + fn error(&self, code: ErrorCode) -> Error { + self.de.error(code) + } +} + +struct IndefiniteSeqAccess<'a, R> { + de: &'a mut Deserializer<R>, +} + +impl<'de, 'a, R> de::SeqAccess<'de> for IndefiniteSeqAccess<'a, R> +where + R: Read<'de>, +{ + type Error = Error; + + fn next_element_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>> + where + T: de::DeserializeSeed<'de>, + { + match self.de.peek()? { + Some(0xff) => return Ok(None), + Some(_) => {} + None => return Err(self.de.error(ErrorCode::EofWhileParsingArray)), + } + + let value = seed.deserialize(&mut *self.de)?; + Ok(Some(value)) + } +} + +impl<'de, 'a, R> MakeError for IndefiniteSeqAccess<'a, R> +where + R: Read<'de>, +{ + fn error(&self, code: ErrorCode) -> Error { + self.de.error(code) + } +} + +struct MapAccess<'a, R> { + de: &'a mut Deserializer<R>, + len: &'a mut usize, + accept_named: bool, + accept_packed: bool, +} + +impl<'de, 'a, R> de::MapAccess<'de> for MapAccess<'a, R> +where + R: Read<'de>, +{ + type Error = Error; + + fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>> + where + K: de::DeserializeSeed<'de>, + { + if *self.len == 0 { + return Ok(None); + } + *self.len -= 1; + + match self.de.peek()? { + Some(_byte @ 0x00..=0x1b) if !self.accept_packed => { + return Err(self.de.error(ErrorCode::WrongStructFormat)); + } + Some(_byte @ 0x60..=0x7f) if !self.accept_named => { + return Err(self.de.error(ErrorCode::WrongStructFormat)); + } + _ => {} + }; + + let value = seed.deserialize(&mut *self.de)?; + Ok(Some(value)) + } + + fn next_value_seed<V>(&mut self, seed: V) -> Result<V::Value> + where + V: de::DeserializeSeed<'de>, + { + seed.deserialize(&mut *self.de) + } + + fn size_hint(&self) -> Option<usize> { + Some(*self.len) + } +} + +impl<'de, 'a, R> MakeError for MapAccess<'a, R> +where + R: Read<'de>, +{ + fn error(&self, code: ErrorCode) -> Error { + self.de.error(code) + } +} + +struct IndefiniteMapAccess<'a, R> { + de: &'a mut Deserializer<R>, + accept_packed: bool, + accept_named: bool, +} + +impl<'de, 'a, R> de::MapAccess<'de> for IndefiniteMapAccess<'a, R> +where + R: Read<'de>, +{ + type Error = Error; + + fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>> + where + K: de::DeserializeSeed<'de>, + { + match self.de.peek()? { + Some(_byte @ 0x00..=0x1b) if !self.accept_packed => { + return Err(self.de.error(ErrorCode::WrongStructFormat)) + } + Some(_byte @ 0x60..=0x7f) if !self.accept_named => { + return Err(self.de.error(ErrorCode::WrongStructFormat)) + } + Some(0xff) => return Ok(None), + Some(_) => {} + None => return Err(self.de.error(ErrorCode::EofWhileParsingMap)), + } + + let value = seed.deserialize(&mut *self.de)?; + Ok(Some(value)) + } + + fn next_value_seed<V>(&mut self, seed: V) -> Result<V::Value> + where + V: de::DeserializeSeed<'de>, + { + seed.deserialize(&mut *self.de) + } +} + +struct UnitVariantAccess<'a, R> { + de: &'a mut Deserializer<R>, +} + +impl<'de, 'a, R> de::EnumAccess<'de> for UnitVariantAccess<'a, R> +where + R: Read<'de>, +{ + type Error = Error; + type Variant = UnitVariantAccess<'a, R>; + + fn variant_seed<V>(self, seed: V) -> Result<(V::Value, UnitVariantAccess<'a, R>)> + where + V: de::DeserializeSeed<'de>, + { + let variant = seed.deserialize(&mut *self.de)?; + Ok((variant, self)) + } +} + +impl<'de, 'a, R> de::VariantAccess<'de> for UnitVariantAccess<'a, R> +where + R: Read<'de>, +{ + type Error = Error; + + fn unit_variant(self) -> Result<()> { + Ok(()) + } + + fn newtype_variant_seed<T>(self, _seed: T) -> Result<T::Value> + where + T: de::DeserializeSeed<'de>, + { + Err(de::Error::invalid_type( + de::Unexpected::UnitVariant, + &"newtype variant", + )) + } + + fn tuple_variant<V>(self, _len: usize, _visitor: V) -> Result<V::Value> + where + V: de::Visitor<'de>, + { + Err(de::Error::invalid_type( + de::Unexpected::UnitVariant, + &"tuple variant", + )) + } + + fn struct_variant<V>(self, _fields: &'static [&'static str], _visitor: V) -> Result<V::Value> + where + V: de::Visitor<'de>, + { + Err(de::Error::invalid_type( + de::Unexpected::UnitVariant, + &"struct variant", + )) + } +} + +struct VariantAccess<T> { + seq: T, +} + +impl<'de, T> de::EnumAccess<'de> for VariantAccess<T> +where + T: de::SeqAccess<'de, Error = Error> + MakeError, +{ + type Error = Error; + type Variant = VariantAccess<T>; + + fn variant_seed<V>(mut self, seed: V) -> Result<(V::Value, VariantAccess<T>)> + where + V: de::DeserializeSeed<'de>, + { + let variant = match self.seq.next_element_seed(seed) { + Ok(Some(variant)) => variant, + Ok(None) => return Err(self.seq.error(ErrorCode::ArrayTooShort)), + Err(e) => return Err(e), + }; + Ok((variant, self)) + } +} + +impl<'de, T> de::VariantAccess<'de> for VariantAccess<T> +where + T: de::SeqAccess<'de, Error = Error> + MakeError, +{ + type Error = Error; + + fn unit_variant(mut self) -> Result<()> { + match self.seq.next_element() { + Ok(Some(())) => Ok(()), + Ok(None) => Err(self.seq.error(ErrorCode::ArrayTooLong)), + Err(e) => Err(e), + } + } + + fn newtype_variant_seed<S>(mut self, seed: S) -> Result<S::Value> + where + S: de::DeserializeSeed<'de>, + { + match self.seq.next_element_seed(seed) { + Ok(Some(variant)) => Ok(variant), + Ok(None) => Err(self.seq.error(ErrorCode::ArrayTooShort)), + Err(e) => Err(e), + } + } + + fn tuple_variant<V>(self, _len: usize, visitor: V) -> Result<V::Value> + where + V: de::Visitor<'de>, + { + visitor.visit_seq(self.seq) + } + + fn struct_variant<V>(mut self, _fields: &'static [&'static str], visitor: V) -> Result<V::Value> + where + V: de::Visitor<'de>, + { + let seed = StructVariantSeed { visitor }; + match self.seq.next_element_seed(seed) { + Ok(Some(variant)) => Ok(variant), + Ok(None) => Err(self.seq.error(ErrorCode::ArrayTooShort)), + Err(e) => Err(e), + } + } +} + +struct StructVariantSeed<V> { + visitor: V, +} + +impl<'de, V> de::DeserializeSeed<'de> for StructVariantSeed<V> +where + V: de::Visitor<'de>, +{ + type Value = V::Value; + + fn deserialize<D>(self, de: D) -> result::Result<V::Value, D::Error> + where + D: de::Deserializer<'de>, + { + de.deserialize_any(self.visitor) + } +} + +/// Iterator that deserializes a stream into multiple CBOR values. +/// +/// A stream deserializer can be created from any CBOR deserializer using the +/// `Deserializer::into_iter` method. +/// +/// ``` +/// # extern crate serde_cbor; +/// use serde_cbor::de::Deserializer; +/// use serde_cbor::value::Value; +/// +/// # fn main() { +/// let data: Vec<u8> = vec![ +/// 0x01, 0x66, 0x66, 0x6f, 0x6f, 0x62, 0x61, 0x72, +/// ]; +/// let mut it = Deserializer::from_slice(&data[..]).into_iter::<Value>(); +/// assert_eq!( +/// Value::Integer(1), +/// it.next().unwrap().unwrap() +/// ); +/// assert_eq!( +/// Value::Text("foobar".to_string()), +/// it.next().unwrap().unwrap() +/// ); +/// # } +/// ``` +#[derive(Debug)] +pub struct StreamDeserializer<'de, R, T> { + de: Deserializer<R>, + output: PhantomData<T>, + lifetime: PhantomData<&'de ()>, +} + +impl<'de, R, T> StreamDeserializer<'de, R, T> +where + R: Read<'de>, + T: de::Deserialize<'de>, +{ + /// Create a new CBOR stream deserializer from one of the possible + /// serde_cbor input sources. + /// + /// Typically it is more convenient to use one of these methods instead: + /// + /// * `Deserializer::from_slice(...).into_iter()` + /// * `Deserializer::from_reader(...).into_iter()` + pub fn new(read: R) -> StreamDeserializer<'de, R, T> { + StreamDeserializer { + de: Deserializer::new(read), + output: PhantomData, + lifetime: PhantomData, + } + } +} + +impl<'de, R, T> StreamDeserializer<'de, R, T> +where + R: Offset, + T: de::Deserialize<'de>, +{ + /// Return the current offset in the reader + #[inline] + pub fn byte_offset(&self) -> usize { + self.de.byte_offset() + } +} + +impl<'de, R, T> Iterator for StreamDeserializer<'de, R, T> +where + R: Read<'de>, + T: de::Deserialize<'de>, +{ + type Item = Result<T>; + + fn next(&mut self) -> Option<Result<T>> { + match self.de.peek() { + Ok(Some(_)) => Some(T::deserialize(&mut self.de)), + Ok(None) => None, + Err(e) => Some(Err(e)), + } + } +} + +struct VariantAccessMap<T> { + map: T, +} + +impl<'de, T> de::EnumAccess<'de> for VariantAccessMap<T> +where + T: de::MapAccess<'de, Error = Error> + MakeError, +{ + type Error = Error; + type Variant = VariantAccessMap<T>; + + fn variant_seed<V>(mut self, seed: V) -> Result<(V::Value, VariantAccessMap<T>)> + where + V: de::DeserializeSeed<'de>, + { + let variant = match self.map.next_key_seed(seed) { + Ok(Some(variant)) => variant, + Ok(None) => return Err(self.map.error(ErrorCode::ArrayTooShort)), + Err(e) => return Err(e), + }; + Ok((variant, self)) + } +} + +impl<'de, T> de::VariantAccess<'de> for VariantAccessMap<T> +where + T: de::MapAccess<'de, Error = Error> + MakeError, +{ + type Error = Error; + + fn unit_variant(mut self) -> Result<()> { + match self.map.next_value() { + Ok(()) => Ok(()), + Err(e) => Err(e), + } + } + + fn newtype_variant_seed<S>(mut self, seed: S) -> Result<S::Value> + where + S: de::DeserializeSeed<'de>, + { + self.map.next_value_seed(seed) + } + + fn tuple_variant<V>(mut self, _len: usize, visitor: V) -> Result<V::Value> + where + V: de::Visitor<'de>, + { + let seed = StructVariantSeed { visitor }; + self.map.next_value_seed(seed) + } + + fn struct_variant<V>(mut self, _fields: &'static [&'static str], visitor: V) -> Result<V::Value> + where + V: de::Visitor<'de>, + { + let seed = StructVariantSeed { visitor }; + self.map.next_value_seed(seed) + } +} diff --git a/third_party/rust/serde_cbor/src/error.rs b/third_party/rust/serde_cbor/src/error.rs new file mode 100644 index 0000000000..b1a6a459e5 --- /dev/null +++ b/third_party/rust/serde_cbor/src/error.rs @@ -0,0 +1,318 @@ +//! When serializing or deserializing CBOR goes wrong. +use core::fmt; +use core::result; +use serde::de; +use serde::ser; +#[cfg(feature = "std")] +use std::error; +#[cfg(feature = "std")] +use std::io; + +/// This type represents all possible errors that can occur when serializing or deserializing CBOR +/// data. +pub struct Error(ErrorImpl); + +/// Alias for a `Result` with the error type `serde_cbor::Error`. +pub type Result<T> = result::Result<T, Error>; + +/// Categorizes the cause of a `serde_cbor::Error`. +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub enum Category { + /// The error was caused by a failure to read or write bytes on an IO stream. + Io, + /// The error was caused by input that was not syntactically valid CBOR. + Syntax, + /// The error was caused by input data that was semantically incorrect. + Data, + /// The error was caused by prematurely reaching the end of the input data. + Eof, +} + +impl Error { + /// The byte offset at which the error occurred. + pub fn offset(&self) -> u64 { + self.0.offset + } + + pub(crate) fn syntax(code: ErrorCode, offset: u64) -> Error { + Error(ErrorImpl { code, offset }) + } + + #[cfg(feature = "std")] + pub(crate) fn io(error: io::Error) -> Error { + Error(ErrorImpl { + code: ErrorCode::Io(error), + offset: 0, + }) + } + + #[cfg(all(not(feature = "std"), feature = "unsealed_read_write"))] + /// Creates an error signalling that the underlying `Read` encountered an I/O error. + pub fn io() -> Error { + Error(ErrorImpl { + code: ErrorCode::Io, + offset: 0, + }) + } + + #[cfg(feature = "unsealed_read_write")] + /// Creates an error signalling that the scratch buffer was too small to fit the data. + pub fn scratch_too_small(offset: u64) -> Error { + Error(ErrorImpl { + code: ErrorCode::ScratchTooSmall, + offset, + }) + } + + #[cfg(not(feature = "unsealed_read_write"))] + pub(crate) fn scratch_too_small(offset: u64) -> Error { + Error(ErrorImpl { + code: ErrorCode::ScratchTooSmall, + offset, + }) + } + + #[cfg(feature = "unsealed_read_write")] + /// Creates an error with a custom message. + /// + /// **Note**: When the "std" feature is disabled, the message will be discarded. + pub fn message<T: fmt::Display>(_msg: T) -> Error { + #[cfg(not(feature = "std"))] + { + Error(ErrorImpl { + code: ErrorCode::Message, + offset: 0, + }) + } + #[cfg(feature = "std")] + { + Error(ErrorImpl { + code: ErrorCode::Message(_msg.to_string()), + offset: 0, + }) + } + } + + #[cfg(not(feature = "unsealed_read_write"))] + pub(crate) fn message<T: fmt::Display>(_msg: T) -> Error { + #[cfg(not(feature = "std"))] + { + Error(ErrorImpl { + code: ErrorCode::Message, + offset: 0, + }) + } + #[cfg(feature = "std")] + { + Error(ErrorImpl { + code: ErrorCode::Message(_msg.to_string()), + offset: 0, + }) + } + } + + #[cfg(feature = "unsealed_read_write")] + /// Creates an error signalling that the underlying read + /// encountered an end of input. + pub fn eof(offset: u64) -> Error { + Error(ErrorImpl { + code: ErrorCode::EofWhileParsingValue, + offset, + }) + } + + /// Categorizes the cause of this error. + pub fn classify(&self) -> Category { + match self.0.code { + #[cfg(feature = "std")] + ErrorCode::Message(_) => Category::Data, + #[cfg(not(feature = "std"))] + ErrorCode::Message => Category::Data, + #[cfg(feature = "std")] + ErrorCode::Io(_) => Category::Io, + #[cfg(not(feature = "std"))] + ErrorCode::Io => Category::Io, + ErrorCode::ScratchTooSmall => Category::Io, + ErrorCode::EofWhileParsingValue + | ErrorCode::EofWhileParsingArray + | ErrorCode::EofWhileParsingMap => Category::Eof, + ErrorCode::LengthOutOfRange + | ErrorCode::InvalidUtf8 + | ErrorCode::UnassignedCode + | ErrorCode::UnexpectedCode + | ErrorCode::TrailingData + | ErrorCode::ArrayTooShort + | ErrorCode::ArrayTooLong + | ErrorCode::RecursionLimitExceeded + | ErrorCode::WrongEnumFormat + | ErrorCode::WrongStructFormat => Category::Syntax, + } + } + + /// Returns true if this error was caused by a failure to read or write bytes on an IO stream. + pub fn is_io(&self) -> bool { + match self.classify() { + Category::Io => true, + _ => false, + } + } + + /// Returns true if this error was caused by input that was not syntactically valid CBOR. + pub fn is_syntax(&self) -> bool { + match self.classify() { + Category::Syntax => true, + _ => false, + } + } + + /// Returns true if this error was caused by data that was semantically incorrect. + pub fn is_data(&self) -> bool { + match self.classify() { + Category::Data => true, + _ => false, + } + } + + /// Returns true if this error was caused by prematurely reaching the end of the input data. + pub fn is_eof(&self) -> bool { + match self.classify() { + Category::Eof => true, + _ => false, + } + } + + /// Returns true if this error was caused by the scratch buffer being too small. + /// + /// Note this being `true` implies that `is_io()` is also `true`. + pub fn is_scratch_too_small(&self) -> bool { + match self.0.code { + ErrorCode::ScratchTooSmall => true, + _ => false, + } + } +} + +#[cfg(feature = "std")] +impl error::Error for Error { + fn source(&self) -> Option<&(dyn error::Error + 'static)> { + match self.0.code { + ErrorCode::Io(ref err) => Some(err), + _ => None, + } + } +} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + if self.0.offset == 0 { + fmt::Display::fmt(&self.0.code, f) + } else { + write!(f, "{} at offset {}", self.0.code, self.0.offset) + } + } +} + +impl fmt::Debug for Error { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt::Debug::fmt(&self.0, fmt) + } +} + +impl de::Error for Error { + fn custom<T: fmt::Display>(msg: T) -> Error { + Error::message(msg) + } + + fn invalid_type(unexp: de::Unexpected<'_>, exp: &dyn de::Expected) -> Error { + if let de::Unexpected::Unit = unexp { + Error::custom(format_args!("invalid type: null, expected {}", exp)) + } else { + Error::custom(format_args!("invalid type: {}, expected {}", unexp, exp)) + } + } +} + +impl ser::Error for Error { + fn custom<T: fmt::Display>(msg: T) -> Error { + Error::message(msg) + } +} + +#[cfg(feature = "std")] +impl From<io::Error> for Error { + fn from(e: io::Error) -> Error { + Error::io(e) + } +} + +#[cfg(not(feature = "std"))] +impl From<core::fmt::Error> for Error { + fn from(_: core::fmt::Error) -> Error { + Error(ErrorImpl { + code: ErrorCode::Message, + offset: 0, + }) + } +} + +#[derive(Debug)] +struct ErrorImpl { + code: ErrorCode, + offset: u64, +} + +#[derive(Debug)] +pub(crate) enum ErrorCode { + #[cfg(feature = "std")] + Message(String), + #[cfg(not(feature = "std"))] + Message, + #[cfg(feature = "std")] + Io(io::Error), + #[allow(unused)] + #[cfg(not(feature = "std"))] + Io, + ScratchTooSmall, + EofWhileParsingValue, + EofWhileParsingArray, + EofWhileParsingMap, + LengthOutOfRange, + InvalidUtf8, + UnassignedCode, + UnexpectedCode, + TrailingData, + ArrayTooShort, + ArrayTooLong, + RecursionLimitExceeded, + WrongEnumFormat, + WrongStructFormat, +} + +impl fmt::Display for ErrorCode { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + #[cfg(feature = "std")] + ErrorCode::Message(ref msg) => f.write_str(msg), + #[cfg(not(feature = "std"))] + ErrorCode::Message => f.write_str("Unknown error"), + #[cfg(feature = "std")] + ErrorCode::Io(ref err) => fmt::Display::fmt(err, f), + #[cfg(not(feature = "std"))] + ErrorCode::Io => f.write_str("Unknown I/O error"), + ErrorCode::ScratchTooSmall => f.write_str("Scratch buffer too small"), + ErrorCode::EofWhileParsingValue => f.write_str("EOF while parsing a value"), + ErrorCode::EofWhileParsingArray => f.write_str("EOF while parsing an array"), + ErrorCode::EofWhileParsingMap => f.write_str("EOF while parsing a map"), + ErrorCode::LengthOutOfRange => f.write_str("length out of range"), + ErrorCode::InvalidUtf8 => f.write_str("invalid UTF-8"), + ErrorCode::UnassignedCode => f.write_str("unassigned type"), + ErrorCode::UnexpectedCode => f.write_str("unexpected code"), + ErrorCode::TrailingData => f.write_str("trailing data"), + ErrorCode::ArrayTooShort => f.write_str("array too short"), + ErrorCode::ArrayTooLong => f.write_str("array too long"), + ErrorCode::RecursionLimitExceeded => f.write_str("recursion limit exceeded"), + ErrorCode::WrongEnumFormat => f.write_str("wrong enum format"), + ErrorCode::WrongStructFormat => f.write_str("wrong struct format"), + } + } +} diff --git a/third_party/rust/serde_cbor/src/lib.rs b/third_party/rust/serde_cbor/src/lib.rs new file mode 100644 index 0000000000..5566854153 --- /dev/null +++ b/third_party/rust/serde_cbor/src/lib.rs @@ -0,0 +1,369 @@ +//! CBOR and serialization. +//! +//! # Usage +//! +//! Serde CBOR supports Rust 1.40 and up. Add this to your `Cargo.toml`: +//! ```toml +//! [dependencies] +//! serde_cbor = "0.10" +//! ``` +//! +//! Storing and loading Rust types is easy and requires only +//! minimal modifications to the program code. +//! +//! ```rust +//! use serde_derive::{Deserialize, Serialize}; +//! use std::error::Error; +//! use std::fs::File; +//! +//! // Types annotated with `Serialize` can be stored as CBOR. +//! // To be able to load them again add `Deserialize`. +//! #[derive(Debug, Serialize, Deserialize)] +//! struct Mascot { +//! name: String, +//! species: String, +//! year_of_birth: u32, +//! } +//! +//! fn main() -> Result<(), Box<dyn Error>> { +//! let ferris = Mascot { +//! name: "Ferris".to_owned(), +//! species: "crab".to_owned(), +//! year_of_birth: 2015, +//! }; +//! +//! let ferris_file = File::create("examples/ferris.cbor")?; +//! // Write Ferris to the given file. +//! // Instead of a file you can use any type that implements `io::Write` +//! // like a HTTP body, database connection etc. +//! serde_cbor::to_writer(ferris_file, &ferris)?; +//! +//! let tux_file = File::open("examples/tux.cbor")?; +//! // Load Tux from a file. +//! // Serde CBOR performs roundtrip serialization meaning that +//! // the data will not change in any way. +//! let tux: Mascot = serde_cbor::from_reader(tux_file)?; +//! +//! println!("{:?}", tux); +//! // prints: Mascot { name: "Tux", species: "penguin", year_of_birth: 1996 } +//! +//! Ok(()) +//! } +//! ``` +//! +//! There are a lot of options available to customize the format. +//! To operate on untyped CBOR values have a look at the `Value` type. +//! +//! # Type-based Serialization and Deserialization +//! Serde provides a mechanism for low boilerplate serialization & deserialization of values to and +//! from CBOR via the serialization API. To be able to serialize a piece of data, it must implement +//! the `serde::Serialize` trait. To be able to deserialize a piece of data, it must implement the +//! `serde::Deserialize` trait. Serde provides an annotation to automatically generate the +//! code for these traits: `#[derive(Serialize, Deserialize)]`. +//! +//! The CBOR API also provides an enum `serde_cbor::Value`. +//! +//! # Packed Encoding +//! When serializing structs or enums in CBOR the keys or enum variant names will be serialized +//! as string keys to a map. Especially in embedded environments this can increase the file +//! size too much. In packed encoding all struct keys, as well as any enum variant that has no data, +//! will be serialized as variable sized integers. The first 24 entries in any struct consume only a +//! single byte! Packed encoding uses serde's preferred [externally tagged enum +//! format](https://serde.rs/enum-representations.html) and therefore serializes enum variant names +//! as string keys when that variant contains data. So, in the packed encoding example, `FirstVariant` +//! encodes to a single byte, but encoding `SecondVariant` requires 16 bytes. +//! +//! To serialize a document in this format use `Serializer::new(writer).packed_format()` or +//! the shorthand `ser::to_vec_packed`. The deserialization works without any changes. +//! +//! If you would like to omit the enum variant encoding for all variants, including ones that +//! contain data, you can add `legacy_enums()` in addition to `packed_format()`, as can seen +//! in the Serialize using minimal encoding example. +//! +//! # Self describing documents +//! In some contexts different formats are used but there is no way to declare the format used +//! out of band. For this reason CBOR has a magic number that may be added before any document. +//! Self describing documents are created with `serializer.self_describe()`. +//! +//! # Examples +//! Read a CBOR value that is known to be a map of string keys to string values and print it. +//! +//! ```rust +//! use std::collections::BTreeMap; +//! use serde_cbor::from_slice; +//! +//! let slice = b"\xa5aaaAabaBacaCadaDaeaE"; +//! let value: BTreeMap<String, String> = from_slice(slice).unwrap(); +//! println!("{:?}", value); // {"e": "E", "d": "D", "a": "A", "c": "C", "b": "B"} +//! ``` +//! +//! Read a general CBOR value with an unknown content. +//! +//! ```rust +//! use serde_cbor::from_slice; +//! use serde_cbor::value::Value; +//! +//! let slice = b"\x82\x01\xa1aaab"; +//! let value: Value = from_slice(slice).unwrap(); +//! println!("{:?}", value); // Array([U64(1), Object({String("a"): String("b")})]) +//! ``` +//! +//! Serialize an object. +//! +//! ```rust +//! use std::collections::BTreeMap; +//! use serde_cbor::to_vec; +//! +//! let mut programming_languages = BTreeMap::new(); +//! programming_languages.insert("rust", vec!["safe", "concurrent", "fast"]); +//! programming_languages.insert("python", vec!["powerful", "friendly", "open"]); +//! programming_languages.insert("js", vec!["lightweight", "interpreted", "object-oriented"]); +//! let encoded = to_vec(&programming_languages); +//! assert_eq!(encoded.unwrap().len(), 103); +//! ``` +//! +//! Deserializing data in the middle of a slice +//! ``` +//! # extern crate serde_cbor; +//! use serde_cbor::Deserializer; +//! +//! # fn main() { +//! let data: Vec<u8> = vec![ +//! 0x66, 0x66, 0x6f, 0x6f, 0x62, 0x61, 0x72, 0x66, 0x66, 0x6f, 0x6f, 0x62, +//! 0x61, 0x72, +//! ]; +//! let mut deserializer = Deserializer::from_slice(&data); +//! let value: &str = serde::de::Deserialize::deserialize(&mut deserializer) +//! .unwrap(); +//! let rest = &data[deserializer.byte_offset()..]; +//! assert_eq!(value, "foobar"); +//! assert_eq!(rest, &[0x66, 0x66, 0x6f, 0x6f, 0x62, 0x61, 0x72]); +//! # } +//! ``` +//! +//! Serialize using packed encoding +//! +//! ```rust +//! use serde_derive::{Deserialize, Serialize}; +//! use serde_cbor::ser::to_vec_packed; +//! use WithTwoVariants::*; +//! +//! #[derive(Debug, Serialize, Deserialize)] +//! enum WithTwoVariants { +//! FirstVariant, +//! SecondVariant(u8), +//! } +//! +//! let cbor = to_vec_packed(&FirstVariant).unwrap(); +//! assert_eq!(cbor.len(), 1); +//! +//! let cbor = to_vec_packed(&SecondVariant(0)).unwrap(); +//! assert_eq!(cbor.len(), 16); // Includes 13 bytes of "SecondVariant" +//! ``` +//! +//! Serialize using minimal encoding +//! +//! ```rust +//! use serde_derive::{Deserialize, Serialize}; +//! use serde_cbor::{Result, Serializer, ser::{self, IoWrite}}; +//! use WithTwoVariants::*; +//! +//! fn to_vec_minimal<T>(value: &T) -> Result<Vec<u8>> +//! where +//! T: serde::Serialize, +//! { +//! let mut vec = Vec::new(); +//! value.serialize(&mut Serializer::new(&mut IoWrite::new(&mut vec)).packed_format().legacy_enums())?; +//! Ok(vec) +//! } +//! +//! #[derive(Debug, Serialize, Deserialize)] +//! enum WithTwoVariants { +//! FirstVariant, +//! SecondVariant(u8), +//! } +//! +//! let cbor = to_vec_minimal(&FirstVariant).unwrap(); +//! assert_eq!(cbor.len(), 1); +//! +//! let cbor = to_vec_minimal(&SecondVariant(0)).unwrap(); +//! assert_eq!(cbor.len(), 3); +//! ``` +//! +//! # `no-std` support +//! +//! Serde CBOR supports building in a `no_std` context, use the following lines +//! in your `Cargo.toml` dependencies: +//! ``` toml +//! [dependencies] +//! serde = { version = "1.0", default-features = false } +//! serde_cbor = { version = "0.10", default-features = false } +//! ``` +//! +//! Without the `std` feature the functions [from_reader], [from_slice], [to_vec], and [to_writer] +//! are not exported. To export [from_slice] and [to_vec] enable the `alloc` feature. The `alloc` +//! feature uses the [`alloc` library][alloc-lib] and requires at least version 1.36.0 of Rust. +//! +//! [alloc-lib]: https://doc.rust-lang.org/alloc/ +//! +//! *Note*: to use derive macros in serde you will need to declare `serde` +//! dependency like so: +//! ``` toml +//! serde = { version = "1.0", default-features = false, features = ["derive"] } +//! ``` +//! +//! Serialize an object with `no_std` and without `alloc`. +//! ``` rust +//! # #[macro_use] extern crate serde_derive; +//! # fn main() -> Result<(), serde_cbor::Error> { +//! use serde::Serialize; +//! use serde_cbor::Serializer; +//! use serde_cbor::ser::SliceWrite; +//! +//! #[derive(Serialize)] +//! struct User { +//! user_id: u32, +//! password_hash: [u8; 4], +//! } +//! +//! let mut buf = [0u8; 100]; +//! let writer = SliceWrite::new(&mut buf[..]); +//! let mut ser = Serializer::new(writer); +//! let user = User { +//! user_id: 42, +//! password_hash: [1, 2, 3, 4], +//! }; +//! user.serialize(&mut ser)?; +//! let writer = ser.into_inner(); +//! let size = writer.bytes_written(); +//! let expected = [ +//! 0xa2, 0x67, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x2a, 0x6d, +//! 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x5f, 0x68, 0x61, 0x73, +//! 0x68, 0x84, 0x1, 0x2, 0x3, 0x4 +//! ]; +//! assert_eq!(&buf[..size], expected); +//! # Ok(()) +//! # } +//! ``` +//! +//! Deserialize an object. +//! ``` rust +//! # #[macro_use] extern crate serde_derive; +//! # fn main() -> Result<(), serde_cbor::Error> { +//! #[derive(Debug, PartialEq, Deserialize)] +//! struct User { +//! user_id: u32, +//! password_hash: [u8; 4], +//! } +//! +//! let value = [ +//! 0xa2, 0x67, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x2a, 0x6d, +//! 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x5f, 0x68, 0x61, 0x73, +//! 0x68, 0x84, 0x1, 0x2, 0x3, 0x4 +//! ]; +//! +//! // from_slice_with_scratch will not alter input data, use it whenever you +//! // borrow from somewhere else. +//! // You will have to size your scratch according to the input data you +//! // expect. +//! use serde_cbor::de::from_slice_with_scratch; +//! let mut scratch = [0u8; 32]; +//! let user: User = from_slice_with_scratch(&value[..], &mut scratch)?; +//! assert_eq!(user, User { +//! user_id: 42, +//! password_hash: [1, 2, 3, 4], +//! }); +//! +//! let mut value = [ +//! 0xa2, 0x67, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x2a, 0x6d, +//! 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x5f, 0x68, 0x61, 0x73, +//! 0x68, 0x84, 0x1, 0x2, 0x3, 0x4 +//! ]; +//! +//! // from_mut_slice will move data around the input slice, you may only use it +//! // on data you may own or can modify. +//! use serde_cbor::de::from_mut_slice; +//! let user: User = from_mut_slice(&mut value[..])?; +//! assert_eq!(user, User { +//! user_id: 42, +//! password_hash: [1, 2, 3, 4], +//! }); +//! # Ok(()) +//! # } +//! ``` +//! +//! # Limitations +//! +//! While Serde CBOR strives to support all features of Serde and CBOR +//! there are a few limitations. +//! +//! * [Tags] are ignored during deserialization and can't be emitted during +//! serialization. This is because Serde has no concept of tagged +//! values. See: [#3] +//! * Unknown [simple values] cause an `UnassignedCode` error. +//! The simple values *False* and *True* are recognized and parsed as bool. +//! *Null* and *Undefined* are both deserialized as *unit*. +//! The *unit* type is serialized as *Null*. See: [#86] +//! * [128-bit integers] can't be directly encoded in CBOR. If you need them +//! store them as a byte string. See: [#77] +//! +//! [Tags]: https://tools.ietf.org/html/rfc7049#section-2.4.4 +//! [#3]: https://github.com/pyfisch/cbor/issues/3 +//! [simple values]: https://tools.ietf.org/html/rfc7049#section-3.5 +//! [#86]: https://github.com/pyfisch/cbor/issues/86 +//! [128-bit integers]: https://doc.rust-lang.org/std/primitive.u128.html +//! [#77]: https://github.com/pyfisch/cbor/issues/77 + +#![deny(missing_docs)] +#![cfg_attr(not(feature = "std"), no_std)] + +// When we are running tests in no_std mode we need to explicitly link std, because `cargo test` +// will not work without it. +#[cfg(all(not(feature = "std"), test))] +extern crate std; + +#[cfg(feature = "alloc")] +extern crate alloc; + +pub mod de; +pub mod error; +mod read; +pub mod ser; +pub mod tags; +mod write; + +#[cfg(feature = "std")] +pub mod value; + +// Re-export the [items recommended by serde](https://serde.rs/conventions.html). +#[doc(inline)] +pub use crate::de::{Deserializer, StreamDeserializer}; + +#[doc(inline)] +pub use crate::error::{Error, Result}; + +#[doc(inline)] +pub use crate::ser::Serializer; + +// Convenience functions for serialization and deserialization. +// These functions are only available in `std` mode. +#[cfg(feature = "std")] +#[doc(inline)] +pub use crate::de::from_reader; + +#[cfg(any(feature = "std", feature = "alloc"))] +#[doc(inline)] +pub use crate::de::from_slice; + +#[cfg(any(feature = "std", feature = "alloc"))] +#[doc(inline)] +pub use crate::ser::to_vec; + +#[cfg(feature = "std")] +#[doc(inline)] +pub use crate::ser::to_writer; + +// Re-export the value type like serde_json +#[cfg(feature = "std")] +#[doc(inline)] +pub use crate::value::Value; diff --git a/third_party/rust/serde_cbor/src/read.rs b/third_party/rust/serde_cbor/src/read.rs new file mode 100644 index 0000000000..1b53018df8 --- /dev/null +++ b/third_party/rust/serde_cbor/src/read.rs @@ -0,0 +1,637 @@ +#[cfg(feature = "alloc")] +use alloc::{vec, vec::Vec}; +#[cfg(feature = "std")] +use core::cmp; +use core::mem; + +#[cfg(feature = "std")] +use std::io::{self, Read as StdRead}; + +use crate::error::{Error, ErrorCode, Result}; + +#[cfg(not(feature = "unsealed_read_write"))] +/// Trait used by the deserializer for iterating over input. +/// +/// This trait is sealed by default, enabling the `unsealed_read_write` feature removes this bound +/// to allow objects outside of this crate to implement this trait. +pub trait Read<'de>: private::Sealed { + #[doc(hidden)] + /// Read n bytes from the input. + /// + /// Implementations that can are asked to return a slice with a Long lifetime that outlives the + /// decoder, but others (eg. ones that need to allocate the data into a temporary buffer) can + /// return it with a Short lifetime that just lives for the time of read's mutable borrow of + /// the reader. + /// + /// This may, as a side effect, clear the reader's scratch buffer (as the provided + /// implementation does). + + // A more appropriate lifetime setup for this (that would allow the Deserializer::convert_str + // to stay a function) would be something like `fn read<'a, 'r: 'a>(&'a mut 'r immut self, ...) -> ... + // EitherLifetime<'r, 'de>>`, which borrows self mutably for the duration of the function and + // downgrates that reference to an immutable one that outlives the result (protecting the + // scratch buffer from changes), but alas, that can't be expressed (yet?). + fn read<'a>(&'a mut self, n: usize) -> Result<EitherLifetime<'a, 'de>> { + self.clear_buffer(); + self.read_to_buffer(n)?; + + Ok(self.take_buffer()) + } + + #[doc(hidden)] + fn next(&mut self) -> Result<Option<u8>>; + + #[doc(hidden)] + fn peek(&mut self) -> Result<Option<u8>>; + + #[doc(hidden)] + fn clear_buffer(&mut self); + + #[doc(hidden)] + fn read_to_buffer(&mut self, n: usize) -> Result<()>; + + #[doc(hidden)] + fn take_buffer<'a>(&'a mut self) -> EitherLifetime<'a, 'de>; + + #[doc(hidden)] + fn read_into(&mut self, buf: &mut [u8]) -> Result<()>; + + #[doc(hidden)] + fn discard(&mut self); + + #[doc(hidden)] + fn offset(&self) -> u64; +} + +#[cfg(feature = "unsealed_read_write")] +/// Trait used by the deserializer for iterating over input. +pub trait Read<'de> { + /// Read n bytes from the input. + /// + /// Implementations that can are asked to return a slice with a Long lifetime that outlives the + /// decoder, but others (eg. ones that need to allocate the data into a temporary buffer) can + /// return it with a Short lifetime that just lives for the time of read's mutable borrow of + /// the reader. + /// + /// This may, as a side effect, clear the reader's scratch buffer (as the provided + /// implementation does). + + // A more appropriate lifetime setup for this (that would allow the Deserializer::convert_str + // to stay a function) would be something like `fn read<'a, 'r: 'a>(&'a mut 'r immut self, ...) -> ... + // EitherLifetime<'r, 'de>>`, which borrows self mutably for the duration of the function and + // downgrates that reference to an immutable one that outlives the result (protecting the + // scratch buffer from changes), but alas, that can't be expressed (yet?). + fn read<'a>(&'a mut self, n: usize) -> Result<EitherLifetime<'a, 'de>> { + self.clear_buffer(); + self.read_to_buffer(n)?; + + Ok(self.take_buffer()) + } + + /// Read the next byte from the input, if any. + fn next(&mut self) -> Result<Option<u8>>; + + /// Peek at the next byte of the input, if any. This does not advance the reader, so the result + /// of this function will remain the same until a read or clear occurs. + fn peek(&mut self) -> Result<Option<u8>>; + + /// Clear the underlying scratch buffer + fn clear_buffer(&mut self); + + /// Append n bytes from the reader to the reader's scratch buffer (without clearing it) + fn read_to_buffer(&mut self, n: usize) -> Result<()>; + + /// Read out everything accumulated in the reader's scratch buffer. This may, as a side effect, + /// clear it. + fn take_buffer<'a>(&'a mut self) -> EitherLifetime<'a, 'de>; + + /// Read from the input until `buf` is full or end of input is encountered. + fn read_into(&mut self, buf: &mut [u8]) -> Result<()>; + + /// Discard any data read by `peek`. + fn discard(&mut self); + + /// Returns the offset from the start of the reader. + fn offset(&self) -> u64; +} + +/// Represents a reader that can return its current position +pub trait Offset { + fn byte_offset(&self) -> usize; +} + +/// Represents a buffer with one of two lifetimes. +pub enum EitherLifetime<'short, 'long> { + /// The short lifetime + Short(&'short [u8]), + /// The long lifetime + Long(&'long [u8]), +} + +#[cfg(not(feature = "unsealed_read_write"))] +mod private { + pub trait Sealed {} +} + +/// CBOR input source that reads from a std::io input stream. +#[cfg(feature = "std")] +#[derive(Debug)] +pub struct IoRead<R> +where + R: io::Read, +{ + reader: OffsetReader<R>, + scratch: Vec<u8>, + ch: Option<u8>, +} + +#[cfg(feature = "std")] +impl<R> IoRead<R> +where + R: io::Read, +{ + /// Creates a new CBOR input source to read from a std::io input stream. + pub fn new(reader: R) -> IoRead<R> { + IoRead { + reader: OffsetReader { reader, offset: 0 }, + scratch: vec![], + ch: None, + } + } + + #[inline] + fn next_inner(&mut self) -> Result<Option<u8>> { + let mut buf = [0; 1]; + loop { + match self.reader.read(&mut buf) { + Ok(0) => return Ok(None), + Ok(_) => return Ok(Some(buf[0])), + Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {} + Err(e) => return Err(Error::io(e)), + } + } + } +} + +#[cfg(all(feature = "std", not(feature = "unsealed_read_write")))] +impl<R> private::Sealed for IoRead<R> where R: io::Read {} + +#[cfg(feature = "std")] +impl<'de, R> Read<'de> for IoRead<R> +where + R: io::Read, +{ + #[inline] + fn next(&mut self) -> Result<Option<u8>> { + match self.ch.take() { + Some(ch) => Ok(Some(ch)), + None => self.next_inner(), + } + } + + #[inline] + fn peek(&mut self) -> Result<Option<u8>> { + match self.ch { + Some(ch) => Ok(Some(ch)), + None => { + self.ch = self.next_inner()?; + Ok(self.ch) + } + } + } + + fn read_to_buffer(&mut self, mut n: usize) -> Result<()> { + // defend against malicious input pretending to be huge strings by limiting growth + self.scratch.reserve(cmp::min(n, 16 * 1024)); + + if n == 0 { + return Ok(()); + } + + if let Some(ch) = self.ch.take() { + self.scratch.push(ch); + n -= 1; + } + + // n == 0 is OK here and needs no further special treatment + + let transfer_result = { + // Prepare for take() (which consumes its reader) by creating a reference adaptor + // that'll only live in this block + let reference = self.reader.by_ref(); + // Append the first n bytes of the reader to the scratch vector (or up to + // an error or EOF indicated by a shorter read) + let mut taken = reference.take(n as u64); + taken.read_to_end(&mut self.scratch) + }; + + match transfer_result { + Ok(r) if r == n => Ok(()), + Ok(_) => Err(Error::syntax( + ErrorCode::EofWhileParsingValue, + self.offset(), + )), + Err(e) => Err(Error::io(e)), + } + } + + fn clear_buffer(&mut self) { + self.scratch.clear(); + } + + fn take_buffer<'a>(&'a mut self) -> EitherLifetime<'a, 'de> { + EitherLifetime::Short(&self.scratch) + } + + fn read_into(&mut self, buf: &mut [u8]) -> Result<()> { + self.reader.read_exact(buf).map_err(|e| { + if e.kind() == io::ErrorKind::UnexpectedEof { + Error::syntax(ErrorCode::EofWhileParsingValue, self.offset()) + } else { + Error::io(e) + } + }) + } + + #[inline] + fn discard(&mut self) { + self.ch = None; + } + + fn offset(&self) -> u64 { + self.reader.offset + } +} + +#[cfg(feature = "std")] +impl<R> Offset for IoRead<R> +where + R: std::io::Read, +{ + fn byte_offset(&self) -> usize { + self.offset() as usize + } +} + +#[cfg(feature = "std")] +#[derive(Debug)] +struct OffsetReader<R> { + reader: R, + offset: u64, +} + +#[cfg(feature = "std")] +impl<R> io::Read for OffsetReader<R> +where + R: io::Read, +{ + #[inline] + fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { + let r = self.reader.read(buf); + if let Ok(count) = r { + self.offset += count as u64; + } + r + } +} + +/// A CBOR input source that reads from a slice of bytes. +#[cfg(any(feature = "std", feature = "alloc"))] +#[derive(Debug)] +pub struct SliceRead<'a> { + slice: &'a [u8], + scratch: Vec<u8>, + index: usize, +} + +#[cfg(any(feature = "std", feature = "alloc"))] +impl<'a> SliceRead<'a> { + /// Creates a CBOR input source to read from a slice of bytes. + pub fn new(slice: &'a [u8]) -> SliceRead<'a> { + SliceRead { + slice, + scratch: vec![], + index: 0, + } + } + + fn end(&self, n: usize) -> Result<usize> { + match self.index.checked_add(n) { + Some(end) if end <= self.slice.len() => Ok(end), + _ => Err(Error::syntax( + ErrorCode::EofWhileParsingValue, + self.slice.len() as u64, + )), + } + } +} + +#[cfg(any(feature = "std", feature = "alloc"))] +impl<'a> Offset for SliceRead<'a> { + #[inline] + fn byte_offset(&self) -> usize { + self.index + } +} + +#[cfg(all( + any(feature = "std", feature = "alloc"), + not(feature = "unsealed_read_write") +))] +impl<'a> private::Sealed for SliceRead<'a> {} + +#[cfg(any(feature = "std", feature = "alloc"))] +impl<'a> Read<'a> for SliceRead<'a> { + #[inline] + fn next(&mut self) -> Result<Option<u8>> { + Ok(if self.index < self.slice.len() { + let ch = self.slice[self.index]; + self.index += 1; + Some(ch) + } else { + None + }) + } + + #[inline] + fn peek(&mut self) -> Result<Option<u8>> { + Ok(if self.index < self.slice.len() { + Some(self.slice[self.index]) + } else { + None + }) + } + + fn clear_buffer(&mut self) { + self.scratch.clear(); + } + + fn read_to_buffer(&mut self, n: usize) -> Result<()> { + let end = self.end(n)?; + let slice = &self.slice[self.index..end]; + self.scratch.extend_from_slice(slice); + self.index = end; + + Ok(()) + } + + #[inline] + fn read<'b>(&'b mut self, n: usize) -> Result<EitherLifetime<'b, 'a>> { + let end = self.end(n)?; + let slice = &self.slice[self.index..end]; + self.index = end; + Ok(EitherLifetime::Long(slice)) + } + + fn take_buffer<'b>(&'b mut self) -> EitherLifetime<'b, 'a> { + EitherLifetime::Short(&self.scratch) + } + + #[inline] + fn read_into(&mut self, buf: &mut [u8]) -> Result<()> { + let end = self.end(buf.len())?; + buf.copy_from_slice(&self.slice[self.index..end]); + self.index = end; + Ok(()) + } + + #[inline] + fn discard(&mut self) { + self.index += 1; + } + + fn offset(&self) -> u64 { + self.index as u64 + } +} + +/// A CBOR input source that reads from a slice of bytes using a fixed size scratch buffer. +/// +/// [`SliceRead`](struct.SliceRead.html) and [`MutSliceRead`](struct.MutSliceRead.html) are usually +/// preferred over this, as they can handle indefinite length items. +#[derive(Debug)] +pub struct SliceReadFixed<'a, 'b> { + slice: &'a [u8], + scratch: &'b mut [u8], + index: usize, + scratch_index: usize, +} + +impl<'a, 'b> SliceReadFixed<'a, 'b> { + /// Creates a CBOR input source to read from a slice of bytes, backed by a scratch buffer. + pub fn new(slice: &'a [u8], scratch: &'b mut [u8]) -> SliceReadFixed<'a, 'b> { + SliceReadFixed { + slice, + scratch, + index: 0, + scratch_index: 0, + } + } + + fn end(&self, n: usize) -> Result<usize> { + match self.index.checked_add(n) { + Some(end) if end <= self.slice.len() => Ok(end), + _ => Err(Error::syntax( + ErrorCode::EofWhileParsingValue, + self.slice.len() as u64, + )), + } + } + + fn scratch_end(&self, n: usize) -> Result<usize> { + match self.scratch_index.checked_add(n) { + Some(end) if end <= self.scratch.len() => Ok(end), + _ => Err(Error::scratch_too_small(self.index as u64)), + } + } +} + +#[cfg(not(feature = "unsealed_read_write"))] +impl<'a, 'b> private::Sealed for SliceReadFixed<'a, 'b> {} + +impl<'a, 'b> Read<'a> for SliceReadFixed<'a, 'b> { + #[inline] + fn next(&mut self) -> Result<Option<u8>> { + Ok(if self.index < self.slice.len() { + let ch = self.slice[self.index]; + self.index += 1; + Some(ch) + } else { + None + }) + } + + #[inline] + fn peek(&mut self) -> Result<Option<u8>> { + Ok(if self.index < self.slice.len() { + Some(self.slice[self.index]) + } else { + None + }) + } + + fn clear_buffer(&mut self) { + self.scratch_index = 0; + } + + fn read_to_buffer(&mut self, n: usize) -> Result<()> { + let end = self.end(n)?; + let scratch_end = self.scratch_end(n)?; + let slice = &self.slice[self.index..end]; + self.scratch[self.scratch_index..scratch_end].copy_from_slice(&slice); + self.index = end; + self.scratch_index = scratch_end; + + Ok(()) + } + + fn read<'c>(&'c mut self, n: usize) -> Result<EitherLifetime<'c, 'a>> { + let end = self.end(n)?; + let slice = &self.slice[self.index..end]; + self.index = end; + Ok(EitherLifetime::Long(slice)) + } + + fn take_buffer<'c>(&'c mut self) -> EitherLifetime<'c, 'a> { + EitherLifetime::Short(&self.scratch[0..self.scratch_index]) + } + + #[inline] + fn read_into(&mut self, buf: &mut [u8]) -> Result<()> { + let end = self.end(buf.len())?; + buf.copy_from_slice(&self.slice[self.index..end]); + self.index = end; + Ok(()) + } + + #[inline] + fn discard(&mut self) { + self.index += 1; + } + + fn offset(&self) -> u64 { + self.index as u64 + } +} + +#[cfg(any(feature = "std", feature = "alloc"))] +impl<'a, 'b> Offset for SliceReadFixed<'a, 'b> { + #[inline] + fn byte_offset(&self) -> usize { + self.index + } +} + +/// A CBOR input source that reads from a slice of bytes, and can move data around internally to +/// reassemble indefinite strings without the need of an allocated scratch buffer. +#[derive(Debug)] +pub struct MutSliceRead<'a> { + /// A complete view of the reader's data. It is promised that bytes before buffer_end are not + /// mutated any more. + slice: &'a mut [u8], + /// Read cursor position in slice + index: usize, + /// Number of bytes already discarded from the slice + before: usize, + /// End of the buffer area that contains all bytes read_into_buffer. This is always <= index. + buffer_end: usize, +} + +impl<'a> MutSliceRead<'a> { + /// Creates a CBOR input source to read from a slice of bytes. + pub fn new(slice: &'a mut [u8]) -> MutSliceRead<'a> { + MutSliceRead { + slice, + index: 0, + before: 0, + buffer_end: 0, + } + } + + fn end(&self, n: usize) -> Result<usize> { + match self.index.checked_add(n) { + Some(end) if end <= self.slice.len() => Ok(end), + _ => Err(Error::syntax( + ErrorCode::EofWhileParsingValue, + self.slice.len() as u64, + )), + } + } +} + +#[cfg(not(feature = "unsealed_read_write"))] +impl<'a> private::Sealed for MutSliceRead<'a> {} + +impl<'a> Read<'a> for MutSliceRead<'a> { + #[inline] + fn next(&mut self) -> Result<Option<u8>> { + // This is duplicated from SliceRead, can that be eased? + Ok(if self.index < self.slice.len() { + let ch = self.slice[self.index]; + self.index += 1; + Some(ch) + } else { + None + }) + } + + #[inline] + fn peek(&mut self) -> Result<Option<u8>> { + // This is duplicated from SliceRead, can that be eased? + Ok(if self.index < self.slice.len() { + Some(self.slice[self.index]) + } else { + None + }) + } + + fn clear_buffer(&mut self) { + self.slice = &mut mem::replace(&mut self.slice, &mut [])[self.index..]; + self.before += self.index; + self.index = 0; + self.buffer_end = 0; + } + + fn read_to_buffer(&mut self, n: usize) -> Result<()> { + let end = self.end(n)?; + debug_assert!( + self.buffer_end <= self.index, + "MutSliceRead invariant violated: scratch buffer exceeds index" + ); + self.slice[self.buffer_end..end].rotate_left(self.index - self.buffer_end); + self.buffer_end += n; + self.index = end; + + Ok(()) + } + + fn take_buffer<'b>(&'b mut self) -> EitherLifetime<'b, 'a> { + let (left, right) = mem::replace(&mut self.slice, &mut []).split_at_mut(self.index); + self.slice = right; + self.before += self.index; + self.index = 0; + + let left = &left[..self.buffer_end]; + self.buffer_end = 0; + + EitherLifetime::Long(left) + } + + #[inline] + fn read_into(&mut self, buf: &mut [u8]) -> Result<()> { + // This is duplicated from SliceRead, can that be eased? + let end = self.end(buf.len())?; + buf.copy_from_slice(&self.slice[self.index..end]); + self.index = end; + Ok(()) + } + + #[inline] + fn discard(&mut self) { + self.index += 1; + } + + fn offset(&self) -> u64 { + (self.before + self.index) as u64 + } +} diff --git a/third_party/rust/serde_cbor/src/ser.rs b/third_party/rust/serde_cbor/src/ser.rs new file mode 100644 index 0000000000..7016dc340a --- /dev/null +++ b/third_party/rust/serde_cbor/src/ser.rs @@ -0,0 +1,743 @@ +//! Serialize a Rust data structure to CBOR data. + +#[cfg(feature = "alloc")] +use alloc::vec::Vec; + +#[cfg(feature = "std")] +pub use crate::write::IoWrite; +pub use crate::write::{SliceWrite, Write}; + +use crate::error::{Error, Result}; +use half::f16; +use serde::ser::{self, Serialize}; +#[cfg(feature = "std")] +use std::io; + +use crate::tags::{get_tag, CBOR_NEWTYPE_NAME}; + +/// Serializes a value to a vector. +#[cfg(any(feature = "std", feature = "alloc"))] +pub fn to_vec<T>(value: &T) -> Result<Vec<u8>> +where + T: ser::Serialize, +{ + let mut vec = Vec::new(); + value.serialize(&mut Serializer::new(&mut vec))?; + Ok(vec) +} + +/// Serializes a value to a vector in packed format. +#[cfg(feature = "std")] +pub fn to_vec_packed<T>(value: &T) -> Result<Vec<u8>> +where + T: ser::Serialize, +{ + let mut vec = Vec::new(); + value.serialize(&mut Serializer::new(&mut IoWrite::new(&mut vec)).packed_format())?; + Ok(vec) +} + +/// Serializes a value to a writer. +#[cfg(feature = "std")] +pub fn to_writer<W, T>(writer: W, value: &T) -> Result<()> +where + W: io::Write, + T: ser::Serialize, +{ + value.serialize(&mut Serializer::new(&mut IoWrite::new(writer))) +} + +/// A structure for serializing Rust values to CBOR. +#[derive(Debug)] +pub struct Serializer<W> { + writer: W, + packed: bool, + enum_as_map: bool, +} + +impl<W> Serializer<W> +where + W: Write, +{ + /// Creates a new CBOR serializer. + /// + /// `to_vec` and `to_writer` should normally be used instead of this method. + #[inline] + pub fn new(writer: W) -> Self { + Serializer { + writer, + packed: false, + enum_as_map: true, + } + } + + /// Choose concise/packed format for serializer. + /// + /// In the packed format enum variant names and field names + /// are replaced with numeric indizes to conserve space. + pub fn packed_format(mut self) -> Self { + self.packed = true; + self + } + + /// Enable old enum format used by `serde_cbor` versions <= v0.9. + /// + /// The `legacy_enums` option determines how enums are encoded. + /// + /// This makes no difference when encoding and decoding enums using + /// this crate, but it shows up when decoding to a `Value` or decoding + /// in other languages. + /// + /// # Examples + /// + /// Given the following enum + /// + /// ```rust + /// enum Enum { + /// Unit, + /// NewType(i32), + /// Tuple(String, bool), + /// Struct{ x: i32, y: i32 }, + /// } + /// ``` + /// we will give the `Value` with the same encoding for each case using + /// JSON notation. + /// + /// ## Default encodings + /// + /// * `Enum::Unit` encodes as `"Unit"` + /// * `Enum::NewType(10)` encodes as `{"NewType": 10}` + /// * `Enum::Tuple("x", true)` encodes as `{"Tuple": ["x", true]}` + /// + /// ## Legacy encodings + /// + /// * `Enum::Unit` encodes as `"Unit"` + /// * `Enum::NewType(10)` encodes as `["NewType", 10]` + /// * `Enum::Tuple("x", true)` encodes as `["Tuple", "x", true]` + /// * `Enum::Struct{ x: 5, y: -5 }` encodes as `["Struct", {"x": 5, "y": -5}]` + pub fn legacy_enums(mut self) -> Self { + self.enum_as_map = false; + self + } + + /// Writes a CBOR self-describe tag to the stream. + /// + /// Tagging allows a decoder to distinguish different file formats based on their content + /// without further information. + #[inline] + pub fn self_describe(&mut self) -> Result<()> { + let mut buf = [6 << 5 | 25, 0, 0]; + (&mut buf[1..]).copy_from_slice(&55799u16.to_be_bytes()); + self.writer.write_all(&buf).map_err(|e| e.into()) + } + + /// Unwrap the `Writer` from the `Serializer`. + #[inline] + pub fn into_inner(self) -> W { + self.writer + } + + #[inline] + fn write_u8(&mut self, major: u8, value: u8) -> Result<()> { + if value <= 0x17 { + self.writer.write_all(&[major << 5 | value]) + } else { + let buf = [major << 5 | 24, value]; + self.writer.write_all(&buf) + } + .map_err(|e| e.into()) + } + + #[inline] + fn write_u16(&mut self, major: u8, value: u16) -> Result<()> { + if value <= u16::from(u8::max_value()) { + self.write_u8(major, value as u8) + } else { + let mut buf = [major << 5 | 25, 0, 0]; + (&mut buf[1..]).copy_from_slice(&value.to_be_bytes()); + self.writer.write_all(&buf).map_err(|e| e.into()) + } + } + + #[inline] + fn write_u32(&mut self, major: u8, value: u32) -> Result<()> { + if value <= u32::from(u16::max_value()) { + self.write_u16(major, value as u16) + } else { + let mut buf = [major << 5 | 26, 0, 0, 0, 0]; + (&mut buf[1..]).copy_from_slice(&value.to_be_bytes()); + self.writer.write_all(&buf).map_err(|e| e.into()) + } + } + + #[inline] + fn write_u64(&mut self, major: u8, value: u64) -> Result<()> { + if value <= u64::from(u32::max_value()) { + self.write_u32(major, value as u32) + } else { + let mut buf = [major << 5 | 27, 0, 0, 0, 0, 0, 0, 0, 0]; + (&mut buf[1..]).copy_from_slice(&value.to_be_bytes()); + self.writer.write_all(&buf).map_err(|e| e.into()) + } + } + + #[inline] + fn serialize_collection<'a>( + &'a mut self, + major: u8, + len: Option<usize>, + ) -> Result<CollectionSerializer<'a, W>> { + let needs_eof = match len { + Some(len) => { + self.write_u64(major, len as u64)?; + false + } + None => { + self.writer + .write_all(&[major << 5 | 31]) + .map_err(|e| e.into())?; + true + } + }; + + Ok(CollectionSerializer { + ser: self, + needs_eof, + }) + } +} + +impl<'a, W> ser::Serializer for &'a mut Serializer<W> +where + W: Write, +{ + type Ok = (); + type Error = Error; + + type SerializeSeq = CollectionSerializer<'a, W>; + type SerializeTuple = &'a mut Serializer<W>; + type SerializeTupleStruct = &'a mut Serializer<W>; + type SerializeTupleVariant = &'a mut Serializer<W>; + type SerializeMap = CollectionSerializer<'a, W>; + type SerializeStruct = StructSerializer<'a, W>; + type SerializeStructVariant = StructSerializer<'a, W>; + + #[inline] + fn serialize_bool(self, value: bool) -> Result<()> { + let value = if value { 0xf5 } else { 0xf4 }; + self.writer.write_all(&[value]).map_err(|e| e.into()) + } + + #[inline] + fn serialize_i8(self, value: i8) -> Result<()> { + if value < 0 { + self.write_u8(1, -(value + 1) as u8) + } else { + self.write_u8(0, value as u8) + } + } + + #[inline] + fn serialize_i16(self, value: i16) -> Result<()> { + if value < 0 { + self.write_u16(1, -(value + 1) as u16) + } else { + self.write_u16(0, value as u16) + } + } + + #[inline] + fn serialize_i32(self, value: i32) -> Result<()> { + if value < 0 { + self.write_u32(1, -(value + 1) as u32) + } else { + self.write_u32(0, value as u32) + } + } + + #[inline] + fn serialize_i64(self, value: i64) -> Result<()> { + if value < 0 { + self.write_u64(1, -(value + 1) as u64) + } else { + self.write_u64(0, value as u64) + } + } + + #[inline] + fn serialize_i128(self, value: i128) -> Result<()> { + if value < 0 { + if -(value + 1) > i128::from(u64::max_value()) { + return Err(Error::message("The number can't be stored in CBOR")); + } + self.write_u64(1, -(value + 1) as u64) + } else { + if value > i128::from(u64::max_value()) { + return Err(Error::message("The number can't be stored in CBOR")); + } + self.write_u64(0, value as u64) + } + } + + #[inline] + fn serialize_u8(self, value: u8) -> Result<()> { + self.write_u8(0, value) + } + + #[inline] + fn serialize_u16(self, value: u16) -> Result<()> { + self.write_u16(0, value) + } + + #[inline] + fn serialize_u32(self, value: u32) -> Result<()> { + self.write_u32(0, value) + } + + #[inline] + fn serialize_u64(self, value: u64) -> Result<()> { + self.write_u64(0, value) + } + + #[inline] + fn serialize_u128(self, value: u128) -> Result<()> { + if value > u128::from(u64::max_value()) { + return Err(Error::message("The number can't be stored in CBOR")); + } + self.write_u64(0, value as u64) + } + + #[inline] + #[allow(clippy::float_cmp)] + fn serialize_f32(self, value: f32) -> Result<()> { + if value.is_infinite() { + if value.is_sign_positive() { + self.writer.write_all(&[0xf9, 0x7c, 0x00]) + } else { + self.writer.write_all(&[0xf9, 0xfc, 0x00]) + } + } else if value.is_nan() { + self.writer.write_all(&[0xf9, 0x7e, 0x00]) + } else if f32::from(f16::from_f32(value)) == value { + let mut buf = [0xf9, 0, 0]; + (&mut buf[1..]).copy_from_slice(&f16::from_f32(value).to_bits().to_be_bytes()); + self.writer.write_all(&buf) + } else { + let mut buf = [0xfa, 0, 0, 0, 0]; + (&mut buf[1..]).copy_from_slice(&value.to_bits().to_be_bytes()); + self.writer.write_all(&buf) + } + .map_err(|e| e.into()) + } + + #[inline] + #[allow(clippy::float_cmp)] + fn serialize_f64(self, value: f64) -> Result<()> { + if !value.is_finite() || f64::from(value as f32) == value { + self.serialize_f32(value as f32) + } else { + let mut buf = [0xfb, 0, 0, 0, 0, 0, 0, 0, 0]; + (&mut buf[1..]).copy_from_slice(&value.to_bits().to_be_bytes()); + self.writer.write_all(&buf).map_err(|e| e.into()) + } + } + + #[inline] + fn serialize_char(self, value: char) -> Result<()> { + // A char encoded as UTF-8 takes 4 bytes at most. + let mut buf = [0; 4]; + self.serialize_str(value.encode_utf8(&mut buf)) + } + + #[inline] + fn serialize_str(self, value: &str) -> Result<()> { + self.write_u64(3, value.len() as u64)?; + self.writer + .write_all(value.as_bytes()) + .map_err(|e| e.into()) + } + + #[inline] + fn serialize_bytes(self, value: &[u8]) -> Result<()> { + self.write_u64(2, value.len() as u64)?; + self.writer.write_all(value).map_err(|e| e.into()) + } + + #[inline] + fn serialize_unit(self) -> Result<()> { + self.serialize_none() + } + + #[inline] + fn serialize_some<T>(self, value: &T) -> Result<()> + where + T: ?Sized + ser::Serialize, + { + value.serialize(self) + } + + #[inline] + fn serialize_none(self) -> Result<()> { + self.writer.write_all(&[0xf6]).map_err(|e| e.into()) + } + + #[inline] + fn serialize_unit_struct(self, _name: &'static str) -> Result<()> { + self.serialize_unit() + } + + #[inline] + fn serialize_unit_variant( + self, + _name: &'static str, + variant_index: u32, + variant: &'static str, + ) -> Result<()> { + if self.packed { + self.serialize_u32(variant_index) + } else { + self.serialize_str(variant) + } + } + + #[inline] + fn serialize_newtype_struct<T>(self, name: &'static str, value: &T) -> Result<()> + where + T: ?Sized + ser::Serialize, + { + if name == CBOR_NEWTYPE_NAME { + for tag in get_tag().into_iter() { + self.write_u64(6, tag)?; + } + } + value.serialize(self) + } + + #[inline] + fn serialize_newtype_variant<T>( + self, + name: &'static str, + variant_index: u32, + variant: &'static str, + value: &T, + ) -> Result<()> + where + T: ?Sized + ser::Serialize, + { + if self.enum_as_map { + self.write_u64(5, 1u64)?; + variant.serialize(&mut *self)?; + } else { + self.writer.write_all(&[4 << 5 | 2]).map_err(|e| e.into())?; + self.serialize_unit_variant(name, variant_index, variant)?; + } + value.serialize(self) + } + + #[inline] + fn serialize_seq(self, len: Option<usize>) -> Result<CollectionSerializer<'a, W>> { + self.serialize_collection(4, len) + } + + #[inline] + fn serialize_tuple(self, len: usize) -> Result<&'a mut Serializer<W>> { + self.write_u64(4, len as u64)?; + Ok(self) + } + + #[inline] + fn serialize_tuple_struct( + self, + _name: &'static str, + len: usize, + ) -> Result<&'a mut Serializer<W>> { + self.serialize_tuple(len) + } + + #[inline] + fn serialize_tuple_variant( + self, + name: &'static str, + variant_index: u32, + variant: &'static str, + len: usize, + ) -> Result<&'a mut Serializer<W>> { + if self.enum_as_map { + self.write_u64(5, 1u64)?; + variant.serialize(&mut *self)?; + self.serialize_tuple(len) + } else { + self.write_u64(4, (len + 1) as u64)?; + self.serialize_unit_variant(name, variant_index, variant)?; + Ok(self) + } + } + + #[inline] + fn serialize_map(self, len: Option<usize>) -> Result<CollectionSerializer<'a, W>> { + self.serialize_collection(5, len) + } + + #[cfg(not(feature = "std"))] + fn collect_str<T: ?Sized>(self, value: &T) -> Result<()> + where + T: core::fmt::Display, + { + use crate::write::FmtWrite; + use core::fmt::Write; + + let mut w = FmtWrite::new(&mut self.writer); + write!(w, "{}", value)?; + Ok(()) + } + + #[inline] + fn serialize_struct(self, _name: &'static str, len: usize) -> Result<StructSerializer<'a, W>> { + self.write_u64(5, len as u64)?; + Ok(StructSerializer { ser: self, idx: 0 }) + } + + #[inline] + fn serialize_struct_variant( + self, + name: &'static str, + variant_index: u32, + variant: &'static str, + len: usize, + ) -> Result<StructSerializer<'a, W>> { + if self.enum_as_map { + self.write_u64(5, 1u64)?; + } else { + self.writer.write_all(&[4 << 5 | 2]).map_err(|e| e.into())?; + } + self.serialize_unit_variant(name, variant_index, variant)?; + self.serialize_struct(name, len) + } + + #[inline] + fn is_human_readable(&self) -> bool { + false + } +} + +impl<'a, W> ser::SerializeTuple for &'a mut Serializer<W> +where + W: Write, +{ + type Ok = (); + type Error = Error; + + #[inline] + fn serialize_element<T>(&mut self, value: &T) -> Result<()> + where + T: ?Sized + ser::Serialize, + { + value.serialize(&mut **self) + } + + #[inline] + fn end(self) -> Result<()> { + Ok(()) + } +} + +impl<'a, W> ser::SerializeTupleStruct for &'a mut Serializer<W> +where + W: Write, +{ + type Ok = (); + type Error = Error; + + #[inline] + fn serialize_field<T>(&mut self, value: &T) -> Result<()> + where + T: ?Sized + ser::Serialize, + { + value.serialize(&mut **self) + } + + #[inline] + fn end(self) -> Result<()> { + Ok(()) + } +} + +impl<'a, W> ser::SerializeTupleVariant for &'a mut Serializer<W> +where + W: Write, +{ + type Ok = (); + type Error = Error; + + #[inline] + fn serialize_field<T>(&mut self, value: &T) -> Result<()> + where + T: ?Sized + ser::Serialize, + { + value.serialize(&mut **self) + } + + #[inline] + fn end(self) -> Result<()> { + Ok(()) + } +} + +#[doc(hidden)] +pub struct StructSerializer<'a, W> { + ser: &'a mut Serializer<W>, + idx: u32, +} + +impl<'a, W> StructSerializer<'a, W> +where + W: Write, +{ + #[inline] + fn serialize_field_inner<T>(&mut self, key: &'static str, value: &T) -> Result<()> + where + T: ?Sized + ser::Serialize, + { + if self.ser.packed { + self.idx.serialize(&mut *self.ser)?; + } else { + key.serialize(&mut *self.ser)?; + } + value.serialize(&mut *self.ser)?; + self.idx += 1; + Ok(()) + } + + #[inline] + fn skip_field_inner(&mut self, _: &'static str) -> Result<()> { + self.idx += 1; + Ok(()) + } + + #[inline] + fn end_inner(self) -> Result<()> { + Ok(()) + } +} + +impl<'a, W> ser::SerializeStruct for StructSerializer<'a, W> +where + W: Write, +{ + type Ok = (); + type Error = Error; + + #[inline] + fn serialize_field<T>(&mut self, key: &'static str, value: &T) -> Result<()> + where + T: ?Sized + ser::Serialize, + { + self.serialize_field_inner(key, value) + } + + #[inline] + fn skip_field(&mut self, key: &'static str) -> Result<()> { + self.skip_field_inner(key) + } + + #[inline] + fn end(self) -> Result<()> { + self.end_inner() + } +} + +impl<'a, W> ser::SerializeStructVariant for StructSerializer<'a, W> +where + W: Write, +{ + type Ok = (); + type Error = Error; + + #[inline] + fn serialize_field<T>(&mut self, key: &'static str, value: &T) -> Result<()> + where + T: ?Sized + ser::Serialize, + { + self.serialize_field_inner(key, value) + } + + #[inline] + fn skip_field(&mut self, key: &'static str) -> Result<()> { + self.skip_field_inner(key) + } + + #[inline] + fn end(self) -> Result<()> { + self.end_inner() + } +} + +#[doc(hidden)] +pub struct CollectionSerializer<'a, W> { + ser: &'a mut Serializer<W>, + needs_eof: bool, +} + +impl<'a, W> CollectionSerializer<'a, W> +where + W: Write, +{ + #[inline] + fn end_inner(self) -> Result<()> { + if self.needs_eof { + self.ser.writer.write_all(&[0xff]).map_err(|e| e.into()) + } else { + Ok(()) + } + } +} + +impl<'a, W> ser::SerializeSeq for CollectionSerializer<'a, W> +where + W: Write, +{ + type Ok = (); + type Error = Error; + + #[inline] + fn serialize_element<T>(&mut self, value: &T) -> Result<()> + where + T: ?Sized + ser::Serialize, + { + value.serialize(&mut *self.ser) + } + + #[inline] + fn end(self) -> Result<()> { + self.end_inner() + } +} + +impl<'a, W> ser::SerializeMap for CollectionSerializer<'a, W> +where + W: Write, +{ + type Ok = (); + type Error = Error; + + #[inline] + fn serialize_key<T>(&mut self, key: &T) -> Result<()> + where + T: ?Sized + ser::Serialize, + { + key.serialize(&mut *self.ser) + } + + #[inline] + fn serialize_value<T>(&mut self, value: &T) -> Result<()> + where + T: ?Sized + ser::Serialize, + { + value.serialize(&mut *self.ser) + } + + #[inline] + fn end(self) -> Result<()> { + self.end_inner() + } +} diff --git a/third_party/rust/serde_cbor/src/tags.rs b/third_party/rust/serde_cbor/src/tags.rs new file mode 100644 index 0000000000..8adccb8ea8 --- /dev/null +++ b/third_party/rust/serde_cbor/src/tags.rs @@ -0,0 +1,220 @@ +//! Support for cbor tags +use core::fmt; +use core::marker::PhantomData; +use serde::de::{ + Deserialize, Deserializer, EnumAccess, IntoDeserializer, MapAccess, SeqAccess, Visitor, +}; +use serde::forward_to_deserialize_any; +use serde::ser::{Serialize, Serializer}; + +/// signals that a newtype is from a CBOR tag +pub(crate) const CBOR_NEWTYPE_NAME: &str = "\0cbor_tag"; + +/// A value that is optionally tagged with a cbor tag +/// +/// this only serves as an intermediate helper for tag serialization or deserialization +pub struct Tagged<T> { + /// cbor tag + pub tag: Option<u64>, + /// value + pub value: T, +} + +impl<T> Tagged<T> { + /// Create a new tagged value + pub fn new(tag: Option<u64>, value: T) -> Self { + Self { tag, value } + } +} + +impl<T: Serialize> Serialize for Tagged<T> { + fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> { + set_tag(self.tag); + let r = s.serialize_newtype_struct(CBOR_NEWTYPE_NAME, &self.value); + set_tag(None); + r + } +} + +fn untagged<T>(value: T) -> Tagged<T> { + Tagged::new(None, value) +} + +macro_rules! delegate { + ($name: ident, $type: ty) => { + fn $name<E: serde::de::Error>(self, v: $type) -> Result<Self::Value, E> { + T::deserialize(v.into_deserializer()).map(untagged) + } + }; +} + +struct EnumDeserializer<A>(A); + +impl<'de, A> Deserializer<'de> for EnumDeserializer<A> +where + A: EnumAccess<'de>, +{ + type Error = A::Error; + + fn deserialize_any<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Self::Error> { + visitor.visit_enum(self.0) + } + + forward_to_deserialize_any! { + bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string + bytes byte_buf option unit unit_struct newtype_struct seq tuple + tuple_struct map struct enum identifier ignored_any + } +} + +struct NoneDeserializer<E>(PhantomData<E>); + +impl<'de, E> Deserializer<'de> for NoneDeserializer<E> +where + E: serde::de::Error, +{ + type Error = E; + + fn deserialize_any<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Self::Error> { + visitor.visit_none() + } + + forward_to_deserialize_any! { + bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string + bytes byte_buf option unit unit_struct newtype_struct seq tuple + tuple_struct map struct enum identifier ignored_any + } +} + +struct BytesDeserializer<'a, E>(&'a [u8], PhantomData<E>); + +impl<'de, 'a, E> Deserializer<'de> for BytesDeserializer<'a, E> +where + E: serde::de::Error, +{ + type Error = E; + + fn deserialize_any<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Self::Error> { + visitor.visit_bytes(self.0) + } + + forward_to_deserialize_any! { + bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string + bytes byte_buf option unit unit_struct newtype_struct seq tuple + tuple_struct map struct enum identifier ignored_any + } +} + +/// A visitor that intercepts *just* visit_newtype_struct and passes through everything else. +struct MaybeTaggedVisitor<T>(PhantomData<T>); + +impl<'de, T: Deserialize<'de>> Visitor<'de> for MaybeTaggedVisitor<T> { + type Value = Tagged<T>; + + fn expecting(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.write_str("a cbor tag newtype") + } + + delegate!(visit_bool, bool); + + delegate!(visit_i8, i8); + delegate!(visit_i16, i16); + delegate!(visit_i32, i32); + delegate!(visit_i64, i64); + + delegate!(visit_u8, u8); + delegate!(visit_u16, u16); + delegate!(visit_u32, u32); + delegate!(visit_u64, u64); + + delegate!(visit_f32, f32); + delegate!(visit_f64, f64); + + delegate!(visit_char, char); + delegate!(visit_str, &str); + delegate!(visit_borrowed_str, &'de str); + + #[cfg(feature = "std")] + delegate!(visit_byte_buf, Vec<u8>); + + #[cfg(feature = "std")] + delegate!(visit_string, String); + + fn visit_bytes<E: serde::de::Error>(self, value: &[u8]) -> Result<Self::Value, E> { + T::deserialize(BytesDeserializer(value, PhantomData)).map(untagged) + } + + fn visit_borrowed_bytes<E: serde::de::Error>(self, value: &'de [u8]) -> Result<Self::Value, E> { + T::deserialize(serde::de::value::BorrowedBytesDeserializer::new(value)).map(untagged) + } + + fn visit_unit<E: serde::de::Error>(self) -> Result<Self::Value, E> { + T::deserialize(().into_deserializer()).map(untagged) + } + + fn visit_none<E: serde::de::Error>(self) -> Result<Self::Value, E> { + T::deserialize(NoneDeserializer(PhantomData)).map(untagged) + } + + fn visit_some<D: Deserializer<'de>>(self, deserializer: D) -> Result<Self::Value, D::Error> { + T::deserialize(deserializer).map(untagged) + } + + fn visit_seq<A: SeqAccess<'de>>(self, seq: A) -> Result<Self::Value, A::Error> { + T::deserialize(serde::de::value::SeqAccessDeserializer::new(seq)).map(untagged) + } + + fn visit_map<V: MapAccess<'de>>(self, map: V) -> Result<Self::Value, V::Error> { + T::deserialize(serde::de::value::MapAccessDeserializer::new(map)).map(untagged) + } + + fn visit_enum<A: EnumAccess<'de>>(self, data: A) -> Result<Self::Value, A::Error> { + T::deserialize(EnumDeserializer(data)).map(untagged) + } + + fn visit_newtype_struct<D: serde::Deserializer<'de>>( + self, + deserializer: D, + ) -> Result<Self::Value, D::Error> { + let t = get_tag(); + T::deserialize(deserializer).map(|v| Tagged::new(t, v)) + } +} + +impl<'de, T: serde::de::Deserialize<'de>> serde::de::Deserialize<'de> for Tagged<T> { + fn deserialize<D: serde::de::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> { + deserializer.deserialize_any(MaybeTaggedVisitor::<T>(PhantomData)) + } +} + +/// function to get the current cbor tag +/// +/// The only place where it makes sense to call this function is within visit_newtype_struct of a serde visitor. +/// This is a low level API. In most cases it is preferable to use Tagged +pub fn current_cbor_tag() -> Option<u64> { + get_tag() +} + +#[cfg(feature = "tags")] +pub(crate) fn set_tag(value: Option<u64>) { + CBOR_TAG.with(|f| *f.borrow_mut() = value); +} + +#[cfg(feature = "tags")] +pub(crate) fn get_tag() -> Option<u64> { + CBOR_TAG.with(|f| *f.borrow()) +} + +#[cfg(not(feature = "tags"))] +pub(crate) fn set_tag(_value: Option<u64>) {} + +#[cfg(not(feature = "tags"))] +pub(crate) fn get_tag() -> Option<u64> { + None +} + +#[cfg(feature = "tags")] +use std::cell::RefCell; + +#[cfg(feature = "tags")] +thread_local!(static CBOR_TAG: RefCell<Option<u64>> = RefCell::new(None)); diff --git a/third_party/rust/serde_cbor/src/value/de.rs b/third_party/rust/serde_cbor/src/value/de.rs new file mode 100644 index 0000000000..f5bdbb7467 --- /dev/null +++ b/third_party/rust/serde_cbor/src/value/de.rs @@ -0,0 +1,166 @@ +use std::collections::BTreeMap; +use std::fmt; + +use crate::value::Value; +use serde::de; + +impl<'de> de::Deserialize<'de> for Value { + #[inline] + fn deserialize<D>(deserializer: D) -> Result<Value, D::Error> + where + D: de::Deserializer<'de>, + { + struct ValueVisitor; + + impl<'de> de::Visitor<'de> for ValueVisitor { + type Value = Value; + + fn expecting(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.write_str("any valid CBOR value") + } + + #[inline] + fn visit_str<E>(self, value: &str) -> Result<Value, E> + where + E: de::Error, + { + self.visit_string(String::from(value)) + } + + #[inline] + fn visit_string<E>(self, value: String) -> Result<Value, E> + where + E: de::Error, + { + Ok(Value::Text(value)) + } + #[inline] + fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E> + where + E: de::Error, + { + self.visit_byte_buf(v.to_owned()) + } + + #[inline] + fn visit_byte_buf<E>(self, v: Vec<u8>) -> Result<Self::Value, E> + where + E: de::Error, + { + Ok(Value::Bytes(v)) + } + + #[inline] + fn visit_u64<E>(self, v: u64) -> Result<Self::Value, E> + where + E: de::Error, + { + Ok(Value::Integer(v.into())) + } + + #[inline] + fn visit_i64<E>(self, v: i64) -> Result<Self::Value, E> + where + E: de::Error, + { + Ok(Value::Integer(v.into())) + } + + #[inline] + fn visit_i128<E>(self, v: i128) -> Result<Self::Value, E> + where + E: de::Error, + { + Ok(Value::Integer(v)) + } + + #[inline] + fn visit_bool<E>(self, v: bool) -> Result<Self::Value, E> + where + E: de::Error, + { + Ok(Value::Bool(v)) + } + + #[inline] + fn visit_none<E>(self) -> Result<Self::Value, E> + where + E: de::Error, + { + self.visit_unit() + } + + #[inline] + fn visit_unit<E>(self) -> Result<Self::Value, E> + where + E: de::Error, + { + Ok(Value::Null) + } + + #[inline] + fn visit_seq<V>(self, mut visitor: V) -> Result<Self::Value, V::Error> + where + V: de::SeqAccess<'de>, + { + let mut vec = Vec::new(); + + while let Some(elem) = visitor.next_element()? { + vec.push(elem); + } + + Ok(Value::Array(vec)) + } + + #[inline] + fn visit_map<V>(self, mut visitor: V) -> Result<Value, V::Error> + where + V: de::MapAccess<'de>, + { + let mut values = BTreeMap::new(); + + while let Some((key, value)) = visitor.next_entry()? { + values.insert(key, value); + } + + Ok(Value::Map(values)) + } + + #[inline] + fn visit_f64<E>(self, v: f64) -> Result<Self::Value, E> + where + E: de::Error, + { + Ok(Value::Float(v)) + } + + fn visit_newtype_struct<D>(self, deserializer: D) -> Result<Self::Value, D::Error> + where + D: serde::Deserializer<'de>, + { + let tag = crate::tags::get_tag(); + let inner = deserializer.deserialize_any(self); + match tag { + Some(tag) => inner.map(|v| Value::Tag(tag, Box::new(v))), + None => inner, + } + } + } + + deserializer.deserialize_any(ValueVisitor) + } +} + +/// Convert a `serde_cbor::Value` into a type `T` +#[allow(clippy::needless_pass_by_value)] +pub fn from_value<T>(value: Value) -> Result<T, crate::error::Error> +where + T: de::DeserializeOwned, +{ + // TODO implement in a way that doesn't require + // roundtrip through buffer (i.e. by implementing + // `serde::de::Deserializer` for `Value` and then doing + // `T::deserialize(value)`). + let buf = crate::to_vec(&value)?; + crate::from_slice(buf.as_slice()) +} diff --git a/third_party/rust/serde_cbor/src/value/mod.rs b/third_party/rust/serde_cbor/src/value/mod.rs new file mode 100644 index 0000000000..7bd2255314 --- /dev/null +++ b/third_party/rust/serde_cbor/src/value/mod.rs @@ -0,0 +1,156 @@ +//! CBOR values, keys and serialization routines. + +mod de; +mod ser; + +use std::cmp::{Ord, Ordering, PartialOrd}; +use std::collections::BTreeMap; + +#[doc(inline)] +pub use self::de::from_value; +#[doc(inline)] +pub use self::ser::to_value; + +/// The `Value` enum, a loosely typed way of representing any valid CBOR value. +/// +/// Maps are sorted according to the canonical ordering +/// described in [RFC 7049 bis]. +/// Therefore values are unambiguously serialized +/// to a canonical form of CBOR from the same RFC. +/// +/// [RFC 7049 bis]: https://tools.ietf.org/html/draft-ietf-cbor-7049bis-04#section-2 +#[derive(Clone, Debug)] +pub enum Value { + /// Represents the absence of a value or the value undefined. + Null, + /// Represents a boolean value. + Bool(bool), + /// Integer CBOR numbers. + /// + /// The biggest value that can be represented is 2^64 - 1. + /// While the smallest value is -2^64. + /// Values outside this range can't be serialized + /// and will cause an error. + Integer(i128), + /// Represents a floating point value. + Float(f64), + /// Represents a byte string. + Bytes(Vec<u8>), + /// Represents an UTF-8 encoded string. + Text(String), + /// Represents an array of values. + Array(Vec<Value>), + /// Represents a map. + /// + /// Maps are also called tables, dictionaries, hashes, or objects (in JSON). + /// While any value can be used as a CBOR key + /// it is better to use only one type of key in a map + /// to avoid ambiguity. + /// If floating point values are used as keys they are compared bit-by-bit for equality. + /// If arrays or maps are used as keys the comparisons + /// to establish canonical order may be slow and therefore insertion + /// and retrieval of values will be slow too. + Map(BTreeMap<Value, Value>), + /// Represents a tagged value + Tag(u64, Box<Value>), + // The hidden variant allows the enum to be extended + // with variants for tags and simple values. + #[doc(hidden)] + __Hidden, +} + +impl PartialEq for Value { + fn eq(&self, other: &Value) -> bool { + self.cmp(other) == Ordering::Equal + } +} + +impl Eq for Value {} + +impl PartialOrd for Value { + fn partial_cmp(&self, other: &Value) -> Option<Ordering> { + Some(self.cmp(other)) + } +} + +impl Ord for Value { + fn cmp(&self, other: &Value) -> Ordering { + // Determine the canonical order of two values: + // 1. Smaller major type sorts first. + // 2. Shorter sequence sorts first. + // 3. Compare integers by magnitude. + // 4. Compare byte and text sequences lexically. + // 5. Compare the serializations of both types. (expensive) + use self::Value::*; + if self.major_type() != other.major_type() { + return self.major_type().cmp(&other.major_type()); + } + match (self, other) { + (Integer(a), Integer(b)) => a.abs().cmp(&b.abs()), + (Bytes(a), Bytes(b)) if a.len() != b.len() => a.len().cmp(&b.len()), + (Text(a), Text(b)) if a.len() != b.len() => a.len().cmp(&b.len()), + (Array(a), Array(b)) if a.len() != b.len() => a.len().cmp(&b.len()), + (Map(a), Map(b)) if a.len() != b.len() => a.len().cmp(&b.len()), + (Bytes(a), Bytes(b)) => a.cmp(b), + (Text(a), Text(b)) => a.cmp(b), + (a, b) => { + let a = crate::to_vec(a).expect("self is serializable"); + let b = crate::to_vec(b).expect("other is serializable"); + a.cmp(&b) + } + } + } +} + +macro_rules! impl_from { + ($variant:path, $for_type:ty) => { + impl From<$for_type> for Value { + fn from(v: $for_type) -> Value { + $variant(v.into()) + } + } + }; +} + +impl_from!(Value::Bool, bool); +impl_from!(Value::Integer, i8); +impl_from!(Value::Integer, i16); +impl_from!(Value::Integer, i32); +impl_from!(Value::Integer, i64); +// i128 omitted because not all numbers fit in CBOR serialization +impl_from!(Value::Integer, u8); +impl_from!(Value::Integer, u16); +impl_from!(Value::Integer, u32); +impl_from!(Value::Integer, u64); +// u128 omitted because not all numbers fit in CBOR serialization +impl_from!(Value::Float, f32); +impl_from!(Value::Float, f64); +impl_from!(Value::Bytes, Vec<u8>); +impl_from!(Value::Text, String); +// TODO: figure out if these impls should be more generic or removed. +impl_from!(Value::Array, Vec<Value>); +impl_from!(Value::Map, BTreeMap<Value, Value>); + +impl Value { + fn major_type(&self) -> u8 { + use self::Value::*; + match self { + Null => 7, + Bool(_) => 7, + Integer(v) => { + if *v >= 0 { + 0 + } else { + 1 + } + } + Tag(_, _) => 6, + Float(_) => 7, + Bytes(_) => 2, + Text(_) => 3, + Array(_) => 4, + Map(_) => 5, + __Hidden => unreachable!(), + } + } +} diff --git a/third_party/rust/serde_cbor/src/value/ser.rs b/third_party/rust/serde_cbor/src/value/ser.rs new file mode 100644 index 0000000000..347aae9601 --- /dev/null +++ b/third_party/rust/serde_cbor/src/value/ser.rs @@ -0,0 +1,443 @@ +// Copyright 2017 Serde Developers +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::collections::BTreeMap; + +use crate::error::Error; +use serde::{self, Serialize}; + +use crate::tags::Tagged; +use crate::value::Value; + +impl serde::Serialize for Value { + #[inline] + fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + where + S: serde::Serializer, + { + match *self { + Value::Integer(v) => serializer.serialize_i128(v), + Value::Bytes(ref v) => serializer.serialize_bytes(&v), + Value::Text(ref v) => serializer.serialize_str(&v), + Value::Array(ref v) => v.serialize(serializer), + Value::Map(ref v) => v.serialize(serializer), + Value::Tag(tag, ref v) => Tagged::new(Some(tag), v).serialize(serializer), + Value::Float(v) => serializer.serialize_f64(v), + Value::Bool(v) => serializer.serialize_bool(v), + Value::Null => serializer.serialize_unit(), + Value::__Hidden => unreachable!(), + } + } +} + +struct Serializer; + +impl serde::Serializer for Serializer { + type Ok = Value; + type Error = Error; + + type SerializeSeq = SerializeVec; + type SerializeTuple = SerializeVec; + type SerializeTupleStruct = SerializeVec; + type SerializeTupleVariant = SerializeTupleVariant; + type SerializeMap = SerializeMap; + type SerializeStruct = SerializeMap; + type SerializeStructVariant = SerializeStructVariant; + + #[inline] + fn serialize_bool(self, value: bool) -> Result<Value, Error> { + Ok(Value::Bool(value)) + } + + #[inline] + fn serialize_i8(self, value: i8) -> Result<Value, Error> { + self.serialize_i64(i64::from(value)) + } + + #[inline] + fn serialize_i16(self, value: i16) -> Result<Value, Error> { + self.serialize_i64(i64::from(value)) + } + + #[inline] + fn serialize_i32(self, value: i32) -> Result<Value, Error> { + self.serialize_i64(i64::from(value)) + } + + #[inline] + fn serialize_i64(self, value: i64) -> Result<Value, Error> { + self.serialize_i128(i128::from(value)) + } + + fn serialize_i128(self, value: i128) -> Result<Value, Error> { + Ok(Value::Integer(value)) + } + + #[inline] + fn serialize_u8(self, value: u8) -> Result<Value, Error> { + self.serialize_u64(u64::from(value)) + } + + #[inline] + fn serialize_u16(self, value: u16) -> Result<Value, Error> { + self.serialize_u64(u64::from(value)) + } + + #[inline] + fn serialize_u32(self, value: u32) -> Result<Value, Error> { + self.serialize_u64(u64::from(value)) + } + + #[inline] + fn serialize_u64(self, value: u64) -> Result<Value, Error> { + Ok(Value::Integer(value.into())) + } + + #[inline] + fn serialize_f32(self, value: f32) -> Result<Value, Error> { + self.serialize_f64(f64::from(value)) + } + + #[inline] + fn serialize_f64(self, value: f64) -> Result<Value, Error> { + Ok(Value::Float(value)) + } + + #[inline] + fn serialize_char(self, value: char) -> Result<Value, Error> { + let mut s = String::new(); + s.push(value); + self.serialize_str(&s) + } + + #[inline] + fn serialize_str(self, value: &str) -> Result<Value, Error> { + Ok(Value::Text(value.to_owned())) + } + + fn serialize_bytes(self, value: &[u8]) -> Result<Value, Error> { + Ok(Value::Bytes(value.to_vec())) + } + + #[inline] + fn serialize_unit(self) -> Result<Value, Error> { + Ok(Value::Null) + } + + #[inline] + fn serialize_unit_struct(self, _name: &'static str) -> Result<Value, Error> { + self.serialize_unit() + } + + #[inline] + fn serialize_unit_variant( + self, + _name: &'static str, + _variant_index: u32, + variant: &'static str, + ) -> Result<Value, Error> { + self.serialize_str(variant) + } + + #[inline] + fn serialize_newtype_struct<T: ?Sized>( + self, + _name: &'static str, + value: &T, + ) -> Result<Value, Error> + where + T: Serialize, + { + value.serialize(self) + } + + fn serialize_newtype_variant<T: ?Sized>( + self, + _name: &'static str, + _variant_index: u32, + variant: &'static str, + value: &T, + ) -> Result<Value, Error> + where + T: Serialize, + { + let mut values = BTreeMap::new(); + values.insert(Value::from(variant.to_owned()), to_value(&value)?); + Ok(Value::Map(values)) + } + + #[inline] + fn serialize_none(self) -> Result<Value, Error> { + self.serialize_unit() + } + + #[inline] + fn serialize_some<T: ?Sized>(self, value: &T) -> Result<Value, Error> + where + T: Serialize, + { + value.serialize(self) + } + + fn serialize_seq(self, len: Option<usize>) -> Result<Self::SerializeSeq, Error> { + Ok(SerializeVec { + vec: Vec::with_capacity(len.unwrap_or(0)), + }) + } + + fn serialize_tuple(self, len: usize) -> Result<Self::SerializeTuple, Error> { + self.serialize_seq(Some(len)) + } + + fn serialize_tuple_struct( + self, + _name: &'static str, + len: usize, + ) -> Result<Self::SerializeTupleStruct, Error> { + self.serialize_tuple(len) + } + + fn serialize_tuple_variant( + self, + _name: &'static str, + _variant_index: u32, + variant: &'static str, + len: usize, + ) -> Result<Self::SerializeTupleVariant, Error> { + Ok(SerializeTupleVariant { + name: String::from(variant), + vec: Vec::with_capacity(len), + }) + } + + fn serialize_map(self, _len: Option<usize>) -> Result<Self::SerializeMap, Error> { + Ok(SerializeMap { + map: BTreeMap::new(), + next_key: None, + }) + } + + fn serialize_struct( + self, + _name: &'static str, + len: usize, + ) -> Result<Self::SerializeStruct, Error> { + self.serialize_map(Some(len)) + } + + fn serialize_struct_variant( + self, + _name: &'static str, + _variant_index: u32, + variant: &'static str, + _len: usize, + ) -> Result<Self::SerializeStructVariant, Error> { + Ok(SerializeStructVariant { + name: String::from(variant), + map: BTreeMap::new(), + }) + } + + #[inline] + fn is_human_readable(&self) -> bool { + false + } +} + +pub struct SerializeVec { + vec: Vec<Value>, +} + +pub struct SerializeTupleVariant { + name: String, + vec: Vec<Value>, +} + +pub struct SerializeMap { + map: BTreeMap<Value, Value>, + next_key: Option<Value>, +} + +pub struct SerializeStructVariant { + name: String, + map: BTreeMap<Value, Value>, +} + +impl serde::ser::SerializeSeq for SerializeVec { + type Ok = Value; + type Error = Error; + + fn serialize_element<T: ?Sized>(&mut self, value: &T) -> Result<(), Error> + where + T: Serialize, + { + self.vec.push(to_value(&value)?); + Ok(()) + } + + fn end(self) -> Result<Value, Error> { + Ok(Value::Array(self.vec)) + } +} + +impl serde::ser::SerializeTuple for SerializeVec { + type Ok = Value; + type Error = Error; + + fn serialize_element<T: ?Sized>(&mut self, value: &T) -> Result<(), Error> + where + T: Serialize, + { + serde::ser::SerializeSeq::serialize_element(self, value) + } + + fn end(self) -> Result<Value, Error> { + serde::ser::SerializeSeq::end(self) + } +} + +impl serde::ser::SerializeTupleStruct for SerializeVec { + type Ok = Value; + type Error = Error; + + fn serialize_field<T: ?Sized>(&mut self, value: &T) -> Result<(), Error> + where + T: Serialize, + { + serde::ser::SerializeSeq::serialize_element(self, value) + } + + fn end(self) -> Result<Value, Error> { + serde::ser::SerializeSeq::end(self) + } +} + +impl serde::ser::SerializeTupleVariant for SerializeTupleVariant { + type Ok = Value; + type Error = Error; + + fn serialize_field<T: ?Sized>(&mut self, value: &T) -> Result<(), Error> + where + T: Serialize, + { + self.vec.push(to_value(&value)?); + Ok(()) + } + + fn end(self) -> Result<Value, Error> { + let mut object = BTreeMap::new(); + + object.insert(Value::from(self.name), Value::Array(self.vec)); + + Ok(Value::Map(object)) + } +} + +impl serde::ser::SerializeMap for SerializeMap { + type Ok = Value; + type Error = Error; + + fn serialize_key<T: ?Sized>(&mut self, key: &T) -> Result<(), Error> + where + T: Serialize, + { + self.next_key = Some(to_value(&key)?); + Ok(()) + } + + fn serialize_value<T: ?Sized>(&mut self, value: &T) -> Result<(), Error> + where + T: Serialize, + { + let key = self.next_key.take(); + // Panic because this indicates a bug in the program rather than an + // expected failure. + let key = key.expect("serialize_value called before serialize_key"); + self.map.insert(key, to_value(&value)?); + Ok(()) + } + + fn end(self) -> Result<Value, Error> { + Ok(Value::Map(self.map)) + } +} + +impl serde::ser::SerializeStruct for SerializeMap { + type Ok = Value; + type Error = Error; + + fn serialize_field<T: ?Sized>(&mut self, key: &'static str, value: &T) -> Result<(), Error> + where + T: Serialize, + { + serde::ser::SerializeMap::serialize_key(self, key)?; + serde::ser::SerializeMap::serialize_value(self, value) + } + + fn end(self) -> Result<Value, Error> { + serde::ser::SerializeMap::end(self) + } +} + +impl serde::ser::SerializeStructVariant for SerializeStructVariant { + type Ok = Value; + type Error = Error; + + fn serialize_field<T: ?Sized>(&mut self, key: &'static str, value: &T) -> Result<(), Error> + where + T: Serialize, + { + self.map + .insert(Value::from(String::from(key)), to_value(&value)?); + Ok(()) + } + + fn end(self) -> Result<Value, Error> { + let mut object = BTreeMap::new(); + + object.insert(Value::from(self.name), Value::Map(self.map)); + + Ok(Value::Map(object)) + } +} + +/// Convert a `T` into `serde_cbor::Value` which is an enum that can represent +/// any valid CBOR data. +/// +/// ```rust +/// extern crate serde; +/// +/// #[macro_use] +/// extern crate serde_derive; +/// extern crate serde_cbor; +/// +/// use std::error::Error; +/// +/// #[derive(Serialize)] +/// struct User { +/// fingerprint: String, +/// location: String, +/// } +/// +/// fn main() { +/// let u = User { +/// fingerprint: "0xF9BA143B95FF6D82".to_owned(), +/// location: "Menlo Park, CA".to_owned(), +/// }; +/// +/// let v = serde_cbor::value::to_value(u).unwrap(); +/// } +/// ``` +#[allow(clippy::needless_pass_by_value)] +// Taking by value is more friendly to iterator adapters, option and result +pub fn to_value<T>(value: T) -> Result<Value, Error> +where + T: Serialize, +{ + value.serialize(Serializer) +} diff --git a/third_party/rust/serde_cbor/src/write.rs b/third_party/rust/serde_cbor/src/write.rs new file mode 100644 index 0000000000..94c326ef96 --- /dev/null +++ b/third_party/rust/serde_cbor/src/write.rs @@ -0,0 +1,175 @@ +#[cfg(feature = "alloc")] +use alloc::vec::Vec; +#[cfg(not(feature = "std"))] +use core::fmt; +#[cfg(feature = "std")] +use std::io; + +use crate::error; + +#[cfg(not(feature = "unsealed_read_write"))] +/// A sink for serialized CBOR. +/// +/// This trait is similar to the [`Write`]() trait in the standard library, +/// but has a smaller and more general API. +/// +/// Any object implementing `std::io::Write` +/// can be wrapped in an [`IoWrite`](../write/struct.IoWrite.html) that implements +/// this trait for the underlying object. +pub trait Write: private::Sealed { + /// The type of error returned when a write operation fails. + #[doc(hidden)] + type Error: Into<error::Error>; + + /// Attempts to write an entire buffer into this write. + #[doc(hidden)] + fn write_all(&mut self, buf: &[u8]) -> Result<(), Self::Error>; +} + +#[cfg(feature = "unsealed_read_write")] +/// A sink for serialized CBOR. +/// +/// This trait is similar to the [`Write`]() trait in the standard library, +/// but has a smaller and more general API. +/// +/// Any object implementing `std::io::Write` +/// can be wrapped in an [`IoWrite`](../write/struct.IoWrite.html) that implements +/// this trait for the underlying object. +/// +/// This trait is sealed by default, enabling the `unsealed_read_write` feature removes this bound +/// to allow objects outside of this crate to implement this trait. +pub trait Write { + /// The type of error returned when a write operation fails. + type Error: Into<error::Error>; + + /// Attempts to write an entire buffer into this write. + fn write_all(&mut self, buf: &[u8]) -> Result<(), Self::Error>; +} + +#[cfg(not(feature = "unsealed_read_write"))] +mod private { + pub trait Sealed {} +} + +impl<W> Write for &mut W +where + W: Write, +{ + type Error = W::Error; + + fn write_all(&mut self, buf: &[u8]) -> Result<(), Self::Error> { + (*self).write_all(buf) + } +} + +#[cfg(not(feature = "unsealed_read_write"))] +impl<W> private::Sealed for &mut W where W: Write {} + +#[cfg(feature = "std")] +/// A wrapper for types that implement +/// [`std::io::Write`](https://doc.rust-lang.org/std/io/trait.Write.html) to implement the local +/// [`Write`](trait.Write.html) trait. +#[derive(Debug)] +pub struct IoWrite<W>(W); + +#[cfg(feature = "std")] +impl<W: io::Write> IoWrite<W> { + /// Wraps an `io::Write` writer to make it compatible with [`Write`](trait.Write.html) + pub fn new(w: W) -> IoWrite<W> { + IoWrite(w) + } +} + +#[cfg(feature = "std")] +impl<W: io::Write> Write for IoWrite<W> { + type Error = io::Error; + + fn write_all(&mut self, buf: &[u8]) -> Result<(), Self::Error> { + self.0.write_all(buf) + } +} + +#[cfg(all(feature = "std", not(feature = "unsealed_read_write")))] +impl<W> private::Sealed for IoWrite<W> where W: io::Write {} + +#[cfg(any(feature = "std", feature = "alloc"))] +impl Write for Vec<u8> { + type Error = error::Error; + + fn write_all(&mut self, buf: &[u8]) -> Result<(), Self::Error> { + self.extend_from_slice(buf); + Ok(()) + } +} + +#[cfg(all( + any(feature = "std", feature = "alloc"), + not(feature = "unsealed_read_write") +))] +impl private::Sealed for Vec<u8> {} + +#[cfg(not(feature = "std"))] +#[derive(Debug)] +pub struct FmtWrite<'a, W: Write>(&'a mut W); + +#[cfg(not(feature = "std"))] +impl<'a, W: Write> FmtWrite<'a, W> { + /// Wraps an `fmt::Write` writer to make it compatible with [`Write`](trait.Write.html) + pub fn new(w: &'a mut W) -> FmtWrite<'a, W> { + FmtWrite(w) + } +} + +#[cfg(not(feature = "std"))] +impl<'a, W: Write> fmt::Write for FmtWrite<'a, W> { + fn write_str(&mut self, s: &str) -> fmt::Result { + self.0.write_all(s.as_bytes()).map_err(|_| fmt::Error) + } +} + +#[cfg(all(not(feature = "std"), not(feature = "unsealed_read_write")))] +impl<'a, W> private::Sealed for FmtWrite<'a, W> where W: Write {} + +/// Implements [`Write`](trait.Write.html) for mutable byte slices (`&mut [u8]`). +/// +/// Returns an error if the value to serialize is too large to fit in the slice. +#[derive(Debug)] +pub struct SliceWrite<'a> { + slice: &'a mut [u8], + index: usize, +} + +impl<'a> SliceWrite<'a> { + /// Wraps a mutable slice so it can be used as a `Write`. + pub fn new(slice: &'a mut [u8]) -> SliceWrite<'a> { + SliceWrite { slice, index: 0 } + } + + /// Returns the number of bytes written to the underlying slice. + pub fn bytes_written(&self) -> usize { + self.index + } + + /// Returns the underlying slice. + pub fn into_inner(self) -> &'a mut [u8] { + self.slice + } +} + +impl<'a> Write for SliceWrite<'a> { + type Error = error::Error; + + fn write_all(&mut self, buf: &[u8]) -> Result<(), Self::Error> { + if self.slice.len() - self.index < buf.len() { + // This buffer will not fit in our slice + return Err(error::Error::scratch_too_small(self.index as u64)); + } + let end = self.index + buf.len(); + self.slice[self.index..end].copy_from_slice(buf); + self.index = end; + Ok(()) + } +} + +#[cfg(not(feature = "unsealed_read_write"))] +impl<'a> private::Sealed for SliceWrite<'a> {} diff --git a/third_party/rust/serde_cbor/tests/bennofs.rs b/third_party/rust/serde_cbor/tests/bennofs.rs new file mode 100644 index 0000000000..1b289f40d4 --- /dev/null +++ b/third_party/rust/serde_cbor/tests/bennofs.rs @@ -0,0 +1,60 @@ +#[macro_use] +extern crate serde_derive; + +use serde::Serialize; +use serde_cbor::ser::SliceWrite; +use serde_cbor::{self, Serializer}; + +#[derive(Debug, PartialEq, Serialize, Deserialize)] +struct Example { + foo: Foo, + payload: u8, +} + +#[derive(Debug, PartialEq, Serialize, Deserialize)] +struct Foo { + x: u8, + color: Color, +} + +#[derive(Debug, PartialEq, Serialize, Deserialize)] +enum Color { + Red, + Blue, + Yellow(u8), +} + +const EXAMPLE: Example = Example { + foo: Foo { + x: 0xAA, + color: Color::Yellow(40), + }, + payload: 0xCC, +}; + +#[cfg(feature = "std")] +mod std_tests { + use super::*; + + #[test] + fn test() { + let serialized = serde_cbor::ser::to_vec_packed(&EXAMPLE).expect("bennofs 1"); + println!("{:?}", serialized); + let deserialized: Example = serde_cbor::from_slice(&serialized).expect("bennofs 2"); + assert_eq!(EXAMPLE, deserialized); + } +} + +#[test] +fn test() { + let mut slice = [0u8; 64]; + let writer = SliceWrite::new(&mut slice); + let mut serializer = Serializer::new(writer).packed_format(); + EXAMPLE.serialize(&mut serializer).unwrap(); + let writer = serializer.into_inner(); + let end = writer.bytes_written(); + let slice = writer.into_inner(); + let deserialized: Example = + serde_cbor::de::from_slice_with_scratch(&slice[..end], &mut []).unwrap(); + assert_eq!(EXAMPLE, deserialized); +} diff --git a/third_party/rust/serde_cbor/tests/canonical.rs b/third_party/rust/serde_cbor/tests/canonical.rs new file mode 100644 index 0000000000..438e29e7d4 --- /dev/null +++ b/third_party/rust/serde_cbor/tests/canonical.rs @@ -0,0 +1,104 @@ +#[cfg(feature = "std")] +mod std_tests { + use serde_cbor::value::Value; + + #[test] + fn integer_canonical_sort_order() { + let expected = [ + 0, + 23, + 24, + 255, + 256, + 65535, + 65536, + 4294967295, + -1, + -24, + -25, + -256, + -257, + -65536, + -65537, + -4294967296, + ] + .iter() + .map(|i| Value::Integer(*i)) + .collect::<Vec<_>>(); + + let mut sorted = expected.clone(); + sorted.sort(); + + assert_eq!(expected, sorted); + } + + #[test] + fn string_canonical_sort_order() { + let expected = ["", "a", "b", "aa"] + .iter() + .map(|s| Value::Text(s.to_string())) + .collect::<Vec<_>>(); + + let mut sorted = expected.clone(); + sorted.sort(); + + assert_eq!(expected, sorted); + } + + #[test] + fn bytes_canonical_sort_order() { + let expected = vec![vec![], vec![0u8], vec![1u8], vec![0u8, 0u8]] + .into_iter() + .map(|v| Value::Bytes(v)) + .collect::<Vec<_>>(); + + let mut sorted = expected.clone(); + sorted.sort(); + + assert_eq!(expected, sorted); + } + + #[test] + fn simple_data_canonical_sort_order() { + let expected = vec![Value::Bool(false), Value::Bool(true), Value::Null]; + + let mut sorted = expected.clone(); + sorted.sort(); + + assert_eq!(expected, sorted); + } + + #[test] + fn major_type_canonical_sort_order() { + let expected = vec![ + Value::Integer(0), + Value::Integer(-1), + Value::Bytes(vec![]), + Value::Text("".to_string()), + Value::Null, + ]; + + let mut sorted = expected.clone(); + sorted.sort(); + + assert_eq!(expected, sorted); + } + + #[test] + fn test_rfc_example() { + // See: https://tools.ietf.org/html/draft-ietf-cbor-7049bis-04#section-4.10 + let expected = vec![ + Value::Integer(10), + Value::Integer(100), + Value::Integer(-1), + Value::Text("z".to_owned()), + Value::Text("aa".to_owned()), + Value::Array(vec![Value::Integer(100)]), + Value::Array(vec![Value::Integer(-1)]), + Value::Bool(false), + ]; + let mut sorted = expected.clone(); + sorted.sort(); + assert_eq!(expected, sorted); + } +} diff --git a/third_party/rust/serde_cbor/tests/crash.cbor b/third_party/rust/serde_cbor/tests/crash.cbor Binary files differnew file mode 100644 index 0000000000..a3bc785ca3 --- /dev/null +++ b/third_party/rust/serde_cbor/tests/crash.cbor diff --git a/third_party/rust/serde_cbor/tests/de.rs b/third_party/rust/serde_cbor/tests/de.rs new file mode 100644 index 0000000000..01d7914502 --- /dev/null +++ b/third_party/rust/serde_cbor/tests/de.rs @@ -0,0 +1,747 @@ +#[macro_use] +extern crate serde_derive; + +use serde_cbor; +use serde_cbor::de; + +#[test] +fn test_str() { + let s: &str = + de::from_slice_with_scratch(&[0x66, 0x66, 0x6f, 0x6f, 0x62, 0x61, 0x72], &mut []).unwrap(); + assert_eq!(s, "foobar"); +} + +#[test] +fn test_bytes() { + let s: &[u8] = + de::from_slice_with_scratch(&[0x46, 0x66, 0x6f, 0x6f, 0x62, 0x61, 0x72], &mut []).unwrap(); + assert_eq!(s, b"foobar"); +} + +#[test] +fn test_int() { + let num: i64 = de::from_slice_with_scratch(&[0x39, 0x07, 0xde], &mut []).unwrap(); + assert_eq!(num, -2015); +} + +#[test] +fn test_float() { + let float: f64 = de::from_slice_with_scratch(b"\xfa\x47\xc3\x50\x00", &mut []).unwrap(); + assert_eq!(float, 100000.0); +} + +#[test] +fn test_indefinite_object() { + #[derive(Debug, Deserialize, PartialEq)] + struct Foo { + a: u64, + b: [u64; 2], + } + let expected = Foo { a: 1, b: [2, 3] }; + let actual: Foo = + de::from_slice_with_scratch(b"\xbfaa\x01ab\x9f\x02\x03\xff\xff", &mut []).unwrap(); + assert_eq!(expected, actual); +} + +#[cfg(feature = "std")] +mod std_tests { + use std::collections::BTreeMap; + + use serde::de as serde_de; + use serde_cbor::value::Value; + use serde_cbor::{de, error, to_vec, Deserializer}; + + #[test] + fn test_string1() { + let value: error::Result<Value> = + de::from_slice(&[0x66, 0x66, 0x6f, 0x6f, 0x62, 0x61, 0x72]); + assert_eq!(value.unwrap(), Value::Text("foobar".to_owned())); + } + + #[test] + fn test_string2() { + let value: error::Result<Value> = de::from_slice(&[ + 0x71, 0x49, 0x20, 0x6d, 0x65, 0x74, 0x20, 0x61, 0x20, 0x74, 0x72, 0x61, 0x76, 0x65, + 0x6c, 0x6c, 0x65, 0x72, + ]); + assert_eq!(value.unwrap(), Value::Text("I met a traveller".to_owned())); + } + + #[test] + fn test_string3() { + let slice = b"\x78\x2fI met a traveller from an antique land who said"; + let value: error::Result<Value> = de::from_slice(slice); + assert_eq!( + value.unwrap(), + Value::Text("I met a traveller from an antique land who said".to_owned()) + ); + } + + #[test] + fn test_byte_string() { + let value: error::Result<Value> = + de::from_slice(&[0x46, 0x66, 0x6f, 0x6f, 0x62, 0x61, 0x72]); + assert_eq!(value.unwrap(), Value::Bytes(b"foobar".to_vec())); + } + + #[test] + fn test_numbers1() { + let value: error::Result<Value> = de::from_slice(&[0x00]); + assert_eq!(value.unwrap(), Value::Integer(0)); + } + + #[test] + fn test_numbers2() { + let value: error::Result<Value> = de::from_slice(&[0x1a, 0x00, 0xbc, 0x61, 0x4e]); + assert_eq!(value.unwrap(), Value::Integer(12345678)); + } + + #[test] + fn test_numbers3() { + let value: error::Result<Value> = de::from_slice(&[0x39, 0x07, 0xde]); + assert_eq!(value.unwrap(), Value::Integer(-2015)); + } + + #[test] + fn test_bool() { + let value: error::Result<Value> = de::from_slice(b"\xf4"); + assert_eq!(value.unwrap(), Value::Bool(false)); + } + + #[test] + fn test_trailing_bytes() { + let value: error::Result<Value> = de::from_slice(b"\xf4trailing"); + assert!(value.is_err()); + } + + #[test] + fn test_list1() { + let value: error::Result<Value> = de::from_slice(b"\x83\x01\x02\x03"); + assert_eq!( + value.unwrap(), + Value::Array(vec![ + Value::Integer(1), + Value::Integer(2), + Value::Integer(3) + ]) + ); + } + + #[test] + fn test_list2() { + let value: error::Result<Value> = de::from_slice(b"\x82\x01\x82\x02\x81\x03"); + assert_eq!( + value.unwrap(), + Value::Array(vec![ + Value::Integer(1), + Value::Array(vec![ + Value::Integer(2), + Value::Array(vec![Value::Integer(3)]) + ]) + ]) + ); + } + + #[test] + fn test_object() { + let value: error::Result<Value> = de::from_slice(b"\xa5aaaAabaBacaCadaDaeaE"); + let mut object = BTreeMap::new(); + object.insert(Value::Text("a".to_owned()), Value::Text("A".to_owned())); + object.insert(Value::Text("b".to_owned()), Value::Text("B".to_owned())); + object.insert(Value::Text("c".to_owned()), Value::Text("C".to_owned())); + object.insert(Value::Text("d".to_owned()), Value::Text("D".to_owned())); + object.insert(Value::Text("e".to_owned()), Value::Text("E".to_owned())); + assert_eq!(value.unwrap(), Value::Map(object)); + } + + #[test] + fn test_indefinite_object() { + let value: error::Result<Value> = de::from_slice(b"\xbfaa\x01ab\x9f\x02\x03\xff\xff"); + let mut object = BTreeMap::new(); + object.insert(Value::Text("a".to_owned()), Value::Integer(1)); + object.insert( + Value::Text("b".to_owned()), + Value::Array(vec![Value::Integer(2), Value::Integer(3)]), + ); + assert_eq!(value.unwrap(), Value::Map(object)); + } + + #[test] + fn test_indefinite_list() { + let value: error::Result<Value> = de::from_slice(b"\x9f\x01\x02\x03\xff"); + assert_eq!( + value.unwrap(), + Value::Array(vec![ + Value::Integer(1), + Value::Integer(2), + Value::Integer(3) + ]) + ); + } + + #[test] + fn test_indefinite_string() { + let value: error::Result<Value> = + de::from_slice(b"\x7f\x65Mary \x64Had \x62a \x67Little \x60\x64Lamb\xff"); + assert_eq!( + value.unwrap(), + Value::Text("Mary Had a Little Lamb".to_owned()) + ); + } + + #[test] + fn test_indefinite_byte_string() { + let value: error::Result<Value> = de::from_slice(b"\x5f\x42\x01\x23\x42\x45\x67\xff"); + assert_eq!(value.unwrap(), Value::Bytes(b"\x01#Eg".to_vec())); + } + + #[test] + fn test_multiple_indefinite_strings() { + let input = b"\x82\x7f\x65Mary \x64Had \x62a \x67Little \x60\x64Lamb\xff\x5f\x42\x01\x23\x42\x45\x67\xff"; + _test_multiple_indefinite_strings(de::from_slice(input)); + _test_multiple_indefinite_strings(de::from_mut_slice(input.to_vec().as_mut())); + let mut buf = [0u8; 64]; + _test_multiple_indefinite_strings(de::from_slice_with_scratch(input, &mut buf)); + } + fn _test_multiple_indefinite_strings(value: error::Result<Value>) { + // This assures that buffer rewinding in infinite buffers works as intended. + assert_eq!( + value.unwrap(), + Value::Array(vec![ + Value::Text("Mary Had a Little Lamb".to_owned()), + Value::Bytes(b"\x01#Eg".to_vec()) + ]) + ); + } + + #[test] + fn test_float() { + let value: error::Result<Value> = de::from_slice(b"\xfa\x47\xc3\x50\x00"); + assert_eq!(value.unwrap(), Value::Float(100000.0)); + } + + #[test] + fn test_self_describing() { + let value: error::Result<Value> = + de::from_slice(&[0xd9, 0xd9, 0xf7, 0x66, 0x66, 0x6f, 0x6f, 0x62, 0x61, 0x72]); + let expected = Value::Text("foobar".to_owned()); + let strip_tags = |x: Value| { + if let Value::Tag(_, inner) = x { + *inner + } else { + x + } + }; + assert_eq!(strip_tags(value.unwrap()), expected); + } + + #[test] + fn test_f16() { + let mut x: Value = de::from_slice(&[0xf9, 0x41, 0x00]).unwrap(); + assert_eq!(x, Value::Float(2.5)); + x = de::from_slice(&[0xf9, 0x41, 0x90]).unwrap(); + assert_eq!(x, Value::Float(2.78125)); + x = de::from_slice(&[0xf9, 0x50, 0x90]).unwrap(); + assert_eq!(x, Value::Float(36.5)); + x = de::from_slice(&[0xf9, 0xd0, 0x90]).unwrap(); + assert_eq!(x, Value::Float(-36.5)); + } + + #[test] + fn test_crazy_list() { + let slice = b"\x88\x1b\x00\x00\x00\x1c\xbe\x99\x1d\xc7\x3b\x00\x7a\xcf\x51\xdc\x51\x70\xdb\x3a\x1b\x3a\x06\xdd\xf5\xf6\xf7\xfb\x41\x76\x5e\xb1\xf8\x00\x00\x00\xf9\x7c\x00"; + let value: Vec<Value> = de::from_slice(slice).unwrap(); + assert_eq!( + value, + vec![ + Value::Integer(123456789959), + Value::Integer(-34567897654325468), + Value::Integer(-456787678), + Value::Bool(true), + Value::Null, + Value::Null, + Value::Float(23456543.5), + Value::Float(::std::f64::INFINITY) + ] + ); + } + + #[test] + fn test_nan() { + let value: f64 = de::from_slice(b"\xf9\x7e\x00").unwrap(); + assert!(value.is_nan()); + } + + #[test] + fn test_32f16() { + let value: f32 = de::from_slice(b"\xf9\x50\x00").unwrap(); + assert_eq!(value, 32.0f32); + } + + #[test] + // The file was reported as not working by user kie0tauB + // but it parses to a cbor value. + fn test_kietaub_file() { + let file = include_bytes!("kietaub.cbor"); + let value_result: error::Result<Value> = de::from_slice(file); + value_result.unwrap(); + } + + #[test] + fn test_option_roundtrip() { + let obj1 = Some(10u32); + + let v = to_vec(&obj1).unwrap(); + let obj2: Result<Option<u32>, _> = serde_cbor::de::from_reader(&v[..]); + println!("{:?}", obj2); + + assert_eq!(obj1, obj2.unwrap()); + } + + #[test] + fn test_option_none_roundtrip() { + let obj1 = None; + + let v = to_vec(&obj1).unwrap(); + println!("{:?}", v); + let obj2: Result<Option<u32>, _> = serde_cbor::de::from_reader(&v[..]); + + assert_eq!(obj1, obj2.unwrap()); + } + + #[test] + fn test_variable_length_map() { + let slice = b"\xbf\x67\x6d\x65\x73\x73\x61\x67\x65\x64\x70\x6f\x6e\x67\xff"; + let value: Value = de::from_slice(slice).unwrap(); + let mut map = BTreeMap::new(); + map.insert( + Value::Text("message".to_string()), + Value::Text("pong".to_string()), + ); + assert_eq!(value, Value::Map(map)) + } + + #[test] + fn test_object_determinism_roundtrip() { + let expected = b"\xa2aa\x01ab\x82\x02\x03"; + + // 0.1% chance of not catching failure + for _ in 0..10 { + assert_eq!( + &to_vec(&de::from_slice::<Value>(expected).unwrap()).unwrap(), + expected + ); + } + } + + #[test] + fn stream_deserializer() { + let slice = b"\x01\x66foobar"; + let mut it = Deserializer::from_slice(slice).into_iter::<Value>(); + assert_eq!(Value::Integer(1), it.next().unwrap().unwrap()); + assert_eq!( + Value::Text("foobar".to_string()), + it.next().unwrap().unwrap() + ); + assert!(it.next().is_none()); + } + + #[test] + fn stream_deserializer_eof() { + let slice = b"\x01\x66foob"; + let mut it = Deserializer::from_slice(slice).into_iter::<Value>(); + assert_eq!(Value::Integer(1), it.next().unwrap().unwrap()); + assert!(it.next().unwrap().unwrap_err().is_eof()); + } + + #[test] + fn stream_deserializer_eof_in_indefinite() { + let slice = b"\x7f\x65Mary \x64Had \x62a \x60\x67Little \x60\x64Lamb\xff"; + let indices: &[usize] = &[ + 2, // announcement but no data + 10, // mid-buffer EOF + 12, // neither new element nor end marker + ]; + for end_of_slice in indices { + let mut it = Deserializer::from_slice(&slice[..*end_of_slice]).into_iter::<Value>(); + assert!(it.next().unwrap().unwrap_err().is_eof()); + + let mut mutcopy = slice[..*end_of_slice].to_vec(); + let mut it = Deserializer::from_mut_slice(mutcopy.as_mut()).into_iter::<Value>(); + assert!(it.next().unwrap().unwrap_err().is_eof()); + + let mut buf = [0u8; 64]; + let mut it = Deserializer::from_slice_with_scratch(&slice[..*end_of_slice], &mut buf) + .into_iter::<Value>(); + assert!(it.next().unwrap().unwrap_err().is_eof()); + } + } + + #[test] + fn crash() { + let file = include_bytes!("crash.cbor"); + let value_result: error::Result<Value> = de::from_slice(file); + assert_eq!( + value_result.unwrap_err().classify(), + serde_cbor::error::Category::Syntax + ); + } + + fn from_slice_stream<'a, T>(slice: &'a [u8]) -> error::Result<(&'a [u8], T)> + where + T: serde_de::Deserialize<'a>, + { + let mut deserializer = Deserializer::from_slice(slice); + let value = serde_de::Deserialize::deserialize(&mut deserializer)?; + let rest = &slice[deserializer.byte_offset()..]; + + Ok((rest, value)) + } + + #[test] + fn test_slice_offset() { + let v: Vec<u8> = vec![ + 0x66, 0x66, 0x6f, 0x6f, 0x62, 0x61, 0x72, 0x66, 0x66, 0x6f, 0x6f, 0x62, 0x61, 0x72, + ]; + let (rest, value): (&[u8], String) = from_slice_stream(&v[..]).unwrap(); + assert_eq!(value, "foobar"); + assert_eq!(rest, &[0x66, 0x66, 0x6f, 0x6f, 0x62, 0x61, 0x72]); + let (rest, value): (&[u8], String) = from_slice_stream(rest).unwrap(); + assert_eq!(value, "foobar"); + assert_eq!(rest, &[]); + } + + #[derive(Debug, Copy, Clone)] + struct Options { + standard: bool, + legacy: bool, + packed: bool, + named: bool, + } + + impl Default for Options { + fn default() -> Self { + Options { + standard: true, + legacy: true, + packed: true, + named: true, + } + } + } + + impl Options { + fn no_standard(self) -> Self { + Options { + standard: false, + ..self + } + } + + fn no_legacy(self) -> Self { + Options { + legacy: false, + ..self + } + } + + fn no_packed(self) -> Self { + Options { + packed: false, + ..self + } + } + + fn no_named(self) -> Self { + Options { + named: false, + ..self + } + } + } + + fn from_slice_stream_options<'a, T>( + slice: &'a [u8], + options: Options, + ) -> error::Result<(&'a [u8], T)> + where + T: serde_de::Deserialize<'a>, + { + let deserializer = Deserializer::from_slice(slice); + let deserializer = if !options.packed { + deserializer.disable_packed_format() + } else { + deserializer + }; + let deserializer = if !options.named { + deserializer.disable_named_format() + } else { + deserializer + }; + let deserializer = if !options.standard { + deserializer.disable_standard_enums() + } else { + deserializer + }; + let mut deserializer = if !options.legacy { + deserializer.disable_legacy_enums() + } else { + deserializer + }; + let value = serde_de::Deserialize::deserialize(&mut deserializer)?; + let rest = &slice[deserializer.byte_offset()..]; + + Ok((rest, value)) + } + + #[test] + fn test_deserializer_enums() { + #[derive(Debug, PartialEq, Deserialize)] + enum Enum { + Unit, + NewType(i32), + Tuple(String, bool), + Struct { x: i32, y: i32 }, + } + + // This is the format used in serde >= 0.10 + // + // Serialization of Enum::NewType(10) + let v: Vec<u8> = vec![ + 0xa1, // map 1pair + 0x67, 0x4e, 0x65, 0x77, 0x54, 0x79, 0x70, 0x65, // utf8 string: NewType + 0x1a, // u32 + 0x00, 0x00, 0x00, 0x0a, // 10 (dec) + ]; + let (_rest, value): (&[u8], Enum) = from_slice_stream(&v[..]).unwrap(); + assert_eq!(value, Enum::NewType(10)); + let (_rest, value): (&[u8], Enum) = + from_slice_stream_options(&v[..], Options::default().no_legacy()).unwrap(); + assert_eq!(value, Enum::NewType(10)); + let value: error::Result<(&[u8], Enum)> = + from_slice_stream_options(&v[..], Options::default().no_standard()); + assert_eq!( + value.unwrap_err().classify(), + serde_cbor::error::Category::Syntax + ); + let value: error::Result<(&[u8], Enum)> = + from_slice_stream_options(&v[..], Options::default().no_standard().no_legacy()); + assert_eq!( + value.unwrap_err().classify(), + serde_cbor::error::Category::Syntax + ); + // Serialization of Enum::Unit + let v: Vec<u8> = vec![ + 0x64, 0x55, 0x6e, 0x69, 0x74, // utf8 string: Unit + ]; + let (_rest, value): (&[u8], Enum) = from_slice_stream(&v[..]).unwrap(); + assert_eq!(value, Enum::Unit); + let (_rest, value): (&[u8], Enum) = + from_slice_stream_options(&v[..], Options::default().no_legacy()).unwrap(); + assert_eq!(value, Enum::Unit); + let (_rest, value): (&[u8], Enum) = + from_slice_stream_options(&v[..], Options::default().no_standard()).unwrap(); + assert_eq!(value, Enum::Unit); + let value: error::Result<(&[u8], Enum)> = + from_slice_stream_options(&v[..], Options::default().no_legacy().no_standard()); + assert_eq!( + value.unwrap_err().classify(), + serde_cbor::error::Category::Syntax + ); + + // This is the format used in serde <= 0.9 + let v: Vec<u8> = vec![ + 0x82, // array 2 items + 0x67, 0x4e, 0x65, 0x77, 0x54, 0x79, 0x70, 0x65, // utf8 string: NewType + 0x1a, // u32 + 0x00, 0x00, 0x00, 0x0a, // 10 (dec) + ]; + let (_rest, value): (&[u8], Enum) = from_slice_stream(&v[..]).unwrap(); + assert_eq!(value, Enum::NewType(10)); + let value: error::Result<(&[u8], Enum)> = + from_slice_stream_options(&v[..], Options::default().no_legacy()); + assert_eq!( + value.unwrap_err().classify(), + serde_cbor::error::Category::Syntax + ); + let value: error::Result<(&[u8], Enum)> = + from_slice_stream_options(&v[..], Options::default().no_standard()); + assert_eq!(value.unwrap().1, Enum::NewType(10)); + let value: error::Result<(&[u8], Enum)> = + from_slice_stream_options(&v[..], Options::default().no_standard().no_legacy()); + assert_eq!( + value.unwrap_err().classify(), + serde_cbor::error::Category::Syntax + ); + } + + #[test] + fn test_packed_deserialization() { + #[derive(Debug, PartialEq, Deserialize)] + struct User { + user_id: u32, + password_hash: [u8; 4], + } + + // unpacked + let v: Vec<u8> = vec![ + 0xa2, // map 2pair + 0x67, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, // utf8 string: user_id + 0x0a, // integer: 10 + // utf8 string: password_hash + 0x6d, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x5f, 0x68, 0x61, 0x73, 0x68, + 0x84, 0x01, 0x02, 0x03, 0x04, // 4 byte array [1, 2, 3, 4] + ]; + + let (_rest, value): (&[u8], User) = from_slice_stream(&v[..]).unwrap(); + assert_eq!( + value, + User { + user_id: 10, + password_hash: [1, 2, 3, 4], + } + ); + let (_rest, value): (&[u8], User) = + from_slice_stream_options(&v[..], Options::default().no_packed()).unwrap(); + assert_eq!( + value, + User { + user_id: 10, + password_hash: [1, 2, 3, 4], + } + ); + let value: error::Result<(&[u8], User)> = + from_slice_stream_options(&v[..], Options::default().no_named()); + assert_eq!( + value.unwrap_err().classify(), + serde_cbor::error::Category::Syntax + ); + + // unpacked - indefinite length + let v: Vec<u8> = vec![ + 0xbf, // map to be followed by a break + 0x67, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, // utf8 string: user_id + 0x0a, // integer: 10 + // utf8 string: password_hash + 0x6d, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x5f, 0x68, 0x61, 0x73, 0x68, + 0x84, 0x01, 0x02, 0x03, 0x04, // 4 byte array [1, 2, 3, 4] + 0xff, // break + ]; + + let (_rest, value): (&[u8], User) = from_slice_stream(&v[..]).unwrap(); + assert_eq!( + value, + User { + user_id: 10, + password_hash: [1, 2, 3, 4], + } + ); + let (_rest, value): (&[u8], User) = + from_slice_stream_options(&v[..], Options::default().no_packed()).unwrap(); + assert_eq!( + value, + User { + user_id: 10, + password_hash: [1, 2, 3, 4], + } + ); + let value: error::Result<(&[u8], User)> = + from_slice_stream_options(&v[..], Options::default().no_named()); + assert_eq!( + value.unwrap_err().classify(), + serde_cbor::error::Category::Syntax + ); + + // packed + let v: Vec<u8> = vec![ + 0xa2, // map 2pair + 0x00, // index 0 + 0x0a, // integer: 10 + 0x01, // index 1 + 0x84, 0x01, 0x02, 0x03, 0x04, // 4 byte array [1, 2, 3, 4] + ]; + + let (_rest, value): (&[u8], User) = from_slice_stream(&v[..]).unwrap(); + assert_eq!( + value, + User { + user_id: 10, + password_hash: [1, 2, 3, 4], + } + ); + let (_rest, value): (&[u8], User) = + from_slice_stream_options(&v[..], Options::default().no_named()).unwrap(); + assert_eq!( + value, + User { + user_id: 10, + password_hash: [1, 2, 3, 4], + } + ); + let value: error::Result<(&[u8], User)> = + from_slice_stream_options(&v[..], Options::default().no_packed()); + assert_eq!( + value.unwrap_err().classify(), + serde_cbor::error::Category::Syntax + ); + + // packed - indefinite length + let v: Vec<u8> = vec![ + 0xbf, // map, to be followed by a break + 0x00, // index 0 + 0x0a, // integer: 10 + 0x01, // index 1 + 0x84, 0x01, 0x02, 0x03, 0x04, // 4 byte array [1, 2, 3, 4] + 0xff, // break + ]; + + let (_rest, value): (&[u8], User) = from_slice_stream(&v[..]).unwrap(); + assert_eq!( + value, + User { + user_id: 10, + password_hash: [1, 2, 3, 4], + } + ); + let (_rest, value): (&[u8], User) = + from_slice_stream_options(&v[..], Options::default().no_named()).unwrap(); + assert_eq!( + value, + User { + user_id: 10, + password_hash: [1, 2, 3, 4], + } + ); + let value: error::Result<(&[u8], User)> = + from_slice_stream_options(&v[..], Options::default().no_packed()); + assert_eq!( + value.unwrap_err().classify(), + serde_cbor::error::Category::Syntax + ); + } + + use serde_cbor::{de::from_slice, ser::to_vec_packed}; + use std::net::{IpAddr, Ipv4Addr}; + #[test] + fn test_ipaddr_deserialization() { + let ip = IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)); + let buf = to_vec_packed(&ip).unwrap(); + let deserialized_ip = from_slice::<IpAddr>(&buf).unwrap(); + assert_eq!(ip, deserialized_ip); + + let buf = to_vec(&ip).unwrap(); + let deserialized_ip = from_slice::<IpAddr>(&buf).unwrap(); + assert_eq!(ip, deserialized_ip); + } + + #[test] + fn attempt_stack_overflow() { + // Create a tag 17, followed by 999 more tag 17: + // 17(17(17(17(17(17(17(17(17(17(17(17(17(17(17(17(17(17(... + // This causes deep recursion in the decoder and may + // exhaust the stack and therfore result in a stack overflow. + let input = vec![0xd1; 1000]; + let err = serde_cbor::from_slice::<serde_cbor::Value>(&input).expect_err("recursion limit"); + assert!(err.is_syntax()); + } +} diff --git a/third_party/rust/serde_cbor/tests/enum.rs b/third_party/rust/serde_cbor/tests/enum.rs new file mode 100644 index 0000000000..630500d6b5 --- /dev/null +++ b/third_party/rust/serde_cbor/tests/enum.rs @@ -0,0 +1,236 @@ +use serde::Serialize; +use serde_cbor; +use serde_cbor::ser::{Serializer, SliceWrite}; + +#[macro_use] +extern crate serde_derive; + +#[test] +fn test_simple_data_enum_roundtrip() { + #[derive(Debug, Serialize, Deserialize, PartialEq)] + enum DataEnum { + A(u32), + B(f32), + } + + let a = DataEnum::A(42); + + let mut slice = [0u8; 64]; + let writer = SliceWrite::new(&mut slice); + let mut serializer = Serializer::new(writer); + a.serialize(&mut serializer).unwrap(); + let writer = serializer.into_inner(); + let end = writer.bytes_written(); + let slice = writer.into_inner(); + let deserialized: DataEnum = + serde_cbor::de::from_slice_with_scratch(&slice[..end], &mut []).unwrap(); + assert_eq!(a, deserialized); +} + +#[cfg(feature = "std")] +mod std_tests { + use std::collections::BTreeMap; + + use serde_cbor::ser::{IoWrite, Serializer}; + use serde_cbor::value::Value; + use serde_cbor::{from_slice, to_vec}; + + pub fn to_vec_legacy<T>(value: &T) -> serde_cbor::Result<Vec<u8>> + where + T: serde::ser::Serialize, + { + let mut vec = Vec::new(); + value.serialize(&mut Serializer::new(&mut IoWrite::new(&mut vec)).legacy_enums())?; + Ok(vec) + } + + #[derive(Debug, Serialize, Deserialize, PartialEq, Eq)] + enum Enum { + A, + B, + } + + #[derive(Debug, Serialize, Deserialize, PartialEq, Eq)] + struct EnumStruct { + e: Enum, + } + + #[test] + fn test_enum() { + let enum_struct = EnumStruct { e: Enum::B }; + let raw = &to_vec(&enum_struct).unwrap(); + println!("raw enum {:?}", raw); + let re: EnumStruct = from_slice(raw).unwrap(); + assert_eq!(enum_struct, re); + } + + #[repr(u16)] + #[derive(Debug, Serialize, Deserialize, PartialEq, Eq)] + enum ReprEnum { + A, + B, + } + + #[derive(Debug, Serialize, Deserialize, PartialEq, Eq)] + struct ReprEnumStruct { + e: ReprEnum, + } + + #[test] + fn test_repr_enum() { + let repr_enum_struct = ReprEnumStruct { e: ReprEnum::B }; + let re: ReprEnumStruct = from_slice(&to_vec(&repr_enum_struct).unwrap()).unwrap(); + assert_eq!(repr_enum_struct, re); + } + + #[derive(Debug, Serialize, Deserialize, PartialEq, Eq)] + enum DataEnum { + A(u32), + B(bool, u8), + C { x: u8, y: String }, + } + + #[test] + fn test_data_enum() { + let data_enum_a = DataEnum::A(4); + let re_a: DataEnum = from_slice(&to_vec(&data_enum_a).unwrap()).unwrap(); + assert_eq!(data_enum_a, re_a); + let data_enum_b = DataEnum::B(true, 42); + let re_b: DataEnum = from_slice(&to_vec(&data_enum_b).unwrap()).unwrap(); + assert_eq!(data_enum_b, re_b); + let data_enum_c = DataEnum::C { + x: 3, + y: "foo".to_owned(), + }; + println!("{:?}", &to_vec(&data_enum_c).unwrap()); + let re_c: DataEnum = from_slice(&to_vec(&data_enum_c).unwrap()).unwrap(); + assert_eq!(data_enum_c, re_c); + } + + #[test] + fn test_serialize() { + assert_eq!(to_vec_legacy(&Enum::A).unwrap(), &[97, 65]); + assert_eq!(to_vec_legacy(&Enum::B).unwrap(), &[97, 66]); + assert_eq!( + to_vec_legacy(&DataEnum::A(42)).unwrap(), + &[130, 97, 65, 24, 42] + ); + assert_eq!( + to_vec_legacy(&DataEnum::B(true, 9)).unwrap(), + &[131, 97, 66, 245, 9] + ); + } + + #[test] + fn test_newtype_struct() { + #[derive(Debug, Deserialize, Serialize, PartialEq, Eq)] + pub struct Newtype(u8); + assert_eq!(to_vec(&142u8).unwrap(), to_vec(&Newtype(142u8)).unwrap()); + assert_eq!(from_slice::<Newtype>(&[24, 142]).unwrap(), Newtype(142)); + } + + #[derive(Deserialize, PartialEq, Debug)] + enum Foo { + #[serde(rename = "require")] + Require, + } + + #[test] + fn test_variable_length_array() { + let slice = b"\x9F\x67\x72\x65\x71\x75\x69\x72\x65\xFF"; + let value: Vec<Foo> = from_slice(slice).unwrap(); + assert_eq!(value, [Foo::Require]); + } + + #[derive(Serialize, Deserialize, PartialEq, Debug)] + enum Bar { + Empty, + Number(i32), + Flag(String, bool), + Point { x: i32, y: i32 }, + } + + #[test] + fn test_enum_as_map() { + // unit variants serialize like bare strings + let empty_s = to_vec_legacy(&Bar::Empty).unwrap(); + let empty_str_s = to_vec_legacy(&"Empty").unwrap(); + assert_eq!(empty_s, empty_str_s); + + // tuple-variants serialize like ["<variant>", values..] + let number_s = to_vec_legacy(&Bar::Number(42)).unwrap(); + let number_vec = vec![Value::Text("Number".to_string()), Value::Integer(42)]; + let number_vec_s = to_vec_legacy(&number_vec).unwrap(); + assert_eq!(number_s, number_vec_s); + + let flag_s = to_vec_legacy(&Bar::Flag("foo".to_string(), true)).unwrap(); + let flag_vec = vec![ + Value::Text("Flag".to_string()), + Value::Text("foo".to_string()), + Value::Bool(true), + ]; + let flag_vec_s = to_vec_legacy(&flag_vec).unwrap(); + assert_eq!(flag_s, flag_vec_s); + + // struct-variants serialize like ["<variant>", {struct..}] + let point_s = to_vec_legacy(&Bar::Point { x: 5, y: -5 }).unwrap(); + let mut struct_map = BTreeMap::new(); + struct_map.insert(Value::Text("x".to_string()), Value::Integer(5)); + struct_map.insert(Value::Text("y".to_string()), Value::Integer(-5)); + let point_vec = vec![ + Value::Text("Point".to_string()), + Value::Map(struct_map.clone()), + ]; + let point_vec_s = to_vec_legacy(&point_vec).unwrap(); + assert_eq!(point_s, point_vec_s); + + // enum_as_map matches serde_json's default serialization for enums. + + // unit variants still serialize like bare strings + let empty_s = to_vec(&Bar::Empty).unwrap(); + assert_eq!(empty_s, empty_str_s); + + // 1-element tuple variants serialize like {"<variant>": value} + let number_s = to_vec(&Bar::Number(42)).unwrap(); + let mut number_map = BTreeMap::new(); + number_map.insert("Number", 42); + let number_map_s = to_vec(&number_map).unwrap(); + assert_eq!(number_s, number_map_s); + + // multi-element tuple variants serialize like {"<variant>": [values..]} + let flag_s = to_vec(&Bar::Flag("foo".to_string(), true)).unwrap(); + let mut flag_map = BTreeMap::new(); + flag_map.insert( + "Flag", + vec![Value::Text("foo".to_string()), Value::Bool(true)], + ); + let flag_map_s = to_vec(&flag_map).unwrap(); + assert_eq!(flag_s, flag_map_s); + + // struct-variants serialize like {"<variant>", {struct..}} + let point_s = to_vec(&Bar::Point { x: 5, y: -5 }).unwrap(); + let mut point_map = BTreeMap::new(); + point_map.insert("Point", Value::Map(struct_map)); + let point_map_s = to_vec(&point_map).unwrap(); + assert_eq!(point_s, point_map_s); + + // deserialization of all encodings should just work + let empty_str_ds = from_slice(&empty_str_s).unwrap(); + assert_eq!(Bar::Empty, empty_str_ds); + + let number_vec_ds = from_slice(&number_vec_s).unwrap(); + assert_eq!(Bar::Number(42), number_vec_ds); + let number_map_ds = from_slice(&number_map_s).unwrap(); + assert_eq!(Bar::Number(42), number_map_ds); + + let flag_vec_ds = from_slice(&flag_vec_s).unwrap(); + assert_eq!(Bar::Flag("foo".to_string(), true), flag_vec_ds); + let flag_map_ds = from_slice(&flag_map_s).unwrap(); + assert_eq!(Bar::Flag("foo".to_string(), true), flag_map_ds); + + let point_vec_ds = from_slice(&point_vec_s).unwrap(); + assert_eq!(Bar::Point { x: 5, y: -5 }, point_vec_ds); + let point_map_ds = from_slice(&point_map_s).unwrap(); + assert_eq!(Bar::Point { x: 5, y: -5 }, point_map_ds); + } +} diff --git a/third_party/rust/serde_cbor/tests/kietaub.cbor b/third_party/rust/serde_cbor/tests/kietaub.cbor Binary files differnew file mode 100644 index 0000000000..866a093132 --- /dev/null +++ b/third_party/rust/serde_cbor/tests/kietaub.cbor diff --git a/third_party/rust/serde_cbor/tests/ser.rs b/third_party/rust/serde_cbor/tests/ser.rs new file mode 100644 index 0000000000..d374ce2faf --- /dev/null +++ b/third_party/rust/serde_cbor/tests/ser.rs @@ -0,0 +1,254 @@ +use serde::Serialize; +use serde_cbor::ser::{Serializer, SliceWrite}; + +#[test] +fn test_str() { + serialize_and_compare("foobar", b"ffoobar"); +} + +#[test] +fn test_list() { + serialize_and_compare(&[1, 2, 3], b"\x83\x01\x02\x03"); +} + +#[test] +fn test_float() { + serialize_and_compare(12.3f64, b"\xfb@(\x99\x99\x99\x99\x99\x9a"); +} + +#[test] +fn test_integer() { + // u8 + serialize_and_compare(24, b"\x18\x18"); + // i8 + serialize_and_compare(-5, b"\x24"); + // i16 + serialize_and_compare(-300, b"\x39\x01\x2b"); + // i32 + serialize_and_compare(-23567997, b"\x3a\x01\x67\x9e\x7c"); + // u64 + serialize_and_compare(::core::u64::MAX, b"\x1b\xff\xff\xff\xff\xff\xff\xff\xff"); +} + +fn serialize_and_compare<T: Serialize>(value: T, expected: &[u8]) { + let mut slice = [0u8; 64]; + let writer = SliceWrite::new(&mut slice); + let mut serializer = Serializer::new(writer); + value.serialize(&mut serializer).unwrap(); + let writer = serializer.into_inner(); + let end = writer.bytes_written(); + let slice = writer.into_inner(); + assert_eq!(&slice[..end], expected); +} + +#[cfg(feature = "std")] +mod std_tests { + use serde::Serializer; + use serde_cbor::ser; + use serde_cbor::{from_slice, to_vec}; + use std::collections::BTreeMap; + + #[test] + fn test_string() { + let value = "foobar".to_owned(); + assert_eq!(&to_vec(&value).unwrap()[..], b"ffoobar"); + } + + #[test] + fn test_list() { + let value = vec![1, 2, 3]; + assert_eq!(&to_vec(&value).unwrap()[..], b"\x83\x01\x02\x03"); + } + + #[test] + fn test_object() { + let mut object = BTreeMap::new(); + object.insert("a".to_owned(), "A".to_owned()); + object.insert("b".to_owned(), "B".to_owned()); + object.insert("c".to_owned(), "C".to_owned()); + object.insert("d".to_owned(), "D".to_owned()); + object.insert("e".to_owned(), "E".to_owned()); + let vec = to_vec(&object).unwrap(); + let test_object = from_slice(&vec[..]).unwrap(); + assert_eq!(object, test_object); + } + + #[test] + fn test_object_list_keys() { + let mut object = BTreeMap::new(); + object.insert(vec![0i64], ()); + object.insert(vec![100i64], ()); + object.insert(vec![-1i64], ()); + object.insert(vec![-2i64], ()); + object.insert(vec![0i64, 0i64], ()); + object.insert(vec![0i64, -1i64], ()); + let vec = to_vec(&serde_cbor::value::to_value(object.clone()).unwrap()).unwrap(); + assert_eq!( + vec![ + 166, 129, 0, 246, 129, 24, 100, 246, 129, 32, 246, 129, 33, 246, 130, 0, 0, 246, + 130, 0, 32, 246 + ], + vec + ); + let test_object = from_slice(&vec[..]).unwrap(); + assert_eq!(object, test_object); + } + + #[test] + fn test_object_object_keys() { + use std::iter::FromIterator; + let mut object = BTreeMap::new(); + let keys = vec![ + vec!["a"], + vec!["b"], + vec!["c"], + vec!["d"], + vec!["aa"], + vec!["a", "aa"], + ] + .into_iter() + .map(|v| BTreeMap::from_iter(v.into_iter().map(|s| (s.to_owned(), ())))); + + for key in keys { + object.insert(key, ()); + } + let vec = to_vec(&serde_cbor::value::to_value(object.clone()).unwrap()).unwrap(); + assert_eq!( + vec![ + 166, 161, 97, 97, 246, 246, 161, 97, 98, 246, 246, 161, 97, 99, 246, 246, 161, 97, + 100, 246, 246, 161, 98, 97, 97, 246, 246, 162, 97, 97, 246, 98, 97, 97, 246, 246 + ], + vec + ); + let test_object = from_slice(&vec[..]).unwrap(); + assert_eq!(object, test_object); + } + + #[test] + fn test_float() { + let vec = to_vec(&12.3f64).unwrap(); + assert_eq!(vec, b"\xfb@(\x99\x99\x99\x99\x99\x9a"); + } + + #[test] + fn test_f32() { + let vec = to_vec(&4000.5f32).unwrap(); + assert_eq!(vec, b"\xfa\x45\x7a\x08\x00"); + } + + #[test] + fn test_infinity() { + let vec = to_vec(&::std::f64::INFINITY).unwrap(); + assert_eq!(vec, b"\xf9|\x00"); + } + + #[test] + fn test_neg_infinity() { + let vec = to_vec(&::std::f64::NEG_INFINITY).unwrap(); + assert_eq!(vec, b"\xf9\xfc\x00"); + } + + #[test] + fn test_nan() { + let vec = to_vec(&::std::f32::NAN).unwrap(); + assert_eq!(vec, b"\xf9\x7e\x00"); + } + + #[test] + fn test_integer() { + // u8 + let vec = to_vec(&24).unwrap(); + assert_eq!(vec, b"\x18\x18"); + // i8 + let vec = to_vec(&-5).unwrap(); + assert_eq!(vec, b"\x24"); + // i16 + let vec = to_vec(&-300).unwrap(); + assert_eq!(vec, b"\x39\x01\x2b"); + // i32 + let vec = to_vec(&-23567997).unwrap(); + assert_eq!(vec, b"\x3a\x01\x67\x9e\x7c"); + // u64 + let vec = to_vec(&::std::u64::MAX).unwrap(); + assert_eq!(vec, b"\x1b\xff\xff\xff\xff\xff\xff\xff\xff"); + } + + #[test] + fn test_self_describing() { + let mut vec = Vec::new(); + { + let mut serializer = ser::Serializer::new(&mut vec); + serializer.self_describe().unwrap(); + serializer.serialize_u64(9).unwrap(); + } + assert_eq!(vec, b"\xd9\xd9\xf7\x09"); + } + + #[test] + fn test_ip_addr() { + use std::net::Ipv4Addr; + + let addr = Ipv4Addr::new(8, 8, 8, 8); + let vec = to_vec(&addr).unwrap(); + println!("{:?}", vec); + assert_eq!(vec.len(), 5); + let test_addr: Ipv4Addr = from_slice(&vec).unwrap(); + assert_eq!(addr, test_addr); + } + + /// Test all of CBOR's fixed-length byte string types + #[test] + fn test_byte_string() { + // Very short byte strings have 1-byte headers + let short = vec![0, 1, 2, 255]; + let mut short_s = Vec::new(); + serde_cbor::Serializer::new(&mut short_s) + .serialize_bytes(&short) + .unwrap(); + assert_eq!(&short_s[..], [0x44, 0, 1, 2, 255]); + + // byte strings > 23 bytes have 2-byte headers + let medium = vec![ + 0u8, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 255, + ]; + let mut medium_s = Vec::new(); + serde_cbor::Serializer::new(&mut medium_s) + .serialize_bytes(&medium) + .unwrap(); + assert_eq!( + &medium_s[..], + [ + 0x58, 24, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, + 21, 22, 255 + ] + ); + + // byte strings > 256 bytes have 3-byte headers + let long_vec = (0..256).map(|i| (i & 0xFF) as u8).collect::<Vec<_>>(); + let mut long_s = Vec::new(); + serde_cbor::Serializer::new(&mut long_s) + .serialize_bytes(&long_vec) + .unwrap(); + assert_eq!(&long_s[0..3], [0x59, 1, 0]); + assert_eq!(&long_s[3..], &long_vec[..]); + + // byte strings > 2^16 bytes have 5-byte headers + let very_long_vec = (0..65536).map(|i| (i & 0xFF) as u8).collect::<Vec<_>>(); + let mut very_long_s = Vec::new(); + serde_cbor::Serializer::new(&mut very_long_s) + .serialize_bytes(&very_long_vec) + .unwrap(); + assert_eq!(&very_long_s[0..5], [0x5a, 0, 1, 0, 0]); + assert_eq!(&very_long_s[5..], &very_long_vec[..]); + + // byte strings > 2^32 bytes have 9-byte headers, but they take too much RAM + // to test in Travis. + } + + #[test] + fn test_half() { + let vec = to_vec(&42.5f32).unwrap(); + assert_eq!(vec, b"\xF9\x51\x50"); + assert_eq!(from_slice::<f32>(&vec[..]).unwrap(), 42.5f32); + } +} diff --git a/third_party/rust/serde_cbor/tests/std_types.rs b/third_party/rust/serde_cbor/tests/std_types.rs new file mode 100644 index 0000000000..7a7ded484c --- /dev/null +++ b/third_party/rust/serde_cbor/tests/std_types.rs @@ -0,0 +1,186 @@ +#[macro_use] +extern crate serde_derive; + +#[cfg(feature = "std")] +mod std_tests { + use std::u8; + + use serde_cbor::de::from_mut_slice; + use serde_cbor::ser::{to_vec, to_vec_packed}; + use serde_cbor::{from_reader, from_slice}; + + fn to_binary(s: &'static str) -> Vec<u8> { + assert!(s.len() % 2 == 0); + let mut b = Vec::with_capacity(s.len() / 2); + for i in 0..s.len() / 2 { + b.push(u8::from_str_radix(&s[i * 2..(i + 1) * 2], 16).unwrap()); + } + b + } + + macro_rules! testcase { + ($name:ident, f64, $expr:expr, $s:expr) => { + #[test] + fn $name() { + let expr: f64 = $expr; + let mut serialized = to_binary($s); + assert_eq!(to_vec(&expr).unwrap(), serialized); + let parsed: f64 = from_slice(&serialized[..]).unwrap(); + if !expr.is_nan() { + assert_eq!(expr, parsed); + } else { + assert!(parsed.is_nan()) + } + + let parsed: f64 = from_reader(&mut &serialized[..]).unwrap(); + if !expr.is_nan() { + assert_eq!(expr, parsed); + } else { + assert!(parsed.is_nan()) + } + + let parsed: f64 = from_mut_slice(&mut serialized[..]).unwrap(); + if !expr.is_nan() { + assert_eq!(expr, parsed); + } else { + assert!(parsed.is_nan()) + } + } + }; + ($name:ident, $ty:ty, $expr:expr, $s:expr) => { + #[test] + fn $name() { + let expr: $ty = $expr; + let mut serialized = to_binary($s); + assert_eq!( + to_vec(&expr).expect("ser1 works"), + serialized, + "serialization differs" + ); + let parsed: $ty = from_slice(&serialized[..]).expect("de1 works"); + assert_eq!(parsed, expr, "parsed result differs"); + let packed = &to_vec_packed(&expr).expect("serializing packed")[..]; + let parsed_from_packed: $ty = from_slice(packed).expect("parsing packed"); + assert_eq!(parsed_from_packed, expr, "packed roundtrip fail"); + + let parsed: $ty = from_reader(&mut &serialized[..]).unwrap(); + assert_eq!(parsed, expr, "parsed result differs"); + let mut packed = to_vec_packed(&expr).expect("serializing packed"); + let parsed_from_packed: $ty = + from_reader(&mut &packed[..]).expect("parsing packed"); + assert_eq!(parsed_from_packed, expr, "packed roundtrip fail"); + + let parsed: $ty = from_mut_slice(&mut serialized[..]).unwrap(); + assert_eq!(parsed, expr, "parsed result differs"); + let parsed_from_packed: $ty = + from_mut_slice(&mut packed[..]).expect("parsing packed"); + assert_eq!(parsed_from_packed, expr, "packed roundtrip fail"); + } + }; + } + + testcase!(test_bool_false, bool, false, "f4"); + testcase!(test_bool_true, bool, true, "f5"); + testcase!(test_isize_neg_256, isize, -256, "38ff"); + testcase!(test_isize_neg_257, isize, -257, "390100"); + testcase!(test_isize_255, isize, 255, "18ff"); + testcase!(test_i8_5, i8, 5, "05"); + testcase!(test_i8_23, i8, 23, "17"); + testcase!(test_i8_24, i8, 24, "1818"); + testcase!(test_i8_neg_128, i8, -128, "387f"); + testcase!(test_u32_98745874, u32, 98745874, "1a05e2be12"); + testcase!(test_f32_1234_point_5, f32, 1234.5, "fa449a5000"); + testcase!(test_f64_12345_point_6, f64, 12345.6, "fb40c81ccccccccccd"); + testcase!(test_f64_nan, f64, ::std::f64::NAN, "f97e00"); + testcase!(test_f64_infinity, f64, ::std::f64::INFINITY, "f97c00"); + testcase!(test_f64_neg_infinity, f64, -::std::f64::INFINITY, "f9fc00"); + testcase!(test_char_null, char, '\x00', "6100"); + testcase!(test_char_broken_heart, char, '💔', "64f09f9294"); + testcase!( + test_str_pangram_de, + String, + "aâø↓é".to_owned(), + "6a61c3a2c3b8e28693c3a9" + ); + testcase!(test_unit, (), (), "f6"); + + #[derive(Debug, PartialEq, Deserialize, Serialize)] + struct UnitStruct; + testcase!(test_unit_struct, UnitStruct, UnitStruct, "f6"); + + #[derive(Debug, PartialEq, Deserialize, Serialize)] + struct NewtypeStruct(bool); + testcase!( + test_newtype_struct, + NewtypeStruct, + NewtypeStruct(true), + "f5" + ); + + testcase!(test_option_none, Option<u8>, None, "f6"); + testcase!(test_option_some, Option<u8>, Some(42), "182a"); + + #[derive(Debug, PartialEq, Deserialize, Serialize)] + struct Person { + name: String, + year_of_birth: u16, + profession: Option<String>, + } + + testcase!(test_person_struct, + Person, + Person { + name: "Grace Hopper".to_string(), + year_of_birth: 1906, + profession: Some("computer scientist".to_string()), + }, + "a3646e616d656c477261636520486f707065726d796561725f6f665f62697274681907726a70726f66657373696f6e72636f6d707574657220736369656e74697374"); + + #[derive(Debug, PartialEq, Deserialize, Serialize)] + struct OptionalPerson { + name: String, + #[serde(skip_serializing_if = "Option::is_none")] + year_of_birth: Option<u16>, + profession: Option<String>, + } + + testcase!(test_optional_person_struct, + OptionalPerson, + OptionalPerson { + name: "Grace Hopper".to_string(), + year_of_birth: None, + profession: Some("computer scientist".to_string()), + }, + "a2646e616d656c477261636520486f707065726a70726f66657373696f6e72636f6d707574657220736369656e74697374"); + + #[derive(Debug, PartialEq, Deserialize, Serialize)] + enum Color { + Red, + Blue, + Yellow, + Other(u64), + Alpha(u64, u8), + } + + testcase!(test_color_enum, Color, Color::Blue, "64426c7565"); + testcase!( + test_color_enum_transparent, + Color, + Color::Other(42), + "a1654f74686572182a" + ); + testcase!( + test_color_enum_with_alpha, + Color, + Color::Alpha(234567, 60), + "a165416c706861821a00039447183c" + ); + testcase!(test_i128_a, i128, -1i128, "20"); + testcase!( + test_i128_b, + i128, + -18446744073709551616i128, + "3BFFFFFFFFFFFFFFFF" + ); + testcase!(test_u128, u128, 17, "11"); +} diff --git a/third_party/rust/serde_cbor/tests/tags.rs b/third_party/rust/serde_cbor/tests/tags.rs new file mode 100644 index 0000000000..92534c023d --- /dev/null +++ b/third_party/rust/serde_cbor/tests/tags.rs @@ -0,0 +1,48 @@ +#[cfg(feature = "tags")] +mod tagtests { + use serde_cbor::value::Value; + use serde_cbor::{from_slice, to_vec}; + + fn decode_hex(s: &str) -> std::result::Result<Vec<u8>, std::num::ParseIntError> { + (0..s.len()) + .step_by(2) + .map(|i| u8::from_str_radix(&s[i..i + 2], 16)) + .collect() + } + + // get bytes from http://cbor.me/ trees + fn parse_cbor_me(example: &str) -> std::result::Result<Vec<u8>, std::num::ParseIntError> { + let hex = example + .split("\n") + .flat_map(|line| line.split("#").take(1)) + .collect::<Vec<&str>>() + .join("") + .replace(" ", ""); + decode_hex(&hex) + } + + #[test] + fn tagged_cbor_roundtrip() { + let data = r#" +C1 # tag(1) + 82 # array(2) + C2 # tag(2) + 63 # text(3) + 666F6F # "foo" + C3 # tag(3) + A1 # map(1) + C4 # tag(4) + 61 # text(1) + 61 # "a" + C5 # tag(5) + 61 # text(1) + 62 # "b" + "#; + let bytes1 = parse_cbor_me(&data).unwrap(); + let value1: Value = from_slice(&bytes1).unwrap(); + let bytes2 = to_vec(&value1).unwrap(); + let value2: Value = from_slice(&bytes2).unwrap(); + assert_eq!(bytes1, bytes2); + assert_eq!(value1, value2); + } +} diff --git a/third_party/rust/serde_cbor/tests/value.rs b/third_party/rust/serde_cbor/tests/value.rs new file mode 100644 index 0000000000..554d74266c --- /dev/null +++ b/third_party/rust/serde_cbor/tests/value.rs @@ -0,0 +1,100 @@ +#[macro_use] +extern crate serde_derive; + +#[cfg(feature = "std")] +mod std_tests { + use serde_cbor; + + use std::collections::BTreeMap; + + #[derive(Serialize, Deserialize, Clone, Debug, PartialEq)] + struct TupleStruct(String, i32, u64); + + #[derive(Serialize, Deserialize, Clone, Debug, PartialEq)] + struct UnitStruct; + + #[derive(Serialize, Deserialize, Clone, Debug, PartialEq)] + struct Struct<'a> { + tuple_struct: TupleStruct, + tuple: (String, f32, f64), + map: BTreeMap<String, String>, + bytes: &'a [u8], + array: Vec<String>, + unit_array: Vec<UnitStruct>, + } + + use serde_cbor::value::Value; + use std::iter::FromIterator; + + #[test] + fn serde() { + let tuple_struct = TupleStruct(format!("test"), -60, 3000); + + let tuple = (format!("hello"), -50.0040957, -12.094635556478); + + let map = BTreeMap::from_iter( + [ + (format!("key1"), format!("value1")), + (format!("key2"), format!("value2")), + (format!("key3"), format!("value3")), + (format!("key4"), format!("value4")), + ] + .iter() + .cloned(), + ); + + let bytes = b"test byte string"; + + let array = vec![format!("one"), format!("two"), format!("three")]; + let unit_array = vec![UnitStruct, UnitStruct, UnitStruct]; + + let data = Struct { + tuple_struct, + tuple, + map, + bytes, + array, + unit_array, + }; + + let value = serde_cbor::value::to_value(data.clone()).unwrap(); + println!("{:?}", value); + + let data_ser = serde_cbor::to_vec(&value).unwrap(); + let data_de_value: Value = serde_cbor::from_slice(&data_ser).unwrap(); + + fn as_object(value: &Value) -> &BTreeMap<Value, Value> { + if let Value::Map(ref v) = value { + return v; + } + panic!() + } + + for ((k1, v1), (k2, v2)) in as_object(&value) + .iter() + .zip(as_object(&data_de_value).iter()) + { + assert_eq!(k1, k2); + assert_eq!(v1, v2); + } + + assert_eq!(value, data_de_value); + } + + #[derive(Debug, Deserialize, Serialize)] + struct SmallStruct { + spam: u32, + eggs: u32, + } + + #[test] + fn small_struct() { + // Test whether the packed format works. + // Field names should not be serialized, + // instead field indizes are serialized. + let value = SmallStruct { spam: 17, eggs: 42 }; + let data = serde_cbor::ser::to_vec_packed(&value).unwrap(); + let reference = b"\xa2\x00\x11\x01\x18\x2a"; + assert_eq!(data, reference); + } +} |