parity-scale-codec-3.6.4/.cargo_vcs_info.json0000644000000001360000000000100145160ustar { "git": { "sha1": "a9bc815f26c733f639792423c8bb9ea69d273c2c" }, "path_in_vcs": "" }parity-scale-codec-3.6.4/.editorconfig000064400000000000000000000003601046102023000157620ustar 00000000000000root = true [*] indent_style=tab indent_size=tab tab_width=4 end_of_line=lf charset=utf-8 trim_trailing_whitespace=true max_line_length=120 insert_final_newline=true [*.{yml,sh}] indent_style=space indent_size=2 tab_width=8 end_of_line=lf parity-scale-codec-3.6.4/.github/dependabot.yml000064400000000000000000000003101046102023000174700ustar 00000000000000version: 2 updates: - package-ecosystem: github-actions directory: '/' schedule: interval: daily - package-ecosystem: cargo directory: '/' schedule: interval: 'daily' parity-scale-codec-3.6.4/.github/workflows/release-bot.yml000064400000000000000000000012761046102023000216360ustar 00000000000000name: Pushes release updates to a pre-defined Matrix room on: release: types: - edited - prereleased - published jobs: ping_matrix: runs-on: ubuntu-latest steps: - name: send message uses: s3krit/matrix-message-action@v0.0.3 with: room_id: ${{ secrets.MATRIX_ROOM_ID }} access_token: ${{ secrets.MATRIX_ACCESS_TOKEN }} message: "**${{github.event.repository.full_name}}:** A release has been ${{github.event.action}}
Release version [${{github.event.release.tag_name}}](${{github.event.release.html_url}})

***Description:***
${{github.event.release.body}}
" server: "matrix.parity.io" parity-scale-codec-3.6.4/.gitignore000064400000000000000000000000671046102023000153010ustar 00000000000000target/ .DS* .*.swp .idea .vscode .DS_Store Cargo.lock parity-scale-codec-3.6.4/.gitlab-ci.yml000064400000000000000000000132711046102023000157460ustar 00000000000000# .gitlab-ci.yml # stages: - check - test - build variables: GIT_STRATEGY: fetch GIT_DEPTH: "100" CARGO_INCREMENTAL: 0 CI_IMAGE: "paritytech/ci-unified:bullseye-1.70.0-2023-05-23" default: cache: {} interruptible: true retry: max: 2 when: - runner_system_failure - unknown_failure - api_failure .docker-env: &docker-env image: $CI_IMAGE before_script: - cargo -vV - rustc -vV - rustup show - bash --version rules: - if: $CI_PIPELINE_SOURCE == "trigger" - if: $CI_PIPELINE_SOURCE == "web" - if: $CI_PIPELINE_SOURCE == "schedule" - if: $CI_COMMIT_REF_NAME == "master" - if: $CI_COMMIT_REF_NAME == "tags" - if: $CI_COMMIT_REF_NAME =~ /^[0-9]+$/ # PRs - if: $CI_COMMIT_REF_NAME =~ /^v[0-9]+\.[0-9]+.*$/ # i.e. v1.0, v2.1rc1 tags: - linux-docker-vm-c2 #### stage: check check-clippy: stage: check <<: *docker-env script: - rustup component add clippy --toolchain stable-x86_64-unknown-linux-gnu - time cargo +stable clippy --locked -- -Dwarnings - time cargo +stable clippy --locked -p parity-scale-codec-derive -- -Dwarnings - time cargo +stable clippy --locked --test clippy -- -Dwarnings check-rust-stable-no_derive_no_std: stage: check <<: *docker-env variables: RUSTFLAGS: "-Cdebug-assertions=y -Dwarnings" script: - time cargo +stable check --verbose --no-default-features --features bit-vec,bytes,generic-array check-rust-stable-no_std-chain-error: stage: check <<: *docker-env variables: RUSTFLAGS: "-Cdebug-assertions=y -Dwarnings" script: - time cargo +stable check --verbose --no-default-features --features chain-error check-rust-stable-no_derive: stage: check <<: *docker-env variables: RUSTFLAGS: "-Cdebug-assertions=y -Dwarnings" script: - time cargo +stable check --verbose --features bit-vec,bytes,generic-array check-rust-stable-only_mel: stage: check <<: *docker-env variables: RUSTFLAGS: "-Cdebug-assertions=y -Dwarnings" script: - time cargo +stable check --verbose --features max-encoded-len #### stage: test test-rust-stable: stage: test <<: *docker-env variables: RUSTFLAGS: "-Cdebug-assertions=y -Dwarnings" script: - time cargo +stable test --verbose --all --features bit-vec,bytes,generic-array,derive,max-encoded-len test-rust-stable-no_derive: stage: test <<: *docker-env variables: RUSTFLAGS: "-Cdebug-assertions=y -Dwarnings" script: - time cargo +stable test --verbose --features bit-vec,bytes,generic-array test-rust-stable-only_mel: stage: test <<: *docker-env variables: RUSTFLAGS: "-Cdebug-assertions=y -Dwarnings" script: - time cargo +stable test --verbose --features max-encoded-len test-rust-stable-only_mel-no_default_std: stage: test <<: *docker-env variables: RUSTFLAGS: "-Cdebug-assertions=y -Dwarnings" script: - time cargo +stable test --verbose --features max-encoded-len,std --no-default-features bench-rust-nightly: stage: test <<: *docker-env script: - time cargo +nightly bench --features bit-vec,bytes,generic-array,derive miri: stage: test <<: *docker-env variables: RUST_BACKTRACE: 1 MIRIFLAGS: "-Zmiri-disable-isolation" script: - time cargo +nightly miri test --features bit-vec,bytes,generic-array,arbitrary --release # check that build is no_std compatible # more info: https://github.com/paritytech/parity-scale-codec/pull/389 build-no-std: stage: test <<: *docker-env variables: RUST_BACKTRACE: 1 script: # this target doesn't support std envs; it should flag any unexpected uses of std - rustup target add thumbv6m-none-eabi - time cargo build --target thumbv6m-none-eabi --no-default-features build-no-atomic-ptrs: stage: test <<: *docker-env variables: RUST_BACKTRACE: 1 script: # this target doesn't have atomic ptrs. Some parts of alloc are not available there # we want to make sure that this crate still works on those targets - cargo +nightly check --target bpfel-unknown-none -Zbuild-std="core,alloc" --no-default-features --features generic-array,derive,max-encoded-len,chain-error #### stage: build build-linux-ubuntu-amd64: stage: build <<: *docker-env rules: - if: $CI_PIPELINE_SOURCE == "web" - if: $CI_PIPELINE_SOURCE == "schedule" - if: $CI_COMMIT_REF_NAME == "master" - if: $CI_COMMIT_REF_NAME == "tags" script: - cargo build --verbose --release --features bit-vec,bytes,generic-array,derive parity-scale-codec-3.6.4/CHANGELOG.md000064400000000000000000000200151046102023000151150ustar 00000000000000# Changelog All notable changes to this crate are documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this crate adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [3.6.4] - 2023-07-14 ### Added - Now `#[derive(Encode)]` implements the `size_hint()` method for structures and enumerations. This improves the performance of the `encode()` method by pre-allocating memory. ## [3.6.3] - 2023-07-03 ### Fixed - Provide full path to elements from `::core` in `Decode` derivation (caused compilation error when `no-implicit-prelude` was used). ## [3.6.2] - 2023-06-30 ### Fixed - Trying to deserialize a boxed newtype containing a big array won't overflow the stack anymore. ## [3.6.1] - 2023-06-19 ### Fixed - Deriving `Decode` will not trigger clippy warnings anymore ## [3.6.0] - 2023-06-15 ### Added - Added `Decode::decode_into` to allow deserializing into unitialized memory. - Added a `DecodeFinished` type to be used with `Decode::decode_into`. ### Fixed - Trying to deserialize a big boxed array (e.g. `Box<[u8; 1024 * 1024 * 1024]>`) won't overflow the stack anymore. - Trying to deserialize big nested enums with many variants won't overflow the stack anymore. - Elements of partially read arrays will now be properly dropped if the whole array wasn't decoded. ### Changed - The derive macros will now be reexported only when the `derive` feature is enabled, as opposed to how it was previously where enabling `parity-scale-codec-derive` would suffice. - The `max-encoded-len` feature won't automatically enable the derive macros nor pull in the `parity-scale-codec-derive` dependency. ## [3.5.0] ### Added - `ConstEncodedLen` marker trait for types that implement `MaxEncodedLen`. [#428](https://github.com/paritytech/parity-scale-codec/pull/428) ## [3.4.0] This release renders the `full` feature defunct. The implementations guarded behind this feature are now always provided. ### Changes - All implementations guarded behind `full` are not unconditionally implemented. ## [3.3.0] This release exports `decode_vec_with_len` to support custom decoding of `Vec`s. ### Added - Export `decode_vec_with_len`. ## [3.2.1] - 2022-09-14 This release fixes compilation on no-std envs. ### Changed - Use core RangeInclusive instead of std [#378](https://github.com/paritytech/parity-scale-codec/pull/378) ## [3.2.0] - 2022-09-13 This release (specifically [#375](https://github.com/paritytech/parity-scale-codec/pull/375)) bumps the MSRV to 1.60.0 as it depends on the Cargo.toml weak dependency feature. ### Changed - Don't include bitvec with std feature unless asked for explicitly. [#375](https://github.com/paritytech/parity-scale-codec/pull/375) - Implement `MaxEncodedLen` on more core lib types. [#350](https://github.com/paritytech/parity-scale-codec/pull/350) ## [3.1.5] - 2022-06-11 A quick release to fix an issue introduced in 3.1.4 that broke compiling on no-std. ### Changed - Fix compiling on no-std. (see https://github.com/paritytech/parity-scale-codec/commit/c25f14a46546c75e4208363ced9d89aa81c85e7f) ## [3.1.3] - 2022-06-10 ### Changed - Impl `MaxEncodedLen` for `Box`. [#349](https://github.com/paritytech/parity-scale-codec/pull/349) - Add `decode_from_bytes`. [#342](https://github.com/paritytech/parity-scale-codec/pull/342) ## [3.1.2] - 2022-03-22 Be aware that version 3.0.0. up to 3.1.1 contained some bugs in the `BitVec` encoder that could lead to an invalid encoding. Thus, we yanked these crate version and it is advised to upgrade to 3.1.2. Any release before 3.0.0 wasn't affected by this bug. ### Changed - Optimised the `Decode::decode` for `[T; N]` by @xgreenx. [#299](https://github.com/paritytech/parity-scale-codec/pull/299) - Add some doc for the derive macro by @thiolliere. [#301](https://github.com/paritytech/parity-scale-codec/pull/301) - Add bytes::Bytes implementation by @vorot93. [#309](https://github.com/paritytech/parity-scale-codec/pull/309) - Upgrade to BitVec 1.0 by @bkchr. [#311](https://github.com/paritytech/parity-scale-codec/pull/311) - BREAKING CHANGE: DecodeLimit and DecodeAll extensions now advance input by @wigy-opensource-developer. [#314](https://github.com/paritytech/parity-scale-codec/pull/314) - Make `CompactRef` public by @andrenth. [#321](https://github.com/paritytech/parity-scale-codec/pull/321) - Add ability to re-export parity-scale-codec crate by @gshep. [#325](https://github.com/paritytech/parity-scale-codec/pull/325) - BitVec: Improve the encoding and consolidate the implementations by @bkchr. [#327](https://github.com/paritytech/parity-scale-codec/pull/327) - Fix crate access by putting a leading `::` by @bkchr. [#328](https://github.com/paritytech/parity-scale-codec/pull/328) ## [3.0.0] - 2022-02-02 ### Fix - Optimised the Decode::decode for [T; N] [#299](https://github.com/paritytech/parity-scale-codec/pull/299) ### Changed - Migrated to 2021 edition, enforcing MSRV of `1.56.1`. [#298](https://github.com/paritytech/parity-scale-codec/pull/298) - Upgrade to BitVec 1.0 [#311](https://github.com/paritytech/parity-scale-codec/pull/311) - DecodeLimit and DecodeAll extensions now advance input [#314](https://github.com/paritytech/parity-scale-codec/pull/314) ### Added - Add bytes::Bytes implementation [#309](https://github.com/paritytech/parity-scale-codec/pull/309) ## [2.3.1] - 2021-09-28 ### Fix - Improve macro hygiene of `Encode` and `Decode` proc. macro expansions. ([#291](https://github.com/paritytech/parity-scale-codec/pull/291), [#293](https://github.com/paritytech/parity-scale-codec/pull/293)) ## [2.3.0] - 2021-09-11 ### Added - `decode_and_advance_with_depth_limit` to the `DecodeLimit` trait. This allows advancing the cursor while decoding the input. PR #286 ## [2.2.0] - 2021-07-02 ### Added - Add support for custom where bounds `codec(mel_bound(T: MaxEncodedLen))` when deriving the traits. PR #279 - `MaxEncodedLen` trait for items that have a statically known maximum encoded size. ([#268](https://github.com/paritytech/parity-scale-codec/pull/268)) - `#[codec(crate = )]` top-level attribute to be used with the new `MaxEncodedLen` trait, which allows to specify a different path to the crate that contains the `MaxEncodedLen` trait. Useful when using generating a type through a macro and this type should implement `MaxEncodedLen` and the final crate doesn't have `parity-scale-codec` as dependency. ## [2.1.3] - 2021-06-14 ### Changed - Lint attributes now pass through to the derived impls of `Encode`, `Decode` and `CompactAs`. PR #272 ## [2.1.0] - 2021-04-06 ### Fix - Add support for custom where bounds `codec(encode_bound(T: Encode))` and `codec(decode_bound(T: Decode))` when deriving the traits. Pr #262 - Switch to const generics for array implementations. Pr #261 ## [2.0.1] - 2021-02-26 ### Fix - Fix type inference issue in `Decode` derive macro. Pr #254 ## [2.0.0] - 2021-01-26 ### Added - `Decode::skip` allows to skip some encoded types. Pr #243 - `Decode::encoded_fixed_size` allows to get the fixed encoded size of a type. PR #243 - `Error` now contains a chain of causes. This full error description can also be activated on no std using the feature `chain-error`. PR #242 - `Encode::encoded_size` allows to get the encoded size of a type more efficiently. PR #245 ### Changed - `CompactAs::decode_from` now returns result. This allow for decoding to fail from their compact form. - derive macro use literal index e.g. `#[codec(index = 15)]` instead of `#[codec(index = "15")]` - Version of crates `bitvec` and `generic-array` is updated. - `Encode::encode_to` now bounds the generic `W: Output + ?Sized` instead of `W: Output`. - `Output` can now be used as a trait object. ### Removed - `EncodeAppend::append` is removed in favor of `EncodeAppend::append_or_new`. - `Output::push` is removed in favor of `Encode::encode_to`. - Some bounds on `HasCompact::Type` are removed. - `Error::what` is removed in favor of `Error::to_string` (implemented through trait `Display`). - `Error::description` is removed in favor of `Error::to_string` (implemented through trait `Display`). parity-scale-codec-3.6.4/CODEOWNERS000064400000000000000000000016521046102023000147050ustar 00000000000000# Lists some code owners. # # A codeowner just oversees some part of the codebase. If an owned file is changed then the # corresponding codeowner receives a review request. An approval of the codeowner might be # required for merging a PR (depends on repository settings). # # For details about syntax, see: # https://help.github.com/en/articles/about-code-owners # But here are some important notes: # # - Glob syntax is git-like, e.g. `/core` means the core directory in the root, unlike `core` # which can be everywhere. # - Multiple owners are supported. # - Either handle (e.g, @github_user or @github_org/team) or email can be used. Keep in mind, # that handles might work better because they are more recognizable on GitHub, # eyou can use them for mentioning unlike an email. # - The latest matching rule, if multiple, takes precedence. # CI /.github/ @paritytech/ci /scripts/ @paritytech/ci /.gitlab-ci.yml @paritytech/ci parity-scale-codec-3.6.4/Cargo.toml0000644000000041540000000000100125200ustar # 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 = "2021" rust-version = "1.60.0" name = "parity-scale-codec" version = "3.6.4" authors = ["Parity Technologies "] description = "SCALE - Simple Concatenating Aggregated Little Endians" readme = "README.md" categories = ["encoding"] license = "Apache-2.0" repository = "https://github.com/paritytech/parity-scale-codec" [lib] bench = false [[bench]] name = "benches" harness = false [dependencies.arbitrary] version = "1.0.1" features = ["derive"] optional = true [dependencies.arrayvec] version = "0.7" default-features = false [dependencies.bitvec] version = "1" features = ["alloc"] optional = true default-features = false [dependencies.byte-slice-cast] version = "1.2.2" default-features = false [dependencies.bytes] version = "1" optional = true default-features = false [dependencies.generic-array] version = "0.14.7" optional = true [dependencies.impl-trait-for-tuples] version = "0.2.2" [dependencies.parity-scale-codec-derive] version = ">= 3.6.4" optional = true default-features = false [dependencies.serde] version = "1.0.171" optional = true [dev-dependencies.criterion] version = "0.4.0" [dev-dependencies.paste] version = "1" [dev-dependencies.proptest] version = "1.2.0" [dev-dependencies.quickcheck] version = "1.0" [dev-dependencies.serde_derive] version = "1.0" [dev-dependencies.trybuild] version = "1.0.81" [features] bit-vec = ["bitvec"] chain-error = [] default = ["std"] derive = ["parity-scale-codec-derive"] full = [] fuzz = [ "std", "arbitrary", ] max-encoded-len = ["parity-scale-codec-derive?/max-encoded-len"] std = [ "serde", "bitvec?/std", "byte-slice-cast/std", "chain-error", ] parity-scale-codec-3.6.4/Cargo.toml.orig000064400000000000000000000036271046102023000162050ustar 00000000000000[package] name = "parity-scale-codec" description = "SCALE - Simple Concatenating Aggregated Little Endians" version = "3.6.4" authors = ["Parity Technologies "] license = "Apache-2.0" repository = "https://github.com/paritytech/parity-scale-codec" categories = ["encoding"] edition = "2021" rust-version = "1.60.0" [dependencies] arrayvec = { version = "0.7", default-features = false } serde = { version = "1.0.171", optional = true } parity-scale-codec-derive = { path = "derive", version = ">= 3.6.4", default-features = false, optional = true } bitvec = { version = "1", default-features = false, features = [ "alloc" ], optional = true } bytes = { version = "1", default-features = false, optional = true } byte-slice-cast = { version = "1.2.2", default-features = false } generic-array = { version = "0.14.7", optional = true } arbitrary = { version = "1.0.1", features = ["derive"], optional = true } impl-trait-for-tuples = "0.2.2" [dev-dependencies] criterion = "0.4.0" serde_derive = { version = "1.0" } parity-scale-codec-derive = { path = "derive", default-features = false } quickcheck = "1.0" proptest = "1.2.0" trybuild = "1.0.81" paste = "1" [[bench]] name = "benches" harness = false [lib] bench = false [features] default = ["std"] derive = ["parity-scale-codec-derive"] std = ["serde", "bitvec?/std", "byte-slice-cast/std", "chain-error"] bit-vec = ["bitvec"] fuzz = ["std", "arbitrary"] # Enables the new `MaxEncodedLen` trait. # NOTE: This is still considered experimental and is exempt from the usual # SemVer guarantees. We do not guarantee no code breakage when using this. max-encoded-len = ["parity-scale-codec-derive?/max-encoded-len"] # Make error fully descriptive with chaining error message. # Should not be used in a constrained environment. chain-error = [] # This does not do anthing anymore. Remove with the next major release. full = [] [workspace] members = ["derive", "fuzzer"] parity-scale-codec-3.6.4/LICENSE000064400000000000000000000261351046102023000143220ustar 00000000000000 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. parity-scale-codec-3.6.4/README.md000064400000000000000000000203351046102023000145700ustar 00000000000000# Parity SCALE Codec Rust implementation of the SCALE (Simple Concatenated Aggregate Little-Endian) data format for types used in the Parity Substrate framework. SCALE is a light-weight format which allows encoding (and decoding) which makes it highly suitable for resource-constrained execution environments like blockchain runtimes and low-power, low-memory devices. It is important to note that the encoding context (knowledge of how the types and data structures look) needs to be known separately at both encoding and decoding ends. The encoded data does not include this contextual information. To get a better understanding of how the encoding is done for different types, take a look at the ["Type encoding (SCALE)" page in Substrate docs](https://docs.substrate.io/reference/scale-codec/). ## Implementation The codec is implemented using the following traits: ### Encode The `Encode` trait is used for encoding of data into the SCALE format. The `Encode` trait contains the following functions: * `size_hint(&self) -> usize`: Gets the capacity (in bytes) required for the encoded data. This is to avoid double-allocation of memory needed for the encoding. It can be an estimate and does not need to be an exact number. If the size is not known, even no good maximum, then we can skip this function from the trait implementation. This is required to be a cheap operation, so should not involve iterations etc. * `encode_to(&self, dest: &mut T)`: Encodes the value and appends it to a destination buffer. * `encode(&self) -> Vec`: Encodes the type data and returns a slice. * `using_encoded R>(&self, f: F) -> R`: Encodes the type data and executes a closure on the encoded value. Returns the result from the executed closure. **Note:** Implementations should override `using_encoded` for value types and `encode_to` for allocating types. `size_hint` should be implemented for all types, wherever possible. Wrapper types should override all methods. ### Decode The `Decode` trait is used for deserialization/decoding of encoded data into the respective types. * `fn decode(value: &mut I) -> Result`: Tries to decode the value from SCALE format to the type it is called on. Returns an `Err` if the decoding fails. ### CompactAs The `CompactAs` trait is used for wrapping custom types/structs as compact types, which makes them even more space/memory efficient. The compact encoding is described [here](https://docs.substrate.io/reference/scale-codec/#fn-1). * `encode_as(&self) -> &Self::As`: Encodes the type (self) as a compact type. The type `As` is defined in the same trait and its implementation should be compact encode-able. * `decode_from(_: Self::As) -> Result`: Decodes the type (self) from a compact encode-able type. ### HasCompact The `HasCompact` trait, if implemented, tells that the corresponding type is a compact encode-able type. ### EncodeLike The `EncodeLike` trait needs to be implemented for each type manually. When using derive, it is done automatically for you. Basically the trait gives you the opportunity to accept multiple types to a function that all encode to the same representation. ## Usage Examples Following are some examples to demonstrate usage of the codec. ### Simple types ```rust # // Import macros if derive feature is not used. # #[cfg(not(feature="derive"))] # use parity_scale_codec_derive::{Encode, Decode}; use parity_scale_codec::{Encode, Decode}; #[derive(Debug, PartialEq, Encode, Decode)] enum EnumType { #[codec(index = 15)] A, B(u32, u64), C { a: u32, b: u64, }, } let a = EnumType::A; let b = EnumType::B(1, 2); let c = EnumType::C { a: 1, b: 2 }; a.using_encoded(|ref slice| { assert_eq!(slice, &b"\x0f"); }); b.using_encoded(|ref slice| { assert_eq!(slice, &b"\x01\x01\0\0\0\x02\0\0\0\0\0\0\0"); }); c.using_encoded(|ref slice| { assert_eq!(slice, &b"\x02\x01\0\0\0\x02\0\0\0\0\0\0\0"); }); let mut da: &[u8] = b"\x0f"; assert_eq!(EnumType::decode(&mut da).ok(), Some(a)); let mut db: &[u8] = b"\x01\x01\0\0\0\x02\0\0\0\0\0\0\0"; assert_eq!(EnumType::decode(&mut db).ok(), Some(b)); let mut dc: &[u8] = b"\x02\x01\0\0\0\x02\0\0\0\0\0\0\0"; assert_eq!(EnumType::decode(&mut dc).ok(), Some(c)); let mut dz: &[u8] = &[0]; assert_eq!(EnumType::decode(&mut dz).ok(), None); # fn main() { } ``` ### Compact type with HasCompact ```rust # // Import macros if derive feature is not used. # #[cfg(not(feature="derive"))] # use parity_scale_codec_derive::{Encode, Decode}; use parity_scale_codec::{Encode, Decode, Compact, HasCompact}; #[derive(Debug, PartialEq, Encode, Decode)] struct Test1CompactHasCompact { #[codec(compact)] bar: T, } #[derive(Debug, PartialEq, Encode, Decode)] struct Test1HasCompact { #[codec(encoded_as = "::Type")] bar: T, } let test_val: (u64, usize) = (0u64, 1usize); let encoded = Test1HasCompact { bar: test_val.0 }.encode(); assert_eq!(encoded.len(), test_val.1); assert_eq!(>::decode(&mut &encoded[..]).unwrap().bar, test_val.0); # fn main() { } ``` ### Type with CompactAs ```rust # // Import macros if derive feature is not used. # #[cfg(not(feature="derive"))] # use parity_scale_codec_derive::{Encode, Decode}; use serde_derive::{Serialize, Deserialize}; use parity_scale_codec::{Encode, Decode, Compact, HasCompact, CompactAs, Error}; #[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))] #[derive(PartialEq, Eq, Clone)] struct StructHasCompact(u32); impl CompactAs for StructHasCompact { type As = u32; fn encode_as(&self) -> &Self::As { &12 } fn decode_from(_: Self::As) -> Result { Ok(StructHasCompact(12)) } } impl From> for StructHasCompact { fn from(_: Compact) -> Self { StructHasCompact(12) } } #[derive(Debug, PartialEq, Encode, Decode)] enum TestGenericHasCompact { A { #[codec(compact)] a: T }, } let a = TestGenericHasCompact::A:: { a: StructHasCompact(12325678), }; let encoded = a.encode(); assert_eq!(encoded.len(), 2); # fn main() { } ``` ## Derive attributes The derive implementation supports the following attributes: - `codec(dumb_trait_bound)`: This attribute needs to be placed above the type that one of the trait should be implemented for. It will make the algorithm that determines the to-add trait bounds fall back to just use the type parameters of the type. This can be useful for situation where the algorithm includes private types in the public interface. By using this attribute, you should not get this error/warning again. - `codec(skip)`: Needs to be placed above a field or variant and makes it to be skipped while encoding/decoding. - `codec(compact)`: Needs to be placed above a field and makes the field use compact encoding. (The type needs to support compact encoding.) - `codec(encoded_as = "OtherType")`: Needs to be placed above a field and makes the field being encoded by using `OtherType`. - `codec(index = 0)`: Needs to be placed above an enum variant to make the variant use the given index when encoded. By default the index is determined by counting from `0` beginning wth the first variant. - `codec(encode_bound)`, `codec(decode_bound)` and `codec(mel_bound)`: All 3 attributes take in a `where` clause for the `Encode`, `Decode` and `MaxEncodedLen` trait implementation for the annotated type respectively. - `codec(encode_bound(skip_type_params))`, `codec(decode_bound(skip_type_params))` and `codec(mel_bound(skip_type_params))`: All 3 sub-attributes take in types as arguments to skip trait derivation of the corresponding trait, e.g. T in `codec(encode_bound(skip_type_params(T)))` will not contain a `Encode` trait bound while `Encode` is being derived for the annotated type. ## Known issues Even though this crate supports deserialization of arbitrarily sized array (e.g. `[T; 1024 * 1024 * 1024]`) using such types is not recommended and will most likely result in a stack overflow. If you have a big array inside of your structure which you want to decode you should wrap it in a `Box`, e.g. `Box<[T; 1024 * 1024 * 1024]>`. ------------------------- License: Apache-2.0 parity-scale-codec-3.6.4/benches/benches.rs000064400000000000000000000163541046102023000167030ustar 00000000000000// Copyright 2019 Parity Technologies // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. use std::{time::Duration, any::type_name, convert::{TryFrom, TryInto}}; #[cfg(feature = "bit-vec")] use bitvec::{vec::BitVec, order::Lsb0}; use criterion::{Criterion, black_box, Bencher, criterion_group, criterion_main}; use parity_scale_codec::*; use parity_scale_codec_derive::{Encode, Decode}; fn array_vec_write_u128(b: &mut Bencher) { b.iter(|| { for b in 0..black_box(1_000_000) { let a = 0xffff_ffff_ffff_ffff_ffff_u128; Compact(a ^ b).using_encoded(|x| { black_box(x).len() }); } }); } fn test_vec, &[u8])>(b: &mut Bencher, f: F) { let f = black_box(f); let x = black_box([0xff; 10240]); b.iter(|| { for _b in 0..black_box(10_000) { let mut vec = Vec::::new(); f(&mut vec, &x); } }); } fn vec_write_as_output(b: &mut Bencher) { test_vec(b, |vec, a| { Output::write(vec, a); }); } fn vec_extend(b: &mut Bencher) { test_vec(b, |vec, a| { vec.extend(a); }); } fn vec_extend_from_slice(b: &mut Bencher) { test_vec(b, |vec, a| { vec.extend_from_slice(a); }); } struct NoLimitInput<'a>(&'a [u8]); impl<'a> Input for NoLimitInput<'a> { fn remaining_len(&mut self) -> Result, Error> { Ok(None) } fn read(&mut self, into: &mut [u8]) -> Result<(), Error> { self.0.read(into) } } #[derive(Encode, Decode)] enum Event { ComplexEvent(Vec, u32, i32, u128, i8), } fn vec_append_with_decode_and_encode(b: &mut Bencher) { let data = b"PCX"; b.iter(|| { let mut encoded_events_vec = Vec::new(); for _ in 0..1000 { let mut events = Vec::::decode(&mut &encoded_events_vec[..]) .unwrap_or_default(); events.push(Event::ComplexEvent(data.to_vec(), 4, 5, 6, 9)); encoded_events_vec = events.encode(); } }) } fn vec_append_with_encode_append(b: &mut Bencher) { let data = b"PCX"; b.iter(|| { let mut encoded_events_vec; let events = vec![Event::ComplexEvent(data.to_vec(), 4, 5, 6, 9)]; encoded_events_vec = events.encode(); for _ in 1..1000 { encoded_events_vec = as EncodeAppend>::append_or_new( encoded_events_vec, &[Event::ComplexEvent(data.to_vec(), 4, 5, 6, 9)], ).unwrap(); } }); } fn encode_decode_vec + Codec>(c: &mut Criterion) where T::Error: std::fmt::Debug { let mut g = c.benchmark_group("vec_encode"); for vec_size in [1, 2, 5, 32, 1024, 2048, 16384] { g.bench_with_input(&format!("{}/{}", type_name::(), vec_size), &vec_size, |b, &vec_size| { let vec: Vec = (0..=127u8) .cycle() .take(vec_size) .map(|v| v.try_into().unwrap()) .collect(); let vec = black_box(vec); b.iter(|| vec.encode()) }); } drop(g); let mut g = c.benchmark_group("vec_decode"); for vec_size in [1, 2, 5, 32, 1024, 2048, 16384] { g.bench_with_input(&format!("{}/{}", type_name::(), vec_size), &vec_size, |b, &vec_size| { let vec: Vec = (0..=127u8) .cycle() .take(vec_size) .map(|v| v.try_into().unwrap()) .collect(); let vec = vec.encode(); let vec = black_box(vec); b.iter(|| { let _: Vec = Decode::decode(&mut &vec[..]).unwrap(); }) }); } drop(g); let mut g = c.benchmark_group("vec_decode_no_limit"); for vec_size in [16384, 131072] { g.bench_with_input(&format!("vec_decode_no_limit_{}/{}", type_name::(), vec_size), &vec_size, |b, &vec_size| { let vec: Vec = (0..=127u8) .cycle() .take(vec_size) .map(|v| v.try_into().unwrap()) .collect(); let vec = vec.encode(); let vec = black_box(vec); b.iter(|| { let _: Vec = Decode::decode(&mut NoLimitInput(&vec[..])).unwrap(); }) }); } } fn encode_decode_complex_type(c: &mut Criterion) { #[derive(Encode, Decode, Clone)] struct ComplexType { _val: u32, _other_val: u128, _vec: Vec, } let complex_types = vec![ ComplexType { _val: 3, _other_val: 345634635, _vec: vec![1, 2, 3, 5, 6, 7] }, ComplexType { _val: 1000, _other_val: 0980345634635, _vec: vec![1, 2, 3, 5, 6, 7] }, ComplexType { _val: 43564, _other_val: 342342345634635, _vec: vec![1, 2, 3, 5, 6, 7] }, ]; let mut g = c.benchmark_group("vec_encode_complex_type"); for vec_size in [1, 2, 5, 32, 1024, 2048, 16384] { let complex_types = complex_types.clone(); g.bench_with_input(format!("vec_encode_complex_type/{}", vec_size), &vec_size, move |b, &vec_size| { let vec: Vec = complex_types.clone().into_iter().cycle().take(vec_size).collect(); let vec = black_box(vec); b.iter(|| vec.encode()) }); } drop(g); let mut g = c.benchmark_group("vec_decode_complex_type"); for vec_size in [1, 2, 5, 32, 1024, 2048, 16384] { let complex_types = complex_types.clone(); g.bench_with_input(format!("vec_decode_complex_type/{}", vec_size), &vec_size, move |b, &vec_size| { let vec: Vec = complex_types.clone().into_iter().cycle().take(vec_size).collect(); let vec = vec.encode(); let vec = black_box(vec); b.iter(|| { let _: Vec = Decode::decode(&mut &vec[..]).unwrap(); }) }); } } fn bench_fn(c: &mut Criterion) { c.bench_function("vec_write_as_output", vec_write_as_output); c.bench_function("vec_extend", vec_extend); c.bench_function("vec_extend_from_slice", vec_extend_from_slice); c.bench_function("vec_append_with_decode_and_encode", vec_append_with_decode_and_encode); c.bench_function("vec_append_with_encode_append", vec_append_with_encode_append); c.bench_function("array_vec_write_u128", array_vec_write_u128); } fn encode_decode_bitvec_u8(c: &mut Criterion) { let _ = c; #[cfg(feature = "bit-vec")] { let mut g = c.benchmark_group("bitvec_u8_encode"); for size in [1, 2, 5, 32, 1024] { g.bench_with_input(size.to_string(), &size, |b, &size| { let vec: BitVec = [true, false] .iter() .cloned() .cycle() .take(size) .collect(); let vec = black_box(vec); b.iter(|| vec.encode()) }); } } #[cfg(feature = "bit-vec")] { let mut g = c.benchmark_group("bitvec_u8_decode"); for size in [1, 2, 5, 32, 1024] { g.bench_with_input(size.to_string(), &size, |b, &size| { let vec: BitVec = [true, false] .iter() .cloned() .cycle() .take(size) .collect(); let vec = vec.encode(); let vec = black_box(vec); b.iter(|| { let _: BitVec = Decode::decode(&mut &vec[..]).unwrap(); }) }); } } } criterion_group!{ name = benches; config = Criterion::default().warm_up_time(Duration::from_millis(500)).without_plots(); targets = encode_decode_vec::, encode_decode_vec::, encode_decode_vec::, encode_decode_vec::, encode_decode_vec::, encode_decode_vec::, encode_decode_vec::, encode_decode_vec::, bench_fn, encode_decode_bitvec_u8, encode_decode_complex_type } criterion_main!(benches); parity-scale-codec-3.6.4/rustfmt.toml000064400000000000000000000010051046102023000157030ustar 00000000000000# Basic hard_tabs = true max_width = 100 use_small_heuristics = "Max" # Imports imports_granularity = "Crate" reorder_imports = true # Consistency newline_style = "Unix" # Format comments comment_width = 100 wrap_comments = true # Misc chain_width = 80 spaces_around_ranges = false binop_separator = "Back" reorder_impl_items = false match_arm_leading_pipes = "Preserve" match_arm_blocks = false match_block_trailing_comma = true trailing_comma = "Vertical" trailing_semicolon = false use_field_init_shorthand = true parity-scale-codec-3.6.4/scripts/ci/pre_cache.sh000075500000000000000000000016401046102023000176410ustar 00000000000000#!/bin/bash set -u # if there is no directory for this $CI_COMMIT_REF_NAME/$CI_JOB_NAME # create such directory and # copy recursively all the files from the newest dir which has $CI_JOB_NAME, if it exists # cache lives in /ci-cache/${CI_PROJECT_NAME}/${2}/${CI_COMMIT_REF_NAME}/${CI_JOB_NAME} function prepopulate { if [[ ! -d $1 ]]; then mkdir -p "/ci-cache/$CI_PROJECT_NAME/$2/$CI_COMMIT_REF_NAME"; FRESH_CACHE=$(find "/ci-cache/$CI_PROJECT_NAME/$2" -mindepth 2 -maxdepth 2 \ -type d -name "$CI_JOB_NAME" -exec stat --printf="%Y\t%n\n" {} \; |sort -n -r |head -1 |cut -f2); if [[ -d $FRESH_CACHE ]]; then echo "____Using" "$FRESH_CACHE" "to prepopulate the cache____"; time cp -r "$FRESH_CACHE" "$1"; else echo "_____No such $2 dir, proceeding from scratch_____"; fi else echo "____No need to prepopulate $2 cache____"; fi } prepopulate "$CARGO_TARGET_DIR" targets parity-scale-codec-3.6.4/src/bit_vec.rs000064400000000000000000000161311046102023000160600ustar 00000000000000// Copyright 2019 Parity Technologies // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //! `BitVec` specific serialization. use bitvec::{ vec::BitVec, store::BitStore, order::BitOrder, slice::BitSlice, boxed::BitBox, view::BitView, }; use crate::{ EncodeLike, Encode, Decode, Input, Output, Error, Compact, codec::decode_vec_with_len, }; impl Encode for BitSlice { fn encode_to(&self, dest: &mut W) { let bits = self.len(); assert!( bits <= ARCH32BIT_BITSLICE_MAX_BITS, "Attempted to encode a BitSlice with too many bits.", ); Compact(bits as u32).encode_to(dest); // Iterate over chunks for chunk in self.chunks(core::mem::size_of::() * 8) { let mut element = T::ZERO; element.view_bits_mut::()[..chunk.len()].copy_from_bitslice(chunk); element.encode_to(dest); } } } impl Encode for BitVec { fn encode_to(&self, dest: &mut W) { self.as_bitslice().encode_to(dest) } } impl EncodeLike for BitVec {} /// Equivalent of `BitStore::MAX_BITS` on 32bit machine. const ARCH32BIT_BITSLICE_MAX_BITS: usize = 0x1fff_ffff; impl Decode for BitVec { fn decode(input: &mut I) -> Result { >::decode(input).and_then(move |Compact(bits)| { // Otherwise it is impossible to store it on 32bit machine. if bits as usize > ARCH32BIT_BITSLICE_MAX_BITS { return Err("Attempt to decode a BitVec with too many bits".into()); } let vec = decode_vec_with_len(input, bitvec::mem::elts::(bits as usize))?; let mut result = Self::try_from_vec(vec) .map_err(|_| { Error::from("UNEXPECTED ERROR: `bits` is less or equal to `ARCH32BIT_BITSLICE_MAX_BITS`; So BitVec must be able to handle the number of segment needed for `bits` to be represented; qed") })?; assert!(bits as usize <= result.len()); result.truncate(bits as usize); Ok(result) }) } } impl Encode for BitBox { fn encode_to(&self, dest: &mut W) { self.as_bitslice().encode_to(dest) } } impl EncodeLike for BitBox {} impl Decode for BitBox { fn decode(input: &mut I) -> Result { Ok(BitVec::::decode(input)?.into()) } } #[cfg(test)] mod tests { use super::*; use bitvec::{bitvec, order::{Msb0, Lsb0}}; use crate::{codec::MAX_PREALLOCATION, CompactLen}; macro_rules! test_data { ($inner_type:ident) => ( [ BitVec::<$inner_type, Msb0>::new(), bitvec![$inner_type, Msb0; 0], bitvec![$inner_type, Msb0; 1], bitvec![$inner_type, Msb0; 0, 0], bitvec![$inner_type, Msb0; 1, 0], bitvec![$inner_type, Msb0; 0, 1], bitvec![$inner_type, Msb0; 1, 1], bitvec![$inner_type, Msb0; 1, 0, 1], bitvec![$inner_type, Msb0; 0, 1, 0, 1, 0, 1, 1], bitvec![$inner_type, Msb0; 0, 1, 0, 1, 0, 1, 1, 0], bitvec![$inner_type, Msb0; 1, 1, 0, 1, 0, 1, 1, 0, 1], bitvec![$inner_type, Msb0; 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0], bitvec![$inner_type, Msb0; 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0], bitvec![$inner_type, Msb0; 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0], bitvec![$inner_type, Msb0; 0; 15], bitvec![$inner_type, Msb0; 1; 16], bitvec![$inner_type, Msb0; 0; 17], bitvec![$inner_type, Msb0; 1; 31], bitvec![$inner_type, Msb0; 0; 32], bitvec![$inner_type, Msb0; 1; 33], bitvec![$inner_type, Msb0; 0; 63], bitvec![$inner_type, Msb0; 1; 64], bitvec![$inner_type, Msb0; 0; 65], bitvec![$inner_type, Msb0; 1; MAX_PREALLOCATION * 8 + 1], bitvec![$inner_type, Msb0; 0; MAX_PREALLOCATION * 9], bitvec![$inner_type, Msb0; 1; MAX_PREALLOCATION * 32 + 1], bitvec![$inner_type, Msb0; 0; MAX_PREALLOCATION * 33], ] ) } #[test] fn bitvec_u8() { for v in &test_data!(u8) { let encoded = v.encode(); assert_eq!(*v, BitVec::::decode(&mut &encoded[..]).unwrap()); let elements = bitvec::mem::elts::(v.len()); let compact_len = Compact::compact_len(&(v.len() as u32)); assert_eq!(compact_len + elements, encoded.len(), "{}", v); } } #[test] fn bitvec_u16() { for v in &test_data!(u16) { let encoded = v.encode(); assert_eq!(*v, BitVec::::decode(&mut &encoded[..]).unwrap()); let elements = bitvec::mem::elts::(v.len()); let compact_len = Compact::compact_len(&(v.len() as u32)); assert_eq!(compact_len + elements * 2, encoded.len(), "{}", v); } } #[test] fn bitvec_u32() { for v in &test_data!(u32) { let encoded = v.encode(); assert_eq!(*v, BitVec::::decode(&mut &encoded[..]).unwrap()); let elements = bitvec::mem::elts::(v.len()); let compact_len = Compact::compact_len(&(v.len() as u32)); assert_eq!(compact_len + elements * 4, encoded.len(), "{}", v); } } #[test] fn bitvec_u64() { for v in &test_data!(u64) { let encoded = v.encode(); assert_eq!(*v, BitVec::::decode(&mut &encoded[..]).unwrap()); let elements = bitvec::mem::elts::(v.len()); let compact_len = Compact::compact_len(&(v.len() as u32)); assert_eq!(compact_len + elements * 8, encoded.len(), "{}", v); } } #[test] fn bitslice() { let data: &[u8] = &[0x69]; let slice = BitSlice::::from_slice(data); let encoded = slice.encode(); let decoded = BitVec::::decode(&mut &encoded[..]).unwrap(); assert_eq!(slice, decoded.as_bitslice()); } #[test] fn bitbox() { let data: &[u8] = &[5, 10]; let slice = BitSlice::::from_slice(data); let bb = BitBox::::from_bitslice(slice); let encoded = bb.encode(); let decoded = BitBox::::decode(&mut &encoded[..]).unwrap(); assert_eq!(bb, decoded); } #[test] fn bitvec_u8_encodes_as_expected() { let cases = vec![ (bitvec![u8, Lsb0; 0, 0, 1, 1].encode(), (Compact(4u32), 0b00001100u8).encode()), (bitvec![u8, Lsb0; 0, 1, 1, 1].encode(), (Compact(4u32), 0b00001110u8).encode()), (bitvec![u8, Lsb0; 1, 1, 1, 1].encode(), (Compact(4u32), 0b00001111u8).encode()), (bitvec![u8, Lsb0; 1, 1, 1, 1, 1].encode(), (Compact(5u32), 0b00011111u8).encode()), (bitvec![u8, Lsb0; 1, 1, 1, 1, 1, 0].encode(), (Compact(6u32), 0b00011111u8).encode()), (bitvec![u8, Lsb0; 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 1].encode(), (Compact(12u32), 0b00011111u8, 0b00001011u8).encode()), ]; for (idx, (actual, expected)) in cases.into_iter().enumerate() { assert_eq!(actual, expected, "case at index {} failed; encodings differ", idx); } } } parity-scale-codec-3.6.4/src/codec.rs000064400000000000000000001626151046102023000155330ustar 00000000000000// Copyright 2017-2018 Parity Technologies // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //! Serialization. use core::fmt; use core::{ convert::TryFrom, iter::FromIterator, marker::PhantomData, mem, mem::{ MaybeUninit, }, ops::{Deref, Range, RangeInclusive}, time::Duration, }; use core::num::{ NonZeroI8, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI128, NonZeroU8, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU128, }; use byte_slice_cast::{AsByteSlice, AsMutByteSlice, ToMutByteSlice}; #[cfg(target_has_atomic = "ptr")] use crate::alloc::sync::Arc; use crate::alloc::{ boxed::Box, borrow::{Cow, ToOwned}, collections::{ BTreeMap, BTreeSet, VecDeque, LinkedList, BinaryHeap }, rc::Rc, string::String, vec::Vec, }; use crate::compact::Compact; use crate::DecodeFinished; use crate::encode_like::EncodeLike; use crate::Error; pub(crate) const MAX_PREALLOCATION: usize = 4 * 1024; const A_BILLION: u32 = 1_000_000_000; /// Trait that allows reading of data into a slice. pub trait Input { /// Should return the remaining length of the input data. If no information about the input /// length is available, `None` should be returned. /// /// The length is used to constrain the preallocation while decoding. Returning a garbage /// length can open the doors for a denial of service attack to your application. /// Otherwise, returning `None` can decrease the performance of your application. fn remaining_len(&mut self) -> Result, Error>; /// Read the exact number of bytes required to fill the given buffer. /// /// Note that this function is similar to `std::io::Read::read_exact` and not /// `std::io::Read::read`. fn read(&mut self, into: &mut [u8]) -> Result<(), Error>; /// Read a single byte from the input. fn read_byte(&mut self) -> Result { let mut buf = [0u8]; self.read(&mut buf[..])?; Ok(buf[0]) } /// Descend into nested reference when decoding. /// This is called when decoding a new refence-based instance, /// such as `Vec` or `Box`. Currently all such types are /// allocated on the heap. fn descend_ref(&mut self) -> Result<(), Error> { Ok(()) } /// Ascend to previous structure level when decoding. /// This is called when decoding reference-based type is finished. fn ascend_ref(&mut self) {} /// !INTERNAL USE ONLY! /// /// Decodes a `bytes::Bytes`. #[cfg(feature = "bytes")] #[doc(hidden)] fn scale_internal_decode_bytes(&mut self) -> Result where Self: Sized { Vec::::decode(self).map(bytes::Bytes::from) } } impl<'a> Input for &'a [u8] { fn remaining_len(&mut self) -> Result, Error> { Ok(Some(self.len())) } fn read(&mut self, into: &mut [u8]) -> Result<(), Error> { if into.len() > self.len() { return Err("Not enough data to fill buffer".into()); } let len = into.len(); into.copy_from_slice(&self[..len]); *self = &self[len..]; Ok(()) } } #[cfg(feature = "std")] impl From for Error { fn from(err: std::io::Error) -> Self { use std::io::ErrorKind::*; match err.kind() { NotFound => "io error: NotFound".into(), PermissionDenied => "io error: PermissionDenied".into(), ConnectionRefused => "io error: ConnectionRefused".into(), ConnectionReset => "io error: ConnectionReset".into(), ConnectionAborted => "io error: ConnectionAborted".into(), NotConnected => "io error: NotConnected".into(), AddrInUse => "io error: AddrInUse".into(), AddrNotAvailable => "io error: AddrNotAvailable".into(), BrokenPipe => "io error: BrokenPipe".into(), AlreadyExists => "io error: AlreadyExists".into(), WouldBlock => "io error: WouldBlock".into(), InvalidInput => "io error: InvalidInput".into(), InvalidData => "io error: InvalidData".into(), TimedOut => "io error: TimedOut".into(), WriteZero => "io error: WriteZero".into(), Interrupted => "io error: Interrupted".into(), Other => "io error: Other".into(), UnexpectedEof => "io error: UnexpectedEof".into(), _ => "io error: Unknown".into(), } } } /// Wrapper that implements Input for any `Read` type. #[cfg(feature = "std")] pub struct IoReader(pub R); #[cfg(feature = "std")] impl Input for IoReader { fn remaining_len(&mut self) -> Result, Error> { Ok(None) } fn read(&mut self, into: &mut [u8]) -> Result<(), Error> { self.0.read_exact(into).map_err(Into::into) } } /// Trait that allows writing of data. pub trait Output { /// Write to the output. fn write(&mut self, bytes: &[u8]); /// Write a single byte to the output. fn push_byte(&mut self, byte: u8) { self.write(&[byte]); } } #[cfg(not(feature = "std"))] impl Output for Vec { fn write(&mut self, bytes: &[u8]) { self.extend_from_slice(bytes) } } #[cfg(feature = "std")] impl Output for W { fn write(&mut self, bytes: &[u8]) { (self as &mut dyn std::io::Write).write_all(bytes).expect("Codec outputs are infallible"); } } /// !INTERNAL USE ONLY! /// /// This enum provides type information to optimize encoding/decoding by doing fake specialization. #[doc(hidden)] #[non_exhaustive] pub enum TypeInfo { /// Default value of [`Encode::TYPE_INFO`] to not require implementors to set this value in the trait. Unknown, U8, I8, U16, I16, U32, I32, U64, I64, U128, I128, F32, F64, } /// Trait that allows zero-copy write of value-references to slices in LE format. /// /// Implementations should override `using_encoded` for value types and `encode_to` and `size_hint` for allocating types. /// Wrapper types should override all methods. pub trait Encode { // !INTERNAL USE ONLY! // This const helps SCALE to optimize the encoding/decoding by doing fake specialization. #[doc(hidden)] const TYPE_INFO: TypeInfo = TypeInfo::Unknown; /// If possible give a hint of expected size of the encoding. /// /// This method is used inside default implementation of `encode` /// to avoid re-allocations. fn size_hint(&self) -> usize { 0 } /// Convert self to a slice and append it to the destination. fn encode_to(&self, dest: &mut T) { self.using_encoded(|buf| dest.write(buf)); } /// Convert self to an owned vector. fn encode(&self) -> Vec { let mut r = Vec::with_capacity(self.size_hint()); self.encode_to(&mut r); r } /// Convert self to a slice and then invoke the given closure with it. fn using_encoded R>(&self, f: F) -> R { f(&self.encode()) } /// Calculates the encoded size. /// /// Should be used when the encoded data isn't required. /// /// # Note /// /// This works by using a special [`Output`] that only tracks the size. So, there are no allocations inside the /// output. However, this can not prevent allocations that some types are doing inside their own encoding. fn encoded_size(&self) -> usize { let mut size_tracker = SizeTracker { written: 0 }; self.encode_to(&mut size_tracker); size_tracker.written } } // Implements `Output` and only keeps track of the number of written bytes struct SizeTracker { written: usize, } impl Output for SizeTracker { fn write(&mut self, bytes: &[u8]) { self.written += bytes.len(); } fn push_byte(&mut self, _byte: u8) { self.written += 1; } } /// Trait that allows the length of a collection to be read, without having /// to read and decode the entire elements. pub trait DecodeLength { /// Return the number of elements in `self_encoded`. fn len(self_encoded: &[u8]) -> Result; } /// Trait that allows zero-copy read of value-references from slices in LE format. pub trait Decode: Sized { // !INTERNAL USE ONLY! // This const helps SCALE to optimize the encoding/decoding by doing fake specialization. #[doc(hidden)] const TYPE_INFO: TypeInfo = TypeInfo::Unknown; /// Attempt to deserialise the value from input. fn decode(input: &mut I) -> Result; /// Attempt to deserialize the value from input into a pre-allocated piece of memory. /// /// The default implementation will just call [`Decode::decode`]. /// /// # Safety /// /// If this function returns `Ok` then `dst` **must** be properly initialized. /// /// This is enforced by requiring the implementation to return a [`DecodeFinished`] /// which can only be created by calling [`DecodeFinished::assert_decoding_finished`] which is `unsafe`. fn decode_into(input: &mut I, dst: &mut MaybeUninit) -> Result { let value = Self::decode(input)?; dst.write(value); // SAFETY: We've written the decoded value to `dst` so calling this is safe. unsafe { Ok(DecodeFinished::assert_decoding_finished()) } } /// Attempt to skip the encoded value from input. /// /// The default implementation of this function is just calling [`Decode::decode`]. /// When possible, an implementation should provide a specialized implementation. fn skip(input: &mut I) -> Result<(), Error> { Self::decode(input).map(|_| ()) } /// Returns the fixed encoded size of the type. /// /// If it returns `Some(size)` then all possible values of this /// type have the given size (in bytes) when encoded. /// /// NOTE: A type with a fixed encoded size may return `None`. fn encoded_fixed_size() -> Option { None } } /// Trait that allows zero-copy read/write of value-references to/from slices in LE format. pub trait Codec: Decode + Encode {} impl Codec for S {} /// Trait that bound `EncodeLike` along with `Encode`. Usefull for generic being used in function /// with `EncodeLike` parameters. pub trait FullEncode: Encode + EncodeLike {} impl FullEncode for S {} /// Trait that bound `EncodeLike` along with `Codec`. Usefull for generic being used in function /// with `EncodeLike` parameters. pub trait FullCodec: Decode + FullEncode {} impl FullCodec for S {} /// A marker trait for types that wrap other encodable type. /// /// Such types should not carry any additional information /// that would require to be encoded, because the encoding /// is assumed to be the same as the wrapped type. /// /// The wrapped type that is referred to is the [`Deref::Target`]. pub trait WrapperTypeEncode: Deref {} impl WrapperTypeEncode for Box {} impl EncodeLike for Box {} impl EncodeLike for Box {} impl EncodeLike> for T {} impl WrapperTypeEncode for &T {} impl EncodeLike for &T {} impl EncodeLike for &T {} impl EncodeLike<&T> for T {} impl EncodeLike for &&T {} impl EncodeLike<&&T> for T {} impl WrapperTypeEncode for &mut T {} impl EncodeLike for &mut T {} impl EncodeLike for &mut T {} impl EncodeLike<&mut T> for T {} impl<'a, T: ToOwned + ?Sized> WrapperTypeEncode for Cow<'a, T> {} impl<'a, T: ToOwned + Encode + ?Sized> EncodeLike for Cow<'a, T> {} impl<'a, T: ToOwned + Encode> EncodeLike for Cow<'a, T> {} impl<'a, T: ToOwned + Encode> EncodeLike> for T {} impl WrapperTypeEncode for Rc {} impl EncodeLike for Rc {} impl EncodeLike for Rc {} impl EncodeLike> for T {} impl WrapperTypeEncode for String {} impl EncodeLike for String {} impl EncodeLike<&str> for String {} impl EncodeLike for &str {} #[cfg(target_has_atomic = "ptr")] mod atomic_ptr_targets { use super::*; impl WrapperTypeEncode for Arc {} impl EncodeLike for Arc {} impl EncodeLike for Arc {} impl EncodeLike> for T {} } #[cfg(feature = "bytes")] mod feature_wrapper_bytes { use super::*; use bytes::Bytes; impl WrapperTypeEncode for Bytes {} impl EncodeLike for Bytes {} impl EncodeLike<&[u8]> for Bytes {} impl EncodeLike> for Bytes {} impl EncodeLike for &[u8] {} impl EncodeLike for Vec {} } #[cfg(feature = "bytes")] struct BytesCursor { bytes: bytes::Bytes, position: usize } #[cfg(feature = "bytes")] impl Input for BytesCursor { fn remaining_len(&mut self) -> Result, Error> { Ok(Some(self.bytes.len() - self.position)) } fn read(&mut self, into: &mut [u8]) -> Result<(), Error> { if into.len() > self.bytes.len() - self.position { return Err("Not enough data to fill buffer".into()) } into.copy_from_slice(&self.bytes[self.position..self.position + into.len()]); self.position += into.len(); Ok(()) } fn scale_internal_decode_bytes(&mut self) -> Result { let length = >::decode(self)?.0 as usize; bytes::Buf::advance(&mut self.bytes, self.position); self.position = 0; if length > self.bytes.len() { return Err("Not enough data to fill buffer".into()); } Ok(self.bytes.split_to(length)) } } /// Decodes a given `T` from `Bytes`. #[cfg(feature = "bytes")] pub fn decode_from_bytes(bytes: bytes::Bytes) -> Result where T: Decode { // We could just use implement `Input` for `Bytes` and use `Bytes::split_to` // to move the cursor, however doing it this way allows us to prevent an // unnecessary allocation when the `T` which is being deserialized doesn't // take advantage of the fact that it's being deserialized from `Bytes`. // // `Bytes` can be cheaply created from a `Vec`. It is both zero-copy // *and* zero-allocation. However once you `.clone()` it or call `split_to()` // an extra one-time allocation is triggered where the `Bytes` changes it's internal // representation from essentially being a `Box<[u8]>` into being an `Arc>`. // // If the `T` is `Bytes` or is a structure which contains `Bytes` in it then // we don't really care, because this allocation will have to be made anyway. // // However, if `T` doesn't contain any `Bytes` then this extra allocation is // technically unnecessary, and we can avoid it by tracking the position ourselves // and treating the underlying `Bytes` as a fancy `&[u8]`. let mut input = BytesCursor { bytes, position: 0 }; T::decode(&mut input) } #[cfg(feature = "bytes")] impl Decode for bytes::Bytes { fn decode(input: &mut I) -> Result { input.scale_internal_decode_bytes() } } impl Encode for X where T: Encode + ?Sized, X: WrapperTypeEncode, { fn size_hint(&self) -> usize { (**self).size_hint() } fn using_encoded R>(&self, f: F) -> R { (**self).using_encoded(f) } fn encode(&self) -> Vec { (**self).encode() } fn encode_to(&self, dest: &mut W) { (**self).encode_to(dest) } } /// A marker trait for types that can be created solely from other decodable types. /// /// The decoding of such type is assumed to be the same as the wrapped type. pub trait WrapperTypeDecode: Sized { /// A wrapped type. type Wrapped: Into; // !INTERNAL USE ONLY! // This is a used to specialize `decode` for the wrapped type. #[doc(hidden)] #[inline] fn decode_wrapped(input: &mut I) -> Result where Self::Wrapped: Decode { input.descend_ref()?; let result = Ok(Self::Wrapped::decode(input)?.into()); input.ascend_ref(); result } } impl WrapperTypeDecode for Box { type Wrapped = T; fn decode_wrapped(input: &mut I) -> Result where Self::Wrapped: Decode { input.descend_ref()?; // Placement new is not yet stable, but we can just manually allocate a chunk of memory // and convert it to a `Box` ourselves. // // The explicit types here are written out for clarity. // // TODO: Use `Box::new_uninit` once that's stable. let layout = core::alloc::Layout::new::>(); let ptr: *mut MaybeUninit = if layout.size() == 0 { core::ptr::NonNull::dangling().as_ptr() } else { // SAFETY: Layout has a non-zero size so calling this is safe. let ptr: *mut u8 = unsafe { crate::alloc::alloc::alloc(layout) }; if ptr.is_null() { crate::alloc::alloc::handle_alloc_error(layout); } ptr.cast() }; // SAFETY: Constructing a `Box` from a piece of memory allocated with `std::alloc::alloc` // is explicitly allowed as long as it was allocated with the global allocator // and the memory layout matches. // // Constructing a `Box` from `NonNull::dangling` is also always safe as long // as the underlying type is zero-sized. let mut boxed: Box> = unsafe { Box::from_raw(ptr) }; T::decode_into(input, &mut boxed)?; // Decoding succeeded, so let's get rid of `MaybeUninit`. // // TODO: Use `Box::assume_init` once that's stable. let ptr: *mut MaybeUninit = Box::into_raw(boxed); let ptr: *mut T = ptr.cast(); // SAFETY: `MaybeUninit` doesn't affect the memory layout, so casting the pointer back // into a `Box` is safe. let boxed: Box = unsafe { Box::from_raw(ptr) }; input.ascend_ref(); Ok(boxed) } } impl WrapperTypeDecode for Rc { type Wrapped = T; fn decode_wrapped(input: &mut I) -> Result where Self::Wrapped: Decode { // TODO: This is inefficient; use `Rc::new_uninit` once that's stable. Box::::decode(input).map(|output| output.into()) } } #[cfg(target_has_atomic = "ptr")] impl WrapperTypeDecode for Arc { type Wrapped = T; fn decode_wrapped(input: &mut I) -> Result where Self::Wrapped: Decode { // TODO: This is inefficient; use `Arc::new_uninit` once that's stable. Box::::decode(input).map(|output| output.into()) } } impl Decode for X where T: Decode + Into, X: WrapperTypeDecode, { #[inline] fn decode(input: &mut I) -> Result { Self::decode_wrapped(input) } } /// A macro that matches on a [`TypeInfo`] and expands a given macro per variant. /// /// The first parameter to the given macro will be the type of variant (e.g. `u8`, `u32`, etc.) and other parameters /// given to this macro. /// /// The last parameter is the code that should be executed for the `Unknown` type info. macro_rules! with_type_info { ( $type_info:expr, $macro:ident $( ( $( $params:ident ),* ) )?, { $( $unknown_variant:tt )* }, ) => { match $type_info { TypeInfo::U8 => { $macro!(u8 $( $( , $params )* )? ) }, TypeInfo::I8 => { $macro!(i8 $( $( , $params )* )? ) }, TypeInfo::U16 => { $macro!(u16 $( $( , $params )* )? ) }, TypeInfo::I16 => { $macro!(i16 $( $( , $params )* )? ) }, TypeInfo::U32 => { $macro!(u32 $( $( , $params )* )? ) }, TypeInfo::I32 => { $macro!(i32 $( $( , $params )* )? ) }, TypeInfo::U64 => { $macro!(u64 $( $( , $params )* )? ) }, TypeInfo::I64 => { $macro!(i64 $( $( , $params )* )? ) }, TypeInfo::U128 => { $macro!(u128 $( $( , $params )* )? ) }, TypeInfo::I128 => { $macro!(i128 $( $( , $params )* )? ) }, TypeInfo::Unknown => { $( $unknown_variant )* }, TypeInfo::F32 => { $macro!(f32 $( $( , $params )* )? ) }, TypeInfo::F64 => { $macro!(f64 $( $( , $params )* )? ) }, } }; } /// Something that can be encoded as a reference. pub trait EncodeAsRef<'a, T: 'a> { /// The reference type that is used for encoding. type RefType: Encode + From<&'a T>; } impl Encode for Result { fn size_hint(&self) -> usize { 1 + match *self { Ok(ref t) => t.size_hint(), Err(ref t) => t.size_hint(), } } fn encode_to(&self, dest: &mut W) { match *self { Ok(ref t) => { dest.push_byte(0); t.encode_to(dest); } Err(ref e) => { dest.push_byte(1); e.encode_to(dest); } } } } impl EncodeLike> for Result where T: EncodeLike, LikeT: Encode, E: EncodeLike, LikeE: Encode, {} impl Decode for Result { fn decode(input: &mut I) -> Result { match input.read_byte() .map_err(|e| e.chain("Could not result variant byte for `Result`"))? { 0 => Ok( Ok(T::decode(input).map_err(|e| e.chain("Could not Decode `Result::Ok(T)`"))?) ), 1 => Ok( Err(E::decode(input).map_err(|e| e.chain("Could not decode `Result::Error(E)`"))?) ), _ => Err("unexpected first byte decoding Result".into()), } } } /// Shim type because we can't do a specialised implementation for `Option` directly. #[derive(Eq, PartialEq, Clone, Copy)] pub struct OptionBool(pub Option); impl fmt::Debug for OptionBool { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.0.fmt(f) } } impl Encode for OptionBool { fn size_hint(&self) -> usize { 1 } fn using_encoded R>(&self, f: F) -> R { f(&[match *self { OptionBool(None) => 0u8, OptionBool(Some(true)) => 1u8, OptionBool(Some(false)) => 2u8, }]) } } impl EncodeLike for OptionBool {} impl Decode for OptionBool { fn decode(input: &mut I) -> Result { match input.read_byte()? { 0 => Ok(OptionBool(None)), 1 => Ok(OptionBool(Some(true))), 2 => Ok(OptionBool(Some(false))), _ => Err("unexpected first byte decoding OptionBool".into()), } } } impl, U: Encode> EncodeLike> for Option {} impl Encode for Option { fn size_hint(&self) -> usize { 1 + match *self { Some(ref t) => t.size_hint(), None => 0, } } fn encode_to(&self, dest: &mut W) { match *self { Some(ref t) => { dest.push_byte(1); t.encode_to(dest); } None => dest.push_byte(0), } } } impl Decode for Option { fn decode(input: &mut I) -> Result { match input.read_byte() .map_err(|e| e.chain("Could not decode variant byte for `Option`"))? { 0 => Ok(None), 1 => Ok( Some(T::decode(input).map_err(|e| e.chain("Could not decode `Option::Some(T)`"))?) ), _ => Err("unexpected first byte decoding Option".into()), } } } macro_rules! impl_for_non_zero { ( $( $name:ty ),* $(,)? ) => { $( impl Encode for $name { fn size_hint(&self) -> usize { self.get().size_hint() } fn encode_to(&self, dest: &mut W) { self.get().encode_to(dest) } fn encode(&self) -> Vec { self.get().encode() } fn using_encoded R>(&self, f: F) -> R { self.get().using_encoded(f) } } impl Decode for $name { fn decode(input: &mut I) -> Result { Self::new(Decode::decode(input)?) .ok_or_else(|| Error::from("cannot create non-zero number from 0")) } } )* } } /// Encode the slice without prepending the len. /// /// This is equivalent to encoding all the element one by one, but it is optimized for some types. pub(crate) fn encode_slice_no_len(slice: &[T], dest: &mut W) { macro_rules! encode_to { ( u8, $slice:ident, $dest:ident ) => {{ let typed = unsafe { mem::transmute::<&[T], &[u8]>(&$slice[..]) }; $dest.write(&typed) }}; ( i8, $slice:ident, $dest:ident ) => {{ // `i8` has the same size as `u8`. We can just convert it here and write to the // dest buffer directly. let typed = unsafe { mem::transmute::<&[T], &[u8]>(&$slice[..]) }; $dest.write(&typed) }}; ( $ty:ty, $slice:ident, $dest:ident ) => {{ if cfg!(target_endian = "little") { let typed = unsafe { mem::transmute::<&[T], &[$ty]>(&$slice[..]) }; $dest.write(<[$ty] as AsByteSlice<$ty>>::as_byte_slice(typed)) } else { for item in $slice.iter() { item.encode_to(dest); } } }}; } with_type_info! { ::TYPE_INFO, encode_to(slice, dest), { for item in slice.iter() { item.encode_to(dest); } }, } } /// Decode the vec (without a prepended len). /// /// This is equivalent to decode all elements one by one, but it is optimized in some /// situation. pub fn decode_vec_with_len( input: &mut I, len: usize, ) -> Result, Error> { fn decode_unoptimized( input: &mut I, items_len: usize, ) -> Result, Error> { let input_capacity = input.remaining_len()? .unwrap_or(MAX_PREALLOCATION) .checked_div(mem::size_of::()) .unwrap_or(0); let mut r = Vec::with_capacity(input_capacity.min(items_len)); input.descend_ref()?; for _ in 0..items_len { r.push(T::decode(input)?); } input.ascend_ref(); Ok(r) } macro_rules! decode { ( $ty:ty, $input:ident, $len:ident ) => {{ if cfg!(target_endian = "little") || mem::size_of::() == 1 { let vec = read_vec_from_u8s::<_, $ty>($input, $len)?; Ok(unsafe { mem::transmute::, Vec>(vec) }) } else { decode_unoptimized($input, $len) } }}; } with_type_info! { ::TYPE_INFO, decode(input, len), { decode_unoptimized(input, len) }, } } impl_for_non_zero! { NonZeroI8, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI128, NonZeroU8, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU128, } impl Encode for [T; N] { fn size_hint(&self) -> usize { mem::size_of::() * N } fn encode_to(&self, dest: &mut W) { encode_slice_no_len(&self[..], dest) } } const fn calculate_array_bytesize() -> usize { struct AssertNotOverflow(PhantomData); impl AssertNotOverflow { const OK: () = assert!(mem::size_of::().checked_mul(N).is_some(), "array size overflow"); } #[allow(clippy::let_unit_value)] let () = AssertNotOverflow::::OK; mem::size_of::() * N } impl Decode for [T; N] { #[inline(always)] fn decode(input: &mut I) -> Result { let mut array = MaybeUninit::uninit(); Self::decode_into(input, &mut array)?; // SAFETY: `decode_into` succeeded, so the array is initialized. unsafe { Ok(array.assume_init()) } } fn decode_into(input: &mut I, dst: &mut MaybeUninit) -> Result { let is_primitive = match ::TYPE_INFO { | TypeInfo::U8 | TypeInfo::I8 => true, | TypeInfo::U16 | TypeInfo::I16 | TypeInfo::U32 | TypeInfo::I32 | TypeInfo::U64 | TypeInfo::I64 | TypeInfo::U128 | TypeInfo::I128 | TypeInfo::F32 | TypeInfo::F64 => cfg!(target_endian = "little"), TypeInfo::Unknown => false }; if is_primitive { // Let's read the array in bulk as that's going to be a lot // faster than just reading each element one-by-one. let ptr: *mut [T; N] = dst.as_mut_ptr(); let ptr: *mut u8 = ptr.cast(); let bytesize = calculate_array_bytesize::(); // TODO: This is potentially slow; it'd be better if `Input` supported // reading directly into uninitialized memory. // // SAFETY: The pointer is valid and points to a memory `bytesize` bytes big. unsafe { ptr.write_bytes(0, bytesize); } // SAFETY: We've zero-initialized everything so creating a slice here is safe. let slice: &mut [u8] = unsafe { core::slice::from_raw_parts_mut(ptr, bytesize) }; input.read(slice)?; // SAFETY: We've initialized the whole slice so calling this is safe. unsafe { return Ok(DecodeFinished::assert_decoding_finished()); } } let slice: &mut [MaybeUninit; N] = { let ptr: *mut [T; N] = dst.as_mut_ptr(); let ptr: *mut [MaybeUninit; N] = ptr.cast(); // SAFETY: Casting `&mut MaybeUninit<[T; N]>` into `&mut [MaybeUninit; N]` is safe. unsafe { &mut *ptr } }; /// A wrapper type to make sure the partially read elements are always /// dropped in case an error occurs or the underlying `decode` implementation panics. struct State<'a, T, const N: usize> { count: usize, slice: &'a mut [MaybeUninit; N] } impl<'a, T, const N: usize> Drop for State<'a, T, N> { fn drop(&mut self) { if !mem::needs_drop::() { // If the types don't actually need to be dropped then don't even // try to run the loop below. // // Most likely won't make a difference in release mode, but will // make a difference in debug mode. return; } // TODO: Use `MaybeUninit::slice_assume_init_mut` + `core::ptr::drop_in_place` // once `slice_assume_init_mut` is stable. for item in &mut self.slice[..self.count] { // SAFETY: Each time we've read a new element we incremented `count`, // and we only drop at most `count` elements here, // so all of the elements we drop here are valid. unsafe { item.assume_init_drop(); } } } } let mut state = State { count: 0, slice }; while state.count < state.slice.len() { T::decode_into(input, &mut state.slice[state.count])?; state.count += 1; } // We've successfully read everything, so disarm the `Drop` impl. mem::forget(state); // SAFETY: We've initialized the whole slice so calling this is safe. unsafe { Ok(DecodeFinished::assert_decoding_finished()) } } fn skip(input: &mut I) -> Result<(), Error> { if Self::encoded_fixed_size().is_some() { // Should skip the bytes, but Input does not support skip. for _ in 0..N { T::skip(input)?; } } else { Self::decode(input)?; } Ok(()) } fn encoded_fixed_size() -> Option { Some(::encoded_fixed_size()? * N) } } impl, U: Encode, const N: usize> EncodeLike<[U; N]> for [T; N] {} impl Encode for str { fn size_hint(&self) -> usize { self.as_bytes().size_hint() } fn encode_to(&self, dest: &mut W) { self.as_bytes().encode_to(dest) } fn encode(&self) -> Vec { self.as_bytes().encode() } fn using_encoded R>(&self, f: F) -> R { self.as_bytes().using_encoded(f) } } impl<'a, T: ToOwned + ?Sized> Decode for Cow<'a, T> where ::Owned: Decode, { fn decode(input: &mut I) -> Result { Ok(Cow::Owned(Decode::decode(input)?)) } } impl EncodeLike for PhantomData {} impl Encode for PhantomData { fn encode_to(&self, _dest: &mut W) {} } impl Decode for PhantomData { fn decode(_input: &mut I) -> Result { Ok(PhantomData) } } impl Decode for String { fn decode(input: &mut I) -> Result { Self::from_utf8(Vec::decode(input)?).map_err(|_| "Invalid utf8 sequence".into()) } } /// Writes the compact encoding of `len` do `dest`. pub(crate) fn compact_encode_len_to(dest: &mut W, len: usize) -> Result<(), Error> { if len > u32::MAX as usize { return Err("Attempted to serialize a collection with too many elements.".into()); } Compact(len as u32).encode_to(dest); Ok(()) } impl Encode for [T] { fn size_hint(&self) -> usize { mem::size_of::() + mem::size_of_val(self) } fn encode_to(&self, dest: &mut W) { compact_encode_len_to(dest, self.len()).expect("Compact encodes length"); encode_slice_no_len(self, dest) } } /// Create a `Vec` by casting directly from a buffer of read `u8`s /// /// The encoding of `T` must be equal to its binary representation, and size of `T` must be less or /// equal to [`MAX_PREALLOCATION`]. pub(crate) fn read_vec_from_u8s(input: &mut I, items_len: usize) -> Result, Error> where I: Input, T: ToMutByteSlice + Default + Clone, { debug_assert!(MAX_PREALLOCATION >= mem::size_of::(), "Invalid precondition"); let byte_len = items_len.checked_mul(mem::size_of::()) .ok_or("Item is too big and cannot be allocated")?; let input_len = input.remaining_len()?; // If there is input len and it cannot be pre-allocated then return directly. if input_len.map(|l| l < byte_len).unwrap_or(false) { return Err("Not enough data to decode vector".into()) } // In both these branches we're going to be creating and resizing a Vec, // but casting it to a &mut [u8] for reading. // Note: we checked that if input_len is some then it can preallocated. let r = if input_len.is_some() || byte_len < MAX_PREALLOCATION { // Here we pre-allocate the whole buffer. let mut items: Vec = vec![Default::default(); items_len]; let bytes_slice = items.as_mut_byte_slice(); input.read(bytes_slice)?; items } else { // An allowed number of preallocated item. // Note: `MAX_PREALLOCATION` is expected to be more or equal to size of `T`, precondition. let max_preallocated_items = MAX_PREALLOCATION / mem::size_of::(); // Here we pre-allocate only the maximum pre-allocation let mut items: Vec = vec![]; let mut items_remains = items_len; while items_remains > 0 { let items_len_read = max_preallocated_items.min(items_remains); let items_len_filled = items.len(); let items_new_size = items_len_filled + items_len_read; items.reserve_exact(items_len_read); unsafe { items.set_len(items_new_size); } let bytes_slice = items.as_mut_byte_slice(); let bytes_len_filled = items_len_filled * mem::size_of::(); input.read(&mut bytes_slice[bytes_len_filled..])?; items_remains = items_remains.saturating_sub(items_len_read); } items }; Ok(r) } impl WrapperTypeEncode for Vec {} impl, U: Encode> EncodeLike> for Vec {} impl, U: Encode> EncodeLike<&[U]> for Vec {} impl, U: Encode> EncodeLike> for &[T] {} impl Decode for Vec { fn decode(input: &mut I) -> Result { >::decode(input).and_then(move |Compact(len)| { decode_vec_with_len(input, len as usize) }) } } macro_rules! impl_codec_through_iterator { ($( $type:ident { $( $generics:ident $( : $decode_additional:ident )? ),* } { $( $type_like_generics:ident ),* } { $( $impl_like_generics:tt )* } )*) => {$( impl<$( $generics: Encode ),*> Encode for $type<$( $generics, )*> { fn size_hint(&self) -> usize { mem::size_of::() $( + mem::size_of::<$generics>() * self.len() )* } fn encode_to(&self, dest: &mut W) { compact_encode_len_to(dest, self.len()).expect("Compact encodes length"); for i in self.iter() { i.encode_to(dest); } } } impl<$( $generics: Decode $( + $decode_additional )? ),*> Decode for $type<$( $generics, )*> { fn decode(input: &mut I) -> Result { >::decode(input).and_then(move |Compact(len)| { input.descend_ref()?; let result = Result::from_iter((0..len).map(|_| Decode::decode(input))); input.ascend_ref(); result }) } } impl<$( $impl_like_generics )*> EncodeLike<$type<$( $type_like_generics ),*>> for $type<$( $generics ),*> {} impl<$( $impl_like_generics )*> EncodeLike<&[( $( $type_like_generics, )* )]> for $type<$( $generics ),*> {} impl<$( $impl_like_generics )*> EncodeLike<$type<$( $type_like_generics ),*>> for &[( $( $generics, )* )] {} )*} } impl_codec_through_iterator! { BTreeMap { K: Ord, V } { LikeK, LikeV} { K: EncodeLike, LikeK: Encode, V: EncodeLike, LikeV: Encode } BTreeSet { T: Ord } { LikeT } { T: EncodeLike, LikeT: Encode } LinkedList { T } { LikeT } { T: EncodeLike, LikeT: Encode } BinaryHeap { T: Ord } { LikeT } { T: EncodeLike, LikeT: Encode } } impl EncodeLike for VecDeque {} impl, U: Encode> EncodeLike<&[U]> for VecDeque {} impl, U: Encode> EncodeLike> for &[T] {} impl, U: Encode> EncodeLike> for VecDeque {} impl, U: Encode> EncodeLike> for Vec {} impl Encode for VecDeque { fn size_hint(&self) -> usize { mem::size_of::() + mem::size_of::() * self.len() } fn encode_to(&self, dest: &mut W) { compact_encode_len_to(dest, self.len()).expect("Compact encodes length"); macro_rules! encode_to { ( $ty:ty, $self:ident, $dest:ident ) => {{ if cfg!(target_endian = "little") || mem::size_of::() == 1 { let slices = $self.as_slices(); let typed = unsafe { core::mem::transmute::<(&[T], &[T]), (&[$ty], &[$ty])>(slices) }; $dest.write(<[$ty] as AsByteSlice<$ty>>::as_byte_slice(typed.0)); $dest.write(<[$ty] as AsByteSlice<$ty>>::as_byte_slice(typed.1)); } else { for item in $self { item.encode_to($dest); } } }}; } with_type_info! { ::TYPE_INFO, encode_to(self, dest), { for item in self { item.encode_to(dest); } }, } } } impl Decode for VecDeque { fn decode(input: &mut I) -> Result { Ok(>::decode(input)?.into()) } } impl EncodeLike for () {} impl Encode for () { fn encode_to(&self, _dest: &mut W) { } fn using_encoded R>(&self, f: F) -> R { f(&[]) } fn encode(&self) -> Vec { Vec::new() } } impl Decode for () { fn decode(_: &mut I) -> Result<(), Error> { Ok(()) } } macro_rules! impl_len { ( $( $type:ident< $($g:ident),* > ),* ) => { $( impl<$($g),*> DecodeLength for $type<$($g),*> { fn len(mut self_encoded: &[u8]) -> Result { usize::try_from(u32::from(Compact::::decode(&mut self_encoded)?)) .map_err(|_| "Failed convert decoded size into usize.".into()) } } )*} } // Collection types that support compact decode length. impl_len!(Vec, BTreeSet, BTreeMap, VecDeque, BinaryHeap, LinkedList); macro_rules! tuple_impl { ( ($one:ident, $extra:ident), ) => { impl<$one: Encode> Encode for ($one,) { fn size_hint(&self) -> usize { self.0.size_hint() } fn encode_to(&self, dest: &mut T) { self.0.encode_to(dest); } fn encode(&self) -> Vec { self.0.encode() } fn using_encoded R>(&self, f: F) -> R { self.0.using_encoded(f) } } impl<$one: Decode> Decode for ($one,) { fn decode(input: &mut I) -> Result { match $one::decode(input) { Err(e) => Err(e), Ok($one) => Ok(($one,)), } } } impl<$one: DecodeLength> DecodeLength for ($one,) { fn len(self_encoded: &[u8]) -> Result { $one::len(self_encoded) } } impl<$one: EncodeLike<$extra>, $extra: Encode> crate::EncodeLike<($extra,)> for ($one,) {} }; (($first:ident, $fextra:ident), $( ( $rest:ident, $rextra:ident ), )+) => { impl<$first: Encode, $($rest: Encode),+> Encode for ($first, $($rest),+) { fn size_hint(&self) -> usize { let ( ref $first, $(ref $rest),+ ) = *self; $first.size_hint() $( + $rest.size_hint() )+ } fn encode_to(&self, dest: &mut T) { let ( ref $first, $(ref $rest),+ ) = *self; $first.encode_to(dest); $($rest.encode_to(dest);)+ } } impl<$first: Decode, $($rest: Decode),+> Decode for ($first, $($rest),+) { fn decode(input: &mut INPUT) -> Result { Ok(( match $first::decode(input) { Ok(x) => x, Err(e) => return Err(e), }, $(match $rest::decode(input) { Ok(x) => x, Err(e) => return Err(e), },)+ )) } } impl<$first: EncodeLike<$fextra>, $fextra: Encode, $($rest: EncodeLike<$rextra>, $rextra: Encode),+> crate::EncodeLike<($fextra, $( $rextra ),+)> for ($first, $($rest),+) {} impl<$first: DecodeLength, $($rest),+> DecodeLength for ($first, $($rest),+) { fn len(self_encoded: &[u8]) -> Result { $first::len(self_encoded) } } tuple_impl!( $( ($rest, $rextra), )+ ); } } #[allow(non_snake_case)] mod inner_tuple_impl { use super::*; tuple_impl!( (A0, A1), (B0, B1), (C0, C1), (D0, D1), (E0, E1), (F0, F1), (G0, G1), (H0, H1), (I0, I1), (J0, J1), (K0, K1), (L0, L1), (M0, M1), (N0, N1), (O0, O1), (P0, P1), (Q0, Q1), (R0, R1), ); } macro_rules! impl_endians { ( $( $t:ty; $ty_info:ident ),* ) => { $( impl EncodeLike for $t {} impl Encode for $t { const TYPE_INFO: TypeInfo = TypeInfo::$ty_info; fn size_hint(&self) -> usize { mem::size_of::<$t>() } fn using_encoded R>(&self, f: F) -> R { let buf = self.to_le_bytes(); f(&buf[..]) } } impl Decode for $t { const TYPE_INFO: TypeInfo = TypeInfo::$ty_info; fn decode(input: &mut I) -> Result { let mut buf = [0u8; mem::size_of::<$t>()]; input.read(&mut buf)?; Ok(<$t>::from_le_bytes(buf)) } fn encoded_fixed_size() -> Option { Some(mem::size_of::<$t>()) } } )* } } macro_rules! impl_one_byte { ( $( $t:ty; $ty_info:ident ),* ) => { $( impl EncodeLike for $t {} impl Encode for $t { const TYPE_INFO: TypeInfo = TypeInfo::$ty_info; fn size_hint(&self) -> usize { mem::size_of::<$t>() } fn using_encoded R>(&self, f: F) -> R { f(&[*self as u8][..]) } } impl Decode for $t { const TYPE_INFO: TypeInfo = TypeInfo::$ty_info; fn decode(input: &mut I) -> Result { Ok(input.read_byte()? as $t) } } )* } } impl_endians!(u16; U16, u32; U32, u64; U64, u128; U128, i16; I16, i32; I32, i64; I64, i128; I128); impl_one_byte!(u8; U8, i8; I8); impl_endians!(f32; F32, f64; F64); impl EncodeLike for bool {} impl Encode for bool { fn size_hint(&self) -> usize { mem::size_of::() } fn using_encoded R>(&self, f: F) -> R { f(&[*self as u8][..]) } } impl Decode for bool { fn decode(input: &mut I) -> Result { let byte = input.read_byte()?; match byte { 0 => Ok(false), 1 => Ok(true), _ => Err("Invalid boolean representation".into()) } } fn encoded_fixed_size() -> Option { Some(1) } } impl Encode for Duration { fn size_hint(&self) -> usize { mem::size_of::() + mem::size_of::() } fn encode(&self) -> Vec { let secs = self.as_secs(); let nanos = self.subsec_nanos(); (secs, nanos).encode() } } impl Decode for Duration { fn decode(input: &mut I) -> Result { let (secs, nanos) = <(u64, u32)>::decode(input) .map_err(|e| e.chain("Could not decode `Duration(u64, u32)`"))?; if nanos >= A_BILLION { Err("Could not decode `Duration`: Number of nanoseconds should not be higher than 10^9.".into()) } else { Ok(Duration::new(secs, nanos)) } } } impl EncodeLike for Duration {} impl Encode for Range where T: Encode { fn size_hint(&self) -> usize { 2 * mem::size_of::() } fn encode(&self) -> Vec { (&self.start, &self.end).encode() } } impl Decode for Range where T: Decode { fn decode(input: &mut I) -> Result { let (start, end) = <(T, T)>::decode(input) .map_err(|e| e.chain("Could not decode `Range`"))?; Ok(Range { start, end }) } } impl Encode for RangeInclusive where T: Encode { fn size_hint(&self) -> usize { 2 * mem::size_of::() } fn encode(&self) -> Vec { (self.start(), self.end()).encode() } } impl Decode for RangeInclusive where T: Decode { fn decode(input: &mut I) -> Result { let (start, end) = <(T, T)>::decode(input) .map_err(|e| e.chain("Could not decode `RangeInclusive`"))?; Ok(RangeInclusive::new(start, end)) } } #[cfg(test)] mod tests { use super::*; use std::borrow::Cow; #[test] fn vec_is_sliceable() { let v = b"Hello world".to_vec(); v.using_encoded(|ref slice| assert_eq!(slice, &b"\x2cHello world") ); } #[test] fn encode_borrowed_tuple() { let x = vec![1u8, 2, 3, 4]; let y = 128i64; let encoded = (&x, &y).encode(); assert_eq!((x, y), Decode::decode(&mut &encoded[..]).unwrap()); } #[test] fn cow_works() { let x = &[1u32, 2, 3, 4, 5, 6][..]; let y = Cow::Borrowed(&x); assert_eq!(x.encode(), y.encode()); let z: Cow<'_, [u32]> = Cow::decode(&mut &x.encode()[..]).unwrap(); assert_eq!(*z, *x); } #[test] fn cow_string_works() { let x = "Hello world!"; let y = Cow::Borrowed(&x); assert_eq!(x.encode(), y.encode()); let z: Cow<'_, str> = Cow::decode(&mut &x.encode()[..]).unwrap(); assert_eq!(*z, *x); } fn hexify(bytes: &[u8]) -> String { bytes.iter().map(|ref b| format!("{:02x}", b)).collect::>().join(" ") } #[test] fn string_encoded_as_expected() { let value = String::from("Hello, World!"); let encoded = value.encode(); assert_eq!(hexify(&encoded), "34 48 65 6c 6c 6f 2c 20 57 6f 72 6c 64 21"); assert_eq!(::decode(&mut &encoded[..]).unwrap(), value); } #[test] fn vec_of_u8_encoded_as_expected() { let value = vec![0u8, 1, 1, 2, 3, 5, 8, 13, 21, 34]; let encoded = value.encode(); assert_eq!(hexify(&encoded), "28 00 01 01 02 03 05 08 0d 15 22"); assert_eq!(>::decode(&mut &encoded[..]).unwrap(), value); } #[test] fn vec_of_i16_encoded_as_expected() { let value = vec![0i16, 1, -1, 2, -2, 3, -3]; let encoded = value.encode(); assert_eq!(hexify(&encoded), "1c 00 00 01 00 ff ff 02 00 fe ff 03 00 fd ff"); assert_eq!(>::decode(&mut &encoded[..]).unwrap(), value); } #[test] fn vec_of_option_int_encoded_as_expected() { let value = vec![Some(1i8), Some(-1), None]; let encoded = value.encode(); assert_eq!(hexify(&encoded), "0c 01 01 01 ff 00"); assert_eq!(>>::decode(&mut &encoded[..]).unwrap(), value); } #[test] fn vec_of_option_bool_encoded_as_expected() { let value = vec![OptionBool(Some(true)), OptionBool(Some(false)), OptionBool(None)]; let encoded = value.encode(); assert_eq!(hexify(&encoded), "0c 01 02 00"); assert_eq!(>::decode(&mut &encoded[..]).unwrap(), value); } #[cfg(feature = "bytes")] #[test] fn bytes_works_as_expected() { let input = bytes::Bytes::from_static(b"hello"); let encoded = Encode::encode(&input); let encoded_vec = input.to_vec().encode(); assert_eq!(encoded, encoded_vec); assert_eq!( &b"hello"[..], bytes::Bytes::decode(&mut &encoded[..]).unwrap(), ); } #[cfg(feature = "bytes")] #[test] fn bytes_deserialized_from_bytes_is_zero_copy() { let encoded = bytes::Bytes::from(Encode::encode(&b"hello".to_vec())); let decoded = decode_from_bytes::(encoded.clone()).unwrap(); assert_eq!(decoded, &b"hello"[..]); // The `slice_ref` will panic if the `decoded` is not a subslice of `encoded`. assert_eq!(encoded.slice_ref(&decoded), &b"hello"[..]); } #[cfg(feature = "bytes")] #[test] fn nested_bytes_deserialized_from_bytes_is_zero_copy() { let encoded = bytes::Bytes::from(Encode::encode(&Some(b"hello".to_vec()))); let decoded = decode_from_bytes::>(encoded.clone()).unwrap(); let decoded = decoded.as_ref().unwrap(); assert_eq!(decoded, &b"hello"[..]); // The `slice_ref` will panic if the `decoded` is not a subslice of `encoded`. assert_eq!(encoded.slice_ref(&decoded), &b"hello"[..]); } fn test_encode_length(thing: &T, len: usize) { assert_eq!(::len(&thing.encode()[..]).unwrap(), len); } #[test] fn len_works_for_decode_collection_types() { let vector = vec![10; 10]; let mut btree_map: BTreeMap = BTreeMap::new(); btree_map.insert(1, 1); btree_map.insert(2, 2); let mut btree_set: BTreeSet = BTreeSet::new(); btree_set.insert(1); btree_set.insert(2); let mut vd = VecDeque::new(); vd.push_front(1); vd.push_front(2); let mut bh = BinaryHeap::new(); bh.push(1); bh.push(2); let mut ll = LinkedList::new(); ll.push_back(1); ll.push_back(2); let t1: (Vec<_>,) = (vector.clone(),); let t2: (Vec<_>, u32) = (vector.clone(), 3u32); test_encode_length(&vector, 10); test_encode_length(&btree_map, 2); test_encode_length(&btree_set, 2); test_encode_length(&vd, 2); test_encode_length(&bh, 2); test_encode_length(&ll, 2); test_encode_length(&t1, 10); test_encode_length(&t2, 10); } #[test] fn vec_of_string_encoded_as_expected() { let value = vec![ "Hamlet".to_owned(), "Война и мир".to_owned(), "三国演义".to_owned(), "أَلْف لَيْلَة وَلَيْلَة‎".to_owned() ]; let encoded = value.encode(); assert_eq!(hexify(&encoded), "10 18 48 61 6d 6c 65 74 50 d0 92 d0 be d0 b9 d0 bd d0 b0 20 d0 \ b8 20 d0 bc d0 b8 d1 80 30 e4 b8 89 e5 9b bd e6 bc 94 e4 b9 89 bc d8 a3 d9 8e d9 84 d9 92 \ d9 81 20 d9 84 d9 8e d9 8a d9 92 d9 84 d9 8e d8 a9 20 d9 88 d9 8e d9 84 d9 8e d9 8a d9 92 \ d9 84 d9 8e d8 a9 e2 80 8e"); assert_eq!(>::decode(&mut &encoded[..]).unwrap(), value); } #[derive(Debug, PartialEq)] struct MyWrapper(Compact); impl Deref for MyWrapper { type Target = Compact; fn deref(&self) -> &Self::Target { &self.0 } } impl WrapperTypeEncode for MyWrapper {} impl From> for MyWrapper { fn from(c: Compact) -> Self { MyWrapper(c) } } impl WrapperTypeDecode for MyWrapper { type Wrapped = Compact; } #[test] fn should_work_for_wrapper_types() { let result = vec![0b1100]; assert_eq!(MyWrapper(3u32.into()).encode(), result); assert_eq!(MyWrapper::decode(&mut &*result).unwrap(), MyWrapper(3_u32.into())); } #[test] fn codec_vec_deque_u8_and_u16() { let mut v_u8 = VecDeque::new(); let mut v_u16 = VecDeque::new(); for i in 0..50 { v_u8.push_front(i as u8); v_u16.push_front(i as u16); } for i in 50..100 { v_u8.push_back(i as u8); v_u16.push_back(i as u16); } assert_eq!(Decode::decode(&mut &v_u8.encode()[..]), Ok(v_u8)); assert_eq!(Decode::decode(&mut &v_u16.encode()[..]), Ok(v_u16)); } #[test] fn codec_iterator() { let t1: BTreeSet = FromIterator::from_iter((0..10).flat_map(|i| 0..i)); let t2: LinkedList = FromIterator::from_iter((0..10).flat_map(|i| 0..i)); let t3: BinaryHeap = FromIterator::from_iter((0..10).flat_map(|i| 0..i)); let t4: BTreeMap = FromIterator::from_iter( (0..10) .flat_map(|i| 0..i) .map(|i| (i as u16, i + 10)) ); let t5: BTreeSet> = FromIterator::from_iter((0..10).map(|i| Vec::from_iter(0..i))); let t6: LinkedList> = FromIterator::from_iter((0..10).map(|i| Vec::from_iter(0..i))); let t7: BinaryHeap> = FromIterator::from_iter((0..10).map(|i| Vec::from_iter(0..i))); let t8: BTreeMap, u32> = FromIterator::from_iter( (0..10) .map(|i| Vec::from_iter(0..i)) .map(|i| (i.clone(), i.len() as u32)) ); assert_eq!(Decode::decode(&mut &t1.encode()[..]), Ok(t1)); assert_eq!(Decode::decode(&mut &t2.encode()[..]), Ok(t2)); assert_eq!( Decode::decode(&mut &t3.encode()[..]).map(BinaryHeap::into_sorted_vec), Ok(t3.into_sorted_vec()), ); assert_eq!(Decode::decode(&mut &t4.encode()[..]), Ok(t4)); assert_eq!(Decode::decode(&mut &t5.encode()[..]), Ok(t5)); assert_eq!(Decode::decode(&mut &t6.encode()[..]), Ok(t6)); assert_eq!( Decode::decode(&mut &t7.encode()[..]).map(BinaryHeap::into_sorted_vec), Ok(t7.into_sorted_vec()), ); assert_eq!(Decode::decode(&mut &t8.encode()[..]), Ok(t8)); } #[test] fn io_reader() { let mut io_reader = IoReader(std::io::Cursor::new(&[1u8, 2, 3][..])); let mut v = [0; 2]; io_reader.read(&mut v[..]).unwrap(); assert_eq!(v, [1, 2]); assert_eq!(io_reader.read_byte().unwrap(), 3); assert_eq!(io_reader.read_byte(), Err("io error: UnexpectedEof".into())); } #[test] fn shared_references_implement_encode() { Arc::new(10u32).encode(); Rc::new(10u32).encode(); } #[test] fn not_limit_input_test() { use crate::Input; struct NoLimit<'a>(&'a [u8]); impl<'a> Input for NoLimit<'a> { fn remaining_len(&mut self) -> Result, Error> { Ok(None) } fn read(&mut self, into: &mut [u8]) -> Result<(), Error> { self.0.read(into) } } let len = MAX_PREALLOCATION * 2 + 1; let mut i = Compact(len as u32).encode(); i.resize(i.len() + len, 0); assert_eq!(>::decode(&mut NoLimit(&i[..])).unwrap(), vec![0u8; len]); let i = Compact(len as u32).encode(); assert_eq!( >::decode(&mut NoLimit(&i[..])).err().unwrap().to_string(), "Not enough data to fill buffer", ); let i = Compact(1000u32).encode(); assert_eq!( >::decode(&mut NoLimit(&i[..])).err().unwrap().to_string(), "Not enough data to fill buffer", ); } #[test] fn boolean() { assert_eq!(true.encode(), vec![1]); assert_eq!(false.encode(), vec![0]); assert_eq!(bool::decode(&mut &[1][..]).unwrap(), true); assert_eq!(bool::decode(&mut &[0][..]).unwrap(), false); } #[test] fn some_encode_like() { fn t() {} t::<&[u8]>(); t::<&str>(); } #[test] fn vec_deque_encode_like_vec() { let data: VecDeque = vec![1, 2, 3, 4, 5, 6].into(); let encoded = data.encode(); let decoded = Vec::::decode(&mut &encoded[..]).unwrap(); assert!(decoded.iter().all(|v| data.contains(&v))); assert_eq!(data.len(), decoded.len()); let encoded = decoded.encode(); let decoded = VecDeque::::decode(&mut &encoded[..]).unwrap(); assert_eq!(data, decoded); } #[test] fn vec_decode_right_capacity() { let data: Vec = vec![1, 2, 3]; let mut encoded = data.encode(); encoded.resize(encoded.len() * 2, 0); let decoded = Vec::::decode(&mut &encoded[..]).unwrap(); assert_eq!(data, decoded); assert_eq!(decoded.capacity(), decoded.len()); // Check with non-integer type let data: Vec = vec!["1".into(), "2".into(), "3".into()]; let mut encoded = data.encode(); encoded.resize(65536, 0); let decoded = Vec::::decode(&mut &encoded[..]).unwrap(); assert_eq!(data, decoded); assert_eq!(decoded.capacity(), decoded.len()); } #[test] fn duration() { let num_secs = 13; let num_nanos = 37; let duration = Duration::new(num_secs, num_nanos); let expected = (num_secs, num_nanos as u32).encode(); assert_eq!(duration.encode(), expected); assert_eq!(Duration::decode(&mut &expected[..]).unwrap(), duration); } #[test] fn malformed_duration_encoding_fails() { // This test should fail, as the number of nanoseconds encoded is exactly 10^9. let invalid_nanos = A_BILLION; let encoded = (0u64, invalid_nanos).encode(); assert!(Duration::decode(&mut &encoded[..]).is_err()); let num_secs = 1u64; let num_nanos = 37u32; let invalid_nanos = num_secs as u32 * A_BILLION + num_nanos; let encoded = (num_secs, invalid_nanos).encode(); // This test should fail, as the number of nano seconds encoded is bigger than 10^9. assert!(Duration::decode(&mut &encoded[..]).is_err()); // Now constructing a valid duration and encoding it. Those asserts should not fail. let duration = Duration::from_nanos(invalid_nanos as u64); let expected = (num_secs, num_nanos).encode(); assert_eq!(duration.encode(), expected); assert_eq!(Duration::decode(&mut &expected[..]).unwrap(), duration); } #[test] fn u64_max() { let num_secs = u64::MAX; let num_nanos = 0; let duration = Duration::new(num_secs, num_nanos); let expected = (num_secs, num_nanos).encode(); assert_eq!(duration.encode(), expected); assert_eq!(Duration::decode(&mut &expected[..]).unwrap(), duration); } #[test] fn decoding_does_not_overflow() { let num_secs = u64::MAX; let num_nanos = A_BILLION; // `num_nanos`' carry should make `num_secs` overflow if we were to call `Duration::new()`. // This test checks that the we do not call `Duration::new()`. let encoded = (num_secs, num_nanos).encode(); assert!(Duration::decode(&mut &encoded[..]).is_err()); } #[test] fn string_invalid_utf8() { // `167, 10` is not a valid utf8 sequence, so this should be an error. let mut bytes: &[u8] = &[20, 114, 167, 10, 20, 114]; let obj = ::decode(&mut bytes); assert!(obj.is_err()); } #[test] fn empty_array_encode_and_decode() { let data: [u32; 0] = []; let encoded = data.encode(); assert!(encoded.is_empty()); <[u32; 0]>::decode(&mut &encoded[..]).unwrap(); } macro_rules! test_array_encode_and_decode { ( $( $name:ty ),* $(,)? ) => { $( paste::item! { #[test] fn []() { let data: [$name; 32] = [123 as $name; 32]; let encoded = data.encode(); let decoded: [$name; 32] = Decode::decode(&mut &encoded[..]).unwrap(); assert_eq!(decoded, data); } } )* } } test_array_encode_and_decode!(u8, i8, u16, i16, u32, i32, u64, i64, u128, i128); test_array_encode_and_decode!(f32, f64); fn test_encoded_size(val: impl Encode) { let length = val.using_encoded(|v| v.len()); assert_eq!(length, val.encoded_size()); } struct TestStruct { data: Vec, other: u8, compact: Compact, } impl Encode for TestStruct { fn encode_to(&self, dest: &mut W) { self.data.encode_to(dest); self.other.encode_to(dest); self.compact.encode_to(dest); } } #[test] fn encoded_size_works() { test_encoded_size(120u8); test_encoded_size(30u16); test_encoded_size(1u32); test_encoded_size(2343545u64); test_encoded_size(34358394245459854u128); test_encoded_size(vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10u32]); test_encoded_size(Compact(32445u32)); test_encoded_size(Compact(34353454453545u128)); test_encoded_size(TestStruct { data: vec![1, 2, 4, 5, 6], other: 45, compact: Compact(123234545), }); } #[test] fn ranges() { let range = Range { start: 1, end: 100 }; let range_bytes = (1, 100).encode(); assert_eq!(range.encode(), range_bytes); assert_eq!(Range::decode(&mut &range_bytes[..]), Ok(range)); let range_inclusive = RangeInclusive::new(1, 100); let range_inclusive_bytes = (1, 100).encode(); assert_eq!(range_inclusive.encode(), range_inclusive_bytes); assert_eq!(RangeInclusive::decode(&mut &range_inclusive_bytes[..]), Ok(range_inclusive)); } } parity-scale-codec-3.6.4/src/compact.rs000064400000000000000000000613611046102023000161000ustar 00000000000000// Copyright 2019 Parity Technologies // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //! [Compact encoding](https://docs.substrate.io/v3/advanced/scale-codec/#compactgeneral-integers) use arrayvec::ArrayVec; use crate::alloc::vec::Vec; use crate::codec::{Encode, Decode, Input, Output, EncodeAsRef}; use crate::encode_like::EncodeLike; use crate::Error; #[cfg(feature = "fuzz")] use arbitrary::Arbitrary; struct ArrayVecWrapper(ArrayVec); impl Output for ArrayVecWrapper { fn write(&mut self, bytes: &[u8]) { let old_len = self.0.len(); let new_len = old_len + bytes.len(); assert!(new_len <= self.0.capacity()); unsafe { self.0.set_len(new_len); } self.0[old_len..new_len].copy_from_slice(bytes); } fn push_byte(&mut self, byte: u8) { self.0.push(byte); } } /// Prefix another input with a byte. struct PrefixInput<'a, T> { prefix: Option, input: &'a mut T, } impl<'a, T: 'a + Input> Input for PrefixInput<'a, T> { fn remaining_len(&mut self) -> Result, Error> { let len = if let Some(len) = self.input.remaining_len()? { Some(len.saturating_add(self.prefix.iter().count())) } else { None }; Ok(len) } fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> { match self.prefix.take() { Some(v) if !buffer.is_empty() => { buffer[0] = v; self.input.read(&mut buffer[1..]) } _ => self.input.read(buffer) } } } /// Something that can return the compact encoded length for a given value. pub trait CompactLen { /// Returns the compact encoded length for the given value. fn compact_len(val: &T) -> usize; } /// Compact-encoded variant of T. This is more space-efficient but less compute-efficient. #[derive(Eq, PartialEq, Clone, Copy, Ord, PartialOrd)] #[cfg_attr(feature = "fuzz", derive(Arbitrary))] pub struct Compact(pub T); impl From for Compact { fn from(x: T) -> Compact { Compact(x) } } impl<'a, T: Copy> From<&'a T> for Compact { fn from(x: &'a T) -> Compact { Compact(*x) } } /// Allow foreign structs to be wrap in Compact pub trait CompactAs: From> { /// A compact-encodable type that should be used as the encoding. type As; /// Returns the compact-encodable type. fn encode_as(&self) -> &Self::As; /// Decode `Self` from the compact-decoded type. fn decode_from(_: Self::As) -> Result; } impl EncodeLike for Compact where for<'a> CompactRef<'a, T>: Encode, {} impl Encode for Compact where for<'a> CompactRef<'a, T>: Encode, { fn size_hint(&self) -> usize { CompactRef(&self.0).size_hint() } fn encode_to(&self, dest: &mut W) { CompactRef(&self.0).encode_to(dest) } fn encode(&self) -> Vec { CompactRef(&self.0).encode() } fn using_encoded R>(&self, f: F) -> R { CompactRef(&self.0).using_encoded(f) } } impl<'a, T> EncodeLike for CompactRef<'a, T> where T: CompactAs, for<'b> CompactRef<'b, T::As>: Encode, {} impl<'a, T> Encode for CompactRef<'a, T> where T: CompactAs, for<'b> CompactRef<'b, T::As>: Encode, { fn size_hint(&self) -> usize { CompactRef(self.0.encode_as()).size_hint() } fn encode_to(&self, dest: &mut Out) { CompactRef(self.0.encode_as()).encode_to(dest) } fn encode(&self) -> Vec { CompactRef(self.0.encode_as()).encode() } fn using_encoded R>(&self, f: F) -> R { CompactRef(self.0.encode_as()).using_encoded(f) } } impl Decode for Compact where T: CompactAs, Compact: Decode, { fn decode(input: &mut I) -> Result { let as_ = Compact::::decode(input)?; Ok(Compact(::decode_from(as_.0)?)) } } macro_rules! impl_from_compact { ( $( $ty:ty ),* ) => { $( impl From> for $ty { fn from(x: Compact<$ty>) -> $ty { x.0 } } )* } } impl_from_compact! { (), u8, u16, u32, u64, u128 } /// Compact-encoded variant of &'a T. This is more space-efficient but less compute-efficient. #[derive(Eq, PartialEq, Clone, Copy)] pub struct CompactRef<'a, T>(pub &'a T); impl<'a, T> From<&'a T> for CompactRef<'a, T> { fn from(x: &'a T) -> Self { CompactRef(x) } } impl core::fmt::Debug for Compact where T: core::fmt::Debug { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { self.0.fmt(f) } } #[cfg(feature = "std")] impl serde::Serialize for Compact where T: serde::Serialize { fn serialize(&self, serializer: S) -> Result where S: serde::Serializer { T::serialize(&self.0, serializer) } } #[cfg(feature = "std")] impl<'de, T> serde::Deserialize<'de> for Compact where T: serde::Deserialize<'de> { fn deserialize(deserializer: D) -> Result where D: serde::Deserializer<'de> { T::deserialize(deserializer).map(Compact) } } /// Trait that tells you if a given type can be encoded/decoded in a compact way. pub trait HasCompact: Sized { /// The compact type; this can be type Type: for<'a> EncodeAsRef<'a, Self> + Decode + From + Into; } impl<'a, T: 'a> EncodeAsRef<'a, T> for Compact where CompactRef<'a, T>: Encode + From<&'a T> { type RefType = CompactRef<'a, T>; } impl HasCompact for T where Compact: for<'a> EncodeAsRef<'a, T> + Decode + From + Into { type Type = Compact; } impl<'a> Encode for CompactRef<'a, ()> { fn encode_to(&self, _dest: &mut W) { } fn using_encoded R>(&self, f: F) -> R { f(&[]) } fn encode(&self) -> Vec { Vec::new() } } impl<'a> Encode for CompactRef<'a, u8> { fn size_hint(&self) -> usize { Compact::compact_len(self.0) } fn encode_to(&self, dest: &mut W) { match self.0 { 0..=0b0011_1111 => dest.push_byte(self.0 << 2), _ => ((u16::from(*self.0) << 2) | 0b01).encode_to(dest), } } fn using_encoded R>(&self, f: F) -> R { let mut r = ArrayVecWrapper(ArrayVec::::new()); self.encode_to(&mut r); f(&r.0) } } impl CompactLen for Compact { fn compact_len(val: &u8) -> usize { match val { 0..=0b0011_1111 => 1, _ => 2, } } } impl<'a> Encode for CompactRef<'a, u16> { fn size_hint(&self) -> usize { Compact::compact_len(self.0) } fn encode_to(&self, dest: &mut W) { match self.0 { 0..=0b0011_1111 => dest.push_byte((*self.0 as u8) << 2), 0..=0b0011_1111_1111_1111 => ((*self.0 << 2) | 0b01).encode_to(dest), _ => ((u32::from(*self.0) << 2) | 0b10).encode_to(dest), } } fn using_encoded R>(&self, f: F) -> R { let mut r = ArrayVecWrapper(ArrayVec::::new()); self.encode_to(&mut r); f(&r.0) } } impl CompactLen for Compact { fn compact_len(val: &u16) -> usize { match val { 0..=0b0011_1111 => 1, 0..=0b0011_1111_1111_1111 => 2, _ => 4, } } } impl<'a> Encode for CompactRef<'a, u32> { fn size_hint(&self) -> usize { Compact::compact_len(self.0) } fn encode_to(&self, dest: &mut W) { match self.0 { 0..=0b0011_1111 => dest.push_byte((*self.0 as u8) << 2), 0..=0b0011_1111_1111_1111 => (((*self.0 as u16) << 2) | 0b01).encode_to(dest), 0..=0b0011_1111_1111_1111_1111_1111_1111_1111 => ((*self.0 << 2) | 0b10).encode_to(dest), _ => { dest.push_byte(0b11); self.0.encode_to(dest); } } } fn using_encoded R>(&self, f: F) -> R { let mut r = ArrayVecWrapper(ArrayVec::::new()); self.encode_to(&mut r); f(&r.0) } } impl CompactLen for Compact { fn compact_len(val: &u32) -> usize { match val { 0..=0b0011_1111 => 1, 0..=0b0011_1111_1111_1111 => 2, 0..=0b0011_1111_1111_1111_1111_1111_1111_1111 => 4, _ => 5, } } } impl<'a> Encode for CompactRef<'a, u64> { fn size_hint(&self) -> usize { Compact::compact_len(self.0) } fn encode_to(&self, dest: &mut W) { match self.0 { 0..=0b0011_1111 => dest.push_byte((*self.0 as u8) << 2), 0..=0b0011_1111_1111_1111 => (((*self.0 as u16) << 2) | 0b01).encode_to(dest), 0..=0b0011_1111_1111_1111_1111_1111_1111_1111 => (((*self.0 as u32) << 2) | 0b10).encode_to(dest), _ => { let bytes_needed = 8 - self.0.leading_zeros() / 8; assert!(bytes_needed >= 4, "Previous match arm matches anyting less than 2^30; qed"); dest.push_byte(0b11 + ((bytes_needed - 4) << 2) as u8); let mut v = *self.0; for _ in 0..bytes_needed { dest.push_byte(v as u8); v >>= 8; } assert_eq!(v, 0, "shifted sufficient bits right to lead only leading zeros; qed") } } } fn using_encoded R>(&self, f: F) -> R { let mut r = ArrayVecWrapper(ArrayVec::::new()); self.encode_to(&mut r); f(&r.0) } } impl CompactLen for Compact { fn compact_len(val: &u64) -> usize { match val { 0..=0b0011_1111 => 1, 0..=0b0011_1111_1111_1111 => 2, 0..=0b0011_1111_1111_1111_1111_1111_1111_1111 => 4, _ => { (8 - val.leading_zeros() / 8) as usize + 1 }, } } } impl<'a> Encode for CompactRef<'a, u128> { fn size_hint(&self) -> usize { Compact::compact_len(self.0) } fn encode_to(&self, dest: &mut W) { match self.0 { 0..=0b0011_1111 => dest.push_byte((*self.0 as u8) << 2), 0..=0b0011_1111_1111_1111 => (((*self.0 as u16) << 2) | 0b01).encode_to(dest), 0..=0b0011_1111_1111_1111_1111_1111_1111_1111 => (((*self.0 as u32) << 2) | 0b10).encode_to(dest), _ => { let bytes_needed = 16 - self.0.leading_zeros() / 8; assert!(bytes_needed >= 4, "Previous match arm matches anyting less than 2^30; qed"); dest.push_byte(0b11 + ((bytes_needed - 4) << 2) as u8); let mut v = *self.0; for _ in 0..bytes_needed { dest.push_byte(v as u8); v >>= 8; } assert_eq!(v, 0, "shifted sufficient bits right to lead only leading zeros; qed") } } } fn using_encoded R>(&self, f: F) -> R { let mut r = ArrayVecWrapper(ArrayVec::::new()); self.encode_to(&mut r); f(&r.0) } } impl CompactLen for Compact { fn compact_len(val: &u128) -> usize { match val { 0..=0b0011_1111 => 1, 0..=0b0011_1111_1111_1111 => 2, 0..=0b0011_1111_1111_1111_1111_1111_1111_1111 => 4, _ => { (16 - val.leading_zeros() / 8) as usize + 1 }, } } } impl Decode for Compact<()> { fn decode(_input: &mut I) -> Result { Ok(Compact(())) } } const U8_OUT_OF_RANGE: &str = "out of range decoding Compact"; const U16_OUT_OF_RANGE: &str = "out of range decoding Compact"; const U32_OUT_OF_RANGE: &str = "out of range decoding Compact"; const U64_OUT_OF_RANGE: &str = "out of range decoding Compact"; const U128_OUT_OF_RANGE: &str = "out of range decoding Compact"; impl Decode for Compact { fn decode(input: &mut I) -> Result { let prefix = input.read_byte()?; Ok(Compact(match prefix % 4 { 0 => prefix >> 2, 1 => { let x = u16::decode(&mut PrefixInput{prefix: Some(prefix), input})? >> 2; if x > 0b0011_1111 && x <= 255 { x as u8 } else { return Err(U8_OUT_OF_RANGE.into()); } }, _ => return Err("unexpected prefix decoding Compact".into()), })) } } impl Decode for Compact { fn decode(input: &mut I) -> Result { let prefix = input.read_byte()?; Ok(Compact(match prefix % 4 { 0 => u16::from(prefix) >> 2, 1 => { let x = u16::decode(&mut PrefixInput{prefix: Some(prefix), input})? >> 2; if x > 0b0011_1111 && x <= 0b0011_1111_1111_1111 { x } else { return Err(U16_OUT_OF_RANGE.into()); } }, 2 => { let x = u32::decode(&mut PrefixInput{prefix: Some(prefix), input})? >> 2; if x > 0b0011_1111_1111_1111 && x < 65536 { x as u16 } else { return Err(U16_OUT_OF_RANGE.into()); } }, _ => return Err("unexpected prefix decoding Compact".into()), })) } } impl Decode for Compact { fn decode(input: &mut I) -> Result { let prefix = input.read_byte()?; Ok(Compact(match prefix % 4 { 0 => u32::from(prefix) >> 2, 1 => { let x = u16::decode(&mut PrefixInput{prefix: Some(prefix), input})? >> 2; if x > 0b0011_1111 && x <= 0b0011_1111_1111_1111 { u32::from(x) } else { return Err(U32_OUT_OF_RANGE.into()); } }, 2 => { let x = u32::decode(&mut PrefixInput{prefix: Some(prefix), input})? >> 2; if x > 0b0011_1111_1111_1111 && x <= u32::MAX >> 2 { x } else { return Err(U32_OUT_OF_RANGE.into()); } }, 3 => { if prefix >> 2 == 0 { // just 4 bytes. ok. let x = u32::decode(input)?; if x > u32::MAX >> 2 { x } else { return Err(U32_OUT_OF_RANGE.into()); } } else { // Out of range for a 32-bit quantity. return Err(U32_OUT_OF_RANGE.into()); } }, _ => unreachable!(), })) } } impl Decode for Compact { fn decode(input: &mut I) -> Result { let prefix = input.read_byte()?; Ok(Compact(match prefix % 4 { 0 => u64::from(prefix) >> 2, 1 => { let x = u16::decode(&mut PrefixInput{prefix: Some(prefix), input})? >> 2; if x > 0b0011_1111 && x <= 0b0011_1111_1111_1111 { u64::from(x) } else { return Err(U64_OUT_OF_RANGE.into()); } }, 2 => { let x = u32::decode(&mut PrefixInput{prefix: Some(prefix), input})? >> 2; if x > 0b0011_1111_1111_1111 && x <= u32::MAX >> 2 { u64::from(x) } else { return Err(U64_OUT_OF_RANGE.into()); } }, 3 => match (prefix >> 2) + 4 { 4 => { let x = u32::decode(input)?; if x > u32::MAX >> 2 { u64::from(x) } else { return Err(U64_OUT_OF_RANGE.into()); } }, 8 => { let x = u64::decode(input)?; if x > u64::MAX >> 8 { x } else { return Err(U64_OUT_OF_RANGE.into()); } }, x if x > 8 => return Err("unexpected prefix decoding Compact".into()), bytes_needed => { let mut res = 0; for i in 0..bytes_needed { res |= u64::from(input.read_byte()?) << (i * 8); } if res > u64::MAX >> ((8 - bytes_needed + 1) * 8) { res } else { return Err(U64_OUT_OF_RANGE.into()); } }, }, _ => unreachable!(), })) } } impl Decode for Compact { fn decode(input: &mut I) -> Result { let prefix = input.read_byte()?; Ok(Compact(match prefix % 4 { 0 => u128::from(prefix) >> 2, 1 => { let x = u16::decode(&mut PrefixInput{prefix: Some(prefix), input})? >> 2; if x > 0b0011_1111 && x <= 0b0011_1111_1111_1111 { u128::from(x) } else { return Err(U128_OUT_OF_RANGE.into()); } }, 2 => { let x = u32::decode(&mut PrefixInput{prefix: Some(prefix), input})? >> 2; if x > 0b0011_1111_1111_1111 && x <= u32::MAX >> 2 { u128::from(x) } else { return Err(U128_OUT_OF_RANGE.into()); } }, 3 => match (prefix >> 2) + 4 { 4 => { let x = u32::decode(input)?; if x > u32::MAX >> 2 { u128::from(x) } else { return Err(U128_OUT_OF_RANGE.into()); } }, 8 => { let x = u64::decode(input)?; if x > u64::MAX >> 8 { u128::from(x) } else { return Err(U128_OUT_OF_RANGE.into()); } }, 16 => { let x = u128::decode(input)?; if x > u128::MAX >> 8 { x } else { return Err(U128_OUT_OF_RANGE.into()); } }, x if x > 16 => return Err("unexpected prefix decoding Compact".into()), bytes_needed => { let mut res = 0; for i in 0..bytes_needed { res |= u128::from(input.read_byte()?) << (i * 8); } if res > u128::MAX >> ((16 - bytes_needed + 1) * 8) { res } else { return Err(U128_OUT_OF_RANGE.into()); } }, }, _ => unreachable!(), })) } } #[cfg(test)] mod tests { use super::*; #[test] fn compact_128_encoding_works() { let tests = [ (0u128, 1usize), (63, 1), (64, 2), (16383, 2), (16384, 4), (1073741823, 4), (1073741824, 5), ((1 << 32) - 1, 5), (1 << 32, 6), (1 << 40, 7), (1 << 48, 8), ((1 << 56) - 1, 8), (1 << 56, 9), ((1 << 64) - 1, 9), (1 << 64, 10), (1 << 72, 11), (1 << 80, 12), (1 << 88, 13), (1 << 96, 14), (1 << 104, 15), (1 << 112, 16), ((1 << 120) - 1, 16), (1 << 120, 17), (u128::MAX, 17) ]; for &(n, l) in &tests { let encoded = Compact(n as u128).encode(); assert_eq!(encoded.len(), l); assert_eq!(Compact::compact_len(&n), l); assert_eq!(>::decode(&mut &encoded[..]).unwrap().0, n); } } #[test] fn compact_64_encoding_works() { let tests = [ (0u64, 1usize), (63, 1), (64, 2), (16383, 2), (16384, 4), (1073741823, 4), (1073741824, 5), ((1 << 32) - 1, 5), (1 << 32, 6), (1 << 40, 7), (1 << 48, 8), ((1 << 56) - 1, 8), (1 << 56, 9), (u64::MAX, 9) ]; for &(n, l) in &tests { let encoded = Compact(n as u64).encode(); assert_eq!(encoded.len(), l); assert_eq!(Compact::compact_len(&n), l); assert_eq!(>::decode(&mut &encoded[..]).unwrap().0, n); } } #[test] fn compact_32_encoding_works() { let tests = [(0u32, 1usize), (63, 1), (64, 2), (16383, 2), (16384, 4), (1073741823, 4), (1073741824, 5), (u32::MAX, 5)]; for &(n, l) in &tests { let encoded = Compact(n as u32).encode(); assert_eq!(encoded.len(), l); assert_eq!(Compact::compact_len(&n), l); assert_eq!(>::decode(&mut &encoded[..]).unwrap().0, n); } } #[test] fn compact_16_encoding_works() { let tests = [(0u16, 1usize), (63, 1), (64, 2), (16383, 2), (16384, 4), (65535, 4)]; for &(n, l) in &tests { let encoded = Compact(n as u16).encode(); assert_eq!(encoded.len(), l); assert_eq!(Compact::compact_len(&n), l); assert_eq!(>::decode(&mut &encoded[..]).unwrap().0, n); } assert!(>::decode(&mut &Compact(65536u32).encode()[..]).is_err()); } #[test] fn compact_8_encoding_works() { let tests = [(0u8, 1usize), (63, 1), (64, 2), (255, 2)]; for &(n, l) in &tests { let encoded = Compact(n as u8).encode(); assert_eq!(encoded.len(), l); assert_eq!(Compact::compact_len(&n), l); assert_eq!(>::decode(&mut &encoded[..]).unwrap().0, n); } assert!(>::decode(&mut &Compact(256u32).encode()[..]).is_err()); } fn hexify(bytes: &[u8]) -> String { bytes.iter().map(|ref b| format!("{:02x}", b)).collect::>().join(" ") } #[test] fn compact_integers_encoded_as_expected() { let tests = [ (0u64, "00"), (63, "fc"), (64, "01 01"), (16383, "fd ff"), (16384, "02 00 01 00"), (1073741823, "fe ff ff ff"), (1073741824, "03 00 00 00 40"), ((1 << 32) - 1, "03 ff ff ff ff"), (1 << 32, "07 00 00 00 00 01"), (1 << 40, "0b 00 00 00 00 00 01"), (1 << 48, "0f 00 00 00 00 00 00 01"), ((1 << 56) - 1, "0f ff ff ff ff ff ff ff"), (1 << 56, "13 00 00 00 00 00 00 00 01"), (u64::MAX, "13 ff ff ff ff ff ff ff ff") ]; for &(n, s) in &tests { // Verify u64 encoding let encoded = Compact(n as u64).encode(); assert_eq!(hexify(&encoded), s); assert_eq!(>::decode(&mut &encoded[..]).unwrap().0, n); // Verify encodings for lower-size uints are compatible with u64 encoding if n <= u32::MAX as u64 { assert_eq!(>::decode(&mut &encoded[..]).unwrap().0, n as u32); let encoded = Compact(n as u32).encode(); assert_eq!(hexify(&encoded), s); assert_eq!(>::decode(&mut &encoded[..]).unwrap().0, n as u64); } if n <= u16::MAX as u64 { assert_eq!(>::decode(&mut &encoded[..]).unwrap().0, n as u16); let encoded = Compact(n as u16).encode(); assert_eq!(hexify(&encoded), s); assert_eq!(>::decode(&mut &encoded[..]).unwrap().0, n as u64); } if n <= u8::MAX as u64 { assert_eq!(>::decode(&mut &encoded[..]).unwrap().0, n as u8); let encoded = Compact(n as u8).encode(); assert_eq!(hexify(&encoded), s); assert_eq!(>::decode(&mut &encoded[..]).unwrap().0, n as u64); } } } #[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))] #[derive(PartialEq, Eq, Clone)] struct Wrapper(u8); impl CompactAs for Wrapper { type As = u8; fn encode_as(&self) -> &u8 { &self.0 } fn decode_from(x: u8) -> Result { Ok(Wrapper(x)) } } impl From> for Wrapper { fn from(x: Compact) -> Wrapper { x.0 } } #[test] fn compact_as_8_encoding_works() { let tests = [(0u8, 1usize), (63, 1), (64, 2), (255, 2)]; for &(n, l) in &tests { let compact: Compact = Wrapper(n).into(); let encoded = compact.encode(); assert_eq!(encoded.len(), l); assert_eq!(Compact::compact_len(&n), l); let decoded = >::decode(&mut & encoded[..]).unwrap(); let wrapper: Wrapper = decoded.into(); assert_eq!(wrapper, Wrapper(n)); } } struct WithCompact { _data: T, } #[test] fn compact_as_has_compact() { let _data = WithCompact { _data: Wrapper(1) }; } #[test] fn compact_using_encoded_arrayvec_size() { Compact(u8::MAX).using_encoded(|_| {}); Compact(u16::MAX).using_encoded(|_| {}); Compact(u32::MAX).using_encoded(|_| {}); Compact(u64::MAX).using_encoded(|_| {}); Compact(u128::MAX).using_encoded(|_| {}); CompactRef(&u8::MAX).using_encoded(|_| {}); CompactRef(&u16::MAX).using_encoded(|_| {}); CompactRef(&u32::MAX).using_encoded(|_| {}); CompactRef(&u64::MAX).using_encoded(|_| {}); CompactRef(&u128::MAX).using_encoded(|_| {}); } #[test] #[should_panic] fn array_vec_output_oob() { let mut v = ArrayVecWrapper(ArrayVec::::new()); v.write(&[1, 2, 3, 4, 5]); } #[test] fn array_vec_output() { let mut v = ArrayVecWrapper(ArrayVec::::new()); v.write(&[1, 2, 3, 4]); } macro_rules! check_bound { ( $m:expr, $ty:ty, $typ1:ty, [ $(($ty2:ty, $ty2_err:expr)),* ]) => { $( check_bound!($m, $ty, $typ1, $ty2, $ty2_err); )* }; ( $m:expr, $ty:ty, $typ1:ty, $ty2:ty, $ty2_err:expr) => { let enc = ((<$ty>::MAX >> 2) as $typ1 << 2) | $m; assert_eq!(Compact::<$ty2>::decode(&mut &enc.to_le_bytes()[..]), Err($ty2_err.into())); }; } macro_rules! check_bound_u32 { ( [ $(($ty2:ty, $ty2_err:expr)),* ]) => { $( check_bound_u32!($ty2, $ty2_err); )* }; ( $ty2:ty, $ty2_err:expr ) => { assert_eq!(Compact::<$ty2>::decode(&mut &[0b11, 0xff, 0xff, 0xff, 0xff >> 2][..]), Err($ty2_err.into())); }; } macro_rules! check_bound_high { ( $m:expr, [ $(($ty2:ty, $ty2_err:expr)),* ]) => { $( check_bound_high!($m, $ty2, $ty2_err); )* }; ( $s:expr, $ty2:ty, $ty2_err:expr) => { let mut dest = Vec::new(); dest.push(0b11 + (($s - 4) << 2) as u8); for _ in 0..($s - 1) { dest.push(u8::MAX); } dest.push(0); assert_eq!(Compact::<$ty2>::decode(&mut &dest[..]), Err($ty2_err.into())); }; } #[test] fn compact_u64_test() { for a in [ u64::MAX, u64::MAX - 1, u64::MAX << 8, (u64::MAX << 8) - 1, u64::MAX << 16, (u64::MAX << 16) - 1, ].iter() { let e = Compact::::encode(&Compact(*a)); let d = Compact::::decode(&mut &e[..]).unwrap().0; assert_eq!(*a, d); } } #[test] fn compact_u128_test() { for a in [ u64::MAX as u128, (u64::MAX - 10) as u128, u128::MAX, u128::MAX - 10, ].iter() { let e = Compact::::encode(&Compact(*a)); let d = Compact::::decode(&mut &e[..]).unwrap().0; assert_eq!(*a, d); } } #[test] fn should_avoid_overlapping_definition() { check_bound!( 0b01, u8, u16, [ (u8, U8_OUT_OF_RANGE), (u16, U16_OUT_OF_RANGE), (u32, U32_OUT_OF_RANGE), (u64, U64_OUT_OF_RANGE), (u128, U128_OUT_OF_RANGE)] ); check_bound!( 0b10, u16, u32, [ (u16, U16_OUT_OF_RANGE), (u32, U32_OUT_OF_RANGE), (u64, U64_OUT_OF_RANGE), (u128, U128_OUT_OF_RANGE)] ); check_bound_u32!( [(u32, U32_OUT_OF_RANGE), (u64, U64_OUT_OF_RANGE), (u128, U128_OUT_OF_RANGE)] ); for i in 5..=8 { check_bound_high!(i, [(u64, U64_OUT_OF_RANGE), (u128, U128_OUT_OF_RANGE)]); } for i in 8..=16 { check_bound_high!(i, [(u128, U128_OUT_OF_RANGE)]); } } macro_rules! quick_check_roundtrip { ( $( $ty:ty : $test:ident ),* ) => { $( quickcheck::quickcheck! { fn $test(v: $ty) -> bool { let encoded = Compact(v).encode(); let deencoded = >::decode(&mut &encoded[..]).unwrap().0; v == deencoded } } )* } } quick_check_roundtrip! { u8: u8_roundtrip, u16: u16_roundtrip, u32 : u32_roundtrip, u64 : u64_roundtrip, u128 : u128_roundtrip } } parity-scale-codec-3.6.4/src/const_encoded_len.rs000064400000000000000000000076371046102023000201250ustar 00000000000000// Copyright (C) 2023 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //! Contains the [`ConstEncodedLen`] trait. use crate::MaxEncodedLen; use core::{ marker::PhantomData, num::*, ops::{Range, RangeInclusive}, time::Duration, }; use crate::alloc::boxed::Box; use impl_trait_for_tuples::impl_for_tuples; /// Types that have a constant encoded length. This implies [`MaxEncodedLen`]. /// /// No derive macros is provided; instead use an empty implementation like for a marker trait. pub trait ConstEncodedLen: MaxEncodedLen {} #[impl_for_tuples(18)] impl ConstEncodedLen for Tuple { } impl ConstEncodedLen for [T; N] { } /// Mark `T` or `T` as `CEL`. macro_rules! mark_cel { ( $($n:ident <$t:ident>),+ ) => { $( impl<$t: ConstEncodedLen> ConstEncodedLen for $n<$t> { } )+ }; ( $($t:ty),+ ) => { $( impl ConstEncodedLen for $t { } )+ }; } mark_cel!(u8, u16, u32, u64, u128, i8, i16, i32, i64, i128, bool); mark_cel!(NonZeroU8, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU128, NonZeroI8, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI128); mark_cel!(Duration); mark_cel!(PhantomData); mark_cel!(Box); mark_cel!(Range, RangeInclusive); // `Option`, `Result` and `Compact` are sum types, therefore not `CEL`. #[cfg(test)] mod tests { use super::*; use crate::Encode; use proptest::prelude::*; /// Test that some random instances of `T` have encoded len `T::max_encoded_len()`. macro_rules! test_cel_compliance { ( $( $t:ty ),+ ) => { $( paste::paste! { proptest::proptest! { #[test] fn [< cel_compliance_ $t:snake >](x: $t) { prop_assert_eq!(x.encode().len(), $t::max_encoded_len()); } } } )* }; } type Void = (); test_cel_compliance!(Void); test_cel_compliance!(u8, u16, u32, u64, u128, i8, i16, i32, i64, i128, bool); type TupleArithmetic = (u8, u16, u32, u64, u128, i8, i16, i32, i64, i128); test_cel_compliance!(TupleArithmetic); test_cel_compliance!( NonZeroU8, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU128, NonZeroI8, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI128 ); type TupleNonZero = ( NonZeroU8, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU128, NonZeroI8, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI128, ); test_cel_compliance!(TupleNonZero); type ArrayArithmetic = [(u8, u16, u32, u64, u128, i8, i16, i32, i64, i128); 10]; test_cel_compliance!(ArrayArithmetic); test_cel_compliance!(Duration); type BoxedArithmetic = Box<(u8, u16, u32, u64, u128, i8, i16, i32, i64, i128)>; test_cel_compliance!(BoxedArithmetic); type PhantomArithmetic = PhantomData<(u8, u16, u32, u64, u128, i8, i16, i32, i64, i128)>; test_cel_compliance!(PhantomArithmetic); type Ranges = (Range, Range, Range, Range, Range); test_cel_compliance!(Ranges); type Ranges2D = ( Range<(u8, u8)>, Range<(u16, u16)>, Range<(u32, u32)>, Range<(u64, u64)>, Range<(u128, u128)>, ); test_cel_compliance!(Ranges2D); type RangesInc = ( RangeInclusive, RangeInclusive, RangeInclusive, RangeInclusive, RangeInclusive, ); test_cel_compliance!(RangesInc); type RangesInc2D = ( RangeInclusive<(u8, u8)>, RangeInclusive<(u16, u16)>, RangeInclusive<(u32, u32)>, RangeInclusive<(u64, u64)>, RangeInclusive<(u128, u128)>, ); test_cel_compliance!(RangesInc2D); } parity-scale-codec-3.6.4/src/decode_all.rs000064400000000000000000000056161046102023000165260ustar 00000000000000// Copyright 2017, 2018 Parity Technologies // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. use crate::{Decode, Error}; /// The error message returned when `decode_all` fails. pub(crate) const DECODE_ALL_ERR_MSG: &str = "Input buffer has still data left after decoding!"; /// Extension trait to [`Decode`] that ensures that the given input data is consumed completely while /// decoding. pub trait DecodeAll: Sized { /// Decode `Self` and consume all of the given input data. /// /// If not all data is consumed, an error is returned. fn decode_all(input: &mut &[u8]) -> Result; } impl DecodeAll for T { fn decode_all(input: &mut &[u8]) -> Result { let res = T::decode(input)?; if input.is_empty() { Ok(res) } else { Err(DECODE_ALL_ERR_MSG.into()) } } } #[cfg(test)] mod tests { use super::*; use crate::{Compact, Encode, EncodeLike, Input}; macro_rules! test_decode_all { ( $( $type:ty => $value:expr; )* ) => { $( { let mut encoded = <$type as Encode>::encode(&$value); <$type>::decode_all(&mut encoded.as_slice()).expect( &format!("`{} => {}` decodes all!", stringify!($type), stringify!($value)), ); encoded.extend(&[1, 2, 3, 4, 5, 6]); assert_eq!( <$type>::decode_all(&mut encoded.as_slice()).unwrap_err().to_string(), "Input buffer has still data left after decoding!", ); } )* }; } #[derive(Debug)] struct TestStruct { data: Vec, other: u8, compact: Compact, } impl EncodeLike for TestStruct {} impl Encode for TestStruct { fn encode(&self) -> Vec { let mut res = Vec::new(); self.data.encode_to(&mut res); self.other.encode_to(&mut res); self.compact.encode_to(&mut res); res } } impl Decode for TestStruct { fn decode(input: &mut I) -> Result { Ok(Self { data: Vec::::decode(input)?, other: u8::decode(input)?, compact: Compact::::decode(input)?, }) } } #[test] fn decode_all_works() { test_decode_all! { u8 => 120; u16 => 30; u32 => 1; u64 => 2343545; u128 => 34358394245459854; Vec => vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; Vec => vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; Compact => Compact(32445); Compact => Compact(34353454453545); TestStruct => TestStruct { data: vec![1, 2, 4, 5, 6], other: 45, compact: Compact(123234545) }; } } } parity-scale-codec-3.6.4/src/decode_finished.rs000064400000000000000000000026251046102023000175440ustar 00000000000000// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //! Contains the [`DecodeFinished`] type, sequestered into its own module //! to prevent its direct construction in the whole crate. use core::marker::PhantomData; /// A zero-sized type signifying that the decoding finished. /// /// To be used in [`Decode::decode_into`] to allow the implementation to explicitly /// assert that the `MaybeUninit` passed into that function was properly initialized. pub struct DecodeFinished(PhantomData<*const ()>); impl DecodeFinished { /// Assert that the decoding has finished. /// /// # Safety /// /// Should be used in [`Decode::decode_into`] to signify that /// the `MaybeUninit` passed into that function was properly initialized. #[inline] pub unsafe fn assert_decoding_finished() -> DecodeFinished { DecodeFinished(PhantomData) } } parity-scale-codec-3.6.4/src/depth_limit.rs000064400000000000000000000075641046102023000167610ustar 00000000000000// Copyright 2017, 2018 Parity Technologies // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. use crate::{Decode, Error, Input}; /// The error message returned when depth limit is reached. const DECODE_MAX_DEPTH_MSG: &str = "Maximum recursion depth reached when decoding"; /// Extension trait to [`Decode`] for decoding with a maximum recursion depth. pub trait DecodeLimit: Sized { /// Decode `Self` with the given maximum recursion depth and advance `input` by the number of /// bytes consumed. /// /// If `limit` is hit, an error is returned. fn decode_with_depth_limit(limit: u32, input: &mut I) -> Result; /// Decode `Self` and consume all of the given input data. /// /// If not all data is consumed or `limit` is hit, an error is returned. fn decode_all_with_depth_limit(limit: u32, input: &mut &[u8]) -> Result; } struct DepthTrackingInput<'a, I> { input: &'a mut I, depth: u32, max_depth: u32, } impl<'a, I: Input> Input for DepthTrackingInput<'a, I> { fn remaining_len(&mut self) -> Result, Error> { self.input.remaining_len() } fn read(&mut self, into: &mut [u8]) -> Result<(), Error> { self.input.read(into) } fn read_byte(&mut self) -> Result { self.input.read_byte() } fn descend_ref(&mut self) -> Result<(), Error> { self.input.descend_ref()?; self.depth += 1; if self.depth > self.max_depth { Err(DECODE_MAX_DEPTH_MSG.into()) } else { Ok(()) } } fn ascend_ref(&mut self) { self.input.ascend_ref(); self.depth -= 1; } } impl DecodeLimit for T { fn decode_all_with_depth_limit(limit: u32, input: &mut &[u8]) -> Result { let t = ::decode_with_depth_limit(limit, input)?; if input.is_empty() { Ok(t) } else { Err(crate::decode_all::DECODE_ALL_ERR_MSG.into()) } } fn decode_with_depth_limit(limit: u32, input: &mut I) -> Result { let mut input = DepthTrackingInput { input, depth: 0, max_depth: limit }; T::decode(&mut input) } } #[cfg(test)] mod tests { use super::*; use crate::Encode; #[test] fn decode_limit_works() { type NestedVec = Vec>>>; let nested: NestedVec = vec![vec![vec![vec![1]]]]; let encoded = nested.encode(); let decoded = NestedVec::decode_with_depth_limit(3, &mut encoded.as_slice()).unwrap(); assert_eq!(decoded, nested); assert!(NestedVec::decode_with_depth_limit(2, &mut encoded.as_slice()).is_err()); } #[test] fn decode_limit_advances_input() { type NestedVec = Vec>>>; let nested: NestedVec = vec![vec![vec![vec![1]]]]; let encoded = nested.encode(); let encoded_slice = &mut encoded.as_slice(); let decoded = Vec::::decode_with_depth_limit(1, encoded_slice).unwrap(); assert_eq!(decoded, vec![4]); assert!(NestedVec::decode_with_depth_limit(3, encoded_slice).is_err()); } #[test] fn decode_all_with_limit_advances_input() { type NestedVec = Vec>>>; let nested: NestedVec = vec![vec![vec![vec![1]]]]; let mut encoded = NestedVec::encode(&nested); let decoded = NestedVec::decode_all_with_depth_limit(3, &mut encoded.as_slice()).unwrap(); assert_eq!(decoded, nested); encoded.extend(&[1, 2, 3, 4, 5, 6]); assert_eq!( NestedVec::decode_all_with_depth_limit(3, &mut encoded.as_slice()) .unwrap_err() .to_string(), "Input buffer has still data left after decoding!", ); } } parity-scale-codec-3.6.4/src/encode_append.rs000064400000000000000000000164761046102023000172450ustar 00000000000000// Copyright 2019 Parity Technologies // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. use core::iter::ExactSizeIterator; use crate::alloc::vec::Vec; use crate::{Encode, Decode, Error}; use crate::compact::{Compact, CompactLen}; use crate::encode_like::EncodeLike; /// Trait that allows to append items to an encoded representation without /// decoding all previous added items. pub trait EncodeAppend { /// The item that will be appended. type Item: Encode; /// Append all items in `iter` to the given `self_encoded` representation /// or if `self_encoded` value is empty, `iter` is encoded to the `Self` representation. /// /// # Example /// /// ``` ///# use parity_scale_codec::EncodeAppend; /// /// // Some encoded data /// let data = Vec::new(); /// /// let item = 8u32; /// let encoded = as EncodeAppend>::append_or_new(data, std::iter::once(&item)).expect("Adds new element"); /// /// // Add multiple element /// as EncodeAppend>::append_or_new(encoded, &[700u32, 800u32, 10u32]).expect("Adds new elements"); /// ``` fn append_or_new( self_encoded: Vec, iter: I, ) -> Result, Error> where I: IntoIterator, EncodeLikeItem: EncodeLike, I::IntoIter: ExactSizeIterator; } impl EncodeAppend for Vec { type Item = T; fn append_or_new( self_encoded: Vec, iter: I, ) -> Result, Error> where I: IntoIterator, EncodeLikeItem: EncodeLike, I::IntoIter: ExactSizeIterator, { append_or_new_impl(self_encoded, iter) } } impl EncodeAppend for crate::alloc::collections::VecDeque { type Item = T; fn append_or_new( self_encoded: Vec, iter: I, ) -> Result, Error> where I: IntoIterator, EncodeLikeItem: EncodeLike, I::IntoIter: ExactSizeIterator, { append_or_new_impl(self_encoded, iter) } } /// Extends a SCALE-encoded vector with elements from the given `iter`. /// /// `vec` must either be empty, or contain a valid SCALE-encoded `Vec` payload. fn append_or_new_impl( mut vec: Vec, iter: I, ) -> Result, Error> where Item: Encode, I: IntoIterator, I::IntoIter: ExactSizeIterator, { let iter = iter.into_iter(); let items_to_append = iter.len(); if vec.is_empty() { crate::codec::compact_encode_len_to(&mut vec, items_to_append)?; } else { let old_item_count = u32::from(Compact::::decode(&mut &vec[..])?); let new_item_count = old_item_count .checked_add(items_to_append as u32) .ok_or("cannot append new items into a SCALE-encoded vector: length overflow due to too many items")?; let old_item_count_encoded_bytesize = Compact::::compact_len(&old_item_count); let new_item_count_encoded_bytesize = Compact::::compact_len(&new_item_count); if old_item_count_encoded_bytesize == new_item_count_encoded_bytesize { // The size of the length as encoded by SCALE didn't change, so we can just // keep the old buffer as-is. We just need to update the length prefix. Compact(new_item_count).using_encoded(|length_encoded| vec[..old_item_count_encoded_bytesize].copy_from_slice(length_encoded) ); } else { // We can't update the length as the new length prefix will take up more // space when encoded, so we need to move our data to make space for it. // If this overflows then it means that `vec` is bigger that half of the // total address space, which means that it will be impossible to allocate // enough memory for another vector of at least the same size. // // So let's just immediately bail with an error if this happens. let new_capacity = vec.len().checked_mul(2) .ok_or("cannot append new items into a SCALE-encoded vector: new vector won't fit in memory")?; let mut new_vec = Vec::with_capacity(new_capacity); crate::codec::compact_encode_len_to(&mut new_vec, new_item_count as usize)?; new_vec.extend_from_slice(&vec[old_item_count_encoded_bytesize..]); vec = new_vec; } } // And now we just need to append the new items. iter.for_each(|e| e.encode_to(&mut vec)); Ok(vec) } #[cfg(test)] mod tests { use super::*; use crate::{Input, Encode, EncodeLike}; use std::collections::VecDeque; const TEST_VALUE: u32 = { #[cfg(not(miri))] { 1_000_000 } #[cfg(miri)] { 1_000 } }; #[test] fn vec_encode_append_works() { let encoded = (0..TEST_VALUE).fold(Vec::new(), |encoded, v| { as EncodeAppend>::append_or_new(encoded, std::iter::once(&v)).unwrap() }); let decoded = Vec::::decode(&mut &encoded[..]).unwrap(); assert_eq!(decoded, (0..TEST_VALUE).collect::>()); } #[test] fn vec_encode_append_multiple_items_works() { let encoded = (0..TEST_VALUE).fold(Vec::new(), |encoded, v| { as EncodeAppend>::append_or_new(encoded, &[v, v, v, v]).unwrap() }); let decoded = Vec::::decode(&mut &encoded[..]).unwrap(); let expected = (0..TEST_VALUE).fold(Vec::new(), |mut vec, i| { vec.append(&mut vec![i, i, i, i]); vec }); assert_eq!(decoded, expected); } #[test] fn vecdeque_encode_append_works() { let encoded = (0..TEST_VALUE).fold(Vec::new(), |encoded, v| { as EncodeAppend>::append_or_new(encoded, std::iter::once(&v)).unwrap() }); let decoded = VecDeque::::decode(&mut &encoded[..]).unwrap(); assert_eq!(decoded, (0..TEST_VALUE).collect::>()); } #[test] fn vecdeque_encode_append_multiple_items_works() { let encoded = (0..TEST_VALUE).fold(Vec::new(), |encoded, v| { as EncodeAppend>::append_or_new(encoded, &[v, v, v, v]).unwrap() }); let decoded = VecDeque::::decode(&mut &encoded[..]).unwrap(); let expected = (0..TEST_VALUE).fold(Vec::new(), |mut vec, i| { vec.append(&mut vec![i, i, i, i]); vec }); assert_eq!(decoded, expected); } #[test] fn append_non_copyable() { #[derive(Eq, PartialEq, Debug)] struct NoCopy { data: u32 } impl EncodeLike for NoCopy {} impl Encode for NoCopy { fn encode(&self) -> Vec { self.data.encode() } } impl Decode for NoCopy { fn decode(input: &mut I) -> Result { u32::decode(input).map(|data| Self { data }) } } let append = NoCopy { data: 100 }; let data = Vec::new(); let encoded = as EncodeAppend>::append_or_new(data, std::iter::once(&append)).unwrap(); let decoded = >::decode(&mut &encoded[..]).unwrap(); assert_eq!(vec![append], decoded); } #[test] fn vec_encode_like_append_works() { let encoded = (0..TEST_VALUE).fold(Vec::new(), |encoded, v| { as EncodeAppend>::append_or_new(encoded, std::iter::once(Box::new(v as u32))).unwrap() }); let decoded = Vec::::decode(&mut &encoded[..]).unwrap(); assert_eq!(decoded, (0..TEST_VALUE).collect::>()); } } parity-scale-codec-3.6.4/src/encode_like.rs000064400000000000000000000126721046102023000167140ustar 00000000000000// Copyright 2019 Parity Technologies // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. use crate::codec::Encode; /// A marker trait that tells the compiler that a type encode to the same representation as another /// type. /// /// E.g. `Vec` has the same encoded representation as `&[u8]`. /// /// # Example /// /// ``` ///# use parity_scale_codec::{EncodeLike, Encode}; /// fn encode_like>(data: &R) { /// data.encode(); // Valid `T` encoded value. /// } /// /// fn main() { /// // Just pass the a reference to the normal tuple. /// encode_like::<(u32, u32), _>(&(1u32, 2u32)); /// // Pass a tuple of references /// encode_like::<(u32, u32), _>(&(&1u32, &2u32)); /// // Pass a tuple of a reference and a value. /// encode_like::<(u32, u32), _>(&(&1u32, 2u32)); /// } /// ``` /// /// # Warning /// /// The relation is not symetric, `T` implements `EncodeLike` does not mean `U` has same /// representation as `T`. /// For instance we could imaging a non zero integer to be encoded to the same representation as /// the said integer but not the other way around. /// /// # Limitation /// /// Not all possible implementations of EncodeLike are implemented (for instance `Box>` /// does not implement `EncodeLike`). To bypass this issue either open a PR to add the new /// combination or use [`Ref`](./struct.Ref.html) reference wrapper or define your own wrapper /// and implement `EncodeLike` on it as such: /// ``` ///# use parity_scale_codec::{EncodeLike, Encode, WrapperTypeEncode}; /// fn encode_like>(data: &R) { /// data.encode(); // Valid `T` encoded value. /// } /// /// struct MyWrapper<'a>(&'a (Box>, u32)); /// impl<'a> core::ops::Deref for MyWrapper<'a> { // Or use derive_deref crate /// type Target = (Box>, u32); /// fn deref(&self) -> &Self::Target { &self.0 } /// } /// /// impl<'a> parity_scale_codec::WrapperTypeEncode for MyWrapper<'a> {} /// impl<'a> parity_scale_codec::EncodeLike<(u32, u32)> for MyWrapper<'a> {} /// /// fn main() { /// let v = (Box::new(Box::new(0)), 0); /// encode_like::<(u32, u32), _>(&MyWrapper(&v)); /// } /// ``` pub trait EncodeLike: Sized + Encode {} /// Reference wrapper that implement encode like any type that is encoded like its inner type. /// /// # Example /// /// ```rust /// # use parity_scale_codec::{EncodeLike, Ref}; /// fn foo>(t: T) -> T { /// store_t(Ref::from(&t)); // Store t without moving it, but only using a reference. /// t /// } /// /// fn store_t>(t: T) { /// } /// ``` pub struct Ref<'a, T: EncodeLike, U: Encode>(&'a T, core::marker::PhantomData); impl<'a, T: EncodeLike, U: Encode> core::ops::Deref for Ref<'a, T, U> { type Target = T; fn deref(&self) -> &Self::Target { self.0 } } impl<'a, T: EncodeLike, U: Encode> From<&'a T> for Ref<'a, T, U> { fn from(x: &'a T) -> Self { Ref(x, Default::default()) } } impl<'a, T: EncodeLike, U: Encode> crate::WrapperTypeEncode for Ref<'a, T, U> {} impl<'a, T: EncodeLike, U: Encode> EncodeLike for Ref<'a, T, U> {} impl<'a, T: EncodeLike, U: Encode> EncodeLike for &Ref<'a, T, U> {} #[cfg(test)] mod tests { use super::*; use std::collections::BTreeMap; struct ComplexStuff(T); impl ComplexStuff { fn complex_method(value: &R) -> Vec where T: EncodeLike { value.encode() } } #[test] fn vec_and_slice_are_working() { let slice: &[u8] = &[1, 2, 3, 4]; let data: Vec = slice.iter().copied().collect(); let data_encoded = data.encode(); let slice_encoded = ComplexStuff::>::complex_method(&slice); assert_eq!(slice_encoded, data_encoded); } #[test] fn btreemap_and_slice_are_working() { let slice: &[(u32, u32)] = &[(1, 2), (23, 24), (28, 30), (45, 80)]; let data: BTreeMap = slice.iter().copied().collect(); let data_encoded = data.encode(); let slice_encoded = ComplexStuff::>::complex_method(&slice); assert_eq!(slice_encoded, data_encoded); } #[test] fn interface_testing() { let value = 10u32; let data = (value, value, value); let encoded = ComplexStuff::<(u32, u32, u32)>::complex_method(&data); assert_eq!(data.encode(), encoded); let data = (&value, &value, &value); let encoded = ComplexStuff::<(u32, u32, u32)>::complex_method(&data); assert_eq!(data.encode(), encoded); let data = (&value, value, &value); let encoded = ComplexStuff::<(u32, u32, u32)>::complex_method(&data); assert_eq!(data.encode(), encoded); let vec_data: Vec = vec![1, 2, 3]; ComplexStuff::>::complex_method(&vec_data); ComplexStuff::<&'static str>::complex_method(&String::from("test")); ComplexStuff::<&'static str>::complex_method(&"test"); let slice: &[u8] = &vec_data; assert_eq!( ComplexStuff::<(u32, Vec)>::complex_method(&(1u32, slice.to_vec())), ComplexStuff::<(u32, Vec)>::complex_method(&(1u32, slice)) ); } } parity-scale-codec-3.6.4/src/error.rs000064400000000000000000000065101046102023000155760ustar 00000000000000// Copyright 2021 Parity Technologies // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //! Error type, descriptive or undescriptive depending on features. use crate::alloc::borrow::Cow; #[cfg(feature = "chain-error")] use crate::alloc::boxed::Box; /// Error type. /// /// Descriptive on `std` environment, with chaining error on `chain-error` environment, /// underscriptive otherwise. #[derive(PartialEq, Eq, Clone, Debug)] pub struct Error { #[cfg(feature = "chain-error")] cause: Option>, #[cfg(feature = "chain-error")] desc: Cow<'static, str>, } impl Error { /// Chain error message with description. /// /// When compiled with `chain-error` feature, the description is chained, otherwise the /// description is ditched. pub fn chain(self, desc: impl Into>) -> Self { #[cfg(feature = "chain-error")] { Self { desc: desc.into(), cause: Some(Box::new(self)) } } #[cfg(not(feature = "chain-error"))] { let _ = desc; self } } /// Display error with indentation. #[cfg(feature = "chain-error")] fn display_with_indent(&self, indent: u32, f: &mut core::fmt::Formatter) -> core::fmt::Result { for _ in 0..indent { f.write_str("\t")?; } f.write_str(&self.desc)?; if let Some(cause) = &self.cause { f.write_str(":")?; f.write_str("\n")?; cause.display_with_indent(indent + 1, f) } else { // Only return to new line if the error has been displayed with some indent, // i.e. if the error has some causes. if indent != 0 { f.write_str("\n")?; } Ok(()) } } } impl core::fmt::Display for Error { fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { #[cfg(feature = "chain-error")] { self.display_with_indent(0, f) } #[cfg(not(feature = "chain-error"))] { f.write_str("Codec error") } } } impl From<&'static str> for Error { fn from(desc: &'static str) -> Error { #[cfg(feature = "chain-error")] { Error { desc: desc.into(), cause: None } } #[cfg(not(feature = "chain-error"))] { let _ = desc; Error {} } } } #[cfg(feature = "std")] impl std::error::Error for Error { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { #[cfg(feature = "chain-error")] { self.cause.as_ref().map(|e| e as &(dyn std::error::Error + 'static)) } #[cfg(not(feature = "chain-error"))] { None } } } #[cfg(test)] mod tests { use crate::Error; #[test] fn test_full_error() { let msg: &str = "final type:\n\twrap cause:\n\t\troot cause\n"; let error = Error::from("root cause").chain("wrap cause").chain("final type"); assert_eq!(&error.to_string(), msg); } #[test] fn impl_std_error() { use std::error::Error as _; let error = Error::from("root cause").chain("wrap cause").chain("final type"); let s = error.source().unwrap(); assert_eq!(&s.to_string(), "wrap cause:\n\troot cause\n"); } } parity-scale-codec-3.6.4/src/generic_array.rs000064400000000000000000000042641046102023000172630ustar 00000000000000// Copyright 2019 Parity Technologies // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. use crate::alloc::vec::Vec; use crate::{Encode, Decode, Input, Output, Error}; use crate::encode_like::EncodeLike; impl> Encode for generic_array::GenericArray { fn encode_to(&self, dest: &mut W) { for item in self.iter() { item.encode_to(dest); } } } impl> EncodeLike for generic_array::GenericArray {} impl> Decode for generic_array::GenericArray { fn decode(input: &mut I) -> Result { let mut r = Vec::with_capacity(L::to_usize()); for _ in 0..L::to_usize() { r.push(T::decode(input)?); } let i = generic_array::GenericArray::from_exact_iter(r); match i { Some(a) => Ok(a), None => Err("array length does not match definition".into()), } } } #[cfg(test)] mod tests { use super::*; use generic_array::{typenum, GenericArray, arr}; #[test] fn generic_array() { let test = arr![u8; 3, 4, 5]; let encoded = test.encode(); assert_eq!(test, GenericArray::::decode(&mut &encoded[..]).unwrap()); let test = arr![u16; 3, 4, 5, 6, 7, 8, 0]; let encoded = test.encode(); assert_eq!(test, GenericArray::::decode(&mut &encoded[..]).unwrap()); let test = arr![u32; 3, 4, 5, 0, 1]; let encoded = test.encode(); assert_eq!(test, GenericArray::::decode(&mut &encoded[..]).unwrap()); let test = arr![u64; 3]; let encoded = test.encode(); assert_eq!(test, GenericArray::::decode(&mut &encoded[..]).unwrap()); } } parity-scale-codec-3.6.4/src/joiner.rs000064400000000000000000000020171046102023000157310ustar 00000000000000// Copyright 2017, 2018 Parity Technologies // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //! Trait use core::iter::Extend; use crate::codec::Codec; /// Trait to allow itself to be serialised into a value which can be extended /// by bytes. pub trait Joiner { /// Append encoding of value to `Self`. fn and(self, value: &V) -> Self; } impl Joiner for T where T: for<'a> Extend<&'a u8> { fn and(mut self, value: &V) -> Self { value.using_encoded(|s| self.extend(s)); self } } parity-scale-codec-3.6.4/src/keyedvec.rs000064400000000000000000000021401046102023000162370ustar 00000000000000// Copyright 2017, 2018 Parity Technologies // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //! Serializer and prepender. use core::iter::Extend; use crate::alloc::vec::Vec; use crate::codec::Codec; /// Trait to allow itself to be serialised and prepended by a given slice. pub trait KeyedVec { /// Return an encoding of `Self` prepended by given slice. fn to_keyed_vec(&self, prepend_key: &[u8]) -> Vec; } impl KeyedVec for T { fn to_keyed_vec(&self, prepend_key: &[u8]) -> Vec { self.using_encoded(|slice| { let mut r = prepend_key.to_vec(); r.extend(slice); r }) } } parity-scale-codec-3.6.4/src/lib.rs000064400000000000000000000075321046102023000152200ustar 00000000000000// Copyright 2017-2021 Parity Technologies // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #![doc = include_str!("../README.md")] #![warn(missing_docs)] #![cfg_attr(not(feature = "std"), no_std)] #[cfg(not(feature = "std"))] #[macro_use] #[doc(hidden)] pub extern crate alloc; #[cfg(feature = "derive")] #[allow(unused_imports)] #[macro_use] extern crate parity_scale_codec_derive; #[cfg(all(feature = "std", test))] #[macro_use] extern crate serde_derive; #[cfg(feature = "derive")] pub use parity_scale_codec_derive::*; #[cfg(feature = "std")] #[doc(hidden)] pub mod alloc { pub use std::boxed; pub use std::vec; pub use std::string; pub use std::borrow; pub use std::collections; pub use std::sync; pub use std::rc; pub use std::alloc; } mod codec; mod compact; mod joiner; mod keyedvec; #[cfg(feature = "bit-vec")] mod bit_vec; #[cfg(feature = "generic-array")] mod generic_array; mod decode_all; mod decode_finished; mod depth_limit; mod encode_append; mod encode_like; mod error; #[cfg(feature = "max-encoded-len")] mod max_encoded_len; #[cfg(feature = "max-encoded-len")] mod const_encoded_len; pub use self::error::Error; pub use self::codec::{ Input, Output, Decode, Encode, Codec, EncodeAsRef, WrapperTypeEncode, WrapperTypeDecode, OptionBool, DecodeLength, FullCodec, FullEncode, decode_vec_with_len, }; #[cfg(feature = "std")] pub use self::codec::IoReader; pub use self::compact::{Compact, HasCompact, CompactAs, CompactLen, CompactRef}; pub use self::joiner::Joiner; pub use self::keyedvec::KeyedVec; pub use self::decode_all::DecodeAll; pub use self::decode_finished::DecodeFinished; pub use self::depth_limit::DecodeLimit; pub use self::encode_append::EncodeAppend; pub use self::encode_like::{EncodeLike, Ref}; #[cfg(feature = "max-encoded-len")] pub use max_encoded_len::MaxEncodedLen; #[cfg(feature = "max-encoded-len")] pub use const_encoded_len::ConstEncodedLen; /// Derive macro for [`MaxEncodedLen`][max_encoded_len::MaxEncodedLen]. /// /// # Examples /// /// ``` /// # use parity_scale_codec::{Encode, MaxEncodedLen}; /// #[derive(Encode, MaxEncodedLen)] /// struct Example; /// ``` /// /// ``` /// # use parity_scale_codec::{Encode, MaxEncodedLen}; /// #[derive(Encode, MaxEncodedLen)] /// struct TupleStruct(u8, u32); /// /// assert_eq!(TupleStruct::max_encoded_len(), u8::max_encoded_len() + u32::max_encoded_len()); /// ``` /// /// ``` /// # use parity_scale_codec::{Encode, MaxEncodedLen}; /// #[derive(Encode, MaxEncodedLen)] /// enum GenericEnum { /// A, /// B(T), /// } /// /// assert_eq!(GenericEnum::::max_encoded_len(), u8::max_encoded_len() + u8::max_encoded_len()); /// assert_eq!(GenericEnum::::max_encoded_len(), u8::max_encoded_len() + u128::max_encoded_len()); /// ``` /// /// # Within other macros /// /// Sometimes the `MaxEncodedLen` trait and macro are used within another macro, and it can't be /// guaranteed that the `parity_scale_codec` module is available at the call site. In that case, the /// macro should reexport the `parity_scale_codec` module and specify the path to the reexport: /// /// ```ignore /// pub use parity_scale_codec as codec; /// /// #[derive(Encode, MaxEncodedLen)] /// #[codec(crate = $crate::codec)] /// struct Example; /// ``` #[cfg(all(feature = "derive", feature = "max-encoded-len"))] pub use parity_scale_codec_derive::MaxEncodedLen; #[cfg(feature = "bytes")] pub use self::codec::decode_from_bytes; parity-scale-codec-3.6.4/src/max_encoded_len.rs000064400000000000000000000111151046102023000175460ustar 00000000000000// Copyright (C) 2021 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //! `trait MaxEncodedLen` bounds the maximum encoded length of items. use crate::{Compact, Encode}; use impl_trait_for_tuples::impl_for_tuples; use core::{mem, marker::PhantomData, num::*, ops::{Range, RangeInclusive}, time::Duration}; use crate::alloc::boxed::Box; #[cfg(target_has_atomic = "ptr")] use crate::alloc::sync::Arc; /// Items implementing `MaxEncodedLen` have a statically known maximum encoded size. /// /// Some containers, such as `BoundedVec`, have enforced size limits and this trait /// can be implemented accurately. Other containers, such as `StorageMap`, do not have enforced size /// limits. For those containers, it is necessary to make a documented assumption about the maximum /// usage, and compute the max encoded length based on that assumption. pub trait MaxEncodedLen: Encode { /// Upper bound, in bytes, of the maximum encoded size of this item. fn max_encoded_len() -> usize; } macro_rules! impl_primitives { ( $($t:ty),+ ) => { $( impl MaxEncodedLen for $t { fn max_encoded_len() -> usize { mem::size_of::<$t>() } } )+ }; } impl_primitives!(u8, u16, u32, u64, u128, i8, i16, i32, i64, i128, bool); impl_primitives!( NonZeroU8, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU128, NonZeroI8, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI128 ); macro_rules! impl_compact { ($( $t:ty => $e:expr; )*) => { $( impl MaxEncodedLen for Compact<$t> { fn max_encoded_len() -> usize { $e } } )* }; } impl_compact!( // github.com/paritytech/parity-scale-codec/blob/f0341dabb01aa9ff0548558abb6dcc5c31c669a1/src/compact.rs#L261 u8 => 2; // github.com/paritytech/parity-scale-codec/blob/f0341dabb01aa9ff0548558abb6dcc5c31c669a1/src/compact.rs#L291 u16 => 4; // github.com/paritytech/parity-scale-codec/blob/f0341dabb01aa9ff0548558abb6dcc5c31c669a1/src/compact.rs#L326 u32 => 5; // github.com/paritytech/parity-scale-codec/blob/f0341dabb01aa9ff0548558abb6dcc5c31c669a1/src/compact.rs#L369 u64 => 9; // github.com/paritytech/parity-scale-codec/blob/f0341dabb01aa9ff0548558abb6dcc5c31c669a1/src/compact.rs#L413 u128 => 17; ); // impl_for_tuples for values 19 and higher fails because that's where the WrapperTypeEncode impl stops. #[impl_for_tuples(18)] impl MaxEncodedLen for Tuple { fn max_encoded_len() -> usize { let mut len: usize = 0; for_tuples!( #( len = len.saturating_add(Tuple::max_encoded_len()); )* ); len } } impl MaxEncodedLen for [T; N] { fn max_encoded_len() -> usize { T::max_encoded_len().saturating_mul(N) } } impl MaxEncodedLen for Box { fn max_encoded_len() -> usize { T::max_encoded_len() } } #[cfg(target_has_atomic = "ptr")] impl MaxEncodedLen for Arc { fn max_encoded_len() -> usize { T::max_encoded_len() } } impl MaxEncodedLen for Option { fn max_encoded_len() -> usize { T::max_encoded_len().saturating_add(1) } } impl MaxEncodedLen for Result where T: MaxEncodedLen, E: MaxEncodedLen, { fn max_encoded_len() -> usize { T::max_encoded_len().max(E::max_encoded_len()).saturating_add(1) } } impl MaxEncodedLen for PhantomData { fn max_encoded_len() -> usize { 0 } } impl MaxEncodedLen for Duration { fn max_encoded_len() -> usize { u64::max_encoded_len() + u32::max_encoded_len() } } impl MaxEncodedLen for Range { fn max_encoded_len() -> usize { T::max_encoded_len().saturating_mul(2) } } impl MaxEncodedLen for RangeInclusive { fn max_encoded_len() -> usize { T::max_encoded_len().saturating_mul(2) } } #[cfg(test)] mod tests { use super::*; macro_rules! test_compact_length { ($(fn $name:ident($t:ty);)*) => { $( #[test] fn $name() { assert_eq!(Compact(<$t>::MAX).encode().len(), Compact::<$t>::max_encoded_len()); } )* }; } test_compact_length!( fn compact_u8(u8); fn compact_u16(u16); fn compact_u32(u32); fn compact_u64(u64); fn compact_u128(u128); ); } parity-scale-codec-3.6.4/tests/chain-error.rs000064400000000000000000000044171046102023000172350ustar 00000000000000// Copyright 2021 Parity Technologies // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. use parity_scale_codec_derive::Decode as DeriveDecode; use parity_scale_codec::Decode; #[derive(DeriveDecode, Debug)] struct Wrapper(T); #[derive(DeriveDecode, Debug)] struct StructNamed { _foo: u16 } #[derive(DeriveDecode, Debug)] struct StructUnnamed(u16); #[derive(DeriveDecode, Debug)] enum E { VariantNamed { _foo: u16, }, VariantUnnamed(u16), } #[test] fn full_error_struct_named() { let encoded = vec![0]; let err = r#"Could not decode `Wrapper.0`: Could not decode `StructNamed::_foo`: Not enough data to fill buffer "#; assert_eq!( Wrapper::::decode(&mut &encoded[..]).unwrap_err().to_string(), String::from(err), ); } #[test] fn full_error_struct_unnamed() { let encoded = vec![0]; let err = r#"Could not decode `Wrapper.0`: Could not decode `StructUnnamed.0`: Not enough data to fill buffer "#; assert_eq!( Wrapper::::decode(&mut &encoded[..]).unwrap_err().to_string(), String::from(err), ); } #[test] fn full_error_enum_unknown_variant() { let encoded = vec![2]; let err = r#"Could not decode `E`, variant doesn't exist"#; assert_eq!( E::decode(&mut &encoded[..]).unwrap_err().to_string(), String::from(err), ); } #[test] fn full_error_enum_named_field() { let encoded = vec![0, 0]; let err = r#"Could not decode `E::VariantNamed::_foo`: Not enough data to fill buffer "#; assert_eq!( E::decode(&mut &encoded[..]).unwrap_err().to_string(), String::from(err), ); } #[test] fn full_error_enum_unnamed_field() { let encoded = vec![1, 0]; let err = r#"Could not decode `E::VariantUnnamed.0`: Not enough data to fill buffer "#; assert_eq!( E::decode(&mut &encoded[..]).unwrap_err().to_string(), String::from(err), ); } parity-scale-codec-3.6.4/tests/clippy.rs000064400000000000000000000016211046102023000163160ustar 00000000000000// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //! This file is checked by clippy to make sure that the code generated by the derive macro //! doesn't spew out warnings/errors in users' code. use parity_scale_codec_derive::{Decode, Encode}; #[repr(u8)] #[derive(Decode, Encode)] pub enum CLike { Foo = 0, Bar = 1, } parity-scale-codec-3.6.4/tests/max_encoded_len.rs000064400000000000000000000107631046102023000201310ustar 00000000000000// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //! Tests for MaxEncodedLen derive macro #![cfg(all(feature = "derive", feature = "max-encoded-len"))] use parity_scale_codec::{MaxEncodedLen, Compact, Decode, Encode}; #[derive(Encode, MaxEncodedLen)] struct Primitives { bool: bool, eight: u8, } #[test] fn primitives_max_length() { assert_eq!(Primitives::max_encoded_len(), 2); } #[derive(Encode, MaxEncodedLen)] struct SkippedField { bool: bool, #[codec(skip)] _skipped: u64, } #[test] fn skipped_field_max_length() { assert_eq!(SkippedField::max_encoded_len(), 1); } #[derive(Encode, MaxEncodedLen)] struct Composites { fixed_size_array: [u8; 128], tuple: (u128, u128), } #[test] fn composites_max_length() { assert_eq!(Composites::max_encoded_len(), 128 + 16 + 16); } #[derive(Encode, MaxEncodedLen)] struct Generic { one: T, two: T, } #[test] fn generic_max_length() { assert_eq!(Generic::::max_encoded_len(), u8::max_encoded_len() * 2); assert_eq!(Generic::::max_encoded_len(), u32::max_encoded_len() * 2); } #[derive(Encode, MaxEncodedLen)] struct TwoGenerics { t: T, u: U, } #[test] fn two_generics_max_length() { assert_eq!( TwoGenerics::::max_encoded_len(), u8::max_encoded_len() + u16::max_encoded_len() ); assert_eq!( TwoGenerics::, [u16; 8]>::max_encoded_len(), Compact::::max_encoded_len() + <[u16; 8]>::max_encoded_len() ); } #[derive(Encode, MaxEncodedLen)] struct UnitStruct; #[test] fn unit_struct_max_length() { assert_eq!(UnitStruct::max_encoded_len(), 0); } #[derive(Encode, MaxEncodedLen)] struct TupleStruct(u8, u32); #[test] fn tuple_struct_max_length() { assert_eq!(TupleStruct::max_encoded_len(), u8::max_encoded_len() + u32::max_encoded_len()); } #[derive(Encode, MaxEncodedLen)] struct TupleGeneric(T, T); #[test] fn tuple_generic_max_length() { assert_eq!(TupleGeneric::::max_encoded_len(), u8::max_encoded_len() * 2); assert_eq!(TupleGeneric::::max_encoded_len(), u32::max_encoded_len() * 2); } #[derive(Encode)] struct ConstU32; trait Get: Encode { fn get() -> T; } impl Get for ConstU32 { fn get() -> u32 { N } } #[derive(Encode)] struct SomeVec { element: T, size: N, } impl> MaxEncodedLen for SomeVec { fn max_encoded_len() -> usize { T::max_encoded_len() * N::get() as usize } } #[derive(Encode, MaxEncodedLen)] #[codec(mel_bound(N: Get))] struct SizeGeneric { vec: SomeVec, } #[test] fn some_vec_max_length() { assert_eq!(SomeVec::>::max_encoded_len(), u64::max_encoded_len() * 3); assert_eq!(SizeGeneric::>::max_encoded_len(), u64::max_encoded_len() * 5); } #[derive(Encode, MaxEncodedLen)] #[allow(unused)] enum UnitEnum { A, B, } #[test] fn unit_enum_max_length() { assert_eq!(UnitEnum::max_encoded_len(), 1); } #[derive(Encode, MaxEncodedLen)] #[allow(unused)] enum TupleEnum { A(u32), B, } #[test] fn tuple_enum_max_length() { assert_eq!(TupleEnum::max_encoded_len(), 1 + u32::max_encoded_len()); } #[derive(Encode, MaxEncodedLen)] #[allow(unused)] enum StructEnum { A { sixty_four: u64, one_twenty_eight: u128 }, B, } #[test] fn struct_enum_max_length() { assert_eq!(StructEnum::max_encoded_len(), 1 + u64::max_encoded_len() + u128::max_encoded_len()); } // ensure that enums take the max of variant length, not the sum #[derive(Encode, MaxEncodedLen)] #[allow(unused)] enum EnumMaxNotSum { A(u32), B(u32), } #[test] fn enum_max_not_sum_max_length() { assert_eq!(EnumMaxNotSum::max_encoded_len(), 1 + u32::max_encoded_len()); } #[test] fn skip_type_params() { #[derive(Encode, Decode, MaxEncodedLen)] #[codec(mel_bound(skip_type_params(N)))] struct SomeData { element: T, size: std::marker::PhantomData, } trait SomeTrait {} struct SomeStruct; impl SomeTrait for SomeStruct {} assert_eq!(SomeData::::max_encoded_len(), 4); } parity-scale-codec-3.6.4/tests/max_encoded_len_ui/crate_str.rs000064400000000000000000000002761046102023000226120ustar 00000000000000use parity_scale_codec::{Encode, MaxEncodedLen}; #[derive(Encode, MaxEncodedLen)] #[codec(crate = "parity_scale_codec")] struct Example; fn main() { let _ = Example::max_encoded_len(); } parity-scale-codec-3.6.4/tests/max_encoded_len_ui/crate_str.stderr000064400000000000000000000021511046102023000234630ustar 00000000000000error: Invalid attribute: only `#[codec(dumb_trait_bound)]`, `#[codec(crate = path::to::crate)]`, `#[codec(encode_bound(T: Encode))]`, `#[codec(decode_bound(T: Decode))]`, or `#[codec(mel_bound(T: MaxEncodedLen))]` are accepted as top attribute --> tests/max_encoded_len_ui/crate_str.rs:4:9 | 4 | #[codec(crate = "parity_scale_codec")] | ^^^^^ error[E0277]: the trait bound `Example: WrapperTypeEncode` is not satisfied --> tests/max_encoded_len_ui/crate_str.rs:5:8 | 5 | struct Example; | ^^^^^^^ the trait `WrapperTypeEncode` is not implemented for `Example` | = help: the following other types implement trait `WrapperTypeEncode`: &T &mut T Arc Box Cow<'a, T> Rc String Vec parity_scale_codec::Ref<'a, T, U> = note: required for `Example` to implement `Encode` note: required by a bound in `MaxEncodedLen` --> src/max_encoded_len.rs | | pub trait MaxEncodedLen: Encode { | ^^^^^^ required by this bound in `MaxEncodedLen` parity-scale-codec-3.6.4/tests/max_encoded_len_ui/incomplete_attr.rs000064400000000000000000000002471046102023000240130ustar 00000000000000use parity_scale_codec::{Encode, MaxEncodedLen}; #[derive(Encode, MaxEncodedLen)] #[codec(crate)] struct Example; fn main() { let _ = Example::max_encoded_len(); } parity-scale-codec-3.6.4/tests/max_encoded_len_ui/incomplete_attr.stderr000064400000000000000000000021361046102023000246710ustar 00000000000000error: Invalid attribute: only `#[codec(dumb_trait_bound)]`, `#[codec(crate = path::to::crate)]`, `#[codec(encode_bound(T: Encode))]`, `#[codec(decode_bound(T: Decode))]`, or `#[codec(mel_bound(T: MaxEncodedLen))]` are accepted as top attribute --> tests/max_encoded_len_ui/incomplete_attr.rs:4:9 | 4 | #[codec(crate)] | ^^^^^ error[E0277]: the trait bound `Example: WrapperTypeEncode` is not satisfied --> tests/max_encoded_len_ui/incomplete_attr.rs:5:8 | 5 | struct Example; | ^^^^^^^ the trait `WrapperTypeEncode` is not implemented for `Example` | = help: the following other types implement trait `WrapperTypeEncode`: &T &mut T Arc Box Cow<'a, T> Rc String Vec parity_scale_codec::Ref<'a, T, U> = note: required for `Example` to implement `Encode` note: required by a bound in `MaxEncodedLen` --> src/max_encoded_len.rs | | pub trait MaxEncodedLen: Encode { | ^^^^^^ required by this bound in `MaxEncodedLen` parity-scale-codec-3.6.4/tests/max_encoded_len_ui/missing_crate_specifier.rs000064400000000000000000000002641046102023000255010ustar 00000000000000use parity_scale_codec::{Encode, MaxEncodedLen}; #[derive(Encode, MaxEncodedLen)] #[codec(parity_scale_codec)] struct Example; fn main() { let _ = Example::max_encoded_len(); } parity-scale-codec-3.6.4/tests/max_encoded_len_ui/missing_crate_specifier.stderr000064400000000000000000000022101046102023000263510ustar 00000000000000error: Invalid attribute: only `#[codec(dumb_trait_bound)]`, `#[codec(crate = path::to::crate)]`, `#[codec(encode_bound(T: Encode))]`, `#[codec(decode_bound(T: Decode))]`, or `#[codec(mel_bound(T: MaxEncodedLen))]` are accepted as top attribute --> tests/max_encoded_len_ui/missing_crate_specifier.rs:4:9 | 4 | #[codec(parity_scale_codec)] | ^^^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `Example: WrapperTypeEncode` is not satisfied --> tests/max_encoded_len_ui/missing_crate_specifier.rs:5:8 | 5 | struct Example; | ^^^^^^^ the trait `WrapperTypeEncode` is not implemented for `Example` | = help: the following other types implement trait `WrapperTypeEncode`: &T &mut T Arc Box Cow<'a, T> Rc String Vec parity_scale_codec::Ref<'a, T, U> = note: required for `Example` to implement `Encode` note: required by a bound in `MaxEncodedLen` --> src/max_encoded_len.rs | | pub trait MaxEncodedLen: Encode { | ^^^^^^ required by this bound in `MaxEncodedLen` parity-scale-codec-3.6.4/tests/max_encoded_len_ui/not_encode.rs000064400000000000000000000001431046102023000227320ustar 00000000000000use parity_scale_codec::{MaxEncodedLen}; #[derive(MaxEncodedLen)] struct NotEncode; fn main() {} parity-scale-codec-3.6.4/tests/max_encoded_len_ui/not_encode.stderr000064400000000000000000000014161046102023000236150ustar 00000000000000error[E0277]: the trait bound `NotEncode: WrapperTypeEncode` is not satisfied --> tests/max_encoded_len_ui/not_encode.rs:4:8 | 4 | struct NotEncode; | ^^^^^^^^^ the trait `WrapperTypeEncode` is not implemented for `NotEncode` | = help: the following other types implement trait `WrapperTypeEncode`: &T &mut T Arc Box Cow<'a, T> Rc String Vec parity_scale_codec::Ref<'a, T, U> = note: required for `NotEncode` to implement `Encode` note: required by a bound in `MaxEncodedLen` --> src/max_encoded_len.rs | | pub trait MaxEncodedLen: Encode { | ^^^^^^ required by this bound in `MaxEncodedLen` parity-scale-codec-3.6.4/tests/max_encoded_len_ui/not_mel.rs000064400000000000000000000003201046102023000222470ustar 00000000000000use parity_scale_codec::{Encode, MaxEncodedLen}; #[derive(Encode)] struct NotMel; #[derive(Encode, MaxEncodedLen)] struct Generic { t: T, } fn main() { let _ = Generic::::max_encoded_len(); } parity-scale-codec-3.6.4/tests/max_encoded_len_ui/not_mel.stderr000064400000000000000000000021541046102023000231350ustar 00000000000000error[E0599]: the function or associated item `max_encoded_len` exists for struct `Generic`, but its trait bounds were not satisfied --> tests/max_encoded_len_ui/not_mel.rs:12:29 | 4 | struct NotMel; | ------------- doesn't satisfy `NotMel: MaxEncodedLen` ... 7 | struct Generic { | ----------------- | | | function or associated item `max_encoded_len` not found for this struct | doesn't satisfy `Generic: MaxEncodedLen` ... 12 | let _ = Generic::::max_encoded_len(); | ^^^^^^^^^^^^^^^ function or associated item cannot be called on `Generic` due to unsatisfied trait bounds | = note: trait bound `NotMel: MaxEncodedLen` was not satisfied note: the trait `MaxEncodedLen` must be implemented --> src/max_encoded_len.rs | | pub trait MaxEncodedLen: Encode { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = help: items from traits can only be used if the trait is implemented and in scope = note: the following trait defines an item `max_encoded_len`, perhaps you need to implement it: candidate #1: `MaxEncodedLen` parity-scale-codec-3.6.4/tests/max_encoded_len_ui/pass/codec_crate.rs000064400000000000000000000004261046102023000240220ustar 00000000000000//! This test case demonstrates correct use of the `#[codec(crate = path)]` attribute. use parity_scale_codec::{self as codec, Encode, MaxEncodedLen}; #[derive(Encode, MaxEncodedLen)] #[codec(crate = codec)] struct Example; fn main() { let _ = Example::max_encoded_len(); } parity-scale-codec-3.6.4/tests/max_encoded_len_ui/union.rs000064400000000000000000000002021046102023000217410ustar 00000000000000use parity_scale_codec::{Encode, MaxEncodedLen}; #[derive(Encode, MaxEncodedLen)] union Union { a: u8, b: u16, } fn main() {} parity-scale-codec-3.6.4/tests/max_encoded_len_ui/union.stderr000064400000000000000000000001351046102023000226250ustar 00000000000000error: Union types are not supported. --> $DIR/union.rs:4:1 | 4 | union Union { | ^^^^^ parity-scale-codec-3.6.4/tests/max_encoded_len_ui/unsupported_variant.rs000064400000000000000000000002601046102023000247310ustar 00000000000000use parity_scale_codec::{Encode, MaxEncodedLen}; #[derive(Encode)] struct NotMel; #[derive(Encode, MaxEncodedLen)] enum UnsupportedVariant { NotMel(NotMel), } fn main() {} parity-scale-codec-3.6.4/tests/max_encoded_len_ui/unsupported_variant.stderr000064400000000000000000000011471046102023000256150ustar 00000000000000error[E0599]: no function or associated item named `max_encoded_len` found for struct `NotMel` in the current scope --> tests/max_encoded_len_ui/unsupported_variant.rs:8:9 | 4 | struct NotMel; | ------------- function or associated item `max_encoded_len` not found for this struct ... 8 | NotMel(NotMel), | ^^^^^^ function or associated item not found in `NotMel` | = help: items from traits can only be used if the trait is implemented and in scope = note: the following trait defines an item `max_encoded_len`, perhaps you need to implement it: candidate #1: `MaxEncodedLen` parity-scale-codec-3.6.4/tests/max_encoded_len_ui.rs000064400000000000000000000017121046102023000206200ustar 00000000000000// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #[test] #[cfg(feature = "derive")] fn derive_no_bound_ui() { // As trybuild is using `cargo check`, we don't need the real WASM binaries. std::env::set_var("SKIP_WASM_BUILD", "1"); let t = trybuild::TestCases::new(); t.compile_fail("tests/max_encoded_len_ui/*.rs"); t.pass("tests/max_encoded_len_ui/pass/*.rs"); } parity-scale-codec-3.6.4/tests/mod.rs000064400000000000000000000500761046102023000156050ustar 00000000000000// Copyright 2017, 2018 Parity Technologies // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. use parity_scale_codec::{ Compact, CompactAs, Decode, Encode, EncodeAsRef, Error, HasCompact, Output, }; use parity_scale_codec_derive::{Decode as DeriveDecode, Encode as DeriveEncode}; use serde_derive::{Deserialize, Serialize}; #[derive(Debug, PartialEq, DeriveEncode, DeriveDecode)] struct Unit; #[derive(Debug, PartialEq, DeriveEncode, DeriveDecode)] struct Indexed(u32, u64); #[derive(Debug, PartialEq, DeriveEncode, DeriveDecode, Default)] struct Struct { pub a: A, pub b: B, pub c: C, } #[derive(Debug, PartialEq, DeriveEncode, DeriveDecode)] struct StructWithPhantom { pub a: u32, pub b: u64, _c: std::marker::PhantomData, } type TestType = Struct>; impl Struct { fn new(a: A, b: B, c: C) -> Self { Self { a, b, c } } } #[derive(Debug, PartialEq, DeriveEncode, DeriveDecode)] enum EnumType { #[codec(index = 15)] A, B(u32, u64), C { a: u32, b: u64, }, } #[derive(Debug, PartialEq, DeriveEncode, DeriveDecode)] enum EnumWithDiscriminant { A = 1, B = 15, C = 255, } #[derive(Debug, PartialEq, DeriveEncode, DeriveDecode)] struct TestHasCompact { #[codec(encoded_as = "::Type")] bar: T, } #[derive(Debug, PartialEq, DeriveEncode, DeriveDecode)] struct TestCompactHasCompact { #[codec(compact)] bar: T, } #[derive(Debug, PartialEq, DeriveEncode, DeriveDecode)] enum TestHasCompactEnum { Unnamed(#[codec(encoded_as = "::Type")] T), Named { #[codec(encoded_as = "::Type")] bar: T, }, UnnamedCompact(#[codec(compact)] T), NamedCompact { #[codec(compact)] bar: T, }, } #[derive(Debug, PartialEq, DeriveEncode, DeriveDecode)] struct TestCompactAttribute { #[codec(compact)] bar: u64, } #[derive(Debug, PartialEq, DeriveEncode, DeriveDecode)] enum TestCompactAttributeEnum { Unnamed(#[codec(compact)] u64), Named { #[codec(compact)] bar: u64, }, } #[test] fn should_work_for_simple_enum() { let a = EnumType::A; let b = EnumType::B(1, 2); let c = EnumType::C { a: 1, b: 2 }; a.using_encoded(|ref slice| { assert_eq!(slice, &b"\x0f"); }); b.using_encoded(|ref slice| { assert_eq!(slice, &b"\x01\x01\0\0\0\x02\0\0\0\0\0\0\0"); }); c.using_encoded(|ref slice| { assert_eq!(slice, &b"\x02\x01\0\0\0\x02\0\0\0\0\0\0\0"); }); let mut da: &[u8] = b"\x0f"; assert_eq!(EnumType::decode(&mut da).ok(), Some(a)); let mut db: &[u8] = b"\x01\x01\0\0\0\x02\0\0\0\0\0\0\0"; assert_eq!(EnumType::decode(&mut db).ok(), Some(b)); let mut dc: &[u8] = b"\x02\x01\0\0\0\x02\0\0\0\0\0\0\0"; assert_eq!(EnumType::decode(&mut dc).ok(), Some(c)); let mut dz: &[u8] = &[0]; assert_eq!(EnumType::decode(&mut dz).ok(), None); } #[test] fn should_work_for_enum_with_discriminant() { EnumWithDiscriminant::A.using_encoded(|ref slice| { assert_eq!(slice, &[1]); }); EnumWithDiscriminant::B.using_encoded(|ref slice| { assert_eq!(slice, &[15]); }); EnumWithDiscriminant::C.using_encoded(|ref slice| { assert_eq!(slice, &[255]); }); let mut da: &[u8] = &[1]; assert_eq!(EnumWithDiscriminant::decode(&mut da), Ok(EnumWithDiscriminant::A)); let mut db: &[u8] = &[15]; assert_eq!(EnumWithDiscriminant::decode(&mut db), Ok(EnumWithDiscriminant::B)); let mut dc: &[u8] = &[255]; assert_eq!(EnumWithDiscriminant::decode(&mut dc), Ok(EnumWithDiscriminant::C)); let mut dz: &[u8] = &[2]; assert_eq!(EnumWithDiscriminant::decode(&mut dz).ok(), None); } #[test] fn should_derive_encode() { let v = TestType::new(15, 9, b"Hello world".to_vec()); v.using_encoded(|ref slice| assert_eq!(slice, &b"\x0f\0\0\0\x09\0\0\0\0\0\0\0\x2cHello world")); } #[test] fn should_derive_decode() { let slice = b"\x0f\0\0\0\x09\0\0\0\0\0\0\0\x2cHello world".to_vec(); let v = TestType::decode(&mut &*slice); assert_eq!(v, Ok(TestType::new(15, 9, b"Hello world".to_vec()))); } #[test] fn should_work_for_unit() { let v = Unit; v.using_encoded(|ref slice| { assert_eq!(slice, &[]); }); let mut a: &[u8] = &[]; assert_eq!(Unit::decode(&mut a), Ok(Unit)); } #[test] fn should_work_for_indexed() { let v = Indexed(1, 2); v.using_encoded(|ref slice| assert_eq!(slice, &b"\x01\0\0\0\x02\0\0\0\0\0\0\0")); let mut v: &[u8] = b"\x01\0\0\0\x02\0\0\0\0\0\0\0"; assert_eq!(Indexed::decode(&mut v), Ok(Indexed(1, 2))); } #[test] #[should_panic(expected = "Not enough data to fill buffer")] fn correct_error_for_indexed_0() { let mut wrong: &[u8] = b"\x08"; Indexed::decode(&mut wrong).unwrap(); } #[test] #[should_panic(expected = "Not enough data to fill buffer")] fn correct_error_for_indexed_1() { let mut wrong: &[u8] = b"\0\0\0\0\x01"; Indexed::decode(&mut wrong).unwrap(); } #[test] #[should_panic(expected = "Not enough data to fill buffer")] fn correct_error_for_enumtype() { let mut wrong: &[u8] = b"\x01"; EnumType::decode(&mut wrong).unwrap(); } #[test] #[should_panic(expected = "Not enough data to fill buffer")] fn correct_error_for_named_struct_1() { let mut wrong: &[u8] = b"\x01"; Struct::::decode(&mut wrong).unwrap(); } #[test] #[should_panic(expected = "Not enough data to fill buffer")] fn correct_error_for_named_struct_2() { let mut wrong: &[u8] = b"\0\0\0\0\x01"; Struct::::decode(&mut wrong).unwrap(); } const U64_TEST_COMPACT_VALUES: &[(u64, usize)] = &[ (0u64, 1usize), (63, 1), (64, 2), (16383, 2), (16384, 4), (1073741823, 4), (1073741824, 5), (1 << 32 - 1, 5), (1 << 32, 6), (1 << 40, 7), (1 << 48, 8), (1 << 56 - 1, 8), (1 << 56, 9), (u64::MAX, 9), ]; const U64_TEST_COMPACT_VALUES_FOR_ENUM: &[(u64, usize)] = &[ (0u64, 2usize), (63, 2), (64, 3), (16383, 3), (16384, 5), (1073741823, 5), (1073741824, 6), (1 << 32 - 1, 6), (1 << 32, 7), (1 << 40, 8), (1 << 48, 9), (1 << 56 - 1, 9), (1 << 56, 10), (u64::MAX, 10), ]; #[test] fn encoded_as_with_has_compact_works() { for &(n, l) in U64_TEST_COMPACT_VALUES { let encoded = TestHasCompact { bar: n }.encode(); println!("{}", n); assert_eq!(encoded.len(), l); assert_eq!(>::decode(&mut &encoded[..]).unwrap().bar, n); } } #[test] fn compact_with_has_compact_works() { for &(n, l) in U64_TEST_COMPACT_VALUES { let encoded = TestHasCompact { bar: n }.encode(); println!("{}", n); assert_eq!(encoded.len(), l); assert_eq!(>::decode(&mut &encoded[..]).unwrap().bar, n); } } #[test] fn enum_compact_and_encoded_as_with_has_compact_works() { for &(n, l) in U64_TEST_COMPACT_VALUES_FOR_ENUM { for value in [ TestHasCompactEnum::Unnamed(n), TestHasCompactEnum::Named { bar: n }, TestHasCompactEnum::UnnamedCompact(n), TestHasCompactEnum::NamedCompact { bar: n }, ] .iter() { let encoded = value.encode(); println!("{:?}", value); assert_eq!(encoded.len(), l); assert_eq!(&>::decode(&mut &encoded[..]).unwrap(), value); } } } #[test] fn compact_meta_attribute_works() { for &(n, l) in U64_TEST_COMPACT_VALUES { let encoded = TestCompactAttribute { bar: n }.encode(); assert_eq!(encoded.len(), l); assert_eq!(TestCompactAttribute::decode(&mut &encoded[..]).unwrap().bar, n); } } #[test] fn enum_compact_meta_attribute_works() { for &(n, l) in U64_TEST_COMPACT_VALUES_FOR_ENUM { for value in [TestCompactAttributeEnum::Unnamed(n), TestCompactAttributeEnum::Named { bar: n }] .iter() { let encoded = value.encode(); assert_eq!(encoded.len(), l); assert_eq!(&TestCompactAttributeEnum::decode(&mut &encoded[..]).unwrap(), value); } } } #[test] fn associated_type_bounds() { trait Trait { type EncodableType; type NonEncodableType; } #[derive(DeriveEncode, DeriveDecode, Debug, PartialEq)] struct Struct { field: (Vec, Type), } #[derive(Debug, PartialEq)] struct TraitImplementor; struct NonEncodableType; impl Trait for TraitImplementor { type EncodableType = u32; type NonEncodableType = NonEncodableType; } let value: Struct = Struct { field: (vec![1, 2, 3], 42) }; let encoded = value.encode(); let decoded: Struct = Struct::decode(&mut &encoded[..]).unwrap(); assert_eq!(value, decoded); } #[test] fn generic_bound_encoded_as() { // This struct does not impl Codec nor HasCompact struct StructEncodeAsRef; impl From for StructEncodeAsRef { fn from(_: u32) -> Self { StructEncodeAsRef } } impl<'a> From<&'a StructEncodeAsRef> for &'a u32 { fn from(_: &'a StructEncodeAsRef) -> Self { &0 } } impl<'a> EncodeAsRef<'a, StructEncodeAsRef> for u32 { type RefType = &'a u32; } #[derive(Debug, PartialEq, DeriveEncode, DeriveDecode)] struct TestGeneric> where u32: for<'a> EncodeAsRef<'a, A>, { #[codec(encoded_as = "u32")] a: A, } let a = TestGeneric:: { a: StructEncodeAsRef }; a.encode(); } #[test] fn generic_bound_hascompact() { #[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))] #[derive(PartialEq, Eq, Clone)] // This struct does not impl Codec struct StructHasCompact(u32); impl CompactAs for StructHasCompact { type As = u32; fn encode_as(&self) -> &Self::As { &0 } fn decode_from(_: Self::As) -> Result { Ok(StructHasCompact(0)) } } impl From> for StructHasCompact { fn from(_: Compact) -> Self { StructHasCompact(0) } } #[derive(Debug, PartialEq, DeriveEncode, DeriveDecode)] enum TestGenericHasCompact { A { #[codec(compact)] a: T, }, } let a = TestGenericHasCompact::A:: { a: StructHasCompact(0) }; a.encode(); } #[test] fn generic_trait() { trait TraitNoCodec { type Type; } struct StructNoCodec; #[derive(Debug, PartialEq, DeriveEncode, DeriveDecode)] struct StructCodec; impl TraitNoCodec for StructNoCodec { type Type = StructCodec; } #[derive(Debug, PartialEq, DeriveEncode, DeriveDecode)] struct TestGenericTrait { t: T::Type, } let a = TestGenericTrait:: { t: StructCodec }; a.encode(); } #[test] fn recursive_variant_1_encode_works() { #[derive(Debug, PartialEq, DeriveEncode, DeriveDecode, Default)] struct Recursive { data: N, other: Vec>, } let val: Recursive = Recursive::default(); val.encode(); } #[test] fn recursive_variant_2_encode_works() { #[derive(Debug, PartialEq, DeriveEncode, DeriveDecode, Default)] struct Recursive { data: N, other: Vec>>, } let val: Recursive = Recursive::default(); val.encode(); } #[test] fn private_type_in_where_bound() { // Make the `private type `private_type_in_where_bound::Private` in public interface` warning // an error. #![deny(warnings)] #[derive(Debug, PartialEq, DeriveEncode, DeriveDecode, Default)] struct Private; #[derive(Debug, PartialEq, DeriveEncode, DeriveDecode, Default)] #[codec(dumb_trait_bound)] pub struct Test { data: Vec<(N, Private)>, } let val: Test = Test::default(); val.encode(); } #[test] fn encode_decode_empty_enum() { #[derive(DeriveEncode, DeriveDecode, PartialEq, Debug)] enum EmptyEnumDerive {} fn impls_encode_decode() {} impls_encode_decode::(); assert_eq!( EmptyEnumDerive::decode(&mut &[1, 2, 3][..]), Err("Could not decode `EmptyEnumDerive`, variant doesn't exist".into()) ); } #[test] fn codec_vec_u8() { for v in [vec![0u8; 0], vec![0u8; 10], vec![0u8; 100], vec![0u8; 1000]].iter() { let e = v.encode(); assert_eq!(v, &Vec::::decode(&mut &e[..]).unwrap()); } } #[test] fn recursive_type() { #[derive(DeriveEncode, DeriveDecode)] pub enum Foo { T(Box), A, } #[derive(DeriveEncode, DeriveDecode)] pub struct Bar { field: Foo, } } #[test] fn crafted_input_for_vec_u8() { assert_eq!( Vec::::decode(&mut &Compact(u32::MAX).encode()[..]) .err() .unwrap() .to_string(), "Not enough data to decode vector", ); } #[test] fn crafted_input_for_vec_t() { let msg: String = if cfg!(target_endian = "big") { // use unoptimize decode "Not enough data to fill buffer".into() } else { "Not enough data to decode vector".into() }; assert_eq!( Vec::::decode(&mut &Compact(u32::MAX).encode()[..]) .err() .unwrap() .to_string(), msg, ); } #[test] fn weird_derive() { // Tests that compilation succeeds when the macro invocation // hygiene context is different from the field hygiene context. macro_rules! make_struct { (#[$attr:meta]) => { #[$attr] pub struct MyStruct { field: u8, } }; } make_struct!(#[derive(DeriveEncode, DeriveDecode)]); } #[test] fn output_trait_object() { let _: Box; } #[test] fn custom_trait_bound() { #[derive(DeriveEncode, DeriveDecode)] #[codec(encode_bound(N: Encode, T: Default))] #[codec(decode_bound(N: Decode, T: Default))] struct Something { hello: Hello, val: N, } #[derive(DeriveEncode, DeriveDecode)] #[codec(encode_bound())] #[codec(decode_bound())] struct Hello { _phantom: std::marker::PhantomData, } #[derive(Default)] struct NotEncode; let encoded = Something:: { hello: Hello { _phantom: Default::default() }, val: 32u32 } .encode(); Something::::decode(&mut &encoded[..]).unwrap(); } #[test] #[cfg(feature = "bit-vec")] fn bit_vec_works() { use bitvec::prelude::*; use parity_scale_codec::DecodeAll; // Try some fancy stuff let original_vec = bitvec![u8, Msb0; 1; 8]; let mut original_vec_clone = original_vec.clone(); original_vec_clone = original_vec_clone.split_off(5); original_vec_clone.push(true); original_vec_clone.push(true); original_vec_clone.push(true); original_vec_clone.push(true); original_vec_clone.push(true); assert_eq!(original_vec, original_vec_clone); #[derive(DeriveDecode, DeriveEncode, PartialEq, Debug)] struct MyStruct { v: BitVec, x: u8, } let v1 = MyStruct { v: original_vec, x: 42 }.encode(); let v2 = MyStruct { v: original_vec_clone, x: 42 }.encode(); assert_eq!(v1, v2); let v1 = MyStruct::decode(&mut &v1[..]).unwrap(); let v2 = MyStruct::decode_all(&mut &v2[..]).unwrap(); assert_eq!(v1.x, v2.x); } #[test] fn no_warning_for_deprecated() { #[derive(DeriveEncode, DeriveDecode)] pub enum MyEnum { VariantA, #[deprecated] VariantB, } } #[test] fn decoding_a_huge_array_inside_of_box_does_not_overflow_the_stack() { let data = &[]; let _ = Box::<[u8; 100 * 1024 * 1024]>::decode(&mut data.as_slice()); } #[test] fn decoding_a_huge_array_inside_of_rc_does_not_overflow_the_stack() { let data = &[]; let _ = std::rc::Rc::<[u8; 100 * 1024 * 1024]>::decode(&mut data.as_slice()); } #[test] fn decoding_a_huge_array_inside_of_arc_does_not_overflow_the_stack() { let data = &[]; let _ = std::sync::Arc::<[u8; 100 * 1024 * 1024]>::decode(&mut data.as_slice()); } #[test] fn decoding_a_huge_boxed_newtype_array_does_not_overflow_the_stack() { #[derive(DeriveDecode)] #[repr(transparent)] struct HugeArrayNewtype([u8; 100 * 1024 * 1024]); #[derive(DeriveDecode)] struct HugeArrayNewtypeBox(Box); let data = &[]; assert!(HugeArrayNewtypeBox::decode(&mut data.as_slice()).is_err()); } #[test] fn decoding_two_indirectly_boxed_arrays_works() { // This test will fail if the check for `#[repr(transparent)]` in the derive crate // doesn't work when implementing `Decode::decode_into`. #[derive(DeriveDecode)] #[derive(PartialEq, Eq, Debug)] struct SmallArrays([u8; 2], [u8; 2]); #[derive(DeriveDecode)] struct SmallArraysBox(Box); let data = &[1, 2, 3, 4]; assert_eq!(*SmallArraysBox::decode(&mut data.as_slice()).unwrap().0, SmallArrays([1, 2], [3, 4])); } #[test] fn zero_sized_types_are_properly_decoded_in_a_transparent_boxed_struct() { #[derive(DeriveDecode)] #[repr(transparent)] struct ZstTransparent; #[derive(DeriveDecode)] struct ZstNonTransparent; struct ConsumeByte; #[derive(DeriveDecode)] #[repr(transparent)] struct NewtypeWithZst { _zst_1: ConsumeByte, _zst_2: ZstTransparent, _zst_3: ZstNonTransparent, field: [u8; 1], _zst_4: ConsumeByte } #[derive(DeriveDecode)] struct NewtypeWithZstBox(Box); impl Decode for ConsumeByte { fn decode(input: &mut I) -> Result { let mut buffer = [0; 1]; input.read(&mut buffer).unwrap(); Ok(Self) } } let data = &[1, 2, 3]; assert_eq!(NewtypeWithZst::decode(&mut data.as_slice()).unwrap().field, [2]); } #[test] fn boxed_zero_sized_newtype_with_everything_being_transparent_is_decoded_correctly() { #[derive(DeriveDecode)] #[repr(transparent)] struct Zst; #[derive(DeriveDecode)] #[repr(transparent)] struct NewtypeWithZst(Zst); #[derive(DeriveDecode)] #[repr(transparent)] struct NewtypeWithZstBox(Box); let data = &[]; assert!(NewtypeWithZst::decode(&mut data.as_slice()).is_ok()); } #[test] fn decoding_an_array_of_boxed_zero_sized_types_works() { #[cfg(not(miri))] const SIZE: usize = 100 * 1024 * 1024; #[cfg(miri)] const SIZE: usize = 1024; let data = &[]; assert!(Box::<[(); SIZE]>::decode(&mut data.as_slice()).is_ok()); } #[test] fn incomplete_decoding_of_an_array_drops_partially_read_elements_if_reading_fails() { thread_local! { pub static COUNTER: core::cell::Cell = core::cell::Cell::new(0); } #[derive(DeriveDecode)] struct Foobar(u8); impl Drop for Foobar { fn drop(&mut self) { COUNTER.with(|counter| { counter.set(counter.get() + 1); }); } } let data = &[1, 2, 3]; assert!(<[Foobar; 4]>::decode(&mut data.as_slice()).is_err()); COUNTER.with(|counter| { assert_eq!(counter.get(), 3); }); } #[test] fn incomplete_decoding_of_an_array_drops_partially_read_elements_if_reading_panics() { thread_local! { pub static COUNTER: core::cell::Cell = core::cell::Cell::new(0); } struct Foobar(u8); impl Decode for Foobar { fn decode(input: &mut I) -> Result { let mut buffer = [0; 1]; input.read(&mut buffer).unwrap(); Ok(Self(buffer[0])) } } impl Drop for Foobar { fn drop(&mut self) { COUNTER.with(|counter| { counter.set(counter.get() + 1); }); } } let data = &[1, 2, 3]; let result = std::panic::catch_unwind(|| { let _ = <[Foobar; 4]>::decode(&mut data.as_slice()); }); assert!(result.is_err()); COUNTER.with(|counter| { assert_eq!(counter.get(), 3); }); } #[test] fn deserializing_of_big_recursively_nested_enum_works() { #[derive(PartialEq, Eq, DeriveDecode, DeriveEncode)] struct Data([u8; 1472]); #[derive(PartialEq, Eq, DeriveDecode, DeriveEncode)] enum Enum { Nested(Vec), Data(Data), Variant1, Variant2, Variant3, Variant4, Variant5, Variant6, Variant7, Variant8, Variant9, Variant10, Variant11, Variant12, Variant13, Variant14, Variant15, Variant16, Variant17, Variant18, Variant19, Variant20, Variant21, Variant22, Variant23, Variant24, Variant25, Variant26, Variant27, Variant28, Variant29, Variant30, Variant31, Variant32, Variant33, Variant34, Variant35, Variant36, Variant37, Variant38, Variant39, Variant40, Variant41, } fn gen_dummy_data(depth_remaining: usize) -> Enum { let mut vec = vec![Enum::Data(Data([0; 1472]))]; if depth_remaining > 0 { vec.push(gen_dummy_data(depth_remaining - 1)); } Enum::Nested(vec) } let obj = gen_dummy_data(32); let data = obj.encode(); // This should not overflow the stack. let obj_d = Enum::decode(&mut &data[..]).unwrap(); // NOTE: Not using `assert_eq` since we don't want to print out such a big object if this fails. assert!(obj == obj_d); use parity_scale_codec::DecodeLimit; let obj_d2 = Enum::decode_with_depth_limit(40, &mut &data[..]).unwrap(); assert!(obj == obj_d2); } parity-scale-codec-3.6.4/tests/scale_codec_ui/pass/decode-no-implicit-prelude.rs000064400000000000000000000010571046102023000260130ustar 00000000000000#![no_implicit_prelude] #[derive(::parity_scale_codec::Decode)] #[codec(crate = ::parity_scale_codec)] pub struct Struct { field_1: i8, field_2: i16, field_3: i32, field_4: i64, } #[derive(::parity_scale_codec::Decode)] #[repr(transparent)] struct Transparent { a: u8 } #[derive(::parity_scale_codec::Decode)] #[codec(crate = ::parity_scale_codec)] pub enum Enum { Variant1, Variant2(i8, i16, i32, i64), Variant3 { field_1: i8, field_2: i16, field_3: i32, field_4: i64, } } fn main() {} parity-scale-codec-3.6.4/tests/scale_codec_ui/pass/encode-no-implicit-prelude.rs000064400000000000000000000007201046102023000260210ustar 00000000000000#![no_implicit_prelude] #[derive(::parity_scale_codec::Encode)] #[codec(crate = ::parity_scale_codec)] pub struct Struct { field_1: i8, field_2: i16, field_3: i32, field_4: i64, } #[derive(::parity_scale_codec::Encode)] #[codec(crate = ::parity_scale_codec)] pub enum Enum { Variant1, Variant2(i8, i16, i32, i64), Variant3 { field_1: i8, field_2: i16, field_3: i32, field_4: i64, } } fn main() {} parity-scale-codec-3.6.4/tests/scale_codec_ui.rs000064400000000000000000000015111046102023000177350ustar 00000000000000// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #[test] #[cfg(feature = "derive")] fn scale_codec_ui_tests() { let t = trybuild::TestCases::new(); t.compile_fail("tests/scale_codec_ui/*.rs"); t.pass("tests/scale_codec_ui/pass/*.rs"); } parity-scale-codec-3.6.4/tests/single_field_struct_encoding.rs000064400000000000000000000076511046102023000227250ustar 00000000000000use parity_scale_codec_derive::{Encode as DeriveEncode, Decode as DeriveDecode, CompactAs as DeriveCompactAs}; use parity_scale_codec::{Compact, Decode, Encode, HasCompact}; use serde_derive::{Serialize, Deserialize}; #[derive(Debug, PartialEq, DeriveEncode, DeriveDecode)] struct S { x: u32, } #[cfg_attr(feature = "std", derive(Serialize, Deserialize))] #[derive(Debug, PartialEq, Eq, Clone, Copy, DeriveEncode, DeriveDecode, DeriveCompactAs)] struct SSkip { #[codec(skip)] s1: u32, x: u32, #[codec(skip)] s2: u32, } #[derive(Debug, PartialEq, DeriveEncode, DeriveDecode)] struct Sc { #[codec(compact)] x: u32, } #[derive(Debug, PartialEq, DeriveEncode, DeriveDecode)] struct Sh { #[codec(encoded_as = "::Type")] x: T, } #[cfg_attr(feature = "std", derive(Serialize, Deserialize))] #[derive(Debug, PartialEq, Eq, Clone, Copy, DeriveEncode, DeriveDecode, DeriveCompactAs)] struct U(u32); #[cfg_attr(feature = "std", derive(Serialize, Deserialize))] #[derive(Debug, PartialEq, Eq, Clone, Copy, DeriveEncode, DeriveDecode, DeriveCompactAs)] struct U2 { a: u64 } #[cfg_attr(feature = "std", derive(Serialize, Deserialize))] #[derive(Debug, PartialEq, Eq, Clone, Copy, DeriveEncode, DeriveDecode, DeriveCompactAs)] struct USkip(#[codec(skip)] u32, u32, #[codec(skip)] u32); #[derive(Debug, PartialEq, DeriveEncode, DeriveDecode)] struct Uc(#[codec(compact)] u32); #[derive(Debug, PartialEq, Clone, DeriveEncode, DeriveDecode)] struct Ucas(#[codec(compact)] U); #[derive(Debug, PartialEq, Clone, DeriveEncode, DeriveDecode)] struct USkipcas(#[codec(compact)] USkip); #[derive(Debug, PartialEq, Clone, DeriveEncode, DeriveDecode)] struct SSkipcas(#[codec(compact)] SSkip); #[derive(Debug, PartialEq, DeriveEncode, DeriveDecode)] struct Uh(#[codec(encoded_as = "::Type")] T); #[test] fn test_encoding() { let x = 3u32; let s = S { x }; let s_skip = SSkip { x, s1: Default::default(), s2: Default::default() }; let sc = Sc { x }; let sh = Sh { x }; let u = U(x); let u_skip = USkip(Default::default(), x, Default::default()); let uc = Uc(x); let ucom = Compact(u); let ucas = Ucas(u); let u_skip_cas = USkipcas(u_skip); let s_skip_cas = SSkipcas(s_skip); let uh = Uh(x); let mut s_encoded: &[u8] = &[3, 0, 0, 0]; let mut s_skip_encoded: &[u8] = &[3, 0, 0, 0]; let mut sc_encoded: &[u8] = &[12]; let mut sh_encoded: &[u8] = &[12]; let mut u_encoded: &[u8] = &[3, 0, 0, 0]; let mut u_skip_encoded: &[u8] = &[3, 0, 0, 0]; let mut uc_encoded: &[u8] = &[12]; let mut ucom_encoded: &[u8] = &[12]; let mut ucas_encoded: &[u8] = &[12]; let mut u_skip_cas_encoded: &[u8] = &[12]; let mut s_skip_cas_encoded: &[u8] = &[12]; let mut uh_encoded: &[u8] = &[12]; assert_eq!(s.encode(), s_encoded); assert_eq!(s_skip.encode(), s_skip_encoded); assert_eq!(sc.encode(), sc_encoded); assert_eq!(sh.encode(), sh_encoded); assert_eq!(u.encode(), u_encoded); assert_eq!(u_skip.encode(), u_skip_encoded); assert_eq!(uc.encode(), uc_encoded); assert_eq!(ucom.encode(), ucom_encoded); assert_eq!(ucas.encode(), ucas_encoded); assert_eq!(u_skip_cas.encode(), u_skip_cas_encoded); assert_eq!(s_skip_cas.encode(), s_skip_cas_encoded); assert_eq!(uh.encode(), uh_encoded); assert_eq!(s, S::decode(&mut s_encoded).unwrap()); assert_eq!(s_skip, SSkip::decode(&mut s_skip_encoded).unwrap()); assert_eq!(sc, Sc::decode(&mut sc_encoded).unwrap()); assert_eq!(sh, Sh::decode(&mut sh_encoded).unwrap()); assert_eq!(u, U::decode(&mut u_encoded).unwrap()); assert_eq!(u_skip, USkip::decode(&mut u_skip_encoded).unwrap()); assert_eq!(uc, Uc::decode(&mut uc_encoded).unwrap()); assert_eq!(ucom, >::decode(&mut ucom_encoded).unwrap()); assert_eq!(ucas, Ucas::decode(&mut ucas_encoded).unwrap()); assert_eq!(u_skip_cas, USkipcas::decode(&mut u_skip_cas_encoded).unwrap()); assert_eq!(s_skip_cas, SSkipcas::decode(&mut s_skip_cas_encoded).unwrap()); assert_eq!(uh, Uh::decode(&mut uh_encoded).unwrap()); } parity-scale-codec-3.6.4/tests/size_hint.rs000064400000000000000000000027001046102023000170110ustar 00000000000000use parity_scale_codec::Encode; use parity_scale_codec_derive::Encode as DeriveEncode; #[test] fn size_hint_for_struct() { #[derive(DeriveEncode)] struct Struct { pub a: A, pub b: B, #[codec(skip)] pub c: C, } let v = Struct::, u32> { a: String::from("foo"), b: vec![1, 2, 3], c: 0 }; assert_eq!(v.size_hint(), 23); } #[test] fn size_hint_for_tuple_struct() { #[derive(DeriveEncode)] struct Tuple(String, Vec, #[codec(skip)] u32); let v = Tuple(String::from("foo"), vec![1, 2, 3], 0); assert_eq!(v.size_hint(), 23); } #[test] fn size_hint_for_unit_struct() { #[derive(DeriveEncode)] struct Unit; let v = Unit; assert_eq!(v.size_hint(), 0); } #[test] fn size_hint_for_simple_enum() { #[derive(DeriveEncode)] enum EnumType { #[codec(index = 15)] A, B(u32, u64), C { a: u32, b: u64, }, } let v = EnumType::A; assert_eq!(v.size_hint(), 1); let v = EnumType::B(1, 2); assert_eq!(v.size_hint(), 13); let v = EnumType::C { a: 0, b: 0 }; assert_eq!(v.size_hint(), 13); } #[test] fn size_hint_for_enum_with_discriminant() { #[derive(DeriveEncode)] enum EnumWithDiscriminant { A = 1, B = 15, C = 255, } let discriminant = core::mem::size_of::(); let v = EnumWithDiscriminant::A; assert_eq!(v.size_hint(), discriminant); let v = EnumWithDiscriminant::B; assert_eq!(v.size_hint(), discriminant); let v = EnumWithDiscriminant::C; assert_eq!(v.size_hint(), discriminant); } parity-scale-codec-3.6.4/tests/skip.rs000064400000000000000000000035701046102023000157710ustar 00000000000000use parity_scale_codec_derive::{Encode as DeriveEncode, Decode as DeriveDecode}; use parity_scale_codec::{Encode, Decode}; #[test] fn enum_struct_test() { #[derive(PartialEq, Debug, Default)] struct UncodecType; #[derive(PartialEq, Debug)] struct UncodecUndefaultType; use parity_scale_codec_derive::{Encode as DeriveEncode, Decode as DeriveDecode}; #[derive(PartialEq, Debug, DeriveEncode, DeriveDecode)] enum Enum { #[codec(skip)] A(S), B { #[codec(skip)] _b1: T, b2: u32, }, C( #[codec(skip)] T, u32, ), } #[derive(PartialEq, Debug, DeriveEncode, DeriveDecode)] struct StructNamed { #[codec(skip)] a: T, b: u32, } #[derive(PartialEq, Debug, DeriveEncode, DeriveDecode)] struct StructUnnamed( #[codec(skip)] T, u32, ); let ea: Enum = Enum::A(UncodecUndefaultType); let eb: Enum = Enum::B { _b1: UncodecType, b2: 1 }; let ec: Enum = Enum::C(UncodecType, 1); let sn = StructNamed { a: UncodecType, b: 1 }; let su = StructUnnamed(UncodecType, 1); assert_eq!(ea.encode(), Vec::new()); let mut eb_encoded: &[u8] = &eb.encode(); let mut ec_encoded: &[u8] = &ec.encode(); let mut sn_encoded: &[u8] = &sn.encode(); let mut su_encoded: &[u8] = &su.encode(); assert_eq!(Enum::decode(&mut eb_encoded).unwrap(), eb); assert_eq!(Enum::decode(&mut ec_encoded).unwrap(), ec); assert_eq!(StructNamed::decode(&mut sn_encoded).unwrap(), sn); assert_eq!(StructUnnamed::decode(&mut su_encoded).unwrap(), su); } #[test] fn skip_enum_struct_inner_variant() { // Make sure the skipping does not generates a warning. #![deny(warnings)] #[derive(DeriveEncode, DeriveDecode)] enum Enum { Data { some_named: u32, #[codec(skip)] ignore: Option, } } let encoded = Enum::Data { some_named: 1, ignore: Some(1) }.encode(); assert_eq!(vec![0, 1, 0, 0, 0], encoded); } parity-scale-codec-3.6.4/tests/type_inference.rs000064400000000000000000000017671046102023000200300ustar 00000000000000// Copyright 2021 Parity Technologies // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //! Test for type inference issue in decode. use parity_scale_codec_derive::Decode as DeriveDecode; use parity_scale_codec::Decode; pub trait Trait { type Value; type AccountId: Decode; } #[derive(DeriveDecode)] pub enum A { _C( (T::AccountId, T::AccountId), Vec<(T::Value, T::Value)>, ), } #[derive(DeriveDecode)] pub struct B((T::AccountId, T::AccountId), Vec<(T::Value, T::Value)>); parity-scale-codec-3.6.4/tests/variant_number.rs000064400000000000000000000012721046102023000200340ustar 00000000000000use parity_scale_codec_derive::Encode as DeriveEncode; use parity_scale_codec::Encode; #[test] fn discriminant_variant_counted_in_default_index() { #[derive(DeriveEncode)] enum T { A = 1, B, } assert_eq!(T::A.encode(), vec![1]); assert_eq!(T::B.encode(), vec![1]); } #[test] fn skipped_variant_not_counted_in_default_index() { #[derive(DeriveEncode)] enum T { #[codec(skip)] A, B, } assert_eq!(T::A.encode(), vec![]); assert_eq!(T::B.encode(), vec![0]); } #[test] fn index_attr_variant_counted_and_reused_in_default_index() { #[derive(DeriveEncode)] enum T { #[codec(index = 1)] A, B, } assert_eq!(T::A.encode(), vec![1]); assert_eq!(T::B.encode(), vec![1]); }