cbor4ii-1.2.1/.cargo_vcs_info.json0000644000000001361046102023000124120ustar { "git": { "sha1": "1347c2828edf538896ed5979bd3d60a062b13877" }, "path_in_vcs": "" }cbor4ii-1.2.1/.github/workflows/ci.yml000064400000000000000000000021331046102023000156720ustar 00000000000000name: CI on: push: branches: - master pull_request: {} jobs: check: runs-on: ubuntu-latest env: RUSTFLAGS: "-D warnings" steps: - name: Checkout sources uses: actions/checkout@v4 - name: Install Rust run: rustup update stable - name: Check minimum run: cargo check --all - name: Check serde + use_alloc run: cargo check --all --features serde1,use_alloc - name: Check all run: cargo check --all --all-features --all-targets test: runs-on: ubuntu-latest env: RUSTFLAGS: "-D warnings" steps: - name: Checkout sources uses: actions/checkout@v4 - name: Install Rust run: rustup update stable - name: Install cargo-llvm-cov uses: taiki-e/install-action@cargo-llvm-cov - name: Test all run: cargo llvm-cov test --all --all-features --lcov --output-path lcov.info - name: Upload coverage to Codecov uses: codecov/codecov-action@v5 with: token: ${{ secrets.CODECOV_TOKEN }} files: lcov.info fail_ci_if_error: true cbor4ii-1.2.1/.github/workflows/release.yml000064400000000000000000000007511046102023000167230ustar 00000000000000name: Publish to crates.io on: push: tags: ['v*'] # Triggers when pushing tags starting with 'v' jobs: publish: runs-on: ubuntu-latest environment: release # Optional: for enhanced security permissions: id-token: write # Required for OIDC token exchange steps: - uses: actions/checkout@v5 - uses: rust-lang/crates-io-auth-action@v1 id: auth - run: cargo publish env: CARGO_REGISTRY_TOKEN: ${{ steps.auth.outputs.token }} cbor4ii-1.2.1/.gitignore000064400000000000000000000001401046102023000131430ustar 00000000000000/target /bin Cargo.lock /hongg-fuzz/target /hongg-fuzz/hfuzz_target /hongg-fuzz/hfuzz_workspace cbor4ii-1.2.1/Cargo.lock0000644000000340601046102023000103700ustar # This file is automatically @generated by Cargo. # It is not intended for manual editing. version = 4 [[package]] name = "aho-corasick" version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" dependencies = [ "memchr", ] [[package]] name = "anes" version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" [[package]] name = "anstyle" version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78" [[package]] name = "anyhow" version = "1.0.75" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" [[package]] name = "autocfg" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] name = "bumpalo" version = "3.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" [[package]] name = "cast" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cbor4ii" version = "1.2.1" dependencies = [ "anyhow", "ciborium", "criterion", "data-encoding", "half 2.3.1", "serde", "serde_bytes", "serde_cbor", ] [[package]] name = "cfg-if" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "ciborium" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "effd91f6c78e5a4ace8a5d3c0b6bfaec9e2baaef55f3efc00e45fb2e477ee926" dependencies = [ "ciborium-io", "ciborium-ll", "serde", ] [[package]] name = "ciborium-io" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cdf919175532b369853f5d5e20b26b43112613fd6fe7aee757e35f7a44642656" [[package]] name = "ciborium-ll" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "defaa24ecc093c77630e6c15e17c51f5e187bf35ee514f4e2d67baaa96dae22b" dependencies = [ "ciborium-io", "half 1.8.2", ] [[package]] name = "clap" version = "4.5.53" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c9e340e012a1bf4935f5282ed1436d1489548e8f72308207ea5df0e23d2d03f8" dependencies = [ "clap_builder", ] [[package]] name = "clap_builder" version = "4.5.53" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d76b5d13eaa18c901fd2f7fca939fefe3a0727a953561fefdf3b2922b8569d00" dependencies = [ "anstyle", "clap_lex", ] [[package]] name = "clap_lex" version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1d728cc89cf3aee9ff92b05e62b19ee65a02b5702cff7d5a377e32c6ae29d8d" [[package]] name = "criterion" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e1c047a62b0cc3e145fa84415a3191f628e980b194c2755aa12300a4e6cbd928" dependencies = [ "anes", "cast", "ciborium", "clap", "criterion-plot", "itertools", "num-traits", "oorandom", "plotters", "rayon", "regex", "serde", "serde_json", "tinytemplate", "walkdir", ] [[package]] name = "criterion-plot" version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b1bcc0dc7dfae599d84ad0b1a55f80cde8af3725da8313b528da95ef783e338" dependencies = [ "cast", "itertools", ] [[package]] name = "crossbeam-deque" version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" dependencies = [ "crossbeam-epoch", "crossbeam-utils", ] [[package]] name = "crossbeam-epoch" version = "0.9.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" dependencies = [ "crossbeam-utils", ] [[package]] name = "crossbeam-utils" version = "0.8.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" [[package]] name = "crunchy" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" [[package]] name = "data-encoding" version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7e962a19be5cfc3f3bf6dd8f61eb50107f356ad6270fbb3ed41476571db78be5" [[package]] name = "either" version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" [[package]] name = "half" version = "1.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" [[package]] name = "half" version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bc52e53916c08643f1b56ec082790d1e86a32e58dc5268f897f313fbae7b4872" dependencies = [ "cfg-if", "crunchy", ] [[package]] name = "itertools" version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" dependencies = [ "either", ] [[package]] name = "itoa" version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" [[package]] name = "js-sys" version = "0.3.82" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b011eec8cc36da2aab2d5cff675ec18454fad408585853910a202391cf9f8e65" dependencies = [ "once_cell", "wasm-bindgen", ] [[package]] name = "memchr" version = "2.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" [[package]] name = "num-traits" version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" dependencies = [ "autocfg", ] [[package]] name = "once_cell" version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" [[package]] name = "oorandom" version = "11.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" [[package]] name = "plotters" version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5aeb6f403d7a4911efb1e33402027fc44f29b5bf6def3effcc22d7bb75f2b747" dependencies = [ "num-traits", "plotters-backend", "plotters-svg", "wasm-bindgen", "web-sys", ] [[package]] name = "plotters-backend" version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df42e13c12958a16b3f7f4386b9ab1f3e7933914ecea48da7139435263a4172a" [[package]] name = "plotters-svg" version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51bae2ac328883f7acdfea3d66a7c35751187f870bc81f94563733a154d7a670" dependencies = [ "plotters-backend", ] [[package]] name = "proc-macro2" version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da" dependencies = [ "unicode-ident", ] [[package]] name = "quote" version = "1.0.33" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" dependencies = [ "proc-macro2", ] [[package]] name = "rayon" version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "368f01d005bf8fd9b1206fb6fa653e6c4a81ceb1466406b81792d87c5677a58f" dependencies = [ "either", "rayon-core", ] [[package]] name = "rayon-core" version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91" dependencies = [ "crossbeam-deque", "crossbeam-utils", ] [[package]] name = "regex" version = "1.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343" dependencies = [ "aho-corasick", "memchr", "regex-automata", "regex-syntax", ] [[package]] name = "regex-automata" version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f" dependencies = [ "aho-corasick", "memchr", "regex-syntax", ] [[package]] name = "regex-syntax" version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" [[package]] name = "rustversion" version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" [[package]] name = "ryu" version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" [[package]] name = "same-file" version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" dependencies = [ "winapi-util", ] [[package]] name = "serde" version = "1.0.193" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89" dependencies = [ "serde_derive", ] [[package]] name = "serde_bytes" version = "0.11.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab33ec92f677585af6d88c65593ae2375adde54efdbf16d597f2cbc7a6d368ff" dependencies = [ "serde", ] [[package]] name = "serde_cbor" version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2bef2ebfde456fb76bbcf9f59315333decc4fda0b2b44b420243c11e0f5ec1f5" dependencies = [ "half 1.8.2", "serde", ] [[package]] name = "serde_derive" version = "1.0.193" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "serde_json" version = "1.0.108" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b" dependencies = [ "itoa", "ryu", "serde", ] [[package]] name = "syn" version = "2.0.39" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] [[package]] name = "tinytemplate" version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc" dependencies = [ "serde", "serde_json", ] [[package]] name = "unicode-ident" version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "walkdir" version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d71d857dc86794ca4c280d616f7da00d2dbfd8cd788846559a6813e6aa4b54ee" dependencies = [ "same-file", "winapi-util", ] [[package]] name = "wasm-bindgen" version = "0.2.105" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da95793dfc411fbbd93f5be7715b0578ec61fe87cb1a42b12eb625caa5c5ea60" dependencies = [ "cfg-if", "once_cell", "rustversion", "wasm-bindgen-macro", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-macro" version = "0.2.105" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04264334509e04a7bf8690f2384ef5265f05143a4bff3889ab7a3269adab59c2" dependencies = [ "quote", "wasm-bindgen-macro-support", ] [[package]] name = "wasm-bindgen-macro-support" version = "0.2.105" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "420bc339d9f322e562942d52e115d57e950d12d88983a14c79b86859ee6c7ebc" dependencies = [ "bumpalo", "proc-macro2", "quote", "syn", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" version = "0.2.105" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "76f218a38c84bcb33c25ec7059b07847d465ce0e0a76b995e134a45adcb6af76" dependencies = [ "unicode-ident", ] [[package]] name = "web-sys" version = "0.3.82" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3a1f95c0d03a47f4ae1f7a64643a6bb97465d9b740f0fa8f90ea33915c99a9a1" dependencies = [ "js-sys", "wasm-bindgen", ] [[package]] name = "winapi" version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" dependencies = [ "winapi-i686-pc-windows-gnu", "winapi-x86_64-pc-windows-gnu", ] [[package]] name = "winapi-i686-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" dependencies = [ "winapi", ] [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" cbor4ii-1.2.1/Cargo.toml0000644000000037421046102023000104160ustar # 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 are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2018" name = "cbor4ii" version = "1.2.1" authors = ["quininer "] build = false autolib = false autobins = false autoexamples = false autotests = false autobenches = false description = "CBOR: Concise Binary Object Representation" readme = "README.md" keywords = [ "serde", "cbor", "serialization", ] categories = [ "encoding", "no-std", ] license = "MIT" repository = "https://github.com/quininer/cbor4ii" [package.metadata.docs.rs] all-features = true [features] half-f16 = ["half"] serde1 = [ "serde/alloc", "use_alloc", ] use_alloc = [] use_std = ["use_alloc"] [lib] name = "cbor4ii" path = "src/lib.rs" [[test]] name = "decode" path = "tests/decode.rs" [[test]] name = "serde" path = "tests/serde.rs" [[test]] name = "serde_cbor" path = "tests/serde_cbor.rs" [[bench]] name = "de" path = "benches/bench_de.rs" harness = false required-features = ["serde1"] [[bench]] name = "ser" path = "benches/bench_ser.rs" harness = false required-features = [ "serde1", "use_std", ] [dependencies.half] version = "2" optional = true default-features = false [dependencies.serde] version = "1" optional = true default-features = false [dev-dependencies.anyhow] version = "1" [dev-dependencies.ciborium] version = "0.2" [dev-dependencies.criterion] version = "0.7" [dev-dependencies.data-encoding] version = "2" [dev-dependencies.serde] version = "1" features = ["derive"] [dev-dependencies.serde_bytes] version = "0.11" [dev-dependencies.serde_cbor] version = "0.11" cbor4ii-1.2.1/Cargo.toml.orig000064400000000000000000000020041046102023000140430ustar 00000000000000[package] name = "cbor4ii" version = "1.2.1" authors = ["quininer "] description = "CBOR: Concise Binary Object Representation" repository = "https://github.com/quininer/cbor4ii" categories = [ "encoding", "no-std" ] keywords = [ "serde", "cbor", "serialization" ] license = "MIT" edition = "2018" [features] use_std = [ "use_alloc" ] use_alloc = [] half-f16 = [ "half" ] serde1 = [ "serde/alloc", "use_alloc" ] [dependencies] half = { version = "2", default-features = false, optional = true } serde = { version = "1", default-features = false, optional = true } [dev-dependencies] anyhow = "1" serde = { version = "1", features = [ "derive" ] } serde_bytes = "0.11" data-encoding = "2" serde_cbor = "0.11" ciborium = "0.2" criterion = "0.7" [package.metadata.docs.rs] all-features = true [[bench]] name = "ser" path = "benches/bench_ser.rs" harness = false required-features = [ "serde1", "use_std" ] [[bench]] name = "de" path = "benches/bench_de.rs" harness = false required-features = [ "serde1" ] cbor4ii-1.2.1/LICENSE000064400000000000000000000020341046102023000121640ustar 00000000000000Copyright (c) 2021 quininer 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. cbor4ii-1.2.1/README.md000064400000000000000000000044331046102023000124430ustar 00000000000000# CBOR 0x(4+4)9 0x49 [![github actions](https://github.com/quininer/cbor4ii/workflows/CI/badge.svg)](https://github.com/quininer/cbor4ii/actions) [![crates](https://img.shields.io/crates/v/cbor4ii.svg)](https://crates.io/crates/cbor4ii) [![license](https://img.shields.io/badge/License-MIT-blue.svg)](https://github.com/quininer/cbor4ii/blob/master/LICENSE) [![docs.rs](https://docs.rs/cbor4ii/badge.svg)](https://docs.rs/cbor4ii/) “The Concise Binary Object Representation (CBOR) is a data format whose design goals include the possibility of extremely small code size, fairly small message size, and extensibility without the need for version negotiation.” see [rfc8949](https://www.rfc-editor.org/rfc/rfc8949.html) ## Compatibility The `core` mod should be fully compatible with rfc8949, but some extensions will not be implemented in this crate, such as `datetime`, `bignum`, `bigfloat`. The `serde` mod defines how Rust types should be expressed in CBOR, which is not any standard, so different crate may have inconsistent behavior. This library is intended to be compatible with `serde_cbor`, but will not follow some unreasonable designs of `serde_cbor`. * `cbor4ii` will express the unit type as an empty array instead of null. This avoids the problem that `serde_cbor` cannot distinguish between `None` and `Some(())`. see * `cbor4ii` does not support packed mode, and it may be implemented in future, but it may not be compatible with `serde_cbor`. If you want packed mode, you should look at `bincode`. ## Performance It is not specifically optimized for performance in implementation, but benchmarks shows that its performance is slightly better than `serde_cbor`. And it supports zero-copy deserialization and `deserialize_ignored_any` of serde, so in some scenarios it may perform better than crate that do not support such feature. ## Robustness The decode part has been fuzz tested, and it should not crash or panic during the decoding process. The decode of serde module has a depth limit to prevent stack overflow or OOM caused by specially constructed input. If you want to turn off deep inspection or adjust parameters, you can implement the `dec::Read` trait yourself. # License This project is licensed under [the MIT license](LICENSE). cbor4ii-1.2.1/benches/bench_de.rs000064400000000000000000000031311046102023000146620ustar 00000000000000use std::hint::black_box; use std::collections::HashMap; use serde::{ Serialize, Deserialize }; use criterion::{criterion_group, criterion_main, Criterion}; #[derive(Serialize, Deserialize)] struct Log<'a> { level: usize, id: u64, time: (u64, (u32, u32)), path: &'a str, line: Option, fields: HashMap, msg: &'a str, } fn bench_de(c: &mut Criterion) { let map = { let mut map = HashMap::new(); map.insert("key".into(), "value".into()); map.insert("id".into(), "1".into()); let v = (0..123).map(|_| 'a').collect::(); map.insert("a".into(), v); map }; let msg = { use std::fmt::Write; let mut msg = String::new(); for i in 0..321 { write!(&mut msg, "{}", i).unwrap(); } msg }; let log = Log { level: 3, id: c as *const _ as usize as u64, time: (0x2021, (0x99, 0x11111)), path: file!(), line: Some(line!()), fields: map, msg: &msg }; let buf = cbor4ii::serde::to_vec(Vec::new(), &log).unwrap(); c.bench_function("cbor4ii-de", |b| { b.iter(|| { let log: Log = cbor4ii::serde::from_slice(black_box(&buf)).unwrap(); black_box(log); }) }); c.bench_function("serde_cbor-de", |b| { b.iter(|| { let log: Log = serde_cbor::from_slice(black_box(&buf)).unwrap(); black_box(log); }) }); // ciborium does not support zero copy decode :( } criterion_group!(de, bench_de); criterion_main!(de); cbor4ii-1.2.1/benches/bench_ser.rs000064400000000000000000000032341046102023000150670ustar 00000000000000use std::hint::black_box; use std::collections::HashMap; use serde::Serialize; use criterion::{criterion_group, criterion_main, Criterion}; #[derive(Serialize)] struct Log<'a> { level: usize, id: u64, time: (u64, (u32, u32)), path: &'a str, line: Option, fields: HashMap, msg: &'a str, } fn bench_ser(c: &mut Criterion) { let map = { let mut map = HashMap::new(); map.insert("key".into(), "value".into()); map.insert("id".into(), "1".into()); map }; let msg = { use std::fmt::Write; let mut msg = String::new(); for i in 0..321 { write!(&mut msg, "{}", i).unwrap(); } msg }; let log = Log { level: 3, id: c as *const _ as usize as u64, time: (0x2021, (0x99, 0x11111)), path: file!(), line: Some(line!()), fields: map, msg: &msg }; c.bench_function("cbor4ii-ser", |b| { let mut buf = Vec::new(); b.iter(|| { buf.clear(); cbor4ii::serde::to_writer(black_box(&mut buf), black_box(&log)).unwrap(); }) }); c.bench_function("serde_cbor-ser", |b| { let mut buf = Vec::new(); b.iter(|| { buf.clear(); serde_cbor::to_writer(black_box(&mut buf), black_box(&log)).unwrap(); }) }); c.bench_function("ciborium-ser", |b| { let mut buf = Vec::new(); b.iter(|| { buf.clear(); ciborium::ser::into_writer(black_box(&log), black_box(&mut buf)).unwrap(); }) }); } criterion_group!(ser, bench_ser); criterion_main!(ser); cbor4ii-1.2.1/src/core/dec.rs000064400000000000000000000700401046102023000140010ustar 00000000000000//! decode module use core::convert::TryFrom; use crate::core::{ major, marker, types, error }; use crate::util::ScopeGuard; pub use crate::core::error::DecodeError as Error; #[cfg(feature = "use_alloc")] use crate::alloc::{ boxed::Box, vec::Vec, string::String }; /// Read trait /// /// This is similar to `BufRead` of standard library, /// but can define its own error types, and can get a /// reference with a long enough lifetime to implement zero-copy decode. pub trait Read<'de> { type Error: core::error::Error + 'static; /// Returns the available bytes. /// /// The want value is the expected value. /// If the length of bytes returned is less than this value, /// zero-copy decoding will not be possible. /// /// Returning empty bytes means EOF. fn fill<'short>(&'short mut self, want: usize) -> Result, Self::Error>; /// Advance reader fn advance(&mut self, n: usize); /// Step count /// /// This method maybe called when the decode is started /// to calculate the decode depth. /// If it returns false, the decode will return a depth limit error. #[inline] fn step_in(&mut self) -> bool { true } /// Step count /// /// This method maybe called when the decode is completed /// to calculate the decode depth. #[inline] fn step_out(&mut self) {} } /// Bytes reference pub enum Reference<'de, 'short> { /// If the reader can return bytes as long as its lifetime, /// then zero-copy decoding will be allowed. Long(&'de [u8]), /// Bytes returned normally Short(&'short [u8]) } /// Decode trait pub trait Decode<'de>: Sized { /// Decode to type fn decode>(reader: &mut R) -> Result>; } impl<'de, 'short> Reference<'de, 'short> { #[inline] pub const fn as_ref(&self) -> &[u8] { match self { Reference::Long(buf) => buf, Reference::Short(buf) => buf } } #[inline] pub fn take(&self, len: usize) -> Reference<'de, 'short> { let len = core::cmp::min(self.as_ref().len(), len); match self { Reference::Long(buf) => Reference::Long(&buf[..len]), Reference::Short(buf) => Reference::Short(&buf[..len]) } } } impl<'de, T: Read<'de>> Read<'de> for &mut T { type Error = T::Error; #[inline] fn fill<'short>(&'short mut self, want: usize) -> Result, Self::Error> { (**self).fill(want) } #[inline] fn advance(&mut self, n: usize) { (**self).advance(n) } #[inline] fn step_in(&mut self) -> bool { (**self).step_in() } #[inline] fn step_out(&mut self) { (**self).step_out() } } #[inline] pub(crate) fn peek_one<'de, R: Read<'de>>(name: error::StaticStr, reader: &mut R) -> Result> { let b = reader.fill(1)? .as_ref() .first() .copied() .ok_or_else(|| Error::eof(name, 1))?; Ok(b) } #[inline] pub(crate) fn pull_one<'de, R: Read<'de>>(name: error::StaticStr, reader: &mut R) -> Result> { let b = peek_one(name, reader)?; reader.advance(1); Ok(b) } #[inline] fn pull_exact<'de, R: Read<'de>>(name: error::StaticStr, reader: &mut R, mut buf: &mut [u8]) -> Result<(), Error> { let buf_len = buf.len(); while !buf.is_empty() { let readbuf = reader.fill(buf.len())?; let readbuf = readbuf.as_ref(); if readbuf.is_empty() { return Err(Error::eof(name, buf_len)); } let len = core::cmp::min(buf.len(), readbuf.len()); buf[..len].copy_from_slice(&readbuf[..len]); reader.advance(len); buf = &mut buf[len..]; } Ok(()) } #[inline] fn skip_exact<'de, R: Read<'de>>(name: error::StaticStr, reader: &mut R, mut len: usize) -> Result<(), Error> { while len != 0 { let buf = reader.fill(len)?; let buf = buf.as_ref(); if buf.is_empty() { return Err(Error::eof(name, len)); } let buflen = core::cmp::min(len, buf.len()); reader.advance(buflen); len -= buflen; } Ok(()) } #[derive(Clone, Copy)] pub(crate) struct TypeNum { name: error::StaticStr, major: u8 } impl TypeNum { #[inline] pub(crate) const fn new(name: error::StaticStr, major: u8) -> TypeNum { TypeNum { name, major: major << 5 } } #[inline] pub fn decode_u8<'de, R: Read<'de>>(self, reader: &mut R) -> Result> { let byte = pull_one(self.name, reader)?; let is_major = high(byte) ^ self.major; match low(byte) | is_major { x @ 0 ..= 0x17 => Ok(x), 0x18 => pull_one(self.name, reader), _ => Err(Error::mismatch(self.name, byte)) } } #[inline] fn decode_u16<'de, R: Read<'de>>(self, reader: &mut R) -> Result> { let byte = pull_one(self.name, reader)?; let is_major = high(byte) ^ self.major; let mut buf = [0; 2]; let n = match low(byte) | is_major { x @ 0 ..= 0x17 => return Ok(x.into()), 0x18 => 1, 0x19 => 0, _ => return Err(Error::mismatch(self.name, byte)) }; pull_exact(self.name, reader, &mut buf[n..])?; Ok(u16::from_be_bytes(buf)) } #[inline] fn decode_u32<'de, R: Read<'de>>(self, reader: &mut R) -> Result> { let byte = pull_one(self.name, reader)?; let is_major = high(byte) ^ self.major; let mut buf = [0; 4]; let n = match low(byte) | is_major { x @ 0 ..= 0x17 => return Ok(x.into()), 0x1b.. => return Err(Error::mismatch(self.name, byte)), x => 4-(1 << (x-0x17-1)), // 0x18 => 4-1, // 0x19 => 4-2, // 0x1a => 4-4, }; pull_exact(self.name, reader, &mut buf[n..])?; Ok(u32::from_be_bytes(buf)) } #[inline] pub(crate) fn decode_u64<'de, R: Read<'de>>(self, reader: &mut R) -> Result> { let byte = pull_one(self.name, reader)?; let is_major = high(byte) ^ self.major; let mut buf = [0; 8]; let n = match low(byte) | is_major { x @ 0 ..= 0x17 => return Ok(x.into()), 0x1c.. => return Err(Error::mismatch(self.name, byte)), x => 8-(1 << (x-0x17-1)), // 0x18 => 8-1, // 0x19 => 8-2, // 0x1a => 8-4, // 0x1b => 8-8, }; pull_exact(self.name, reader, &mut buf[n..])?; Ok(u64::from_be_bytes(buf)) } } macro_rules! decode_ux { ( $( $t:ty , $decode_fn:ident );* $( ; )? ) => { $( impl<'de> Decode<'de> for $t { #[inline] fn decode>(reader: &mut R) -> Result> { TypeNum::new(&stringify!($t), major::UNSIGNED).$decode_fn(reader) } } )* } } macro_rules! decode_nx { ( $( $t:ty , $decode_fn:ident );* $( ; )? ) => { $( impl<'de> Decode<'de> for types::Negative<$t> { #[inline] fn decode>(reader: &mut R) -> Result> { TypeNum::new(&concat!("-", stringify!($t)), major::NEGATIVE) .$decode_fn(reader) .map(types::Negative) } } )* } } macro_rules! decode_ix { ( $( $t:ty , $decode_fn:ident );* $( ; )? ) => { $( impl<'de> Decode<'de> for $t { #[inline] fn decode>(reader: &mut R) -> Result> { let name = &stringify!($t); let unsigned_name = &concat!("+", stringify!($t)); let negative_name = &concat!("-", stringify!($t)); let byte = peek_one(name, reader)?; match if_major(byte) { major::UNSIGNED => { let v = TypeNum::new(unsigned_name, major::UNSIGNED).$decode_fn(reader)?; <$t>::try_from(v) .map_err(|_| Error::cast_overflow(unsigned_name)) }, major::NEGATIVE => { let v = TypeNum::new(negative_name, major::NEGATIVE).$decode_fn(reader)?; let v = <$t>::try_from(v) .map_err(|_| Error::cast_overflow(negative_name))?; let v = -v; let v = v.checked_sub(1) .ok_or_else(|| Error::arithmetic_overflow(negative_name, error::ArithmeticOverflow::Underflow))?; Ok(v) }, _ => Err(Error::mismatch(name, byte)) } } } )* } } decode_ux! { u8, decode_u8; u16, decode_u16; u32, decode_u32; u64, decode_u64; } decode_nx! { u8, decode_u8; u16, decode_u16; u32, decode_u32; u64, decode_u64; } decode_ix! { i8, decode_u8; i16, decode_u16; i32, decode_u32; i64, decode_u64; } #[inline] fn decode_x128<'de, R: Read<'de>>(name: error::StaticStr, reader: &mut R) -> Result<[u8; 16], Error> { let len = decode_len(TypeNum::new(name, major::BYTES), reader)?; let len = len.ok_or_else(|| Error::require_length(name, None))?; let mut buf = [0; 16]; if let Some(pos) = buf.len().checked_sub(len) { pull_exact(name, reader, &mut buf[pos..])?; Ok(buf) } else { Err(Error::length_overflow(name, len)) } } impl<'de> Decode<'de> for u128 { #[inline] fn decode>(reader: &mut R) -> Result> { let name = &"u128"; let name_bytes = &"u128::bytes"; let name_tag = &"u128::tag"; let byte = peek_one(name, reader)?; if if_major(byte) == major::UNSIGNED { u64::decode(reader).map(Into::into) } else { let tag = TypeNum::new(name, major::TAG).decode_u8(reader)?; if tag == 2 { let buf = decode_x128(name_bytes, reader)?; Ok(u128::from_be_bytes(buf)) } else { Err(Error::mismatch(name_tag, tag)) } } } } impl<'de> Decode<'de> for i128 { #[inline] fn decode>(reader: &mut R) -> Result> { let name = &"i128"; let name_ubytes = &"+i128::bytes"; let name_nbytes = &"-i128::bytes"; let name_tag = &"i128::tag"; let byte = peek_one(name, reader)?; match if_major(byte) { major::UNSIGNED => u64::decode(reader).map(Into::into), major::NEGATIVE => { // Negative numbers can be as big as 2^64, hence decode them as unsigned 64-bit // value first. let n = TypeNum::new(name, major::NEGATIVE).decode_u64(reader)?; let n = i128::from(n); let n = -n; let n = n - 1; Ok(n) }, _ => { let tag = TypeNum::new(name, major::TAG).decode_u8(reader)?; match tag { 2 => { let buf = decode_x128(name_ubytes, reader)?; let n = u128::from_be_bytes(buf); let n = i128::try_from(n).map_err(|_| Error::cast_overflow(name))?; Ok(n) }, 3 => { let buf = decode_x128(name_nbytes, reader)?; let n = u128::from_be_bytes(buf); let n = i128::try_from(n).map_err(|_| Error::cast_overflow(name))?; let n = -n; let n = n.checked_sub(1) .ok_or_else(|| Error::arithmetic_overflow(name, error::ArithmeticOverflow::Underflow))?; Ok(n) }, _ => Err(Error::mismatch(name_tag, tag)) } } } } } #[inline] fn decode_len<'de, R: Read<'de>>(num: TypeNum, reader: &mut R) -> Result, Error> { let byte = peek_one(num.name, reader)?; if byte != (marker::START | num.major) { let len = num.decode_u64(reader)?; let len = usize::try_from(len).map_err(|_| Error::cast_overflow(num.name))?; Ok(Some(len)) } else { reader.advance(1); Ok(None) } } #[inline] fn decode_bytes_ref<'de, R: Read<'de>>(num: TypeNum, reader: &mut R) -> Result<&'de [u8], Error> { let len = num.decode_u64(reader)?; let len = usize::try_from(len) .map_err(|_| Error::cast_overflow(num.name))?; match reader.fill(len)? { Reference::Long(buf) if buf.len() >= len => { reader.advance(len); Ok(&buf[..len]) }, Reference::Long(buf) => Err(Error::require_length(num.name, Some(buf.len()))), Reference::Short(_) => Err(Error::require_borrowed(num.name)) } } #[inline] #[cfg(feature = "use_alloc")] fn decode_bytes<'a, R: Read<'a>>(num: TypeNum, reader: &mut R, buf: &mut Vec) -> Result, Error> { const CAP_LIMIT: usize = 16 * 1024; if let Some(mut len) = decode_len(num, reader)? { // try long lifetime buffer if let Reference::Long(buf) = reader.fill(len)? { if buf.len() >= len { reader.advance(len); return Ok(Some(&buf[..len])); } } buf.reserve(core::cmp::min(len, CAP_LIMIT)); // TODO try_reserve ? while len != 0 { let readbuf = reader.fill(len)?; let readbuf = readbuf.as_ref(); if readbuf.is_empty() { return Err(Error::eof(num.name, len)); } let readlen = core::cmp::min(readbuf.len(), len); buf.extend_from_slice(&readbuf[..readlen]); reader.advance(readlen); len -= readlen; } Ok(None) } else { // bytes sequence while peek_one(num.name, reader)? != marker::BREAK { if !reader.step_in() { return Err(Error::depth_overflow(num.name)); } let mut reader = ScopeGuard(reader, |reader| reader.step_out()); let reader = &mut *reader; // followed by a series of zero or more strings of // the specified type ("chunks") that have **definite lengths** let longbuf = decode_bytes_ref(num, reader)?; buf.extend_from_slice(longbuf); } Ok(None) } } #[cfg(feature = "use_alloc")] #[inline] fn decode_buf<'de, R>(num: TypeNum, reader: &mut R) -> Result, Error> where R: Read<'de>, { let mut buf = Vec::new(); if let Some(buf_ref) = decode_bytes(num, reader, &mut buf)? { buf.extend_from_slice(buf_ref); } Ok(buf) } #[cfg(feature = "use_alloc")] #[inline] fn decode_cow_buf<'de, R>(num: TypeNum, reader: &mut R) -> Result, Error> where R: Read<'de>, { use crate::alloc::borrow::Cow; let mut buf = Vec::new(); if let Some(buf_ref) = decode_bytes(num, reader, &mut buf)? { core::mem::forget(buf); Ok(Cow::Borrowed(buf_ref)) } else { Ok(Cow::Owned(buf)) } } impl<'de> Decode<'de> for types::Bytes<&'de [u8]> { #[inline] fn decode>(reader: &mut R) -> Result> { let buf = decode_bytes_ref(TypeNum::new(&"bytes", major::BYTES), reader)?; Ok(types::Bytes(buf)) } } #[cfg(feature = "use_alloc")] impl<'de> Decode<'de> for types::Bytes> { #[inline] fn decode>(reader: &mut R) -> Result> { let buf = decode_buf(TypeNum::new(&"bytes", major::BYTES), reader)?; Ok(types::Bytes(buf)) } } #[cfg(feature = "use_alloc")] impl<'de> Decode<'de> for types::Bytes> { #[inline] fn decode>(reader: &mut R) -> Result> { let buf = decode_cow_buf(TypeNum::new(&"bytes", major::BYTES), reader)?; Ok(types::Bytes(buf)) } } impl<'de> Decode<'de> for &'de str { #[inline] fn decode>(reader: &mut R) -> Result> { let name = &"str"; let buf = decode_bytes_ref(TypeNum::new(name, major::STRING), reader)?; core::str::from_utf8(buf).map_err(|_| Error::require_utf8(name)) } } #[cfg(feature = "use_alloc")] impl<'de> Decode<'de> for String { #[inline] fn decode>(reader: &mut R) -> Result> { let types::UncheckedStr(buf) = >>::decode(reader)?; String::from_utf8(buf).map_err(|_| Error::require_utf8(&"str")) } } #[cfg(feature = "use_alloc")] impl<'de> Decode<'de> for crate::alloc::borrow::Cow<'de, str> { #[inline] fn decode>(reader: &mut R) -> Result> { use crate::alloc::borrow::Cow; let name = &"str"; let types::UncheckedStr(buf) = >>::decode(reader)?; match buf { Cow::Borrowed(buf) => core::str::from_utf8(buf) .map(Cow::Borrowed) .map_err(|_| Error::require_utf8(name)), Cow::Owned(buf) => String::from_utf8(buf) .map(Cow::Owned) .map_err(|_| Error::require_utf8(name)) } } } impl<'de> Decode<'de> for types::UncheckedStr<&'de [u8]> { #[inline] fn decode>(reader: &mut R) -> Result> { let buf = decode_bytes_ref(TypeNum::new(&"str", major::STRING), reader)?; Ok(types::UncheckedStr(buf)) } } #[cfg(feature = "use_alloc")] impl<'de> Decode<'de> for types::UncheckedStr> { #[inline] fn decode>(reader: &mut R) -> Result> { let buf = decode_buf(TypeNum::new(&"str", major::STRING), reader)?; Ok(types::UncheckedStr(buf)) } } #[cfg(feature = "use_alloc")] impl<'de> Decode<'de> for types::UncheckedStr> { #[inline] fn decode>(reader: &mut R) -> Result> { let buf = decode_cow_buf(TypeNum::new(&"str", major::STRING), reader)?; Ok(types::UncheckedStr(buf)) } } pub struct ArrayStart(pub Option); impl<'de> types::Array<()> { #[inline] pub fn len>(reader: &mut R) -> Result, Error> { decode_len(TypeNum::new(&"array", major::ARRAY), reader) } } #[cfg(feature = "use_alloc")] impl<'de, T: Decode<'de>> Decode<'de> for Vec { #[inline] fn decode>(reader: &mut R) -> Result> { let name = &"array"; let mut arr = Vec::new(); if !reader.step_in() { return Err(Error::depth_overflow(name)); } let mut reader = ScopeGuard(reader, |reader| reader.step_out()); let reader = &mut *reader; if let Some(len) = types::Array::len(reader)? { arr.reserve(core::cmp::min(len, 256)); // TODO try_reserve ? for _ in 0..len { let value = T::decode(reader)?; arr.push(value); } } else { while !is_break(reader)? { let value = T::decode(reader)?; arr.push(value); } } Ok(arr) } } impl<'de> types::Map<()> { #[inline] pub fn len>(reader: &mut R) -> Result, Error> { decode_len(TypeNum::new(&"map", major::MAP), reader) } } #[cfg(feature = "use_alloc")] impl<'de, K: Decode<'de>, V: Decode<'de>> Decode<'de> for types::Map> { #[inline] fn decode>(reader: &mut R) -> Result> { let name = &"map"; let mut map = Vec::new(); if !reader.step_in() { return Err(Error::depth_overflow(name)); } let mut reader = ScopeGuard(reader, |reader| reader.step_out()); let reader = &mut *reader; if let Some(len) = types::Map::len(reader)? { map.reserve(core::cmp::min(len, 256)); // TODO try_reserve ? for _ in 0..len { let k = K::decode(reader)?; let v = V::decode(reader)?; map.push((k, v)); } } else { while !is_break(reader)? { let k = K::decode(reader)?; let v = V::decode(reader)?; map.push((k, v)); } } Ok(types::Map(map)) } } impl<'de> types::Tag<()> { #[inline] pub fn tag>(reader: &mut R) -> Result> { TypeNum::new(&"tag", major::TAG).decode_u64(reader) } } impl<'de, T: Decode<'de>> Decode<'de> for types::Tag { #[inline] fn decode>(reader: &mut R) -> Result> { let tag = types::Tag::tag(reader)?; let value = T::decode(reader)?; Ok(types::Tag(tag, value)) } } impl<'de> Decode<'de> for types::Simple { #[inline] fn decode>(reader: &mut R) -> Result> { let n = TypeNum::new(&"simple", major::SIMPLE).decode_u8(reader)?; Ok(types::Simple(n)) } } impl<'de> Decode<'de> for bool { #[inline] fn decode>(reader: &mut R) -> Result> { let name = &"bool"; let byte = peek_one(name, reader)?; let ret = match byte { marker::FALSE => false, marker::TRUE => true, _ => return Err(Error::mismatch(name, byte)) }; reader.advance(1); Ok(ret) } } impl<'de, T: Decode<'de>> Decode<'de> for Option { #[inline] fn decode>(reader: &mut R) -> Result> { let byte = peek_one(&"option", reader)?; if byte != marker::NULL && byte != marker::UNDEFINED { T::decode(reader).map(Some) } else { reader.advance(1); Ok(None) } } } impl<'de, T: Decode<'de>> Decode<'de> for types::Maybe> { #[inline] fn decode>(reader: &mut R) -> Result> { let len = >::len(reader)?; match len { Some(0) => Ok(types::Maybe(None)), Some(1) => T::decode(reader).map(Some).map(types::Maybe), _ => Err(Error::require_length(&"maybe", len)) } } } impl<'de> Decode<'de> for types::F16 { #[inline] fn decode>(reader: &mut R) -> Result> { let name = &"f16"; let byte = peek_one(name, reader)?; if byte == marker::F16 { reader.advance(1); let mut buf = [0; 2]; pull_exact(name, reader, &mut buf)?; Ok(types::F16(u16::from_be_bytes(buf))) } else { Err(Error::mismatch(name, byte)) } } } #[cfg(feature = "half-f16")] impl<'de> Decode<'de> for half::f16 { #[inline] fn decode>(reader: &mut R) -> Result> { let types::F16(n) = types::F16::decode(reader)?; Ok(half::f16::from_bits(n)) } } impl<'de> Decode<'de> for f32 { #[inline] fn decode>(reader: &mut R) -> Result> { let name = &"f32"; let byte = peek_one(name, reader)?; if byte == marker::F32 { reader.advance(1); let mut buf = [0; 4]; pull_exact(name, reader, &mut buf)?; Ok(f32::from_be_bytes(buf)) } else { Err(Error::mismatch(name, byte)) } } } impl<'de> Decode<'de> for f64 { #[inline] fn decode>(reader: &mut R) -> Result> { let name = &"f64"; let byte = peek_one(name, reader)?; if byte == marker::F64 { reader.advance(1); let mut buf = [0; 8]; pull_exact(name, reader, &mut buf)?; Ok(f64::from_be_bytes(buf)) } else { Err(Error::mismatch(name, byte)) } } } impl<'de> Decode<'de> for types::Nothing { #[inline] fn decode>(_reader: &mut R) -> Result> { Ok(types::Nothing) } } #[cfg(feature = "use_alloc")] impl<'de, T: Decode<'de>> Decode<'de> for Box { #[inline] fn decode>(reader: &mut R) -> Result> { T::decode(reader).map(Box::new) } } /// Ignore an arbitrary object pub struct IgnoredAny; impl<'de> Decode<'de> for IgnoredAny { fn decode>(reader: &mut R) -> Result> { let name = &"ignored-any"; if !reader.step_in() { return Err(Error::depth_overflow(name)); } let mut reader = ScopeGuard(reader, |reader| reader.step_out()); let reader = &mut *reader; let byte = peek_one(name, reader)?; match if_major(byte) { major::UNSIGNED | major::NEGATIVE => { let skip = match low(byte) { 0 ..= 0x17 => 0, 0x18 => 1, 0x19 => 2, 0x1a => 4, 0x1b => 8, _ => return Err(Error::mismatch(name, byte)) }; skip_exact(name, reader, skip + 1)?; }, major @ major::BYTES | major @ major::STRING | major @ major::ARRAY | major @ major::MAP => { if let Some(len) = decode_len(TypeNum::new(name, major), reader)? { match major { major::BYTES | major::STRING => skip_exact(name, reader, len)?, major::ARRAY | major::MAP => for _ in 0..len { let _ignore = IgnoredAny::decode(reader)?; if major == major::MAP { let _ignore = IgnoredAny::decode(reader)?; } }, _ => () } } else { while !is_break(reader)? { let _ignore = IgnoredAny::decode(reader)?; if major == major::MAP { let _ignore = IgnoredAny::decode(reader)?; } } } }, major @ major::TAG => { let _tag = TypeNum::new(&"tag", major).decode_u64(reader)?; let _ignore = IgnoredAny::decode(reader)?; }, major::SIMPLE => { let skip = match byte { marker::FALSE | marker::TRUE | marker::NULL | marker::UNDEFINED => 0, marker::F16 => 2, marker::F32 => 4, marker::F64 => 8, _ => return Err(Error::unsupported(name, byte)) }; skip_exact(name, reader, skip + 1)?; }, _ => return Err(Error::unsupported(name, byte)) } Ok(IgnoredAny) } } #[inline] pub fn is_break<'de, R: Read<'de>>(reader: &mut R) -> Result> { if peek_one(&"break", reader)? == marker::BREAK { reader.advance(1); Ok(true) } else { Ok(false) } } /// Determine the object type from the given byte. #[inline] pub fn if_major(byte: u8) -> u8 { byte >> 5 } #[inline] pub fn high(byte: u8) -> u8 { byte & 0b11100000 } #[inline] pub fn low(byte: u8) -> u8 { byte & 0b00011111 } #[test] fn high_and_low() { let b = 0b01010101; assert_eq!(high(b), 0b01000000); assert_eq!(low(b), 0b00010101); } cbor4ii-1.2.1/src/core/enc.rs000064400000000000000000000516651046102023000140270ustar 00000000000000//! encode module use core::convert::TryFrom; use crate::core::{ types, major, marker }; pub use crate::core::error::EncodeError as Error; #[cfg(feature = "use_alloc")] use crate::alloc::{ boxed::Box, vec::Vec, string::String }; /// Write trait /// /// This is similar to `Write` of standard library, /// but it can define its own error type and work in `no_std`. pub trait Write { type Error: core::error::Error + 'static; /// write all data fn push(&mut self, input: &[u8]) -> Result<(), Self::Error>; } /// Encode trait pub trait Encode { /// Write the type to writer by CBOR encoding. fn encode(&self, writer: &mut W) -> Result<(), Error>; } impl Encode for &'_ T { #[inline] fn encode(&self, writer: &mut W) -> Result<(), Error> { ::encode(self, writer) } } impl Write for &mut T { type Error = T::Error; #[inline] fn push(&mut self, input: &[u8]) -> Result<(), Self::Error> { (**self).push(input) } } struct TypeNum { type_: u8, value: V } impl TypeNum { #[inline] const fn new(type_: u8, value: V) -> TypeNum { TypeNum { type_, value } } } impl Encode for TypeNum { #[inline] fn encode(&self, writer: &mut W) -> Result<(), Error> { match self.value { x @ 0x00 ..= 0x17 => writer.push(&[self.type_ | x])?, x => writer.push(&[self.type_ | 0x18, x])? } Ok(()) } } impl Encode for TypeNum { #[inline] fn encode(&self, writer: &mut W) -> Result<(), Error> { match u8::try_from(self.value) { Ok(x) => TypeNum::new(self.type_, x).encode(writer)?, Err(_) => { let mut buf = [self.type_ | 0x19, 0, 0]; buf[1..3].copy_from_slice(&self.value.to_be_bytes()); writer.push(&buf)? } } Ok(()) } } impl Encode for TypeNum { #[inline] fn encode(&self, writer: &mut W) -> Result<(), Error> { match u16::try_from(self.value) { Ok(x) => TypeNum::new(self.type_, x).encode(writer)?, Err(_) =>{ let mut buf = [self.type_ | 0x1a, 0, 0, 0, 0]; buf[1..5].copy_from_slice(&self.value.to_be_bytes()); writer.push(&buf)?; } } Ok(()) } } impl Encode for TypeNum { #[inline] fn encode(&self, writer: &mut W) -> Result<(), Error> { match u32::try_from(self.value) { Ok(x) => TypeNum::new(self.type_, x).encode(writer)?, Err(_) => { let mut buf = [self.type_ | 0x1b, 0, 0, 0, 0, 0, 0, 0, 0]; buf[1..9].copy_from_slice(&self.value.to_be_bytes()); writer.push(&buf)?; } } Ok(()) } } #[inline] fn strip_zero(input: &[u8]) -> &[u8] { let pos = input.iter() .position(|&n| n != 0x0) .unwrap_or(input.len()); &input[pos..] } impl Encode for u128 { #[inline] fn encode(&self, writer: &mut W) -> Result<(), Error> { let x = *self; match u64::try_from(x) { Ok(x) => TypeNum::new(major::UNSIGNED << 5, x).encode(writer), Err(_) => { let x = x.to_be_bytes(); let bytes = types::Bytes(strip_zero(&x)); types::Tag(2, bytes).encode(writer) } } } } impl Encode for i128 { #[inline] fn encode(&self, writer: &mut W) -> Result<(), Error> { let x = *self; if let Ok(x) = u128::try_from(x) { x.encode(writer) } else { let x = -1 - x; if let Ok(x) = u64::try_from(x) { types::Negative(x).encode(writer) } else { let x = x.to_be_bytes(); let bytes = types::Bytes(strip_zero(&x)); types::Tag(3, bytes).encode(writer) } } } } macro_rules! encode_ux { ( $( $t:ty ),* ) => { $( impl Encode for $t { #[inline] fn encode(&self, writer: &mut W) -> Result<(), Error> { TypeNum::new(major::UNSIGNED << 5, *self).encode(writer) } } )* } } macro_rules! encode_nx { ( $( $t:ty ),* ) => { $( impl Encode for types::Negative<$t> { #[inline] fn encode(&self, writer: &mut W) -> Result<(), Error> { TypeNum::new(major::NEGATIVE << 5, self.0).encode(writer) } } )* } } macro_rules! encode_ix { ( $( $t:ty = $t2:ty );* $( ; )? ) => { $( impl Encode for $t { #[inline] fn encode(&self, writer: &mut W) -> Result<(), Error> { let x = *self; match <$t2>::try_from(x) { Ok(x) => x.encode(writer), Err(_) => types::Negative((-1 - x) as $t2).encode(writer) } } } )* } } encode_ux!(u8, u16, u32, u64); encode_nx!(u8, u16, u32, u64); encode_ix!( i8 = u8; i16 = u16; i32 = u32; i64 = u64; ); impl Encode for types::Bytes<&'_ [u8]> { #[inline] fn encode(&self, writer: &mut W) -> Result<(), Error> { types::Bytes::bounded(self.0.len(), writer)?; writer.push(self.0)?; Ok(()) } } #[cfg(feature = "use_alloc")] impl Encode for String { #[inline] fn encode(&self, writer: &mut W) -> Result<(), Error> { self.as_str().encode(writer) } } impl Encode for &'_ str { #[inline] fn encode(&self, writer: &mut W) -> Result<(), Error> { types::UncheckedStr::bounded(self.len(), writer)?; writer.push(self.as_bytes())?; Ok(()) } } impl Encode for types::UncheckedStr<&'_ [u8]> { #[inline] fn encode(&self, writer: &mut W) -> Result<(), Error> { types::UncheckedStr::bounded(self.0.len(), writer)?; writer.push(self.0)?; Ok(()) } } impl Encode for &'_ [T] { #[inline] fn encode(&self, writer: &mut W) -> Result<(), Error> { types::Array::bounded(self.len(), writer)?; for value in self.iter() { value.encode(writer)?; } Ok(()) } } impl Encode for types::Map<&'_ [(K, V)]> { #[inline] fn encode(&self, writer: &mut W) -> Result<(), Error> { types::Map::bounded(self.0.len(), writer)?; for (k, v) in self.0.iter() { k.encode(writer)?; v.encode(writer)?; } Ok(()) } } /// Implementation of markers for types with indefinite length suppport. macro_rules! bound_unbound_end { ( $( $t:ty , $major:expr );* $( ; )? ) => { $( impl $t { /// Encode the type with the length prefix. #[inline] pub fn bounded(len: usize, writer: &mut W) -> Result<(), Error> { TypeNum::new($major << 5, len as u64).encode(writer)?; Ok(()) } /// Encode the type with an indefinite size marker. #[inline] pub fn unbounded(writer: &mut W) -> Result<(), Error> { writer.push(&[($major << 5) | marker::START])?; Ok(()) } /// Encode the indefinite size end marker. #[inline] pub fn end(writer: &mut W) -> Result<(), Error> { writer.push(&[marker::BREAK])?; Ok(()) } } )* } } bound_unbound_end! { types::Array<()>, major::ARRAY; types::Map<()>, major::MAP; types::Bytes<()>, major::BYTES; types::UncheckedStr<()>, major::STRING; } impl Encode for types::Tag { #[inline] fn encode(&self, writer: &mut W) -> Result<(), Error> { TypeNum::new(major::TAG << 5, self.0).encode(writer)?; self.1.encode(writer) } } impl Encode for types::Simple { #[inline] fn encode(&self, writer: &mut W) -> Result<(), Error> { TypeNum::new(major::SIMPLE << 5, self.0).encode(writer) } } impl Encode for bool { #[inline] fn encode(&self, writer: &mut W) -> Result<(), Error> { writer.push(&[match *self { true => marker::TRUE, false => marker::FALSE }])?; Ok(()) } } impl Encode for types::Null { #[inline] fn encode(&self, writer: &mut W) -> Result<(), Error> { writer.push(&[marker::NULL])?; Ok(()) } } impl Encode for types::Undefined { #[inline] fn encode(&self, writer: &mut W) -> Result<(), Error> { writer.push(&[marker::UNDEFINED])?; Ok(()) } } impl Encode for types::Maybe<&'_ Option> { #[inline] fn encode(&self, writer: &mut W) -> Result<(), Error> { self.0.as_slice().encode(writer) } } #[cfg(feature = "half-f16")] impl Encode for half::f16 { #[inline] fn encode(&self, writer: &mut W) -> Result<(), Error> { let mut buf = [marker::F16, 0, 0]; buf[1..3].copy_from_slice(&self.to_be_bytes()); writer.push(&buf)?; Ok(()) } } impl Encode for types::F16 { #[inline] fn encode(&self, writer: &mut W) -> Result<(), Error> { let mut buf = [marker::F16, 0, 0]; buf[1..3].copy_from_slice(&self.0.to_be_bytes()); writer.push(&buf)?; Ok(()) } } impl Encode for f32 { #[inline] fn encode(&self, writer: &mut W) -> Result<(), Error> { let mut buf = [marker::F32, 0, 0, 0, 0]; buf[1..5].copy_from_slice(&self.to_be_bytes()); writer.push(&buf)?; Ok(()) } } impl Encode for f64 { #[inline] fn encode(&self, writer: &mut W) -> Result<(), Error> { let mut buf = [marker::F64, 0, 0, 0, 0, 0, 0, 0, 0]; buf[1..9].copy_from_slice(&self.to_be_bytes()); writer.push(&buf)?; Ok(()) } } impl Encode for types::Nothing { #[inline] fn encode(&self, _writer: &mut W) -> Result<(), Error> { Ok(()) } } #[cfg(feature = "use_alloc")] impl Encode for Box { #[inline] fn encode(&self, writer: &mut W) -> Result<(), Error> { ::encode(&**self, writer) } } #[cfg(feature = "use_alloc")] impl Encode for Vec { #[inline] fn encode(&self, writer: &mut W) -> Result<(), Error> { self.as_slice().encode(writer) } } // from https://www.rfc-editor.org/rfc/rfc8949.html#name-examples-of-encoded-cbor-da #[test] #[cfg(feature = "use_std")] fn test_encoded() -> anyhow::Result<()> { pub struct Buffer(Vec); impl Write for Buffer { type Error = std::convert::Infallible; fn push(&mut self, input: &[u8]) -> Result<(), Self::Error> { self.0.extend_from_slice(input); Ok(()) } } fn hex(input: &[u8]) -> String { let mut buf = String::from("0x"); data_encoding::HEXLOWER.encode_append(input, &mut buf); buf } let mut buf = Buffer(Vec::new()); macro_rules! test { ( $( $( @ #[$cfg_meta:meta] )* $input:expr , $expected:expr );* $( ; )? ) => { $( $( #[$cfg_meta] )* { buf.0.clear(); ($input).encode(&mut buf)?; let output = hex(&buf.0); assert_eq!(output, $expected, "{:?}", stringify!($input)); } )* } } let strbuf_ud800_udd51 = { let iter = char::decode_utf16([0xd800u16, 0xdd51u16]); let mut buf = String::new(); for ret in iter { buf.push(ret?); } buf }; test!{ 0u64, "0x00"; 1u64, "0x01"; 10u64, "0x0a"; 23u64, "0x17"; 24u64, "0x1818"; 25u64, "0x1819"; 100u64, "0x1864"; 1000u64, "0x1903e8"; 1000000u64, "0x1a000f4240"; 1000000000000u64, "0x1b000000e8d4a51000"; 18446744073709551615u64, "0x1bffffffffffffffff"; 18446744073709551616u128, "0xc249010000000000000000"; types::Negative((-18446744073709551616i128 - 1) as u64), "0x3bffffffffffffffff"; -18446744073709551617i128, "0xc349010000000000000000"; -1i64, "0x20"; -10i64, "0x29"; -100i64, "0x3863"; -1000i64, "0x3903e7"; @ #[cfg(feature = "half-f16")] half::f16::from_f32(0.0), "0xf90000"; @ #[cfg(feature = "half-f16")] half::f16::from_f32(-0.0), "0xf98000"; @ #[cfg(feature = "half-f16")] half::f16::from_f32(1.0), "0xf93c00"; 1.1f64, "0xfb3ff199999999999a"; @ #[cfg(feature = "half-f16")] half::f16::from_f32(1.5), "0xf93e00"; @ #[cfg(feature = "half-f16")] half::f16::from_f32(65504.0), "0xf97bff"; types::F16(0x7bff), "0xf97bff"; 100000.0f32, "0xfa47c35000"; 3.4028234663852886e+38f32, "0xfa7f7fffff"; 1.0e+300f64, "0xfb7e37e43c8800759c"; @ #[cfg(feature = "half-f16")] half::f16::from_f32(5.960464477539063e-8), "0xf90001"; @ #[cfg(feature = "half-f16")] half::f16::from_f32(0.00006103515625), "0xf90400"; @ #[cfg(feature = "half-f16")] half::f16::from_f32(-4.0), "0xf9c400"; -4.1f64, "0xfbc010666666666666"; @ #[cfg(feature = "half-f16")] half::f16::INFINITY, "0xf97c00"; @ #[cfg(feature = "half-f16")] half::f16::NAN, "0xf97e00"; @ #[cfg(feature = "half-f16")] half::f16::NEG_INFINITY, "0xf9fc00"; f32::INFINITY, "0xfa7f800000"; f32::NAN, "0xfa7fc00000"; f32::NEG_INFINITY, "0xfaff800000"; f64::INFINITY, "0xfb7ff0000000000000"; f64::NAN, "0xfb7ff8000000000000"; f64::NEG_INFINITY, "0xfbfff0000000000000"; false, "0xf4"; true, "0xf5"; types::Null, "0xf6"; types::Undefined, "0xf7"; types::Simple(16), "0xf0"; types::Simple(255), "0xf8ff"; types::Tag(0, "2013-03-21T20:04:00Z"), "0xc074323031332d30332d32315432303a30343a30305a"; types::Tag(1, 1363896240u64), "0xc11a514b67b0"; types::Tag(1, 1363896240.5f64), "0xc1fb41d452d9ec200000"; types::Tag(23, types::Bytes(&[0x01, 0x02, 0x03, 0x04][..])), "0xd74401020304"; types::Tag(24, types::Bytes(&[0x64, 0x49, 0x45, 0x54, 0x46][..])), "0xd818456449455446"; types::Tag(32, "http://www.example.com"), "0xd82076687474703a2f2f7777772e6578616d706c652e636f6d"; types::Bytes(&[0u8; 0][..]), "0x40"; types::Bytes(&[0x01, 0x02, 0x03, 0x04][..]), "0x4401020304"; "", "0x60"; "a", "0x6161"; "IETF", "0x6449455446"; "\"\\", "0x62225c"; "\u{00fc}", "0x62c3bc"; "\u{6c34}", "0x63e6b0b4"; strbuf_ud800_udd51.as_str(), "0x64f0908591"; &[0u8; 0][..], "0x80"; &[1u8, 2, 3][..], "0x83010203"; &[1u8, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25][..], "0x98190102030405060708090a0b0c0d0e0f101112131415161718181819"; types::Map(&[(0u8, 0u8); 0][..]), "0xa0"; types::Map(&[(1u8, 2u8), (3u8, 4u8)][..]), "0xa201020304"; types::Map(&[("a", "A"), ("b", "B"), ("c", "C"), ("d", "D"), ("e", "E")][..]), "0xa56161614161626142616361436164614461656145"; } // [1, [2, 3], [4, 5]] { buf.0.clear(); types::Array::bounded(3, &mut buf)?; 1u8.encode(&mut buf)?; (&[2u64, 3u64][..]).encode(&mut buf)?; (&[4i32, 5i32][..]).encode(&mut buf)?; let output = hex(&buf.0); assert_eq!(output, "0x8301820203820405"); } // {"a": 1, "b": [2, 3]} { buf.0.clear(); types::Map::bounded(2, &mut buf)?; "a".encode(&mut buf)?; 1u32.encode(&mut buf)?; "b".encode(&mut buf)?; (&[2u32, 3u32][..]).encode(&mut buf)?; let output = hex(&buf.0); assert_eq!(output, "0xa26161016162820203"); } // ["a", {"b": "c"}] { buf.0.clear(); types::Array::bounded(2, &mut buf)?; "a".encode(&mut buf)?; types::Map::bounded(1, &mut buf)?; "b".encode(&mut buf)?; "c".encode(&mut buf)?; let output = hex(&buf.0); assert_eq!(output, "0x826161a161626163"); } // (_ h'0102', h'030405') { buf.0.clear(); types::Bytes::unbounded(&mut buf)?; types::Bytes(&[0x01, 0x02][..]).encode(&mut buf)?; types::Bytes(&[0x03, 0x04, 0x05][..]).encode(&mut buf)?; types::Bytes::end(&mut buf)?; let output = hex(&buf.0); assert_eq!(output, "0x5f42010243030405ff"); } // (_ "strea", "ming") { buf.0.clear(); types::UncheckedStr::unbounded(&mut buf)?; "strea".encode(&mut buf)?; "ming".encode(&mut buf)?; types::UncheckedStr::end(&mut buf)?; let output = hex(&buf.0); assert_eq!(output, "0x7f657374726561646d696e67ff"); } // [_ ] { buf.0.clear(); types::Array::unbounded(&mut buf)?; types::Array::end(&mut buf)?; let output = hex(&buf.0); assert_eq!(output, "0x9fff"); } // [_ 1, [2, 3], [_ 4, 5]] { buf.0.clear(); types::Array::unbounded(&mut buf)?; 1u64.encode(&mut buf)?; (&[2u32, 3u32][..]).encode(&mut buf)?; types::Array::unbounded(&mut buf)?; 4u64.encode(&mut buf)?; 5u64.encode(&mut buf)?; types::Array::end(&mut buf)?; types::Array::end(&mut buf)?; let output = hex(&buf.0); assert_eq!(output, "0x9f018202039f0405ffff"); } // [_ 1, [2, 3], [4, 5]] { buf.0.clear(); types::Array::unbounded(&mut buf)?; 1u64.encode(&mut buf)?; (&[2u32, 3u32][..]).encode(&mut buf)?; (&[4u32, 5u32][..]).encode(&mut buf)?; types::Array::end(&mut buf)?; let output = hex(&buf.0); assert_eq!(output, "0x9f01820203820405ff"); } // [1, [2, 3], [_ 4, 5]] { buf.0.clear(); types::Array::bounded(3, &mut buf)?; 1u64.encode(&mut buf)?; (&[2u32, 3u32][..]).encode(&mut buf)?; types::Array::unbounded(&mut buf)?; 4u64.encode(&mut buf)?; 5u64.encode(&mut buf)?; types::Array::end(&mut buf)?; let output = hex(&buf.0); assert_eq!(output, "0x83018202039f0405ff"); } // [1, [_ 2, 3], [4, 5]] { buf.0.clear(); types::Array::bounded(3, &mut buf)?; 1u64.encode(&mut buf)?; types::Array::unbounded(&mut buf)?; 2u64.encode(&mut buf)?; 3u64.encode(&mut buf)?; types::Array::end(&mut buf)?; (&[4u32, 5u32][..]).encode(&mut buf)?; let output = hex(&buf.0); assert_eq!(output, "0x83019f0203ff820405"); } // [_ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25] { buf.0.clear(); types::Array::unbounded(&mut buf)?; for i in 1u32..=25 { i.encode(&mut buf)?; } types::Array::end(&mut buf)?; let output = hex(&buf.0); assert_eq!(output, "0x9f0102030405060708090a0b0c0d0e0f101112131415161718181819ff"); } // {_ "a": 1, "b": [_ 2, 3]} { buf.0.clear(); types::Map::unbounded(&mut buf)?; "a".encode(&mut buf)?; 1u32.encode(&mut buf)?; "b".encode(&mut buf)?; types::Array::unbounded(&mut buf)?; 2i32.encode(&mut buf)?; 3i32.encode(&mut buf)?; types::Array::end(&mut buf)?; types::Array::end(&mut buf)?; let output = hex(&buf.0); assert_eq!(output, "0xbf61610161629f0203ffff"); } // ["a", {_ "b": "c"}] { buf.0.clear(); types::Array::bounded(2, &mut buf)?; "a".encode(&mut buf)?; types::Map::unbounded(&mut buf)?; "b".encode(&mut buf)?; "c".encode(&mut buf)?; types::Array::end(&mut buf)?; let output = hex(&buf.0); assert_eq!(output, "0x826161bf61626163ff"); } // {_ "Fun": true, "Amt": -2} { buf.0.clear(); types::Map::unbounded(&mut buf)?; "Fun".encode(&mut buf)?; true.encode(&mut buf)?; "Amt".encode(&mut buf)?; (-2i32).encode(&mut buf)?; types::Map::end(&mut buf)?; let output = hex(&buf.0); assert_eq!(output, "0xbf6346756ef563416d7421ff"); } assert!(strip_zero(&[0x0]).is_empty()); Ok(()) } cbor4ii-1.2.1/src/core/error.rs000064400000000000000000000107011046102023000143750ustar 00000000000000use core::fmt; use core::convert::TryFrom; /// Static String /// /// Use `&&str` instead of `&str` to reduce type size. pub type StaticStr = &'static &'static str; /// Never type pub type Never = core::convert::Infallible; /// Length type #[derive(Debug)] pub enum Len { /// Indefinite length Indefinite, /// Small length Small(u16), /// Big length Big } #[derive(Debug)] pub enum ArithmeticOverflow { Overflow, Underflow } /// Decode Error #[derive(Debug)] #[non_exhaustive] pub enum DecodeError { Read(E), Mismatch { name: StaticStr, found: u8 }, Unsupported { name: StaticStr, found: u8 }, Eof { name: StaticStr, expect: Len, }, RequireLength { name: StaticStr, found: Len, }, RequireBorrowed { name: StaticStr, }, RequireUtf8 { name: StaticStr, }, LengthOverflow { name: StaticStr, found: Len }, CastOverflow { name: StaticStr }, ArithmeticOverflow { name: StaticStr, ty: ArithmeticOverflow }, DepthOverflow { name: StaticStr }, Custom { name: StaticStr, num: u32 } } impl Len { #[inline] pub fn new(len: usize) -> Len { match u16::try_from(len) { Ok(len) => Len::Small(len), Err(_) => Len::Big } } } impl From for DecodeError { #[cold] fn from(err: E) -> DecodeError { DecodeError::Read(err) } } impl DecodeError { #[cold] pub(crate) fn mismatch(name: StaticStr, found: u8) -> DecodeError { DecodeError::Mismatch { name, found } } #[cold] pub(crate) fn unsupported(name: StaticStr, found: u8) -> DecodeError { DecodeError::Unsupported { name, found } } #[cold] pub(crate) fn eof(name: StaticStr, expect: usize) -> DecodeError { DecodeError::Eof { name, expect: Len::new(expect) } } #[cold] pub(crate) fn require_length(name: StaticStr, found: Option) -> DecodeError { let found = match found { Some(len) => Len::new(len), None => Len::Indefinite }; DecodeError::RequireLength { name, found } } #[cold] pub(crate) fn require_borrowed(name: StaticStr) -> DecodeError { DecodeError::RequireBorrowed { name } } #[cold] pub(crate) fn require_utf8(name: StaticStr) -> DecodeError { DecodeError::RequireUtf8 { name } } #[cold] pub(crate) fn length_overflow(name: StaticStr, found: usize) -> DecodeError { DecodeError::LengthOverflow { name, found: Len::new(found) } } #[cold] pub(crate) fn cast_overflow(name: StaticStr) -> DecodeError { DecodeError::CastOverflow { name } } #[cold] pub(crate) fn arithmetic_overflow(name: StaticStr, ty: ArithmeticOverflow) -> DecodeError { DecodeError::ArithmeticOverflow { name, ty } } #[cold] pub(crate) fn depth_overflow(name: StaticStr) -> DecodeError { DecodeError::DepthOverflow { name } } } impl fmt::Display for DecodeError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Debug::fmt(self, f) } } impl core::error::Error for DecodeError { fn source(&self) -> Option<&(dyn core::error::Error + 'static)> { match self { DecodeError::Read(err) => Some(err), _ => None } } } /// Encode Error #[derive(Debug)] #[non_exhaustive] pub enum EncodeError { Write(E) } impl From for EncodeError { #[cold] fn from(err: E) -> EncodeError { EncodeError::Write(err) } } impl fmt::Display for EncodeError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Debug::fmt(self, f) } } impl core::error::Error for EncodeError { fn source(&self) -> Option<&(dyn core::error::Error + 'static)> { match self { EncodeError::Write(err) => Some(err), } } } #[cfg(target_pointer_width = "64")] #[test] fn test_error_type_size() { // bottom type assert_eq!(core::mem::size_of::>(), 16); // unit type assert_eq!(core::mem::size_of::>(), 16); // a word type assert_eq!(core::mem::size_of::>(), 16); } cbor4ii-1.2.1/src/core/raw_value.rs000064400000000000000000000153701046102023000152400ustar 00000000000000use core::marker::PhantomData; use crate::core::{ enc, dec }; #[derive(PartialEq, Eq, Debug, Clone)] pub struct RawValue<'de>(&'de [u8]); struct RawValueReader<'r, 'de, R> where R: dec::Read<'de> { reader: &'r mut R, readn: usize, _phantom: PhantomData<&'de [u8]> } impl<'r, 'de, R> RawValueReader<'r, 'de, R> where R: dec::Read<'de> { #[inline] fn new(reader: &'r mut R) -> RawValueReader<'r, 'de, R> { RawValueReader { reader, readn: 0, _phantom: PhantomData } } } impl<'de, R> dec::Read<'de> for RawValueReader<'_, 'de, R> where R: dec::Read<'de> { type Error = R::Error; #[inline] fn fill<'short>(&'short mut self, want: usize) -> Result, Self::Error> { let want = match self.readn.checked_add(want) { Some(n) => n, None => return Ok(dec::Reference::Long(&[])) }; let buf = match self.reader.fill(want)? { dec::Reference::Long(buf) if buf.len() >= self.readn => dec::Reference::Long(&buf[self.readn..]), dec::Reference::Long(_) => dec::Reference::Long(&[]), dec::Reference::Short(buf) => dec::Reference::Short(buf) }; Ok(buf) } #[inline] fn advance(&mut self, n: usize) { self.readn += n; } #[inline] fn step_in(&mut self) -> bool { self.reader.step_in() } #[inline] fn step_out(&mut self) { self.reader.step_out() } } impl<'de> dec::Decode<'de> for RawValue<'de> { #[inline] fn decode>(reader: &mut R) -> Result> { let name = &"raw-value"; let mut reader = RawValueReader::new(reader); let _ignore = dec::IgnoredAny::decode(&mut reader)?; let buf = match reader.reader.fill(reader.readn).map_err(dec::Error::Read)? { dec::Reference::Long(buf) if buf.len() >= reader.readn => &buf[..reader.readn], dec::Reference::Long(buf) => return Err(dec::Error::require_length(name, Some(buf.len()))), dec::Reference::Short(_) => return Err(dec::Error::require_borrowed(name)) }; reader.reader.advance(reader.readn); Ok(RawValue(buf)) } } impl enc::Encode for RawValue<'_> { #[inline] fn encode(&self, writer: &mut W) -> Result<(), enc::Error> { writer.push(self.0).map_err(enc::Error::Write) } } impl<'de> RawValue<'de> { pub fn as_bytes(&self) -> &'de [u8] { self.0 } } #[cfg(feature = "use_alloc")] pub mod boxed { use crate::core::Value; use crate::core::utils::BufWriter; use crate::alloc::boxed::Box; use super::*; #[derive(PartialEq, Eq, Debug, Clone)] pub struct BoxedRawValue(Box<[u8]>); impl<'de> dec::Decode<'de> for BoxedRawValue { #[inline] fn decode>(reader: &mut R) -> Result> { let value = RawValue::decode(reader)?; Ok(BoxedRawValue(Box::from(value.0))) } } impl enc::Encode for BoxedRawValue { #[inline] fn encode(&self, writer: &mut W) -> Result<(), enc::Error> { writer.push(&self.0).map_err(enc::Error::Write) } } impl BoxedRawValue { pub fn as_bytes(&self) -> &[u8] { &self.0 } pub fn from_value(value: &Value) -> Result> { use crate::alloc::vec::Vec; use crate::core::enc::Encode; let mut writer = BufWriter::new(Vec::new()); value.encode(&mut writer)?; Ok(BoxedRawValue(writer.into_inner().into_boxed_slice())) } } } #[test] #[cfg(feature = "use_std")] fn test_raw_value() { use crate::core::enc::Encode; use crate::core::dec::Decode; use crate::core::utils::{ BufWriter, SliceReader }; use crate::core::types; use boxed::BoxedRawValue; let buf = { let mut buf = BufWriter::new(Vec::new()); types::Map(&[ ("bar", types::Map(&[ ("value", 0x99u32) ][..])) ][..]).encode(&mut buf).unwrap(); buf }; // raw value { let mut reader = SliceReader::new(buf.buffer()); let map = )>>>::decode(&mut reader).unwrap(); assert_eq!(map.0.len(), 1); assert_eq!(map.0[0].0, "bar"); let bar_raw_value = &map.0[0].1; assert!(!bar_raw_value.as_bytes().is_empty()); let buf2 = { let mut buf = BufWriter::new(Vec::new()); types::Map(&[ ("bar", bar_raw_value) ][..]).encode(&mut buf).unwrap(); buf }; assert_eq!(buf.buffer(), buf2.buffer()); type Bar<'a> = types::Map>; let mut reader = SliceReader::new(buf2.buffer()); let map2 = >>::decode(&mut reader).unwrap(); assert_eq!(map2.0.len(), 1); assert_eq!(map2.0[0].0, "bar"); let bar = &map2.0[0].1; assert_eq!(bar.0.len(), 1); assert_eq!(bar.0[0].0, "value"); assert_eq!(bar.0[0].1, 0x99); } // boxed raw value { let mut reader = SliceReader::new(buf.buffer()); let map = >>::decode(&mut reader).unwrap(); assert_eq!(map.0.len(), 1); assert_eq!(map.0[0].0, "bar"); let bar_raw_value = &map.0[0].1; assert!(!bar_raw_value.as_bytes().is_empty()); // check from value { use crate::core::Value; let mut reader = SliceReader::new(buf.buffer()); let map = >>::decode(&mut reader).unwrap(); let bar_value = &map.0[0].1; let bar_raw_value2 = BoxedRawValue::from_value(&bar_value).unwrap(); assert_eq!(bar_raw_value, &bar_raw_value2); } let buf2 = { let mut buf = BufWriter::new(Vec::new()); types::Map(&[ ("bar", bar_raw_value) ][..]).encode(&mut buf).unwrap(); buf }; assert_eq!(buf.buffer(), buf2.buffer()); type Bar<'a> = types::Map>; let mut reader = SliceReader::new(buf2.buffer()); let map2 = >>::decode(&mut reader).unwrap(); assert_eq!(map2.0.len(), 1); assert_eq!(map2.0[0].0, "bar"); let bar = &map2.0[0].1; assert_eq!(bar.0.len(), 1); assert_eq!(bar.0[0].0, "value"); assert_eq!(bar.0[0].1, 0x99); } } cbor4ii-1.2.1/src/core/types.rs000064400000000000000000000005401046102023000144100ustar 00000000000000//! built-in type pub struct Negative(pub T); pub struct Bytes(pub T); pub struct UncheckedStr(pub T); pub struct Array(pub T); pub struct Map(pub T); pub struct Tag(pub u64, pub T); pub struct Simple(pub u8); pub struct Null; pub struct Undefined; pub struct F16(pub u16); pub struct Maybe(pub T); pub struct Nothing; cbor4ii-1.2.1/src/core/utils.rs000064400000000000000000000067111046102023000144120ustar 00000000000000#[cfg(feature = "use_alloc")] use crate::alloc::vec::Vec; #[cfg(feature = "use_alloc")] use crate::core::enc; use crate::core::dec; /// An in-memory writer. #[cfg(feature = "use_alloc")] pub struct BufWriter(Vec); #[cfg(feature = "use_alloc")] impl BufWriter { /// Creates a new writer. pub fn new(buf: Vec) -> Self { BufWriter(buf) } /// Returns a reference to the underlying data. pub fn buffer(&self) -> &[u8] { &self.0 } /// Returns the underlying vector. pub fn into_inner(self) -> Vec { self.0 } /// Discards the underlying data. pub fn clear(&mut self) { self.0.clear(); } } #[cfg(feature = "use_alloc")] impl enc::Write for BufWriter { type Error = crate::alloc::collections::TryReserveError; #[inline] fn push(&mut self, input: &[u8]) -> Result<(), Self::Error> { self.0.try_reserve(input.len())?; self.0.extend_from_slice(input); Ok(()) } } /// An in-memory reader. pub struct SliceReader<'a> { buf: &'a [u8], limit: usize } impl SliceReader<'_> { pub fn new(buf: &[u8]) -> SliceReader<'_> { SliceReader { buf, limit: 256 } } } impl<'de> dec::Read<'de> for SliceReader<'de> { type Error = crate::core::error::Never; #[inline] fn fill<'b>(&'b mut self, want: usize) -> Result, Self::Error> { let len = core::cmp::min(self.buf.len(), want); Ok(dec::Reference::Long(&self.buf[..len])) } #[inline] fn advance(&mut self, n: usize) { let len = core::cmp::min(self.buf.len(), n); self.buf = &self.buf[len..]; } #[inline] fn step_in(&mut self) -> bool { if let Some(limit) = self.limit.checked_sub(1) { self.limit = limit; true } else { false } } #[inline] fn step_out(&mut self) { self.limit += 1; } } /// A writer to work with [`std::io::Write`]. #[cfg(feature = "use_std")] pub struct IoWriter(W); #[cfg(feature = "use_std")] impl IoWriter { pub fn new(writer: W) -> Self { IoWriter(writer) } pub fn into_inner(self) -> W { self.0 } } #[cfg(feature = "use_std")] impl enc::Write for IoWriter { type Error = std::io::Error; #[inline] fn push(&mut self, input: &[u8]) -> Result<(), Self::Error> { self.0.write_all(input) } } /// A reader to work with [`std::io::BufRead`]. /// /// It has a recursion limit. #[cfg(feature = "use_std")] pub struct IoReader { reader: R, limit: usize, } #[cfg(feature = "use_std")] impl IoReader { pub fn new(reader: R) -> Self { Self { reader, limit: 256 } } pub fn into_inner(self) -> R { self.reader } } #[cfg(feature = "use_std")] impl<'de, R: std::io::BufRead> dec::Read<'de> for IoReader { type Error = std::io::Error; #[inline] fn fill<'b>(&'b mut self, _want: usize) -> Result, Self::Error> { let buf = self.reader.fill_buf()?; Ok(dec::Reference::Short(buf)) } #[inline] fn advance(&mut self, n: usize) { self.reader.consume(n); } #[inline] fn step_in(&mut self) -> bool { if let Some(limit) = self.limit.checked_sub(1) { self.limit = limit; true } else { false } } #[inline] fn step_out(&mut self) { self.limit += 1; } } cbor4ii-1.2.1/src/core.rs000064400000000000000000000234211046102023000132470ustar 00000000000000//! core module mod raw_value; pub mod error; pub mod types; pub mod enc; pub mod dec; pub mod utils; #[cfg(feature = "use_alloc")] use crate::alloc::{ vec::Vec, boxed::Box, string::String }; pub use raw_value::RawValue; #[cfg(feature = "use_alloc")] pub use raw_value::boxed::BoxedRawValue; /// Major type pub mod major { pub const UNSIGNED: u8 = 0; pub const NEGATIVE: u8 = 1; pub const BYTES: u8 = 2; pub const STRING: u8 = 3; pub const ARRAY: u8 = 4; pub const MAP: u8 = 5; pub const TAG: u8 = 6; pub const SIMPLE: u8 = 7; } /// Markers needed to parse sub types. /// The `START` marker can be combined with major types 2, 3, 4 and 5. /// The other values are full bytes representing the major type 7 sub-types. pub mod marker { pub const START: u8 = 0x1f; pub const FALSE: u8 = 0xf4; // simple(20) pub const TRUE: u8 = 0xf5; // simple(21) pub const NULL: u8 = 0xf6; // simple(22) pub const UNDEFINED: u8 = 0xf7; // simple(23) pub const F16: u8 = 0xf9; pub const F32: u8 = 0xfa; pub const F64: u8 = 0xfb; pub const BREAK: u8 = 0xff; } #[cfg(feature = "use_alloc")] #[derive(Debug, Clone, PartialEq)] #[non_exhaustive] pub enum Value { Null, Bool(bool), Integer(i128), Float(f64), Bytes(Vec), Text(String), Array(Vec), Map(Vec<(Value, Value)>), Tag(u64, Box) } #[cfg(feature = "use_alloc")] impl enc::Encode for Value { fn encode(&self, writer: &mut W) -> Result<(), enc::Error> { match self { Value::Null => types::Null.encode(writer), Value::Bool(v) => v.encode(writer), Value::Integer(v) => v.encode(writer), Value::Float(v) => v.encode(writer), Value::Bytes(v) => types::Bytes(v.as_slice()).encode(writer), Value::Text(v) => v.as_str().encode(writer), Value::Array(v) => v.as_slice().encode(writer), Value::Map(v) => types::Map(v.as_slice()).encode(writer), Value::Tag(tag, v) => types::Tag(*tag, &**v).encode(writer) } } } #[cfg(feature = "use_alloc")] impl<'de> dec::Decode<'de> for Value { fn decode>(reader: &mut R) -> Result> { use crate::util::ScopeGuard; let name = &"value"; if !reader.step_in() { return Err(dec::Error::depth_overflow(name)); } let mut reader = ScopeGuard(reader, |reader| reader.step_out()); let reader = &mut *reader; let byte = dec::peek_one(name, reader)?; match dec::if_major(byte) { major::UNSIGNED => u64::decode(reader) .map(|i| Value::Integer(i.into())), major::NEGATIVE => { let types::Negative(v) = >::decode(reader)?; let v = i128::from(v); let v = -v - 1; Ok(Value::Integer(v)) }, major::BYTES => >>::decode(reader) .map(|buf| Value::Bytes(buf.0)), major::STRING => String::decode(reader) .map(Value::Text), major::ARRAY => >::decode(reader) .map(Value::Array), major::MAP => >>::decode(reader) .map(|map| Value::Map(map.0)), major::TAG => { let tag = >::decode(reader)?; Ok(Value::Tag(tag.0, Box::new(tag.1))) }, major::SIMPLE => match byte { marker::FALSE => { reader.advance(1); Ok(Value::Bool(false)) }, marker::TRUE => { reader.advance(1); Ok(Value::Bool(true)) }, marker::NULL | marker::UNDEFINED => { reader.advance(1); Ok(Value::Null) }, #[cfg(feature = "half-f16")] marker::F16 => { let v = half::f16::decode(reader)?; Ok(Value::Float(v.into())) }, marker::F32 => f32::decode(reader) .map(|v| Value::Float(v.into())), marker::F64 => f64::decode(reader) .map(Value::Float), _ => Err(dec::Error::unsupported(name, byte)) }, _ => Err(dec::Error::unsupported(name, byte)) } } } #[cfg(feature = "serde1")] impl serde::Serialize for Value { fn serialize(&self, serializer: S) -> Result where S: serde::Serializer { use serde::ser::{ Error, SerializeMap, SerializeSeq }; match self { Value::Null => serializer.serialize_none(), Value::Bool(v) => serializer.serialize_bool(*v), Value::Integer(v) => serializer.serialize_i128(*v), Value::Float(v) => serializer.serialize_f64(*v), Value::Bytes(v) => serializer.serialize_bytes(v), Value::Text(v) => serializer.serialize_str(v), Value::Array(v) => { let mut seq = serializer.serialize_seq(Some(v.len()))?; for value in v.iter() { seq.serialize_element(value)?; } seq.end() }, Value::Map(v) => { let mut map = serializer.serialize_map(Some(v.len()))?; for (k, v) in v.iter() { map.serialize_entry(k, v)?; } map.end() }, Value::Tag(..) => Err(S::Error::custom("serialization Tag via serde is not supported")) } } } #[cfg(feature = "serde1")] impl<'de> serde::Deserialize<'de> for Value { fn deserialize(deserializer: D) -> Result where D: serde::Deserializer<'de> { use serde::de::{ Error, Visitor, SeqAccess, MapAccess }; struct ValueVisitor; impl<'de> Visitor<'de> for ValueVisitor { type Value = Value; fn expecting(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { formatter.write_str("invalid input or unsupported type") } #[inline] fn visit_bool(self, v: bool) -> Result where E: Error { Ok(Value::Bool(v)) } #[inline] fn visit_i64(self, v: i64) -> Result where E: Error { Ok(Value::Integer(v.into())) } #[inline] fn visit_i128(self, v: i128) -> Result where E: Error { Ok(Value::Integer(v)) } #[inline] fn visit_u64(self, v: u64) -> Result where E: Error, { Ok(Value::Integer(v.into())) } #[inline] fn visit_u128(self, v: u128) -> Result where E: Error, { use core::convert::TryFrom; let v = i128::try_from(v).map_err(E::custom)?; Ok(Value::Integer(v)) } #[inline] fn visit_f64(self, v: f64) -> Result where E: Error, { Ok(Value::Float(v)) } #[inline] fn visit_char(self, v: char) -> Result where E: Error, { Ok(Value::Text(v.into())) } #[inline] fn visit_str(self, v: &str) -> Result where E: Error, { Ok(Value::Text(v.into())) } #[inline] fn visit_string(self, v: String) -> Result where E: Error, { Ok(Value::Text(v)) } #[inline] fn visit_bytes(self, v: &[u8]) -> Result where E: Error, { Ok(Value::Bytes(v.into())) } #[inline] fn visit_byte_buf(self, v: Vec) -> Result where E: Error, { Ok(Value::Bytes(v)) } #[inline] fn visit_none(self) -> Result where E: Error, { Ok(Value::Null) } #[inline] fn visit_unit(self) -> Result where E: Error, { self.visit_none() } #[inline] fn visit_seq(self, mut seq: A) -> Result where A: SeqAccess<'de>, { let mut list = seq.size_hint() .map(|n| Vec::with_capacity(core::cmp::min(n, 256))) .unwrap_or_else(Vec::new); while let Some(v) = seq.next_element()? { list.push(v); } Ok(Value::Array(list)) } #[inline] fn visit_map(self, mut map: A) -> Result where A: MapAccess<'de>, { let mut list = map.size_hint() .map(|n| Vec::with_capacity(core::cmp::min(n, 256))) .unwrap_or_else(Vec::new); while let Some((k, v)) = map.next_entry()? { list.push((k, v)); } Ok(Value::Map(list)) } } deserializer.deserialize_any(ValueVisitor) } } cbor4ii-1.2.1/src/lib.rs000064400000000000000000000004671046102023000130720ustar 00000000000000#![doc = include_str!("../README.md")] #![cfg_attr(not(feature = "use_std"), no_std)] #[cfg(all(not(feature = "use_std"), feature = "use_alloc"))] extern crate alloc; #[cfg(all(feature = "use_std", feature = "use_alloc"))] use std as alloc; mod util; pub mod core; #[cfg(feature = "serde1")] pub mod serde; cbor4ii-1.2.1/src/serde/de.rs000064400000000000000000000331461046102023000140160ustar 00000000000000use crate::alloc::borrow::Cow; use serde::de::{ self, Visitor }; use crate::core::{ major, marker, types, error }; use crate::core::dec::{ self, Decode }; use crate::util::ScopeGuard; use crate::serde::error::DecodeError; pub struct Deserializer { reader: R } impl Deserializer { pub fn new(reader: R) -> Deserializer { Deserializer { reader } } pub fn into_inner(self) -> R { self.reader } } impl<'de, R: dec::Read<'de>> Deserializer { #[inline] fn try_step(&mut self, name: error::StaticStr) -> Result, dec::Error> { if self.reader.step_in() { Ok(ScopeGuard(self, |de| de.reader.step_out())) } else { Err(dec::Error::depth_overflow(name)) } } } macro_rules! deserialize_type { ( @ $t:ty , $name:ident , $visit:ident ) => { #[inline] fn $name(self, visitor: V) -> Result where V: Visitor<'de> { let value = <$t>::decode(&mut self.reader)?; visitor.$visit(value) } }; ( $( $t:ty , $name:ident , $visit:ident );* $( ; )? ) => { $( deserialize_type!(@ $t, $name, $visit); )* }; } impl<'de, R: dec::Read<'de>> serde::Deserializer<'de> for &mut Deserializer { type Error = DecodeError; fn deserialize_any(self, visitor: V) -> Result where V: Visitor<'de> { let name = &"any"; let mut de = self.try_step(name)?; let de = &mut *de; let byte = dec::peek_one(name, &mut de.reader)?; match dec::if_major(byte) { major::UNSIGNED => de.deserialize_u64(visitor), major::NEGATIVE => de.deserialize_i64(visitor), major::BYTES => de.deserialize_byte_buf(visitor), major::STRING => de.deserialize_string(visitor), major::ARRAY => de.deserialize_seq(visitor), major::MAP => de.deserialize_map(visitor), // NOTE: that this does not support untagged enum. // see https://github.com/serde-rs/serde/issues/1682 major::TAG => match byte { 0xc2 => de.deserialize_u128(visitor), 0xc3 => de.deserialize_i128(visitor), _ => Err(dec::Error::unsupported(name, byte).into()) }, major::SIMPLE => match byte { marker::FALSE => { de.reader.advance(1); visitor.visit_bool(false) }, marker::TRUE => { de.reader.advance(1); visitor.visit_bool(true) }, marker::NULL | marker::UNDEFINED => { de.reader.advance(1); visitor.visit_none() }, #[cfg(feature = "half-f16")] marker::F16 => { let v = half::f16::decode(&mut de.reader)?; visitor.visit_f32(v.into()) }, marker::F32 => de.deserialize_f32(visitor), marker::F64 => de.deserialize_f64(visitor), _ => Err(dec::Error::unsupported(name, byte).into()) }, _ => Err(dec::Error::unsupported(name, byte).into()) } } deserialize_type!( bool, deserialize_bool, visit_bool; i8, deserialize_i8, visit_i8; i16, deserialize_i16, visit_i16; i32, deserialize_i32, visit_i32; i64, deserialize_i64, visit_i64; i128, deserialize_i128, visit_i128; u8, deserialize_u8, visit_u8; u16, deserialize_u16, visit_u16; u32, deserialize_u32, visit_u32; u64, deserialize_u64, visit_u64; u128, deserialize_u128, visit_u128; f32, deserialize_f32, visit_f32; f64, deserialize_f64, visit_f64; ); #[inline] fn deserialize_char(self, visitor: V) -> Result where V: Visitor<'de> { // Treat it as a String. // This is a bit wasteful when encountering strings of more than one character, // but we are optimistic this is a cold path. self.deserialize_str(visitor) } #[inline] fn deserialize_bytes(self, visitor: V) -> Result where V: Visitor<'de> { match >>::decode(&mut self.reader)?.0 { Cow::Borrowed(buf) => visitor.visit_borrowed_bytes(buf), Cow::Owned(buf) => visitor.visit_byte_buf(buf) } } #[inline] fn deserialize_byte_buf(self, visitor: V) -> Result where V: Visitor<'de> { self.deserialize_bytes(visitor) } #[inline] fn deserialize_str(self, visitor: V) -> Result where V: Visitor<'de> { match >::decode(&mut self.reader)? { Cow::Borrowed(buf) => visitor.visit_borrowed_str(buf), Cow::Owned(buf) => visitor.visit_string(buf) } } #[inline] fn deserialize_string(self, visitor: V) -> Result where V: Visitor<'de> { self.deserialize_str(visitor) } #[inline] fn deserialize_option(self, visitor: V) -> Result where V: Visitor<'de> { let name = &"option"; let byte = dec::peek_one(name, &mut self.reader)?; if byte != marker::NULL && byte != marker::UNDEFINED { let mut de = self.try_step(name)?; visitor.visit_some(&mut *de) } else { self.reader.advance(1); visitor.visit_none() } } #[inline] fn deserialize_unit(self, visitor: V) -> Result where V: Visitor<'de> { let name = &"unit"; let byte = dec::pull_one(name, &mut self.reader)?; // 0 length array if byte == (major::ARRAY << 5) { visitor.visit_unit() } else { Err(dec::Error::mismatch(name, byte).into()) } } #[inline] fn deserialize_unit_struct(self, _name: &'static str, visitor: V) -> Result where V: Visitor<'de> { self.deserialize_unit(visitor) } #[inline] fn deserialize_newtype_struct(self, _name: &'static str, visitor: V) -> Result where V: Visitor<'de> { visitor.visit_newtype_struct(self) } #[inline] fn deserialize_seq(self, visitor: V) -> Result where V: Visitor<'de> { let name = &"seq"; let mut de = self.try_step(name)?; let seq = Accessor::array(name, &mut de)?; visitor.visit_seq(seq) } #[inline] fn deserialize_tuple( self, len: usize, visitor: V ) -> Result where V: Visitor<'de> { let name = &"tuple"; let mut de = self.try_step(name)?; let seq = Accessor::tuple(name, &mut de, len)?; visitor.visit_seq(seq) } #[inline] fn deserialize_tuple_struct( self, _name: &'static str, len: usize, visitor: V ) -> Result where V: Visitor<'de> { self.deserialize_tuple(len, visitor) } #[inline] fn deserialize_map(self, visitor: V) -> Result where V: Visitor<'de> { let name = &"map"; let mut de = self.try_step(name)?; let map = Accessor::map(name, &mut de)?; visitor.visit_map(map) } #[inline] fn deserialize_struct( self, _name: &'static str, _fields: &'static [&'static str], visitor: V ) -> Result where V: Visitor<'de> { self.deserialize_map(visitor) } #[inline] fn deserialize_enum( self, _name: &'static str, _variants: &'static [&'static str], visitor: V ) -> Result where V: Visitor<'de> { let name = &"enum"; let mut de = self.try_step(name)?; let accessor = EnumAccessor::enum_(name, &mut de)?; visitor.visit_enum(accessor) } #[inline] fn deserialize_identifier(self, visitor: V) -> Result where V: Visitor<'de> { self.deserialize_str(visitor) } #[inline] fn deserialize_ignored_any(self, visitor: V) -> Result where V: Visitor<'de> { let _ignore = dec::IgnoredAny::decode(&mut self.reader)?; visitor.visit_unit() } #[inline] fn is_human_readable(&self) -> bool { false } } struct Accessor<'a, R> { de: &'a mut Deserializer, len: Option } impl<'de, 'a, R: dec::Read<'de>> Accessor<'a, R> { #[inline] pub fn array(_name: error::StaticStr, de: &'a mut Deserializer) -> Result, dec::Error> { let len = types::Array::len(&mut de.reader)?; Ok(Accessor { de, len, }) } #[inline] pub fn tuple(name: error::StaticStr, de: &'a mut Deserializer, len: usize) -> Result, dec::Error> { let array_len = types::Array::len(&mut de.reader)?; if array_len == Some(len) { Ok(Accessor { de, len: array_len, }) } else { Err(dec::Error::require_length(name, array_len)) } } #[inline] pub fn map(_name: error::StaticStr, de: &'a mut Deserializer) -> Result, dec::Error> { let len = types::Map::len(&mut de.reader)?; Ok(Accessor { de, len, }) } } impl<'de, 'a, R> de::SeqAccess<'de> for Accessor<'a, R> where R: dec::Read<'de> { type Error = DecodeError; #[inline] fn next_element_seed(&mut self, seed: T) -> Result, Self::Error> where T: de::DeserializeSeed<'de> { if let Some(len) = self.len.as_mut() { if *len > 0 { *len -= 1; Ok(Some(seed.deserialize(&mut *self.de)?)) } else { Ok(None) } } else if dec::is_break(&mut self.de.reader)? { Ok(None) } else { Ok(Some(seed.deserialize(&mut *self.de)?)) } } #[inline] fn size_hint(&self) -> Option { self.len } } impl<'de, 'a, R: dec::Read<'de>> de::MapAccess<'de> for Accessor<'a, R> { type Error = DecodeError; #[inline] fn next_key_seed(&mut self, seed: K) -> Result, Self::Error> where K: de::DeserializeSeed<'de> { if let Some(len) = self.len.as_mut() { if *len > 0 { *len -= 1; Ok(Some(seed.deserialize(&mut *self.de)?)) } else { Ok(None) } } else if dec::is_break(&mut self.de.reader)? { Ok(None) } else { Ok(Some(seed.deserialize(&mut *self.de)?)) } } #[inline] fn next_value_seed(&mut self, seed: V) -> Result where V: de::DeserializeSeed<'de> { seed.deserialize(&mut *self.de) } #[inline] fn size_hint(&self) -> Option { self.len } } struct EnumAccessor<'a, R> { de: &'a mut Deserializer, } impl<'de, 'a, R: dec::Read<'de>> EnumAccessor<'a, R> { #[inline] pub fn enum_(name: error::StaticStr, de: &'a mut Deserializer) -> Result, dec::Error> { let byte = dec::peek_one(name, &mut de.reader)?; match dec::if_major(byte) { // string major::STRING => Ok(EnumAccessor { de }), // 1 length map major::MAP if byte == (major::MAP << 5) | 1 => { de.reader.advance(1); Ok(EnumAccessor { de }) }, _ => Err(dec::Error::mismatch(name, byte)) } } } impl<'de, 'a, R> de::EnumAccess<'de> for EnumAccessor<'a, R> where R: dec::Read<'de> { type Error = DecodeError; type Variant = EnumAccessor<'a, R>; #[inline] fn variant_seed(self, seed: V) -> Result<(V::Value, Self::Variant), Self::Error> where V: de::DeserializeSeed<'de> { let variant = seed.deserialize(&mut *self.de)?; Ok((variant, self)) } } impl<'de, 'a, R> de::VariantAccess<'de> for EnumAccessor<'a, R> where R: dec::Read<'de> { type Error = DecodeError; #[inline] fn unit_variant(self) -> Result<(), Self::Error> { Ok(()) } #[inline] fn newtype_variant_seed(self, seed: T) -> Result where T: de::DeserializeSeed<'de> { seed.deserialize(&mut *self.de) } #[inline] fn tuple_variant(self, len: usize, visitor: V) -> Result where V: Visitor<'de> { use serde::Deserializer; self.de.deserialize_tuple(len, visitor) } #[inline] fn struct_variant( self, _fields: &'static [&'static str], visitor: V ) -> Result where V: Visitor<'de> { use serde::Deserializer; self.de.deserialize_map(visitor) } } cbor4ii-1.2.1/src/serde/error.rs000064400000000000000000000041151046102023000145510ustar 00000000000000use core::fmt; use crate::core::{ enc, dec }; #[derive(Debug)] pub enum DecodeError { Core(dec::Error), Custom(crate::alloc::boxed::Box) } impl From> for DecodeError { #[inline] #[cold] fn from(err: dec::Error) -> DecodeError { DecodeError::Core(err) } } impl From for DecodeError { #[inline] #[cold] fn from(err: E) -> DecodeError { DecodeError::Core(dec::Error::Read(err)) } } #[cfg(feature = "serde1")] impl serde::de::Error for DecodeError { fn custom(msg: T) -> Self { use crate::alloc::string::ToString; DecodeError::Custom(msg.to_string().into_boxed_str()) } } impl fmt::Display for DecodeError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Debug::fmt(self, f) } } #[cfg(feature = "serde1")] impl serde::ser::StdError for DecodeError {} #[derive(Debug)] pub enum EncodeError { Core(enc::Error), Custom(crate::alloc::boxed::Box) } impl From> for EncodeError { #[inline] #[cold] fn from(err: enc::Error) -> EncodeError { EncodeError::Core(err) } } impl From for EncodeError { #[inline] #[cold] fn from(err: E) -> EncodeError { EncodeError::Core(enc::Error::Write(err)) } } #[cfg(feature = "serde1")] impl serde::ser::Error for EncodeError { fn custom(msg: T) -> Self { use crate::alloc::string::ToString; EncodeError::Custom(msg.to_string().into_boxed_str()) } } impl fmt::Display for EncodeError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Debug::fmt(self, f) } } impl core::error::Error for EncodeError { fn source(&self) -> Option<&(dyn core::error::Error + 'static)> { match self { EncodeError::Core(err) => Some(err), _ => None } } } cbor4ii-1.2.1/src/serde/ser.rs000064400000000000000000000324311046102023000142130ustar 00000000000000use core::fmt; use serde::Serialize; use crate::core::types; use crate::core::enc::{ self, Encode }; use crate::serde::error::EncodeError; pub struct Serializer { writer: W } impl Serializer { pub fn new(writer: W) -> Serializer { Serializer { writer } } pub fn into_inner(self) -> W { self.writer } } impl<'a, W: enc::Write> serde::Serializer for &'a mut Serializer { type Ok = (); type Error = EncodeError; type SerializeSeq = Collect<'a, W>; type SerializeTuple = BoundedCollect<'a, W>; type SerializeTupleStruct = BoundedCollect<'a, W>; type SerializeTupleVariant = BoundedCollect<'a, W>; type SerializeMap = Collect<'a, W>; type SerializeStruct = BoundedCollect<'a, W>; type SerializeStructVariant = BoundedCollect<'a, W>; #[inline] fn serialize_bool(self, v: bool) -> Result { v.encode(&mut self.writer)?; Ok(()) } #[inline] fn serialize_i8(self, v: i8) -> Result { v.encode(&mut self.writer)?; Ok(()) } #[inline] fn serialize_i16(self, v: i16) -> Result { v.encode(&mut self.writer)?; Ok(()) } #[inline] fn serialize_i32(self, v: i32) -> Result { v.encode(&mut self.writer)?; Ok(()) } #[inline] fn serialize_i64(self, v: i64) -> Result { v.encode(&mut self.writer)?; Ok(()) } #[inline] fn serialize_u8(self, v: u8) -> Result { v.encode(&mut self.writer)?; Ok(()) } #[inline] fn serialize_u16(self, v: u16) -> Result { v.encode(&mut self.writer)?; Ok(()) } #[inline] fn serialize_u32(self, v: u32) -> Result { v.encode(&mut self.writer)?; Ok(()) } #[inline] fn serialize_u64(self, v: u64) -> Result { v.encode(&mut self.writer)?; Ok(()) } #[inline] fn serialize_f32(self, v: f32) -> Result { v.encode(&mut self.writer)?; Ok(()) } #[inline] fn serialize_f64(self, v: f64) -> Result { v.encode(&mut self.writer)?; Ok(()) } #[inline] fn serialize_char(self, v: char) -> Result { let mut buf = [0; 4]; self.serialize_str(v.encode_utf8(&mut buf)) } #[inline] fn serialize_str(self, v: &str) -> Result { v.encode(&mut self.writer)?; Ok(()) } #[inline] fn serialize_bytes(self, v: &[u8]) -> Result { types::Bytes(v).encode(&mut self.writer)?; Ok(()) } #[inline] fn serialize_none(self) -> Result { types::Null.encode(&mut self.writer)?; Ok(()) } #[inline] fn serialize_some(self, value: &T) -> Result { value.serialize(self) } #[inline] fn serialize_unit(self) -> Result { types::Array::bounded(0, &mut self.writer)?; Ok(()) } #[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 { self.serialize_str(variant) } #[inline] fn serialize_newtype_struct( self, _name: &'static str, value: &T ) -> Result { value.serialize(self) } #[inline] fn serialize_newtype_variant( self, _name: &'static str, _variant_index: u32, variant: &'static str, value: &T ) -> Result { types::Map::bounded(1, &mut self.writer)?; variant.encode(&mut self.writer)?; value.serialize(self) } #[inline] fn serialize_seq(self, len: Option) -> Result { if let Some(len) = len { types::Array::bounded(len, &mut self.writer)?; } else { types::Array::unbounded(&mut self.writer)?; } Ok(Collect { bounded: len.is_some(), ser: self }) } #[inline] fn serialize_tuple(self, len: usize) -> Result { types::Array::bounded(len, &mut self.writer)?; Ok(BoundedCollect { ser: self }) } #[inline] fn serialize_tuple_struct(self, _name: &'static str, len: usize) -> Result { self.serialize_tuple(len) } #[inline] fn serialize_tuple_variant( self, _name: &'static str, _variant_index: u32, variant: &'static str, len: usize ) -> Result { types::Map::bounded(1, &mut self.writer)?; variant.encode(&mut self.writer)?; types::Array::bounded(len, &mut self.writer)?; Ok(BoundedCollect { ser: self }) } #[inline] fn serialize_map(self, len: Option) -> Result { if let Some(len) = len { types::Map::bounded(len, &mut self.writer)?; } else { types::Map::unbounded(&mut self.writer)?; } Ok(Collect { bounded: len.is_some(), ser: self }) } #[inline] fn serialize_struct(self, _name: &'static str, len: usize) -> Result { types::Map::bounded(len, &mut self.writer)?; Ok(BoundedCollect { ser: self }) } #[inline] fn serialize_struct_variant( self, _name: &'static str, _variant_index: u32, variant: &'static str, len: usize ) -> Result { types::Map::bounded(1, &mut self.writer)?; variant.encode(&mut self.writer)?; types::Map::bounded(len, &mut self.writer)?; Ok(BoundedCollect { ser: self }) } #[inline] fn serialize_i128(self, v: i128) -> Result { v.encode(&mut self.writer)?; Ok(()) } #[inline] fn serialize_u128(self, v: u128) -> Result { v.encode(&mut self.writer)?; Ok(()) } #[inline] fn collect_str(self, value: &T) -> Result where T: fmt::Display + ?Sized, { collect_str(&mut self.writer, &value) } #[inline] fn is_human_readable(&self) -> bool { false } } pub struct Collect<'a, W> { bounded: bool, ser: &'a mut Serializer } pub struct BoundedCollect<'a, W> { ser: &'a mut Serializer } impl serde::ser::SerializeSeq for Collect<'_, W> { type Ok = (); type Error = EncodeError; #[inline] fn serialize_element(&mut self, value: &T) -> Result<(), Self::Error> { value.serialize(&mut *self.ser) } #[inline] fn end(self) -> Result { if !self.bounded { types::Array::end(&mut self.ser.writer)?; } Ok(()) } } impl serde::ser::SerializeTuple for BoundedCollect<'_, W> { type Ok = (); type Error = EncodeError; #[inline] fn serialize_element(&mut self, value: &T) -> Result<(), Self::Error> { value.serialize(&mut *self.ser) } #[inline] fn end(self) -> Result { Ok(()) } } impl serde::ser::SerializeTupleStruct for BoundedCollect<'_, W> { type Ok = (); type Error = EncodeError; #[inline] fn serialize_field(&mut self, value: &T) -> Result<(), Self::Error> { value.serialize(&mut *self.ser) } #[inline] fn end(self) -> Result { Ok(()) } } impl serde::ser::SerializeTupleVariant for BoundedCollect<'_, W> { type Ok = (); type Error = EncodeError; #[inline] fn serialize_field(&mut self, value: &T) -> Result<(), Self::Error> { value.serialize(&mut *self.ser) } #[inline] fn end(self) -> Result { Ok(()) } } impl serde::ser::SerializeMap for Collect<'_, W> { type Ok = (); type Error = EncodeError; #[inline] fn serialize_key(&mut self, key: &T) -> Result<(), Self::Error> { key.serialize(&mut *self.ser) } #[inline] fn serialize_value(&mut self, value: &T) -> Result<(), Self::Error> { value.serialize(&mut *self.ser) } #[inline] fn end(self) -> Result { if !self.bounded { types::Map::end(&mut self.ser.writer)?; } Ok(()) } } impl serde::ser::SerializeStruct for BoundedCollect<'_, W> { type Ok = (); type Error = EncodeError; #[inline] fn serialize_field(&mut self, key: &'static str, value: &T) -> Result<(), Self::Error> { key.serialize(&mut *self.ser)?; value.serialize(&mut *self.ser) } #[inline] fn end(self) -> Result { Ok(()) } } impl serde::ser::SerializeStructVariant for BoundedCollect<'_, W> { type Ok = (); type Error = EncodeError; #[inline] fn serialize_field(&mut self, key: &'static str, value: &T) -> Result<(), Self::Error> { key.serialize(&mut *self.ser)?; value.serialize(&mut *self.ser) } #[inline] fn end(self) -> Result { Ok(()) } } fn collect_str(writer: &mut W, value: &dyn fmt::Display) -> Result<(), EncodeError> { use core::fmt::Write; use serde::ser::Error; let mut writer = FmtWriter::new(writer); if let Err(err) = write!(&mut writer, "{}", value) { if !writer.is_error() { return Err(EncodeError::custom(err)); } } writer.flush()?; Ok(()) } struct FmtWriter<'a, W: enc::Write> { inner: &'a mut W, buf: [u8; 255], pos: u8, state: State>, } enum State { Short, Segment, Error(E) } impl fmt::Write for FmtWriter<'_, W> { #[inline] fn write_str(&mut self, input: &str) -> fmt::Result { macro_rules! try_ { ( $e:expr ) => { match $e { Ok(v) => v, Err(err) => { self.state = State::Error(err); return Err(fmt::Error); } } } } debug_assert!(usize::from(u8::MAX) >= self.buf.len()); match self.state { State::Short => if usize::from(self.pos) + input.len() > self.buf.len() { self.state = State::Segment; try_!(types::UncheckedStr::unbounded(self.inner)); }, State::Segment => (), State::Error(_) => return Err(fmt::Error) } loop { if let Some(buf) = self.buf.get_mut(self.pos.into()..) .and_then(|buf| buf.get_mut(..input.len())) { use core::convert::TryInto; buf.copy_from_slice(input.as_bytes()); let len: u8 = input.len().try_into().unwrap(); // checked by if self.pos += len; break } if self.pos > 0 { try_!(types::UncheckedStr(&self.buf[..self.pos.into()]).encode(self.inner)); self.pos = 0; } if input.len() > self.buf.len() { try_!(input.encode(self.inner)); break } } Ok(()) } } impl FmtWriter<'_, W> { #[inline] fn new(inner: &mut W) -> FmtWriter<'_, W> { FmtWriter { inner, buf: [0; 255], pos: 0, state: State::Short, } } #[inline] fn is_error(&self) -> bool { matches!(self.state, State::Error(_)) } #[inline] fn flush(self) -> Result<(), enc::Error> { match self.state { State::Short | State::Segment => { if matches!(self.state, State::Short) || self.pos != 0 { types::UncheckedStr(&self.buf[..self.pos.into()]).encode(self.inner)?; } if matches!(self.state, State::Segment) { types::UncheckedStr::end(self.inner)?; } Ok(()) }, State::Error(err) => Err(err), } } } cbor4ii-1.2.1/src/serde.rs000064400000000000000000000047361046102023000134310ustar 00000000000000//! serde support mod error; mod ser; mod de; #[cfg(feature = "use_std")] mod io_writer { use std::io; use serde::Serialize; use crate::core::utils::IoWriter; use crate::serde::error::EncodeError; use crate::serde::ser; /// Serializes a value to a writer. pub fn to_writer(writer: W, value: &T) -> Result<(), EncodeError> where W: io::Write, T: Serialize { let writer = IoWriter::new(writer); let mut writer = ser::Serializer::new(writer); value.serialize(&mut writer) } } mod buf_writer { use crate::alloc::vec::Vec; use crate::alloc::collections::TryReserveError; use serde::Serialize; use crate::core::utils::BufWriter; use crate::serde::error::EncodeError; use crate::serde::ser; /// Serializes a value to a writer. pub fn to_vec(buf: Vec, value: &T) -> Result, EncodeError> where T: Serialize { let writer = BufWriter::new(buf); let mut writer = ser::Serializer::new(writer); value.serialize(&mut writer)?; Ok(writer.into_inner().into_inner()) } } mod slice_reader { use core::convert::Infallible; use crate::core::utils::SliceReader; use crate::serde::de; use crate::serde::error::DecodeError; /// Decodes a value from a bytes. pub fn from_slice<'a, T>(buf: &'a [u8]) -> Result> where T: serde::Deserialize<'a>, { let reader = SliceReader::new(buf); let mut deserializer = de::Deserializer::new(reader); serde::Deserialize::deserialize(&mut deserializer) } } #[cfg(feature = "use_std")] mod io_buf_reader { use std::io::{ self, BufRead }; use crate::core::utils::IoReader; use crate::serde::de; use crate::serde::error::DecodeError; /// Decodes a value from a reader. pub fn from_reader(reader: R) -> Result> where T: serde::de::DeserializeOwned, R: BufRead { let reader = IoReader::new(reader); let mut deserializer = de::Deserializer::new(reader); serde::Deserialize::deserialize(&mut deserializer) } } #[cfg(feature = "use_std")] pub use io_writer::to_writer; #[cfg(feature = "use_std")] pub use io_buf_reader::from_reader; pub use buf_writer::to_vec; pub use slice_reader::from_slice; pub use error::{ EncodeError, DecodeError }; pub use ser::Serializer; pub use de::Deserializer; cbor4ii-1.2.1/src/util.rs000064400000000000000000000007351046102023000132770ustar 00000000000000use core::ops::{ Deref, DerefMut }; pub struct ScopeGuard<'a, T>(pub &'a mut T, pub fn(&mut T)); impl Deref for ScopeGuard<'_, T> { type Target = T; #[inline] fn deref(&self) -> &Self::Target { self.0 } } impl DerefMut for ScopeGuard<'_, T> { #[inline] fn deref_mut(&mut self) -> &mut Self::Target { self.0 } } impl Drop for ScopeGuard<'_, T> { #[inline] fn drop(&mut self) { (self.1)(self.0); } } cbor4ii-1.2.1/tests/decode.rs000064400000000000000000000401651046102023000141210ustar 00000000000000#![cfg(feature = "use_std")] use std::convert::Infallible; use anyhow::Context; use cbor4ii::core::Value; use cbor4ii::core::enc::{ self, Encode }; use cbor4ii::core::dec::{ self, Decode }; use cbor4ii::core::types; use cbor4ii::core::utils::{ BufWriter, SliceReader }; #[test] fn test_decode_value() { macro_rules! test { ( @ $input:expr ) => { let buf = data_encoding::BASE64.decode($input.as_bytes()).unwrap(); let mut reader = SliceReader::new(buf.as_slice()); let _ = Value::decode(&mut reader); }; ( $( $input:expr );* $( ; )? ) => { $( test!(@ $input ); )* } } test!{ "ig=="; "eoY="; "v6a/v6a/v7+/pq6urq6urq6urq6urq6urq6urq6urq6urq6urqaurq6urq6urq4krq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6uv7+mv7+/v6aurq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urr+/pr+/v7+mrq6urq6urq6urq6urq6urq6urq6urq6upq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6uQK6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urqSurq6urq6urq6urq6urq6urq6urq6urq6urq6uv7+uJa6urq6urq6urq6urq6urq6urq6urq6urq6urq6uv7+uJa6urq6urq6urq6urq6urq6uQK6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq5Arq6urq6urq6urq6urq6urq6urq6urq6urq5Arq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6upK6urq6urq6urq6urq6urq6urq6urq6urq6urq6/v64lrq6urq6urq6urq6urq6urq6urq6urq6urq6urq6/v64lrq6urq6urq6urq6urq6urq5Arq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urkCurq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6krq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6upq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6upK6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urqaurq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq5Arq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6upK6urq6urq6urq6urq6urq6urq6urq6urq6urq6mrq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq5Arq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6upK6urq6urq6urq6urq6urq6urq6urq6urq6urq6/v64lrq6urq6urq6urq6urq6urq6urq6urq6urq6urq6/v64lrq6urq6urq6urq6urq6urq5Arq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urkCurq6urq6urq6urq6urq6urq6urq6urq6urkCurq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6krq6urq6urq6urq6urq6urq6urq6urq6urq6urr+/riWurq6urq6urq6urq6urq6urq6urq6urq6urq6urr+/riWurq6urq6urq6urq6urq6urkCurq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6uQK6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urqSurq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6mrq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6krq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6upq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urkCurq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6krq6urq6urq6urq6urq6urq6urq6urq6urqSurq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6upK6urq6urq6urq6urq6urq6urq6urq6urq6urq6/v64lrq6urq6urq6urq6urq6urq6urq6urq6urq6urq6/v64lrq6urq6urq6urq6urq6urq5Arq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urkCurq6urq6urq6urq6urq6urq6urq6urq6urkCurq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6krq6urq6urq6urq6urq6urq6urq6urq6urq6urr+/riWurq6urq6urq6urq6urg0AAAAAAAAArq6urq6urr+/riWurq6urq6urq6urq6urq6urkCurq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6uQK6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urqSurq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6mrq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6krq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6upq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urkCurq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6krq6urq6urq6urq6urq6urq6urq6urq6urq6urr+/riWurq6urq6urq6urq6urq6urkCurq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6krq6urq6urq6vrq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urrCwsLCwsLCwsLCwsLCwsLCwsLCwrq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6upq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urkCurq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6/v64lrq6urq6urq6urq6urq6urq5Arq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6upK6urq6urq6ur66urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6wsLCwsLCwsLCwsLCwsLCwsLCwsK6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urqaurq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq5Arq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6upK6urq6urq6urq6urq6urq6urq6urq6urq6urq6/v64lrq6urq6urq6urq6urq6urq5Arq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6upK6urq6urq6ur66urq6urq6urq6urq6urq6urq6/v64lrq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6wsLCwsLCwsLCwsLCwsLCwsLCwsK6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urrCwsLCwsLCwsLCwsLCwsLCwsLCwsIQEAAAAgQCwsLCwsLCwsLCwsK6urq6urq6u"; "v/b29vYBAAAAAAAABPb29gn29vb29pkAEfb29vb29vb2f3///39//3//f/9//3//f/9//3//f///f/9//3//f/8ICAgICAgI9vf39wgICAgICAgI+EAKCgr39wv1CAgICCgILggItAgICAgICAgICAgAAACgAAgICAAICAgICAgI9vf39wgICAgICAgI+EAKCgr39wv1CAgICCgILggItAgICAgICAgICAgAAACgAAgICA==" } } #[test] fn test_decode_buf_segment() -> anyhow::Result<()> { let mut writer = BufWriter::new(Vec::new()); types::UncheckedStr::unbounded(&mut writer)?; "test".encode(&mut writer)?; "test2".encode(&mut writer)?; "test3".encode(&mut writer)?; types::UncheckedStr::end(&mut writer)?; let mut reader = SliceReader::new(writer.buffer()); let output = String::decode(&mut reader)?; assert_eq!("testtest2test3", output); Ok(()) } #[test] fn test_decode_bad_reader_buf() -> anyhow::Result<()> { let mut writer = BufWriter::new(Vec::new()); "test".encode(&mut writer)?; struct LongReader<'a>(&'a [u8]); impl<'de> dec::Read<'de> for LongReader<'de> { type Error = Infallible; #[inline] fn fill<'b>(&'b mut self, _want: usize) -> Result, Self::Error> { Ok(dec::Reference::Short(&self.0)) } #[inline] fn advance(&mut self, n: usize) { let len = core::cmp::min(self.0.len(), n); self.0 = &self.0[len..]; } } let mut buf = writer.into_inner(); buf.resize(1024, 0); let mut reader = LongReader(&buf); let output = String::decode(&mut reader)?; assert_eq!("test", output); Ok(()) } #[test] fn test_decode_array_map() -> anyhow::Result<()> { // array bounded let mut writer = BufWriter::new(Vec::new()); (&[0u32, 1, 2, 3, 4, 5][..]).encode(&mut writer)?; let mut reader = SliceReader::new(writer.buffer()); let len = types::Array::len(&mut reader)?; let len = len.context("expect len")?; for i in 0..len { let n = u64::decode(&mut reader)?; assert_eq!(n, i as u64); } // map unbounded let mut writer = BufWriter::new(Vec::new()); types::Map::unbounded(&mut writer)?; for i in 0u64..6 { i.encode(&mut writer)?; } types::Map::end(&mut writer)?; let mut reader = SliceReader::new(writer.buffer()); let len = types::Map::len(&mut reader)?; assert_eq!(len, None); let mut count = 0u64; while !dec::is_break(&mut reader)? { let n = u64::decode(&mut reader)?; assert_eq!(n, count); count += 1; } Ok(()) } #[test] fn test_value_i128() -> anyhow::Result<()> { #[inline] fn strip_zero(input: &[u8]) -> &[u8] { let pos = input.iter() .position(|&n| n != 0x0) .unwrap_or(input.len()); &input[pos..] } let n = u64::MAX as i128 + 99; let mut writer = BufWriter::new(Vec::new()); Value::Integer(n).encode(&mut writer)?; let mut reader = SliceReader::new(writer.buffer()); let value = Value::decode(&mut reader)?; let int_bytes = n.to_be_bytes(); let int_bytes = strip_zero(&int_bytes); assert_eq!(value, Value::Tag(2, Box::new(Value::Bytes(int_bytes.into())))); Ok(()) } #[test] fn test_mut_ref_write_read() -> anyhow::Result<()> { fn test_write_str(mut writer: W, input: &str) { input.encode(&mut writer).unwrap() } fn test_read_str<'de, R: dec::Read<'de>>(mut reader: R) -> &'de str { <&str>::decode(&mut reader).unwrap() } let input = "123"; let mut writer = BufWriter::new(Vec::new()); test_write_str(&mut writer, input); let mut reader = SliceReader::new(writer.buffer()); let output = test_read_str(&mut reader); assert_eq!(input, output); Ok(()) } #[test] fn test_regression_ignore_tag() { let tag = Value::Tag(u64::MAX - 1, Box::new(Value::Text("hello world".into()))); let mut buf = BufWriter::new(Vec::new()); tag.encode(&mut buf).unwrap(); { let mut reader = SliceReader::new(buf.buffer()); let tag2 = Value::decode(&mut reader).unwrap(); assert_eq!(tag, tag2); } { let mut reader = SliceReader::new(buf.buffer()); let _ignored = dec::IgnoredAny::decode(&mut reader).unwrap(); } } #[test] fn test_regression_min_i64() { let mut buf = BufWriter::new(Vec::new()); i64::MIN.encode(&mut buf).unwrap(); let mut reader = SliceReader::new(buf.buffer()); let min_i64 = i64::decode(&mut reader).unwrap(); assert_eq!(min_i64, i64::MIN); } #[test] fn test_regression_min_i128() { let mut buf = BufWriter::new(Vec::new()); i128::MIN.encode(&mut buf).unwrap(); let mut reader = SliceReader::new(buf.buffer()); let min_i128 = i128::decode(&mut reader).unwrap(); assert_eq!(min_i128, i128::MIN); } #[test] fn test_regression_max_neg_64_as_i128() { let mut buf = BufWriter::new(Vec::new()); let max_neg_64 = -i128::from(u64::MAX) - 1; max_neg_64.encode(&mut buf).unwrap(); assert_eq!(buf.buffer(), [0x3b, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff]); let mut reader = SliceReader::new(buf.buffer()); let decoded = i128::decode(&mut reader).unwrap(); assert_eq!(decoded, -18446744073709551616); } #[test] fn test_max_neg_32_as_i64() { let mut buf = BufWriter::new(Vec::new()); let max_neg_32 = -i64::from(u32::MAX) - 1; max_neg_32.encode(&mut buf).unwrap(); assert_eq!(buf.buffer(), [0x3a, 0xff, 0xff, 0xff, 0xff]); let mut reader = SliceReader::new(buf.buffer()); let decoded = i64::decode(&mut reader).unwrap(); assert_eq!(decoded, -4294967296); } #[test] fn test_max_neg_16_as_i32() { let mut buf = BufWriter::new(Vec::new()); let max_neg_16 = -i32::from(u16::MAX) - 1; max_neg_16.encode(&mut buf).unwrap(); assert_eq!(buf.buffer(), [0x39, 0xff, 0xff]); let mut reader = SliceReader::new(buf.buffer()); let decoded = i32::decode(&mut reader).unwrap(); assert_eq!(decoded, -65536); } #[test] fn test_max_neg_8_as_i16() { let mut buf = BufWriter::new(Vec::new()); let max_neg_8 = -i16::from(u8::MAX) - 1; max_neg_8.encode(&mut buf).unwrap(); assert_eq!(buf.buffer(), [0x38, 0xff]); let mut reader = SliceReader::new(buf.buffer()); let decoded = i16::decode(&mut reader).unwrap(); assert_eq!(decoded, -256); } #[test] fn test_tag() { let mut reader_tag_len1 = SliceReader::new(&[0xd8, 0x2a]); let tag_len1 = types::Tag::tag(&mut reader_tag_len1).unwrap(); assert_eq!(tag_len1, 42); let mut reader_tag_len2 = SliceReader::new(&[0xd9, 0x00, 0x2a]); let tag_len2 = types::Tag::tag(&mut reader_tag_len2).unwrap(); assert_eq!(tag_len2, 42); let mut reader_tag_len4 = SliceReader::new(&[0xda, 0x00, 0x00, 0x00, 0x2a]); let tag_len4 = types::Tag::tag(&mut reader_tag_len4).unwrap(); assert_eq!(tag_len4, 42); let mut reader_tag_len8 = SliceReader::new( &[0xdb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2a]); let tag_len8 = types::Tag::tag(&mut reader_tag_len8).unwrap(); assert_eq!(tag_len8, 42); } #[test] fn test_ignored_any_eof_loop() { let mut buf = BufWriter::new(Vec::new()); "aaa".encode(&mut buf).unwrap(); // bad input let mut buf = buf.into_inner(); buf.pop(); let mut reader = SliceReader::new(&buf); let ret = dec::IgnoredAny::decode(&mut reader); match ret { Err(dec::Error::Eof { name, .. }) => { assert_eq!(name, &"ignored-any"); }, _ => panic!() } } #[test] fn test_cov_case() { let mut buf = BufWriter::new(Vec::new()); // u16 u16::MAX.encode(&mut buf).unwrap(); let v = u16::decode(&mut SliceReader::new(buf.buffer())).unwrap(); assert_eq!(v, u16::MAX); // i128 buf.clear(); i128::MAX.encode(&mut buf).unwrap(); let v = i128::decode(&mut SliceReader::new(buf.buffer())).unwrap(); assert_eq!(v, i128::MAX); // bytes buf.clear(); types::Bytes("123".as_bytes()).encode(&mut buf).unwrap(); let v = >::decode(&mut SliceReader::new(buf.buffer())).unwrap(); assert_eq!(v.0, b"123"); // unchecked str buf.clear(); types::UncheckedStr(&[0xff][..]).encode(&mut buf).unwrap(); let v = >::decode(&mut SliceReader::new(buf.buffer())).unwrap(); assert_eq!(v.0, &[0xff]); // unbounded + bool + ignore buf.clear(); >::unbounded(&mut buf).unwrap(); true.encode(&mut buf).unwrap(); false.encode(&mut buf).unwrap(); >::end(&mut buf).unwrap(); let v = >::decode(&mut SliceReader::new(buf.buffer())).unwrap(); assert_eq!(v, vec![true, false]); let _ignore = dec::IgnoredAny::decode(&mut SliceReader::new(buf.buffer())).unwrap(); // option + f32 buf.clear(); f32::MAX.encode(&mut buf).unwrap(); let v = >::decode(&mut SliceReader::new(buf.buffer())).unwrap(); assert_eq!(v, Some(f32::MAX)); buf.clear(); types::Null.encode(&mut buf).unwrap(); let v = >::decode(&mut SliceReader::new(buf.buffer())).unwrap(); assert_eq!(v, None); buf.clear(); types::Undefined.encode(&mut buf).unwrap(); let v = >::decode(&mut SliceReader::new(buf.buffer())).unwrap(); assert_eq!(v, None); // simple buf.clear(); types::Simple(21).encode(&mut buf).unwrap(); let v = types::Simple::decode(&mut SliceReader::new(buf.buffer())).unwrap(); assert_eq!(v.0, 21); let v = bool::decode(&mut SliceReader::new(buf.buffer())).unwrap(); assert_eq!(v, true); } #[test] fn test_string_from_zero() { let buf = &[0]; let v = ::decode(&mut SliceReader::new(buf)); match v.as_ref().err() { Some(cbor4ii::core::error::DecodeError::Mismatch { name, found }) => { assert_eq!(**name, "str"); assert_eq!(*found, 0); }, _ => panic!("{:?}", v) } } #[test] fn test_nothing() { let mut writer = BufWriter::new(Vec::new()); types::Nothing.encode(&mut writer).unwrap(); let buf = writer.into_inner(); assert!(buf.is_empty()); let mut reader = SliceReader::new(&buf); ::decode(&mut reader).unwrap(); } #[test] fn test_string_box_vec_maybe() { // work { let obj = Some(Box::new(vec![ "1".to_owned(), "2".to_owned(), ])); let mut writer = BufWriter::new(Vec::new()); types::Maybe(&obj).encode(&mut writer).unwrap(); let buf = writer.into_inner(); let mut reader = SliceReader::new(&buf); let obj2 = >>>>::decode(&mut reader).unwrap(); assert_eq!(obj, obj2.0); } // none { let obj: Option = None; let mut writer = BufWriter::new(Vec::new()); types::Maybe(&obj).encode(&mut writer).unwrap(); let buf = writer.into_inner(); let mut reader = SliceReader::new(&buf); let obj2 = >>>>::decode(&mut reader).unwrap(); assert!(obj2.0.is_none()); } // bad slice { let obj: Vec = vec!["1".into(), "2".into(), "3".into()]; let mut writer = BufWriter::new(Vec::new()); obj.encode(&mut writer).unwrap(); let buf = writer.into_inner(); let mut reader = SliceReader::new(&buf); match >>::decode(&mut reader) { Ok(_) => panic!(), Err(dec::Error::RequireLength { name, .. }) => { assert_eq!(name, &"maybe"); }, Err(_) => panic!() } } } cbor4ii-1.2.1/tests/serde.rs000064400000000000000000000324501046102023000137760ustar 00000000000000#![cfg(all(feature = "serde1", feature = "use_std"))] use std::{ io, fmt }; use std::collections::BTreeMap; use serde::{ Serialize, Deserialize }; use cbor4ii::core::dec; use cbor4ii::serde::{ to_vec, from_slice }; #[track_caller] fn de<'a,T>(bytes: &'a [u8], _value: &T) -> T where T: Deserialize<'a> { match from_slice(bytes) { Ok(t) => t, Err(err) => panic!("{:?}: {:?}", err, bytes) } } macro_rules! assert_test { ( $value:expr ) => {{ let buf = to_vec(Vec::new(), &$value).unwrap(); let value = de(&buf, &$value); assert_eq!(value, $value, "{:?}", buf); }} } #[test] fn test_serialize_compat() { let value = vec![ Some(0x99u32), None, Some(0x33u32) ]; assert_test!(value); #[derive(Serialize, Deserialize, Eq, PartialEq, Debug)] enum Enum { Unit, NewType(i32), Tuple(String, bool), Struct { x: i32, y: i32 }, } assert_test!(Enum::Unit); assert_test!(Enum::NewType(0x999)); assert_test!(Enum::Tuple("123".into(), false)); assert_test!(Enum::Struct { x: 0x99, y: -0x99 }); #[derive(Serialize, Deserialize, Eq, PartialEq, Debug)] #[serde(untagged)] enum UntaggedEnum { Bar(i32), Foo(Box) } #[derive(Serialize, Deserialize, Eq, PartialEq, Debug)] struct NewType(T); #[derive(Serialize, Deserialize, Eq, PartialEq, Debug)] struct Test<'a> { name: char, test: TestMap, #[serde(with = "serde_bytes")] bytes: Vec, #[serde(with = "serde_bytes")] bytes2: Vec, map: BTreeMap, untag: (UntaggedEnum, UntaggedEnum), new: NewType, some: Option<()>, str_ref: &'a str } #[derive(Serialize, Deserialize, Eq, PartialEq, Debug)] struct TestMap(BTreeMap); #[derive(Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd, Debug)] struct TestObj(String); #[derive(Serialize, Deserialize, Eq, PartialEq, Debug)] struct BoxSet(Vec); let test = Test { name: 'G', test: TestMap({ let mut map = BTreeMap::new(); map.insert(TestObj("obj".into()), BoxSet(Vec::new())); map.insert(TestObj("obj2".into()), BoxSet(vec![ TestObj("obj3".into()), TestObj("obj4".into()), TestObj(String::new()) ])); map }), bytes: Vec::from("bbbbbbbbbbb".as_bytes()), bytes2: Vec::new(), map: { let mut map = BTreeMap::new(); map.insert("key0".into(), Enum::Unit); map.insert("key1".into(), Enum::Tuple("value".into(), true)); map.insert("key2".into(), Enum::Struct { x: -1, y: 0x123 }); map.insert("key3".into(), Enum::NewType(-999)); map }, untag: (UntaggedEnum::Foo("a".into()), UntaggedEnum::Bar(0)), new: NewType(UntaggedEnum::Foo("???".into())), some: Some(()), str_ref: "hello world" }; assert_test!(test); assert_test!(Some(10u32)); assert_test!(Some(vec![(10u128, 99999i128)])); } #[test] fn test_serde_enum_flatten() { #[derive(Debug, Copy, Clone, Eq, PartialEq, Deserialize, Serialize)] pub enum Platform { Amd64, } #[derive(Debug, Eq, PartialEq, Deserialize, Serialize)] pub struct Package { #[serde(flatten)] pub flattened: Flattened, } #[derive(Debug, Eq, PartialEq, Deserialize, Serialize)] pub struct Flattened { pub platform: Platform } let pkg = Package { flattened: Flattened { platform: Platform::Amd64, }, }; let pkgs = vec![pkg]; assert_test!(pkgs); } #[test] fn test_serde_value() { use cbor4ii::core::Value; assert_test!(Value::Map(vec![( Value::Text("a".into()), Value::Bool(false) )])); assert_test!(Value::Integer(u64::MAX as i128 + 99)); } #[test] fn test_serde_cow() { use std::borrow::Cow; use std::convert::Infallible; struct SlowReader<'de>(&'de [u8]); impl<'de> dec::Read<'de> for SlowReader<'de> { type Error = Infallible; #[inline] fn fill<'b>(&'b mut self, _want: usize) -> Result, Self::Error> { Ok(if self.0.is_empty() { dec::Reference::Long(self.0) } else { dec::Reference::Long(&self.0[..1]) }) } #[inline] fn advance(&mut self, n: usize) { let len = core::cmp::min(self.0.len(), n); self.0 = &self.0[len..]; } } pub fn short_from_slice<'a, T>(buf: &'a [u8]) -> Result> where T: serde::Deserialize<'a>, { let reader = SlowReader(buf); let mut deserializer = cbor4ii::serde::Deserializer::new(reader); serde::Deserialize::deserialize(&mut deserializer) } #[derive(Serialize, Deserialize, Debug, PartialEq)] #[serde(untagged)] enum CowStr<'a> { #[serde(borrow)] Borrowed(&'a str), Owned(String) } impl CowStr<'_> { fn as_ref(&self) -> &str { match self { CowStr::Borrowed(v) => v, CowStr::Owned(v) => v.as_str() } } } assert_test!(Cow::Borrowed("123")); assert_test!(CowStr::Borrowed("321")); let input = "1234567"; let buf = to_vec(Vec::new(), &input).unwrap(); // real cow str ok let value: CowStr = from_slice(&buf).unwrap(); if let CowStr::Borrowed(s) = value { assert_eq!(input, s); } else { panic!() } // real cow str let value: CowStr = short_from_slice(&buf).unwrap(); assert_eq!(input, value.as_ref(), "{:?}", buf); // owned str let value: Cow = short_from_slice(&buf).unwrap(); assert_eq!(input, value.as_ref(), "{:?}", buf); // The current behavior, maybe serde will optimize it in future. // see https://github.com/serde-rs/serde/blob/ce0844b9ecc32377b5e4545d759d385a8c46bc6a/serde/src/de/impls.rs#L1721 // // assert!(matches!(value, Cow::Owned(_))); } #[test] fn test_serde_skip() { #[derive(Serialize, Deserialize, Eq, PartialEq, Debug)] struct SkipIt { a: Option, #[serde(skip_deserializing)] b: Option, c: Option } let skipit = SkipIt { a: Some(0x1), b: Some(0xff), c: Some(0xfb) }; let buf = to_vec(Vec::new(), &skipit).unwrap(); let value = de(&buf, &skipit); assert_eq!(value.a, skipit.a); assert_eq!(value.b, None); assert_eq!(value.c, skipit.c); #[derive(Serialize, Deserialize, Eq, PartialEq, Debug)] struct Full { a: u32, b: String, c: Vec, d: Option>, } #[derive(Serialize, Deserialize, Eq, PartialEq, Debug)] struct Missing1 { a: u32, b: String, c: Vec, } #[derive(Serialize, Deserialize, Eq, PartialEq, Debug)] struct Missing2 { a: u32, b: String, d: Option> } let input = Full { a: u32::MAX, b: String::from("short"), c: vec![0x1, 0x2, 0x3, u64::MAX], d: Some(Box::new(Full { a: 0x42, b: String::new(), c: vec![u32::MAX.into()], d: None })) }; let buf = to_vec(Vec::new(), &input).unwrap(); let value: Missing1 = from_slice(&buf).unwrap(); assert_eq!(value.a, input.a); assert_eq!(value.b, input.b); assert_eq!(value.c, input.c); let value: Missing2 = from_slice(&buf).unwrap(); assert_eq!(value.a, input.a); assert_eq!(value.b, input.b); assert_eq!(value.d, input.d); } #[test] fn test_serde_format_args() { struct Args(T); impl Serialize for Args { fn serialize(&self, serializer: S) -> Result where S: serde::Serializer, { serializer.collect_str(&format_args!("{:?}", self.0)) } } // short { let args = Args((1u32, 2u64, "123")); let buf = to_vec(Vec::new(), &args).unwrap(); let output: &str = from_slice(&buf).unwrap(); assert!(buf.len() <= 256); assert_eq!(output, format!("{:?}", args.0)) } // long { let args = Args(vec![ String::from("123"), std::iter::repeat('*').take(1024).collect(), std::iter::repeat('#').take(32).collect(), String::new(), String::from("321") ]); let buf = to_vec(Vec::new(), &args).unwrap(); let output: String = from_slice(&buf).unwrap(); assert!(buf.len() > 256); assert_eq!(output, format!("{:?}", args.0)) } // error { struct BadDebug; impl fmt::Debug for BadDebug { fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result { Err(fmt::Error) } } let args = Args(BadDebug); assert!(to_vec(Vec::new(), &args).is_err()); } // writer error { struct BadWriter; impl io::Write for BadWriter { fn write(&mut self, _buf: &[u8]) -> io::Result { Err(io::Error::new(io::ErrorKind::Other, "bad writer")) } fn flush(&mut self) -> io::Result<()> { Ok(()) } } let args = Args(1); let mut writer = BadWriter; let err = cbor4ii::serde::to_writer(&mut writer, &args).unwrap_err(); let err = match err { cbor4ii::serde::EncodeError::Core(cbor4ii::core::error::EncodeError::Write(err)) => err, _ => panic!() }; assert_eq!(err.kind(), io::ErrorKind::Other); } } #[test] fn test_serde_any_u128() { #[derive(Serialize, Deserialize, Debug, PartialEq)] #[serde(untagged)] enum AnyU128 { U128(u128), Str(String) } let input = AnyU128::U128(u64::MAX as u128 + 99); let buf = to_vec(Vec::new(), &input).unwrap(); // serde_cbor bug { let value: AnyU128 = serde_cbor::from_slice(&buf).unwrap(); assert_ne!(input, value); assert_eq!(value, AnyU128::Str("\u{1}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}b".into())) } // serde no support https://github.com/serde-rs/serde/issues/1682 assert!(from_slice::(&buf).is_err()) } #[test] fn test_serde_regression_issue4() { #[derive(Deserialize, Serialize, Debug, PartialEq)] enum Foo { A(String), } let foo = Foo::A(String::new()); let mut data = Vec::new(); cbor4ii::serde::to_writer(&mut data, &foo).unwrap(); let reader = std::io::BufReader::new(data.as_slice()); let foo2: Foo = cbor4ii::serde::from_reader(reader).unwrap(); assert_eq!(foo, foo2); } #[test] fn test_serde_regression_issue6() { let val = cbor4ii::core::Value::Null; let ret = cbor4ii::serde::to_vec(vec![], &val).unwrap(); assert_eq!(ret, vec![0xf6]); } #[test] fn test_serde_regression_any_f64() { #[derive(Serialize, Deserialize, Debug, PartialEq)] #[serde(untagged)] enum AnyF64 { F64(f64), Str(String) } let anyf64 = AnyF64::F64(99.); let buf = to_vec(Vec::new(), &anyf64).unwrap(); assert_eq!(anyf64, de(&buf, &anyf64)); } #[test] fn test_serde_ignore_any_simple() { #[derive(Serialize, Debug, PartialEq)] struct Bar { a: f64, b: f64, c: bool } #[derive(Deserialize, Debug, PartialEq)] struct Baz { b: f64, c: bool } let bar = Bar { a: 1., b: 2., c: true }; let bar_bytes = to_vec(Vec::new(), &bar).unwrap(); let baz: Baz = from_slice(&bar_bytes).unwrap(); assert_eq!(bar.b, baz.b); assert_eq!(bar.c, baz.c); } #[test] fn test_regression_min_i64() { let buf = to_vec(Vec::new(), &i64::MIN).unwrap(); let min_i64: i64 = from_slice(&buf).unwrap(); assert_eq!(min_i64, i64::MIN); } #[test] fn test_display_ser_len() { struct Test { long: char, short: char } impl fmt::Display for Test { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let s = (0..257).map(|_| self.long).collect::(); write!(f, "{}", s)?; for _ in 0..257 { write!(f, "{}", self.short)?; } Ok(()) } } impl Serialize for Test { fn serialize(&self, serializer: S) -> Result where S: serde::Serializer, { serializer.collect_str(self) } } let test = Test { long: 'l', short: 's' }; let buf = to_vec(Vec::new(), &test).unwrap(); assert!(dbg!(buf.len()) < 777); // <= 0.3.1 assert!(dbg!(buf.len()) <= 523); } #[cfg(feature = "half-f16")] #[test] fn test_regression_f16() { use cbor4ii::core::Value; use cbor4ii::core::enc::Encode; use cbor4ii::core::utils::BufWriter; let mut buf = BufWriter::new(Vec::new()); half::f16::from_f32(12.).encode(&mut buf).unwrap(); let value: Value = from_slice(buf.buffer()).unwrap(); match value { Value::Float(v) => assert_eq!(v, 12.), _ => panic!() } } cbor4ii-1.2.1/tests/serde_cbor.rs000064400000000000000000000140601046102023000150000ustar 00000000000000#![cfg(all(feature = "serde1", feature = "use_std"))] use std::iter::FromIterator; use std::collections::BTreeMap; use serde::{ Serialize, Deserialize }; use serde_cbor::value::Value; use cbor4ii::serde::to_vec; #[track_caller] fn de<'a,T>(bytes: &'a [u8], _value: &T) -> T where T: Deserialize<'a> { serde_cbor::from_slice(bytes).unwrap() } macro_rules! assert_test { ( $value:expr ) => {{ let buf = to_vec(Vec::new(), &$value).unwrap(); let value = de(&buf, &$value); assert_eq!(value, $value); }} } #[test] fn test_serialize_compat() { let value = vec![ Some(0x99u32), None, Some(0x33u32) ]; assert_test!(value); #[derive(Serialize, Deserialize, Eq, PartialEq, Debug)] enum Enum { Unit, NewType(i32), Tuple(String, bool), Struct { x: i32, y: i32 }, } assert_test!(Enum::Unit); assert_test!(Enum::NewType(0x999)); assert_test!(Enum::Tuple("123".into(), false)); assert_test!(Enum::Struct { x: 0x99, y: -0x99 }); #[derive(Serialize, Deserialize, Eq, PartialEq, Debug)] #[serde(untagged)] enum UntaggedEnum { Bar(i32), Foo(Box) } #[derive(Serialize, Deserialize, Eq, PartialEq, Debug)] struct NewType(T); #[derive(Serialize, Deserialize, Eq, PartialEq, Debug)] struct Test { name: char, test: TestMap, #[serde(with = "serde_bytes")] bytes: Vec, #[serde(with = "serde_bytes")] bytes2: Vec, map: BTreeMap, untag: (UntaggedEnum, UntaggedEnum), new: NewType } #[derive(Serialize, Deserialize, Eq, PartialEq, Debug)] struct TestMap(BTreeMap); #[derive(Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd, Debug)] struct TestObj(String); #[derive(Serialize, Deserialize, Eq, PartialEq, Debug)] struct BoxSet(Vec); let test = Test { name: 'G', test: TestMap({ let mut map = BTreeMap::new(); map.insert(TestObj("obj".into()), BoxSet(Vec::new())); map.insert(TestObj("obj2".into()), BoxSet(vec![ TestObj("obj3".into()), TestObj("obj4".into()), TestObj(String::new()) ])); map }), bytes: Vec::from("bbbbbbbbbbb".as_bytes()), bytes2: Vec::new(), map: { let mut map = BTreeMap::new(); map.insert("key0".into(), Enum::Unit); map.insert("key1".into(), Enum::Tuple("value".into(), true)); map.insert("key2".into(), Enum::Struct { x: -1, y: 0x123 }); map.insert("key3".into(), Enum::NewType(-999)); map }, untag: (UntaggedEnum::Foo("a".into()), UntaggedEnum::Bar(0)), new: NewType(UntaggedEnum::Foo("???".into())) }; assert_test!(test); } #[test] fn test_serialize_display() { use std::fmt; use serde::ser::Serializer; struct Display<'a>(&'a dyn fmt::Debug); impl fmt::Display for Display<'_> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Debug::fmt(self.0, f) } } impl Serialize for Display<'_> { fn serialize(&self, serializer: S) -> Result where S: Serializer { serializer.collect_str(self) } } #[derive(Serialize)] struct Test<'a> { print: Display<'a> } #[derive(Deserialize)] struct Test2 { print: String } { let a = (1u32, "test", 0x99u64); let test = Test { print: Display(&a) }; let buf = to_vec(Vec::new(), &test).unwrap(); let value: Test2 = serde_cbor::from_slice(&buf).unwrap(); assert_eq!(value.print, format!("{:?}", a)); } { let a = ([0x999i64; 100], vec!['#'; 100], &[..; 100][..]); let test = Test { print: Display(&a) }; let buf = to_vec(Vec::new(), &test).unwrap(); let value: Test2 = serde_cbor::from_slice(&buf).unwrap(); assert!(buf.len() > 300); assert_eq!(value.print, format!("{:?}", a)); } } // copy from https://github.com/pyfisch/cbor/blob/master/tests/value.rs #[derive(Serialize, Deserialize, Clone, Debug, PartialEq)] struct TupleStruct(String, i32, u64); #[derive(Serialize, Deserialize, Clone, Debug, PartialEq)] struct U8Struct(u8); #[derive(Serialize, Deserialize, Clone, Debug, PartialEq)] struct Struct<'a> { tuple_struct: TupleStruct, tuple: (String, f32, f64), map: BTreeMap, bytes: &'a [u8], array: Vec, u8_array: Vec, } #[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 u8_array = vec![U8Struct(0), U8Struct(1), U8Struct(1)]; let data = Struct { tuple_struct, tuple, map, bytes, array, u8_array, }; let value = serde_cbor::value::to_value(data.clone()).unwrap(); println!("{:?}", value); let data_ser = to_vec(Vec::new(), &value).unwrap(); let data_de_value: Value = serde_cbor::from_slice(&data_ser).unwrap(); fn as_object(value: &Value) -> &BTreeMap { 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); }