3.0 for crates.io

This commit is contained in:
Lena Hellström 2025-12-16 22:18:00 +01:00
parent a4d858fa02
commit 930e32cb37
89 changed files with 185 additions and 13681 deletions

14
.github/FUNDING.yml vendored
View File

@ -1,14 +0,0 @@
# These are supported funding model platforms
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
patreon: # Replace with a single Patreon username
open_collective: # Replace with a single Open Collective username
ko_fi: bincode
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
liberapay: # Replace with a single Liberapay username
issuehunt: # Replace with a single IssueHunt username
lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry
polar: # Replace with a single Polar username
buy_me_a_coffee: # Replace with a single Buy Me a Coffee username
custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']

View File

@ -1,13 +0,0 @@
version: 2
updates:
- package-ecosystem: cargo
directory: /
schedule:
interval: daily
open-pull-requests-limit: 10
- package-ecosystem: "github-actions"
directory: "/"
schedule:
# Check for updates to GitHub Actions every weekday
interval: "daily"

18
.github/stale.yml vendored
View File

@ -1,18 +0,0 @@
# Number of days of inactivity before an issue becomes stale
daysUntilStale: 60
# Number of days of inactivity before a stale issue is closed
daysUntilClose: 7
# Issues with these labels will never be considered stale
exemptLabels:
- bug
- security
- not-stale
# Label to use when marking an issue as stale
staleLabel: stale
# Comment to post when marking an issue as stale. Set to `false` to disable
markComment: >
This issue has been automatically marked as stale because it has not had
recent activity. It will be closed if no further activity occurs. Thank you
for your contributions.
# Comment to post when closing a stale issue. Set to `false` to disable
closeComment: false

View File

@ -1,40 +0,0 @@
{
"name": "CIFuzz",
"on": [
"pull_request"
],
"jobs": {
"Fuzzing": {
"runs-on": "ubuntu-latest",
"steps": [
{
"name": "Build Fuzzers",
"id": "build",
"uses": "google/oss-fuzz/infra/cifuzz/actions/build_fuzzers@master",
"with": {
"oss-fuzz-project-name": "bincode",
"language": "rust"
}
},
{
"name": "Run Fuzzers",
"uses": "google/oss-fuzz/infra/cifuzz/actions/run_fuzzers@master",
"with": {
"oss-fuzz-project-name": "bincode",
"fuzz-seconds": 300,
"language": "rust"
}
},
{
"name": "Upload Crash",
"uses": "actions/upload-artifact@v4",
"if": "failure() && steps.build.outcome == 'success'",
"with": {
"name": "artifacts",
"path": "./out/artifacts"
}
}
]
}
}
}

View File

@ -1,248 +0,0 @@
{
"name": "Cross platform tests",
"on": {
"push": {
"branches": [
"trunk",
"v*.x",
"ci/*"
]
},
"pull_request": {
"branches": [
"trunk",
"v*.x"
]
}
},
"jobs": {
"test_cross_std": {
"name": "Cross platform test (platforms with standard library)",
"runs-on": "ubuntu-latest",
"strategy": {
"fail-fast": false,
"matrix": {
"platform": [
# Tier 1
"aarch64-unknown-linux-gnu",
# 0050:err:winediag:nodrv_CreateWindow Application tried to create a window, but no driver could be loaded.
# 0050:err:winediag:nodrv_CreateWindow Make sure that your X server is running and that $DISPLAY is set correctly.
# 0050:err:systray:initialize_systray Could not create tray window
# 0024:err:module:import_dll Library bcryptprimitives.dll (which is needed by L"Z:\\target\\i686-pc-windows-gnu\\debug\\deps\\bincode-569310bd32491256.exe") not found
# 0024:err:module:LdrInitializeThunk Importing dlls for L"Z:\\target\\i686-pc-windows-gnu\\debug\\deps\\bincode-569310bd32491256.exe" failed, status c0000135
# "i686-pc-windows-gnu",
# `cross` does not provide a Docker image for target i686-pc-windows-msvc
# "i686-pc-windows-msvc",
"i686-unknown-linux-gnu",
# `cross` does not provide a Docker image for target x86_64-apple-darwin
# "x86_64-apple-darwin",
# 0050:err:winediag:nodrv_CreateWindow Application tried to create a window, but no driver could be loaded.
# 0050:err:winediag:nodrv_CreateWindow Make sure that your X server is running and that $DISPLAY is set correctly.
# 0050:err:systray:initialize_systray Could not create tray window
# 00f4:err:module:import_dll Library bcryptprimitives.dll (which is needed by L"Z:\\target\\x86_64-pc-windows-gnu\\debug\\deps\\bincode-b91af23bf3efc9f3.exe") not found
# 00f4:err:module:LdrInitializeThunk Importing dlls for L"Z:\\target\\x86_64-pc-windows-gnu\\debug\\deps\\bincode-b91af23bf3efc9f3.exe" failed, status c0000135
# "x86_64-pc-windows-gnu",
# `cross` does not provide a Docker image for target x86_64-pc-windows-msvc
# "x86_64-pc-windows-msvc",
"x86_64-unknown-linux-gnu",
# Tier 2
# `cross` does not provide a Docker image for target aarch64-apple-darwin
# "aarch64-apple-darwin",
# `cross` does not provide a Docker image for target aarch64-pc-windows-msvc
# "aarch64-pc-windows-msvc",
"aarch64-unknown-linux-musl",
"arm-unknown-linux-gnueabi",
"arm-unknown-linux-gnueabihf",
"armv7-unknown-linux-gnueabihf",
# `cross` does not provide a Docker image for target loongarch64-unknown-linux-gnu
# "loongarch64-unknown-linux-gnu",
# BLOCKEDTODO(https://github.com/cross-rs/cross/issues/975): currently broken
# "mips-unknown-linux-gnu",
# BLOCKEDTODO(https://github.com/cross-rs/cross/issues/975): currently broken
# "mips64-unknown-linux-gnuabi64",
# BLOCKEDTODO(https://github.com/cross-rs/cross/issues/975): currently broken
# "mips64el-unknown-linux-gnuabi64",
# BLOCKEDTODO(https://github.com/cross-rs/cross/issues/975): currently broken
# "mipsel-unknown-linux-gnu",
"powerpc-unknown-linux-gnu",
"powerpc64-unknown-linux-gnu",
"powerpc64le-unknown-linux-gnu",
"riscv64gc-unknown-linux-gnu",
"s390x-unknown-linux-gnu",
# BLOCKEDTODO(https://github.com/cross-rs/cross/issues/975): currently broken
# "x86_64-unknown-freebsd",
# BLOCKEDTODO(https://github.com/cross-rs/cross/issues/975): currently broken
# "x86_64-unknown-illumos",
"x86_64-unknown-linux-musl",
# BLOCKEDTODO(https://github.com/cross-rs/cross/issues/975): currently broken
# "x86_64-unknown-netbsd",
# Tier 3, only those that have std
# `cross` does not provide a Docker image for target aarch64-apple-ios
# "aarch64-apple-ios",
# `cross` does not provide a Docker image for target aarch64-apple-ios-sim
# "aarch64-apple-ios-sim",
# `cross` does not provide a Docker image for target aarch64-fuchsia
# "aarch64-fuchsia",
# `cross` does not provide a Docker image for target aarch64-unknown-fuchsia
# "aarch64-unknown-fuchsia",
# BLOCKEDTODO(https://github.com/cross-rs/cross/issues/1222): currently broken
# "aarch64-linux-android",
"arm-linux-androideabi",
"arm-unknown-linux-musleabi",
"arm-unknown-linux-musleabihf",
"armv5te-unknown-linux-gnueabi",
"armv5te-unknown-linux-musleabi",
"armv7-linux-androideabi",
"armv7-unknown-linux-gnueabi",
"armv7-unknown-linux-musleabi",
"armv7-unknown-linux-musleabihf",
# BLOCKEDTODO(https://github.com/cross-rs/cross/issues/634): broken
# "asmjs-unknown-emscripten",
"i586-unknown-linux-gnu",
"i586-unknown-linux-musl",
# BLOCKEDTODO(https://github.com/cross-rs/cross/issues/1222): currently broken
# "i686-linux-android",
# BLOCKEDTODO(https://github.com/cross-rs/cross/issues/975): currently broken
# "i686-unknown-freebsd",
"i686-unknown-linux-musl",
# "mips-unknown-linux-musl",
# "mips64-unknown-linux-muslabi64",
# "mips64el-unknown-linux-muslabi64",
# "mipsel-unknown-linux-musl",
# Could not link to `getrandom`
# "sparc64-unknown-linux-gnu",
# BLOCKEDTODO(https://github.com/cross-rs/cross/issues/975): currently broken
# "sparcv9-sun-solaris",
"thumbv7neon-linux-androideabi",
"thumbv7neon-unknown-linux-gnueabihf",
# BLOCKEDTODO(https://github.com/cross-rs/cross/issues/975): currently broken
# "wasm32-unknown-emscripten",
# `cross` does not provide a Docker image for target wasm32-unknown-unknown
# "wasm32-unknown-unknown",
# `cross` does not provide a Docker image for target wasm32-wasi
# "wasm32-wasi",
# `cross` does not provide a Docker image for target x86_64-apple-ios
# "x86_64-apple-ios",
# `cross` does not provide a Docker image for target x86_64-fortanix-unknown-sgx
# "x86_64-fortanix-unknown-sgx",
# `cross` does not provide a Docker image for target x86_64-fuchsia
# "x86_64-fuchsia",
# `cross` does not provide a Docker image for target x86_64-unknown-fuchsia
# "x86_64-unknown-fuchsia",
# BLOCKEDTODO(https://github.com/cross-rs/cross/issues/975): currently broken
# "x86_64-linux-android",
# `cross` does not provide a Docker image for target x86_64-pc-solaris
# "x86_64-pc-solaris",
# `cross` does not provide a Docker image for target x86_64-unknown-linux-gnux32
# "x86_64-unknown-linux-gnux32",
# `cross` does not provide a Docker image for target x86_64-unknown-redox
# "x86_64-unknown-redox",
]
}
},
"steps": [
{
"uses": "actions/checkout@v4",
"name": "Checkout"
},
{
"uses": "actions-rs/toolchain@v1",
"with": {
"profile": "minimal",
"toolchain": "stable",
"override": true
},
"name": "Install Rust stable"
},
{
"uses": "actions-rs/install@v0.1",
"with": {
"crate": "cross"
},
"name": "Install cargo cross"
},
{
"run": "cross test --target ${{ matrix.platform }}",
"name": "Run tests",
"env": {
"RUSTFLAGS": "-D warnings",
"RUST_BACKTRACE": "1",
}
}
]
},
# None of these work, needs more investigation
# "test_cross_no_std": {
# "name": "Cross platform test (no_std, platforms without standard library)",
# "runs-on": "ubuntu-latest",
# "strategy": {
# "fail-fast": false,
# "matrix": {
# "platform": [
# # Tier 3
# "aarch64-unknown-none-softfloat",
# "aarch64-unknown-none",
# "aarch64-unknown-uefi",
# "armebv7r-none-eabi",
# "armebv7r-none-eabihf",
# "armv7a-none-eabi",
# "armv7r-none-eabi",
# "armv7r-none-eabihf",
# "i586-pc-windows-msvc",
# "i686-unknown-uefi",
# "nvptx64-nvidia-cuda",
# "riscv32i-unknown-none-elf",
# "riscv32imac-unknown-none-elf",
# "riscv32imc-unknown-none-elf",
# "riscv64gc-unknown-none-elf",
# "riscv64imac-unknown-none-elf",
# "thumbv6m-none-eabi",
# "thumbv7em-none-eabi",
# "thumbv7em-none-eabihf",
# "thumbv7m-none-eabi",
# "thumbv8m.base-none-eabi",
# "thumbv8m.main-none-eabi",
# "thumbv8m.main-none-eabihf",
# "x86_64-unknown-none",
# "x86_64-unknown-uefi",
# ]
# }
# },
# "steps": [
# {
# "uses": "actions/checkout@v4",
# "name": "Checkout"
# },
# {
# "uses": "actions-rs/toolchain@v1",
# "with": {
# "profile": "minimal",
# "toolchain": "stable",
# "override": true
# },
# "name": "Install Rust stable"
# },
# {
# "uses": "actions-rs/install@v0.1",
# "with": {
# "crate": "cross"
# },
# "name": "Install cargo cross"
# },
# {
# "run": "cross test --target ${{ matrix.platform }} --no-default-features --features alloc,derive",
# "name": "Run tests",
# "env": {
# "RUSTFLAGS": "-D warnings",
# "RUST_BACKTRACE": "1",
# }
# }
# ]
# }
}
}

View File

@ -1,40 +0,0 @@
{
"name": "miri",
"on": {
"push": {
"branches": [
"trunk",
"v*.x",
"ci/*"
]
},
"pull_request": {
"branches": [
"trunk",
"v*.x"
]
}
},
"jobs": {
"miri": {
"name": "MIRI",
"runs-on": "ubuntu-latest",
"steps": [
{
"uses": "actions/checkout@v2",
"name": "Checkout"
},
{
"run": "rustup toolchain install nightly --component miri \n
rustup override set nightly \n
cargo miri setup",
"name": "Install Rust nightly"
},
{
"run": "cargo miri test",
"name": "Default features"
}
]
}
}
}

View File

@ -1,195 +0,0 @@
{
"name": "CI",
"on": {
"push": {
"branches": [
"trunk",
"v*.x",
"ci/*"
]
},
"pull_request": {
"branches": [
"trunk",
"v*.x"
]
}
},
"jobs": {
"check": {
"name": "Check",
"runs-on": "ubuntu-latest",
"strategy": {
"fail-fast": false,
"matrix": {
"rust": [
"stable",
"beta",
"nightly",
"1.85.0"
]
}
},
"steps": [
{
"uses": "actions/checkout@v4",
"name": "Checkout"
},
{
"uses": "actions-rs/toolchain@v1",
"with": {
"profile": "minimal",
"toolchain": "${{ matrix.rust }}",
"override": true
},
"name": "Install Rust ${{ matrix.rust }}"
},
{
"uses": "actions-rs/cargo@v1",
"with": {
"command": "check",
"args": "--all-features"
},
"name": "Run `cargo check`"
},
{
"uses": "actions-rs/cargo@v1",
"with": {
"command": "check",
"args": "--bench *"
},
"name": "Run `cargo check` on benches"
},
{
"uses": "actions-rs/cargo@v1",
"with": {
"command": "check",
"args": "--examples"
},
"name": "Check examples"
}
]
},
"test": {
"name": "Test",
"strategy": {
"matrix": {
"runner": [
"ubuntu-latest",
"windows-latest",
"macos-latest"
],
"rust": [
"stable",
"1.85.0"
],
"features": [
"",
"alloc",
"alloc,derive",
"std",
"std,derive",
"serde",
"alloc,serde",
"std,serde",
"serde,derive",
"alloc,serde,derive",
"std,serde,derive",
]
}
},
"runs-on": "${{ matrix.runner }}",
"steps": [
{
"uses": "actions/checkout@v4",
"name": "Checkout"
},
{
"uses": "actions-rs/toolchain@v1",
"with": {
"profile": "minimal",
"toolchain": "${{ matrix.rust }}",
"override": true
},
"name": "Install Rust ${{ matrix.rust }}"
},
{
"run": "if [ -z \"${{ matrix.features }}\" ]\n
then\n
cargo test --no-default-features\n
else\n
cargo test --no-default-features --features ${{ matrix.features }}\n
fi",
"name": "Run `cargo test` on all features",
"shell": "bash",
"env": {
"RUSTFLAGS": "-D warnings"
}
}
]
},
"lints": {
"name": "Lints",
"runs-on": "ubuntu-latest",
"steps": [
{
"uses": "actions/checkout@v4",
"name": "Checkout"
},
{
"uses": "actions-rs/toolchain@v1",
"with": {
"profile": "minimal",
"toolchain": "1.85.0",
"override": true,
"components": "rustfmt, clippy"
},
"name": "Install Rust stable"
},
{
"uses": "actions-rs/cargo@v1",
"with": {
"command": "fmt",
"args": "--all -- --check"
},
"name": "Run `cargo fmt`"
},
{
"uses": "actions-rs/cargo@v1",
"with": {
"command": "clippy",
"args": "--all-features -- -D warnings"
},
"name": "Run `cargo clippy`"
}
]
},
"compatibility": {
"name": "Compatibility",
"runs-on": "ubuntu-latest",
"steps": [
{
"uses": "actions/checkout@v4",
"name": "Checkout"
},
{
"uses": "actions-rs/toolchain@v1",
"with": {
"profile": "minimal",
"toolchain": "1.85.0",
"override": true,
},
"name": "Install Rust stable"
},
{
"uses": "actions-rs/cargo@v1",
"with": {
"command": "test",
"args": "--manifest-path compatibility/Cargo.toml"
},
"name": "Run compatibility tests"
}
]
}
}
}

View File

@ -1,26 +0,0 @@
{
"name": "Security audit",
"on": {
"schedule": [
{
"cron": "0 0 * * *"
}
]
},
"jobs": {
"audit": {
"runs-on": "ubuntu-latest",
"steps": [
{
"uses": "actions/checkout@v4"
},
{
"uses": "actions-rs/audit-check@v1",
"with": {
"token": "${{ secrets.GITHUB_TOKEN }}"
}
}
]
}
}
}

View File

@ -1 +0,0 @@
newline_style = "Unix"

View File

@ -1,128 +0,0 @@
# Contributor Covenant Code of Conduct
## Our Pledge
We as members, contributors, and leaders pledge to make participation in our
community a harassment-free experience for everyone, regardless of age, body
size, visible or invisible disability, ethnicity, sex characteristics, gender
identity and expression, level of experience, education, socio-economic status,
nationality, personal appearance, race, religion, or sexual identity
and orientation.
We pledge to act and interact in ways that contribute to an open, welcoming,
diverse, inclusive, and healthy community.
## Our Standards
Examples of behavior that contributes to a positive environment for our
community include:
* Demonstrating empathy and kindness toward other people
* Being respectful of differing opinions, viewpoints, and experiences
* Giving and gracefully accepting constructive feedback
* Accepting responsibility and apologizing to those affected by our mistakes,
and learning from the experience
* Focusing on what is best not just for us as individuals, but for the
overall community
Examples of unacceptable behavior include:
* The use of sexualized language or imagery, and sexual attention or
advances of any kind
* Trolling, insulting or derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or email
address, without their explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Enforcement Responsibilities
Community leaders are responsible for clarifying and enforcing our standards of
acceptable behavior and will take appropriate and fair corrective action in
response to any behavior that they deem inappropriate, threatening, offensive,
or harmful.
Community leaders have the right and responsibility to remove, edit, or reject
comments, commits, code, wiki edits, issues, and other contributions that are
not aligned to this Code of Conduct, and will communicate reasons for moderation
decisions when appropriate.
## Scope
This Code of Conduct applies within all community spaces, and also applies when
an individual is officially representing the community in public spaces.
Examples of representing our community include using an official e-mail address,
posting via an official social media account, or acting as an appointed
representative at an online or offline event.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported to the community leaders responsible for enforcement at
abuse@dos.cafe.
All complaints will be reviewed and investigated promptly and fairly.
All community leaders are obligated to respect the privacy and security of the
reporter of any incident.
## Enforcement Guidelines
Community leaders will follow these Community Impact Guidelines in determining
the consequences for any action they deem in violation of this Code of Conduct:
### 1. Correction
**Community Impact**: Use of inappropriate language or other behavior deemed
unprofessional or unwelcome in the community.
**Consequence**: A private, written warning from community leaders, providing
clarity around the nature of the violation and an explanation of why the
behavior was inappropriate. A public apology may be requested.
### 2. Warning
**Community Impact**: A violation through a single incident or series
of actions.
**Consequence**: A warning with consequences for continued behavior. No
interaction with the people involved, including unsolicited interaction with
those enforcing the Code of Conduct, for a specified period of time. This
includes avoiding interactions in community spaces as well as external channels
like social media. Violating these terms may lead to a temporary or
permanent ban.
### 3. Temporary Ban
**Community Impact**: A serious violation of community standards, including
sustained inappropriate behavior.
**Consequence**: A temporary ban from any sort of interaction or public
communication with the community for a specified period of time. No public or
private interaction with the people involved, including unsolicited interaction
with those enforcing the Code of Conduct, is allowed during this period.
Violating these terms may lead to a permanent ban.
### 4. Permanent Ban
**Community Impact**: Demonstrating a pattern of violation of community
standards, including sustained inappropriate behavior, harassment of an
individual, or aggression toward or disparagement of classes of individuals.
**Consequence**: A permanent ban from any sort of public interaction within
the community.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 2.0, available at
https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
Community Impact Guidelines were inspired by [Mozilla's code of conduct
enforcement ladder](https://github.com/mozilla/diversity).
[homepage]: https://www.contributor-covenant.org
For answers to common questions about this code of conduct, see the FAQ at
https://www.contributor-covenant.org/faq. Translations are available at
https://www.contributor-covenant.org/translations.

View File

@ -1,9 +1,9 @@
[workspace]
members = ["derive", "compatibility"]
members = ["derive"]
[package]
name = "bincode"
version = "2.0.1" # remember to update html_root_url and bincode_derive
version = "3.0.0" # remember to update html_root_url and bincode_derive
authors = [
"Ty Overby <ty@pre-alpha.com>",
"Zoey Riordan <zoey@dos.cafe>",
@ -16,58 +16,11 @@ publish = true
repository = "https://github.com/bincode-org/bincode"
documentation = "https://docs.rs/bincode"
readme = "./readme.md"
readme = "./README.md"
categories = ["encoding", "network-programming"]
keywords = ["binary", "encode", "decode", "serialize", "deserialize"]
license = "MIT"
description = "A binary serialization / deserialization strategy for transforming structs into bytes and vice versa!"
edition = "2021"
[features]
default = ["std", "derive"]
std = ["alloc", "serde?/std"]
alloc = ["serde?/alloc"]
derive = ["bincode_derive"]
[dependencies]
bincode_derive = { path = "derive", version = "2.0.1", optional = true }
serde = { version = "1.0", default-features = false, optional = true }
unty = "0.0.4"
# Used for tests
[dev-dependencies]
ouroboros = "0.18.3"
serde_derive = "1.0"
serde_json = { version = "1.0", default-features = false }
tempfile = "3.2"
criterion = "0.6"
rand = "0.8"
uuid = { version = "1.1", features = ["serde"] }
chrono = { version = "0.4", features = ["serde"] }
glam = { version = "0.25", features = ["serde"] }
bincode_1 = { version = "1.3", package = "bincode" }
serde = { version = "1.0", features = ["derive"] }
bumpalo = { version = "3.16.0", features = ["collections"] }
[[bench]]
name = "varint"
harness = false
[[bench]]
name = "inline"
harness = false
[[bench]]
name = "string"
harness = false
[profile.bench]
codegen-units = 1
debug = 1
lto = true
[package.metadata.docs.rs]
all-features = true
rustdoc-args = ["--cfg", "docsrs"]
edition = "2021"

190
README.md
View File

@ -1,128 +1,104 @@
Due to a doxxing incident bincode development has officially ceased and will not resume. Version 1.3.3 is considered a complete version of bincode that is not in need of any updates. Updates will only be pushed to the in the unlikely event of CVEs. Do not contact us for any other reason.
# Bincode is now unmaintained
To those of you who bothered doxxing us. Go touch grass and maybe for once consider your actions have consequences for real people.
Due to a doxxing and harassment incident, development on bincode has ceased. No
further releases will be published on crates.io.
Fuck off and worst regards,
The Bincode Team
As crates.io, unlike many other language-attached package management solutions,
lacks the ability to mark a project as archive or remove the last maintainer,
this final release is being published containing only this README, as well as a
lib.rs containing only a compiler error, to inform potential users of the
maintenance status of this crate.
If you were considering using bincode for a new project or are looking to an
alternative to migrate to, you are encouraged to consider some the following
alternatives, as well as the many other great serialization format crates
available in the rust ecosystem:
- [wincode](https://crates.io/crates/wincode)
# Original readme continues below
Bincode-compatible alternative
#Bincode
- [postcard](https://crates.io/crates/postcard)
<img align="right" src="./logo.svg" />
Similar in spirit and structure to bincode, but a bit differently flavored
[![CI](https://github.com/bincode-org/bincode/workflows/CI/badge.svg)](https://github.com/bincode-org/bincode/actions)
[![](https://img.shields.io/crates/v/bincode.svg)](https://crates.io/crates/bincode)
[![](https://img.shields.io/badge/license-MIT-blue.svg)](https://opensource.org/licenses/MIT)
<!-- [![](https://img.shields.io/badge/bincode-rustc_1.41.1+-lightgray.svg)](https://blog.rust-lang.org/2020/02/27/Rust-1.41.1.html) -->
[![Matrix](https://img.shields.io/matrix/bincode:matrix.org?label=Matrix%20Chat)](https://matrix.to/#/#bincode:matrix.org)
- [rkyv](https://crates.io/crates/rkyv)
A compact encoder / decoder pair that uses a binary zero-fluff encoding scheme.
The size of the encoded object will be the same or smaller than the size that
the object takes up in memory in a running Rust program.
Zero copy deserialization, honestly the best option for many of the usecases
that bincode was intended for, like serializing transient data for
intra-program message passing.
In addition to exposing two simple functions
(one that encodes to `Vec<u8>`, and one that decodes from `&[u8]`),
binary-encode exposes a Reader/Writer API that makes it work
perfectly with other stream-based APIs such as Rust files, network streams,
and the [flate2-rs](https://github.com/rust-lang/flate2-rs) compression
library.
# What the community can do better
## Usage Manifesto
Several tooling factors have lead to bincode's maintenance status being a bigger
issue than it needs to be, including:
The bincode developers do not endorse or support: the gas and oil industry, gambling, the military industrial complex, or any usage of AI. This means we will not accept any contributions coming from or related to these fields. This includes both PRs and filed issues. If you fall in one of these categories; do better.
- crates.io not having functionality for marking a package unmaintained or a
process for the crates.io maintainers to transfer ownership of an abandoned
package to a prospective maintainer
Additionally, if any contribution you make makes use of generative AI, be it in code or PR/issue descriptions, you will be immediately banned from this organization.
In many other programming language communities such as haskell and hackage, or
python and pypi, when the last maintainer of a critical crate just walks away,
there often an in-band status that identifies that package as having no active
maintainers, and usually at least _some_ policy in place for the package
collection maintainers to intervene and transfer ownership of such a package,
allowing the community to assign a new maintainer to the existing package,
automatically pointing the rest of the ecosystem to the new sources with no
intervention required on the consumers part.
## [API Documentation](https://docs.rs/bincode/)
crates.io not having any such functionality or processes creates a pretty
massive pain point when the last maintainer does walk away, placing the burden
on _them_, very often an already burnt out volunteer, to select a new
maintainer. If the existing maintainer does not do this, the only current way
to continue maintenance of the package is to create a differently-named fork,
and then go through the massive hassle of not only convincing the entire
ecosystem to use it, but to settle in on one community preferred fork. This
creates avoidable tension when maintainers _do_ just walk away, with community
members being scared to make the fork themselves, both out of fear of the
amount of work getting the community to adopt it entails, and out of fear of
making the inevitable fork-fight worse by adding another contestant.
## Bincode in the Wild
- crates.io not having visibility for its internal source control
* [google/tarpc](https://github.com/google/tarpc): Bincode is used to serialize and deserialize networked RPC messages.
* [servo/webrender](https://github.com/servo/webrender): Bincode records WebRender API calls for record/replay-style graphics debugging.
* [servo/ipc-channel](https://github.com/servo/ipc-channel): IPC-Channel uses Bincode to send structs between processes using a channel-like API.
* [ajeetdsouza/zoxide](https://github.com/ajeetdsouza/zoxide): zoxide uses Bincode to store a database of directories and their access frequencies on disk.
Much of the drama that resulted in the doxxing and harassment was centered
around the git history being rewritten when the repository was blanked out on
github and moved to sourcehut. While this is a legitimate cause for some level
of concern that merits at least asking a question, it is disappointing that
the community is focusing on it so much when virtually none of the users of
bincode are pulling from the git version anyway, with almost all of the users
using the crates.io release. While the existing bincode releases are tied to
the previous history through the git commit reference cargo release's
`.cargo_vcs_info.json`, the cargo releases, which represent the canonical
version of bincode, are not fundamentally tied to the git repository at all,
and there has been a lot of worrying about _the wrong supply chain_.
## Example
We have faced many questions like "if the github is deleted, where can users
make sure they are getting the old version of the source code" that are
answered with "there haven't been any crates.io releases since the migration
and history rewrite, just bring in an old version with cargo and you'll have
it".
```rust
use bincode::{config, Decode, Encode};
This could have been potentially avoided if crates.io and cargo provided
better visibility into their internal source control used for packing crates.
At the very least, a link to the source code browser on docs.rs from the
crates.io page for a given release could have made more users aware of the
fact that crates.io/cargo provide such internal source control, and a full on
source code viewer, or even better a version comparison tool, integrated into
crates.io would have made things a _lot_ more manageable while there were
still such questions flying around.
#[derive(Encode, Decode, PartialEq, Debug)]
struct Entity {
x: f32,
y: f32,
}
- crates.io metadata is not editable without performing a release
#[derive(Encode, Decode, PartialEq, Debug)]
struct World(Vec<Entity>);
Much of this could have been avoided if the crates.io metadata was
independently editable and included a contact information field (ideally
something like githubs private email solution, where it provides a generated
email address that forwards to something configurable).
fn main() {
let config = config::standard();
let world = World(vec![Entity { x: 0.0, y: 4.0 }, Entity { x: 10.0, y: 20.5 }]);
let encoded: Vec<u8> = bincode::encode_to_vec(&world, config).unwrap();
// The length of the vector is encoded as a varint u64, which in this case gets collapsed to a single byte
// See the documentation on varint for more info for that.
// The 4 floats are encoded in 4 bytes each.
assert_eq!(encoded.len(), 1 + 4 * 4);
let (decoded, len): (World, usize) = bincode::decode_from_slice(&encoded[..], config).unwrap();
assert_eq!(world, decoded);
assert_eq!(len, encoded.len()); // read all bytes
}
```
## Specification
Bincode's format is specified in [docs/spec.md](https://github.com/bincode-org/bincode/blob/trunk/docs/spec.md).
## FAQ
### Is Bincode suitable for storage?
The encoding format is stable, provided the same configuration is used.
This should ensure that later versions can still read data produced by a previous versions of the library if no major version change
has occurred.
Bincode 1 and 2 are completely compatible if the same configuration is used.
Bincode is invariant over byte-order, making an exchange between different
architectures possible. It is also rather space efficient, as it stores no
metadata like struct field names in the output format and writes long streams of
binary data without needing any potentially size-increasing encoding.
As a result, Bincode is suitable for storing data. Be aware that it does not
implement any sort of data versioning scheme or file headers, as these
features are outside the scope of this crate.
### Is Bincode suitable for untrusted inputs?
Bincode attempts to protect against hostile data. There is a maximum size
configuration available (`Configuration::with_limit`), but not enabled in the
default configuration. Enabling it causes pre-allocation size to be limited to
prevent against memory exhaustion attacks.
Deserializing any incoming data will not cause undefined behavior or memory
issues, assuming that the deserialization code for the struct is safe itself.
Bincode can be used for untrusted inputs in the sense that it will not create a
security issues in your application, provided the configuration is changed to enable a
maximum size limit. Malicious inputs will fail upon deserialization.
### What is Bincode's MSRV (minimum supported Rust version)?
Bincode 2.0 has an MSRV of 1.85.0. Any changes to the MSRV are considered a breaking change for semver purposes, except when certain features are enabled. Features affecting MSRV are documented in the crate root.
### Why does bincode not respect `#[repr(u8)]`?
Bincode will encode enum variants as a `u32`. If you're worried about storage size, we can recommend enabling `Configuration::with_variable_int_encoding()`. This option is enabled by default with the `standard` configuration. In this case enum variants will almost always be encoded as a `u8`.
Currently we have not found a compelling case to respect `#[repr(...)]`. You're most likely trying to interop with a format that is similar-but-not-quite-bincode. We only support our own protocol ([spec](https://github.com/bincode-org/bincode/blob/trunk/docs/spec.md)).
If you really want to use bincode to encode/decode a different protocol, consider implementing `Encode` and `Decode` yourself. `bincode-derive` will output the generated implementation in `target/generated/bincode/<name>_Encode.rs` and `target/generated/bincode/<name>_Decode.rs` which should get you started.
At the time of migration, bincode was nowhere _near_ ready for another
release, and being able to independently update the source code link in the
crates.io metadata and provide up to date contact information without having
to roll either a special no-code-changes release off of a branch that only
changed those things, or roll a questionable intermediate release with the
changes, both of which likely would have only raised more concerns from the
community, would have significantly decreased the developer burden of
completing the migration in a public and notorious fashion.

View File

@ -1,17 +0,0 @@
use bincode::config;
use criterion::{black_box, criterion_group, criterion_main, Criterion};
fn inline_decoder_claim_bytes_read(c: &mut Criterion) {
let config = config::standard().with_limit::<100000>();
let slice = bincode::encode_to_vec(vec![String::from("Hello world"); 1000], config).unwrap();
c.bench_function("inline_decoder_claim_bytes_read", |b| {
b.iter(|| {
let _: (Vec<String>, usize) =
black_box(bincode::decode_from_slice(black_box(&slice), config).unwrap());
})
});
}
criterion_group!(benches, inline_decoder_claim_bytes_read);
criterion_main!(benches);

View File

@ -1,73 +0,0 @@
// https://github.com/bincode-org/bincode/issues/618
use bincode::{Decode, Encode};
use criterion::{black_box, criterion_group, criterion_main, Criterion};
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Default, Encode, Decode)]
pub struct MyStruct {
pub v: Vec<String>,
pub string: String,
pub number: usize,
}
impl MyStruct {
#[inline]
pub fn new(v: Vec<String>, string: String, number: usize) -> Self {
Self { v, string, number }
}
}
fn build_data(size: usize) -> Vec<MyStruct> {
(0..size)
.map(|i| {
let vec: Vec<String> = (0..i).map(|i| i.to_string().repeat(100)).collect();
MyStruct::new(vec, size.to_string(), size)
})
.collect()
}
fn index_item_decode(c: &mut Criterion) {
let data = build_data(100);
c.bench_function("bench v1", |b| {
b.iter(|| {
let _ = black_box(bincode_1::serialize(black_box(&data))).unwrap();
});
});
let config = bincode::config::standard();
c.bench_function("bench v2 (standard)", |b| {
b.iter(|| {
let _ = black_box(bincode::encode_to_vec(black_box(&data), config)).unwrap();
});
});
let config = bincode::config::legacy();
c.bench_function("bench v2 (legacy)", |b| {
b.iter(|| {
let _ = black_box(bincode::encode_to_vec(black_box(&data), config)).unwrap();
});
});
let encodedv1 = bincode_1::serialize(&data).unwrap();
let encodedv2 = bincode::encode_to_vec(&data, config).unwrap();
assert_eq!(encodedv1, encodedv2);
c.bench_function("bench v1 decode", |b| {
b.iter(|| {
let _: Vec<MyStruct> =
black_box(bincode_1::deserialize(black_box(&encodedv1))).unwrap();
});
});
c.bench_function("bench v2 decode (legacy)", |b| {
b.iter(|| {
let _: (Vec<MyStruct>, _) =
black_box(bincode::decode_from_slice(black_box(&encodedv1), config)).unwrap();
});
});
}
criterion_group!(benches, index_item_decode);
criterion_main!(benches);

View File

@ -1,152 +0,0 @@
use bincode::config;
use criterion::{criterion_group, criterion_main, Criterion};
use rand::distributions::Distribution;
fn slice_varint_u8(c: &mut Criterion) {
let mut rng = rand::thread_rng();
let dist = rand::distributions::Uniform::from(0..u8::MAX);
let input: Vec<u8> = std::iter::from_fn(|| Some(dist.sample(&mut rng)))
.take(10_000)
.collect();
let config = config::standard();
let bytes = bincode::encode_to_vec(input, config).unwrap();
c.bench_function("slice_varint_u8", |b| {
b.iter(|| {
let _: (Vec<u8>, usize) = bincode::decode_from_slice(&bytes, config).unwrap();
})
});
}
fn slice_varint_u16(c: &mut Criterion) {
let mut rng = rand::thread_rng();
let dist = rand::distributions::Uniform::from(0..u16::MAX);
let input: Vec<u16> = std::iter::from_fn(|| Some(dist.sample(&mut rng)))
.take(10_000)
.collect();
let config = config::standard();
let bytes = bincode::encode_to_vec(input, config).unwrap();
c.bench_function("slice_varint_u16", |b| {
b.iter(|| {
let _: (Vec<u16>, usize) = bincode::decode_from_slice(&bytes, config).unwrap();
})
});
}
fn slice_varint_u32(c: &mut Criterion) {
let mut rng = rand::thread_rng();
let dist = rand::distributions::Uniform::from(0..u32::MAX);
let input: Vec<u32> = std::iter::from_fn(|| Some(dist.sample(&mut rng)))
.take(10_000)
.collect();
let config = config::standard();
let bytes = bincode::encode_to_vec(input, config).unwrap();
c.bench_function("slice_varint_u32", |b| {
b.iter(|| {
let _: (Vec<u32>, usize) = bincode::decode_from_slice(&bytes, config).unwrap();
})
});
}
fn slice_varint_u64(c: &mut Criterion) {
let mut rng = rand::thread_rng();
let dist = rand::distributions::Uniform::from(0..u64::MAX);
let input: Vec<u64> = std::iter::from_fn(|| Some(dist.sample(&mut rng)))
.take(10_000)
.collect();
let config = config::standard();
let bytes = bincode::encode_to_vec(input, config).unwrap();
c.bench_function("slice_varint_u64", |b| {
b.iter(|| {
let _: (Vec<u64>, usize) = bincode::decode_from_slice(&bytes, config).unwrap();
})
});
}
fn bufreader_varint_u8(c: &mut Criterion) {
let mut rng = rand::thread_rng();
let dist = rand::distributions::Uniform::from(0..u8::MAX);
let input: Vec<u8> = std::iter::from_fn(|| Some(dist.sample(&mut rng)))
.take(10_000)
.collect();
let config = config::standard();
let bytes = bincode::encode_to_vec(input, config).unwrap();
c.bench_function("bufreader_varint_u8", |b| {
b.iter(|| {
let _: Vec<u8> =
bincode::decode_from_reader(&mut std::io::BufReader::new(&bytes[..]), config)
.unwrap();
})
});
}
fn bufreader_varint_u16(c: &mut Criterion) {
let mut rng = rand::thread_rng();
let dist = rand::distributions::Uniform::from(0..u16::MAX);
let input: Vec<u16> = std::iter::from_fn(|| Some(dist.sample(&mut rng)))
.take(10_000)
.collect();
let config = config::standard();
let bytes = bincode::encode_to_vec(input, config).unwrap();
c.bench_function("bufreader_varint_u16", |b| {
b.iter(|| {
let _: Vec<u16> =
bincode::decode_from_reader(&mut std::io::BufReader::new(&bytes[..]), config)
.unwrap();
})
});
}
fn bufreader_varint_u32(c: &mut Criterion) {
let mut rng = rand::thread_rng();
let dist = rand::distributions::Uniform::from(0..u32::MAX);
let input: Vec<u32> = std::iter::from_fn(|| Some(dist.sample(&mut rng)))
.take(10_000)
.collect();
let config = config::standard();
let bytes = bincode::encode_to_vec(input, config).unwrap();
c.bench_function("bufreader_varint_u32", |b| {
b.iter(|| {
let _: Vec<u32> =
bincode::decode_from_reader(&mut std::io::BufReader::new(&bytes[..]), config)
.unwrap();
})
});
}
fn bufreader_varint_u64(c: &mut Criterion) {
let mut rng = rand::thread_rng();
let dist = rand::distributions::Uniform::from(0..u64::MAX);
let input: Vec<u64> = std::iter::from_fn(|| Some(dist.sample(&mut rng)))
.take(10_000)
.collect();
let config = config::standard();
let bytes = bincode::encode_to_vec(input, config).unwrap();
c.bench_function("bufreader_varint_u64", |b| {
b.iter(|| {
let _: Vec<u64> =
bincode::decode_from_reader(&mut std::io::BufReader::new(&bytes[..]), config)
.unwrap();
})
});
}
criterion_group!(
benches,
slice_varint_u8,
slice_varint_u16,
slice_varint_u32,
slice_varint_u64,
bufreader_varint_u8,
bufreader_varint_u16,
bufreader_varint_u32,
bufreader_varint_u64,
);
criterion_main!(benches);

View File

@ -1,12 +0,0 @@
[package]
name = "bincode_compatibility"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
bincode_2 = { path = "..", package = "bincode", features = ["serde"] }
bincode_1 = { version = "1", package = "bincode" }
serde = { version = "1", features = ["derive"] }
rand = "0.8"

View File

@ -1,49 +0,0 @@
# Bincode compatibility test
Hello! We are working on releasing bincode 2, and we want to make sure that bincode 2 produces the same output as bincode 1.3.
For this, we need your help. Please read on if you're using bincode in one of your projects.
We have created a test project that can be used to test the compatibility between bincode 1 and 2. It encodes structs with a wide range of settings, checks if the outputs are the same, and then deserializes the struct and checks if the output is the same.
## Adding a test case for your project
To add a test case for your project, please follow the following steps:
- [ ] Fork https://github.com/bincode-org/bincode
- [ ] create a new file `compatibility/src/<name>.rs`.
- [ ] Add a link to your project
- [ ] Add `Licence: MIT OR Apache-2.0` if you agree to distribute your code under this license
- [ ] Add a `mod <name>;` in the `lib.rs`. Make sure it's alphabetically ordered (check the ordering in your file system).
- [ ] Add your structs.
- Adding references to libraries is not recommended. Libraries will not be implementing `bincode 2`'s encoding/decoding system.
- If you need references to libraries, consider adding a test case for that library, and then referencing that test.
- [ ] Make sure structs derive the following traits:
- [ ] `serde::Serialize` and `serde::Deserialize`, like normal
- [ ] `bincode_2::Encode` and `bincode_2::Decode`, for the bincode 2 encode/decode mechanic
- [ ] Because the crate is renamed to `bincode_2`, you also need to add `#[bincode(crate = "bincode_2")]`
- [ ] `Debug, PartialEq`
```rs
#[derive(Serialize, Deserialize, bincode_2::Encode, bincode_2::Decode, Debug, PartialEq)]
#[bincode(crate = "bincode_2")]
pub struct YourStruct {
}
```
- [ ] Use `rand` to be able to generate a random test case for your project.
- [ ] For strings there is a helper function in `crate`: `gen_string(rng: &mut impl Rng) -> String`
- [ ] Add the following code:
```rs
#[test]
pub fn test() {
let mut rng = rand::thread_rng();
for _ in 0..1000 {
crate::test_same(<your_rand_function>(&mut rng));
}
}
```
For examples, see the existing cases in `compatibility/src/`.
- [ ] Open a [pull request](https://github.com/bincode-org/bincode/pulls) with the title `Bincode 1 compatibility: <name of your project>`

View File

@ -1,123 +0,0 @@
#![cfg(test)]
use ::rand::Rng;
use bincode_1::Options;
mod membership;
mod misc;
mod rand;
mod sway;
pub fn test_same_with_config<T, C, O>(t: &T, bincode_1_options: O, bincode_2_config: C)
where
T: bincode_2::Encode
+ bincode_2::Decode<()>
+ serde::Serialize
+ serde::de::DeserializeOwned
+ core::fmt::Debug
+ PartialEq,
C: bincode_2::config::Config,
O: bincode_1::Options + Copy,
{
// This is what bincode 1 serializes to. This will be our comparison value.
let encoded = bincode_1_options.serialize(t).unwrap();
println!("Encoded {t:?} as {encoded:?}");
// Test bincode 2 encode
let bincode_2_output = bincode_2::encode_to_vec(t, bincode_2_config).unwrap();
assert_eq!(
encoded,
bincode_2_output,
"{t:?} serializes differently\nbincode 2 config {:?}",
core::any::type_name::<C>(),
);
// Test bincode 2 serde serialize
let bincode_2_serde_output = bincode_2::serde::encode_to_vec(t, bincode_2_config).unwrap();
assert_eq!(
encoded, bincode_2_serde_output,
"{t:?} serializes differently"
);
// Test bincode 1 deserialize
let decoded: T = bincode_1_options.deserialize(&encoded).unwrap();
assert_eq!(&decoded, t);
// Test bincode 2 decode
let decoded: T = bincode_2::decode_from_slice(&encoded, bincode_2_config)
.unwrap()
.0;
assert_eq!(&decoded, t);
// Test bincode 2 serde deserialize
let decoded: T = bincode_2::serde::decode_from_slice(&encoded, bincode_2_config)
.unwrap()
.0;
assert_eq!(&decoded, t);
}
pub fn test_same<T>(t: T)
where
T: bincode_2::Encode
+ bincode_2::Decode<()>
+ serde::Serialize
+ serde::de::DeserializeOwned
+ core::fmt::Debug
+ PartialEq,
{
test_same_with_config(
&t,
// This is the config used internally by bincode 1
bincode_1::options().with_fixint_encoding(),
// Should match `::legacy()`
bincode_2::config::legacy(),
);
// Check a bunch of different configs:
test_same_with_config(
&t,
bincode_1::options()
.with_big_endian()
.with_varint_encoding(),
bincode_2::config::legacy()
.with_big_endian()
.with_variable_int_encoding(),
);
test_same_with_config(
&t,
bincode_1::options()
.with_little_endian()
.with_varint_encoding(),
bincode_2::config::legacy()
.with_little_endian()
.with_variable_int_encoding(),
);
test_same_with_config(
&t,
bincode_1::options()
.with_big_endian()
.with_fixint_encoding(),
bincode_2::config::legacy()
.with_big_endian()
.with_fixed_int_encoding(),
);
test_same_with_config(
&t,
bincode_1::options()
.with_little_endian()
.with_fixint_encoding(),
bincode_2::config::legacy()
.with_little_endian()
.with_fixed_int_encoding(),
);
}
pub fn gen_string(rng: &mut impl Rng) -> String {
let len = rng.gen_range(0..100usize);
let mut result = String::with_capacity(len * 4);
for _ in 0..len {
result.push(rng.gen_range('\0'..char::MAX));
}
result
}

View File

@ -1,52 +0,0 @@
// Added by [ppamorim](https://github.com/ppamorim)
// Taken from https://github.com/datafuselabs/openraft/blob/209ae677ade5b624fea9f6630e9ff191963f5d74/openraft/src/membership/membership.rs#L21
// License: Openraft is licensed under the terms of the MIT License or the Apache License 2.0, at your choosing.
use rand::{prelude::ThreadRng, Rng};
use std::collections::BTreeSet;
type NodeId = u64;
#[derive(
bincode_2::Encode, bincode_2::Decode, serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq,
)]
#[bincode(crate = "bincode_2")]
pub struct Membership {
/// learners set
learners: BTreeSet<NodeId>,
/// Multi configs.
configs: Vec<BTreeSet<NodeId>>,
/// Cache of all node ids.
all_members: BTreeSet<NodeId>,
}
#[test]
pub fn test() {
let mut rng = rand::thread_rng();
for _ in 0..1000 {
crate::test_same(Membership {
learners: random_btreeset(&mut rng),
configs: vec_random_btreeset(&mut rng),
all_members: random_btreeset(&mut rng),
});
}
}
fn vec_random_btreeset(rng: &mut ThreadRng) -> Vec<BTreeSet<NodeId>> {
let mut vec = Vec::with_capacity(10);
for _ in 0..rng.gen_range(0..10) {
vec.push(random_btreeset(rng));
}
vec
}
fn random_btreeset(rng: &mut ThreadRng) -> BTreeSet<NodeId> {
let mut set = BTreeSet::new();
for _ in 0..rng.gen_range(0..100) {
let v = rng.gen();
set.insert(v);
}
set
}

View File

@ -1,94 +0,0 @@
#[test]
fn test() {
super::test_same((1,));
super::test_same(TupleS(2.0, 3.0, 4.0));
super::test_same(Option::<u32>::Some(5));
super::test_same(Option::<u32>::None);
super::test_same(Result::<u32, u8>::Ok(5));
super::test_same(Result::<u32, u8>::Err(5));
super::test_same(std::net::Ipv4Addr::LOCALHOST);
super::test_same(std::net::Ipv6Addr::LOCALHOST);
}
#[test]
fn test_arrays() {
// serde is known to be weird with arrays
// Arrays of length 32 and less are encoded as tuples, but arrays 33 and up are encoded as slices
// we need to make sure we're compatible with this
super::test_same([0u8; 0]);
super::test_same([1u8; 1]);
super::test_same([1u8, 2]);
super::test_same([1u8, 2, 3]);
super::test_same([1u8, 2, 3, 4]);
super::test_same([1u8, 2, 3, 4, 5]);
super::test_same([1u8, 2, 3, 4, 5, 6]);
super::test_same([1u8, 2, 3, 4, 5, 6, 7]);
super::test_same([1u8, 2, 3, 4, 5, 6, 7, 8]);
super::test_same([1u8, 2, 3, 4, 5, 6, 7, 8, 9]);
super::test_same([1u8, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
super::test_same([1u8, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]);
super::test_same([1u8, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]);
super::test_same([1u8, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]);
super::test_same([1u8, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]);
super::test_same([1u8, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]);
super::test_same([1u8, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]);
super::test_same([1u8, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17]);
super::test_same([
1u8, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
]);
super::test_same([
1u8, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
]);
super::test_same([
1u8, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
]);
super::test_same([
1u8, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
]);
super::test_same([
1u8, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
]);
super::test_same([
1u8, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
]);
super::test_same([
1u8, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
]);
super::test_same([
1u8, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
]);
super::test_same([
1u8, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
25, 26,
]);
super::test_same([
1u8, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
25, 26, 27,
]);
super::test_same([
1u8, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
25, 26, 27, 28,
]);
super::test_same([
1u8, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
25, 26, 27, 28, 29,
]);
super::test_same([
1u8, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
25, 26, 27, 28, 29, 30,
]);
super::test_same([
1u8, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
25, 26, 27, 28, 29, 30, 31,
]);
super::test_same([
1u8, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
25, 26, 27, 28, 29, 30, 31, 32,
]);
}
#[derive(
bincode_2::Encode, bincode_2::Decode, serde::Serialize, serde::Deserialize, Debug, PartialEq,
)]
#[bincode(crate = "bincode_2")]
struct TupleS(f32, f32, f32);

View File

@ -1,25 +0,0 @@
// Simplified case, taken from:
// https://github.com/rust-random/rand/blob/19404d68764ed08513131f82157e2ccad69dcf83/rand_pcg/src/pcg64.rs#L37-L40
// Original license: MIT OR Apache-2.0
use rand::Rng;
#[derive(
Debug, bincode_2::Encode, bincode_2::Decode, serde::Serialize, serde::Deserialize, PartialEq, Eq,
)]
#[bincode(crate = "bincode_2")]
pub struct Lcg64Xsh32 {
state: u64,
increment: u64,
}
#[test]
pub fn test() {
let mut rng = rand::thread_rng();
for _ in 0..1000 {
crate::test_same(Lcg64Xsh32 {
state: rng.gen(),
increment: rng.gen(),
});
}
}

View File

@ -1,85 +0,0 @@
// Credits to Sway in the Rust Programming Language
use rand::Rng;
use serde::{Deserialize, Serialize};
#[test]
pub fn test() {
let mut rng = rand::thread_rng();
for _ in 0..1000 {
crate::test_same(random(&mut rng));
}
}
fn random(rng: &mut impl Rng) -> FTXresponse<Trade> {
if rng.gen() {
FTXresponse::Result(FTXresponseSuccess {
result: Trade::random(rng),
success: rng.gen(),
})
} else {
FTXresponse::Error(FTXresponseFailure {
success: rng.gen(),
error: crate::gen_string(rng),
})
}
}
#[derive(bincode_2::Encode, bincode_2::Decode, Serialize, Deserialize, Debug, PartialEq, Eq)]
#[bincode(crate = "bincode_2")]
pub enum FTXresponse<T> {
Result(FTXresponseSuccess<T>),
Error(FTXresponseFailure),
}
#[derive(
bincode_2::Encode, bincode_2::Decode, serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq,
)]
#[bincode(crate = "bincode_2")]
pub struct FTXresponseSuccess<T> {
pub success: bool,
pub result: T,
}
#[derive(bincode_2::Encode, bincode_2::Decode, Serialize, Deserialize, Debug, PartialEq, Eq)]
#[bincode(crate = "bincode_2")]
pub struct FTXresponseFailure {
pub success: bool,
pub error: String,
}
#[derive(bincode_2::Encode, bincode_2::Decode, Serialize, Deserialize, Debug, PartialEq, Eq)]
#[bincode(crate = "bincode_2")]
pub enum TradeSide {
Buy,
Sell,
}
#[derive(bincode_2::Encode, bincode_2::Decode, Serialize, Deserialize, Debug, PartialEq)]
#[bincode(crate = "bincode_2")]
#[serde(rename_all = "camelCase")]
pub struct Trade {
pub id: u64,
pub liquidation: bool,
pub price: f64,
pub side: TradeSide,
pub size: f64,
pub time: String,
}
impl Trade {
fn random(rng: &mut impl Rng) -> Self {
Self {
id: rng.gen(),
liquidation: rng.gen(),
price: rng.gen(),
side: if rng.gen() {
TradeSide::Buy
} else {
TradeSide::Sell
},
size: rng.gen(),
time: crate::gen_string(rng),
}
}
}

View File

@ -1,6 +1,6 @@
[package]
name = "bincode_derive"
version = "2.0.1" # remember to update bincode
version = "3.0.0" # remember to update bincode
authors = [
"Zoey Riordan <zoey@dos.cafe>",
"Victor Koenders <bincode@trangar.com>",
@ -18,6 +18,3 @@ description = "Implementation of #[derive(Encode, Decode)] for bincode"
[lib]
proc-macro = true
[dependencies]
virtue = "0.0.18"

View File

@ -1,28 +1,104 @@
# Bincode-derive
# Bincode is now unmaintained
The derive crate for bincode. Implements `bincode::Encode` and `bincode::Decode`.
Due to a doxxing and harassment incident, development on bincode has ceased. No
further releases will be published on crates.io.
This crate is roughly split into 2 parts:
As crates.io, unlike many other language-attached package management solutions,
lacks the ability to mark a project as archive or remove the last maintainer,
this final release is being published containing only this README, as well as a
lib.rs containing only a compiler error, to inform potential users of the
maintenance status of this crate.
# Parsing
If you were considering using bincode for a new project or are looking to an
alternative to migrate to, you are encouraged to consider some the following
alternatives, as well as the many other great serialization format crates
available in the rust ecosystem:
Most of parsing is done in the `src/parse/` folder. This will generate the following types:
- `Attributes`, not being used currently
- `Visibility`, not being used currently
- `DataType` either `Struct` or `Enum`, with the name of the data type being parsed
- `Generics` the generics part of the type, e.g. `struct Foo<'a>`
- `GenericConstraints` the "where" part of the type
- [wincode](https://crates.io/crates/wincode)
# Generate
Bincode-compatible alternative
Generating the code implementation is done in either `src/derive_enum.rs` and `src/derive_struct.rs`.
- [postcard](https://crates.io/crates/postcard)
This is supported by the structs in `src/generate`. The most notable points of this module are:
- `StreamBuilder` is a thin but friendly wrapper around `TokenStream`
- `Generator` is the base type of the code generator. This has helper methods to generate implementations:
- `ImplFor` is a helper struct for a single `impl A for B` construction. In this functions can be defined:
- `GenerateFnBody` is a helper struct for a single function in the above `impl`. This is created with a callback to `FnBuilder` which helps set some properties. `GenerateFnBody` has a `stream()` function which returns ` StreamBuilder` for the function.
Similar in spirit and structure to bincode, but a bit differently flavored
For additional derive testing, see the test cases in `../tests`
- [rkyv](https://crates.io/crates/rkyv)
For testing purposes, all generated code is outputted to the current `target/generated/bincode` folder, under file name `<struct/enum name>_Encode.rs` and `<struct/enum name>_Decode.rs`. This can help with debugging.
Zero copy deserialization, honestly the best option for many of the usecases
that bincode was intended for, like serializing transient data for
intra-program message passing.
# What the community can do better
Several tooling factors have lead to bincode's maintenance status being a bigger
issue than it needs to be, including:
- crates.io not having functionality for marking a package unmaintained or a
process for the crates.io maintainers to transfer ownership of an abandoned
package to a prospective maintainer
In many other programming language communities such as haskell and hackage, or
python and pypi, when the last maintainer of a critical crate just walks away,
there often an in-band status that identifies that package as having no active
maintainers, and usually at least _some_ policy in place for the package
collection maintainers to intervene and transfer ownership of such a package,
allowing the community to assign a new maintainer to the existing package,
automatically pointing the rest of the ecosystem to the new sources with no
intervention required on the consumers part.
crates.io not having any such functionality or processes creates a pretty
massive pain point when the last maintainer does walk away, placing the burden
on _them_, very often an already burnt out volunteer, to select a new
maintainer. If the existing maintainer does not do this, the only current way
to continue maintenance of the package is to create a differently-named fork,
and then go through the massive hassle of not only convincing the entire
ecosystem to use it, but to settle in on one community preferred fork. This
creates avoidable tension when maintainers _do_ just walk away, with community
members being scared to make the fork themselves, both out of fear of the
amount of work getting the community to adopt it entails, and out of fear of
making the inevitable fork-fight worse by adding another contestant.
- crates.io not having visibility for its internal source control
Much of the drama that resulted in the doxxing and harassment was centered
around the git history being rewritten when the repository was blanked out on
github and moved to sourcehut. While this is a legitimate cause for some level
of concern that merits at least asking a question, it is disappointing that
the community is focusing on it so much when virtually none of the users of
bincode are pulling from the git version anyway, with almost all of the users
using the crates.io release. While the existing bincode releases are tied to
the previous history through the git commit reference cargo release's
`.cargo_vcs_info.json`, the cargo releases, which represent the canonical
version of bincode, are not fundamentally tied to the git repository at all,
and there has been a lot of worrying about _the wrong supply chain_.
We have faced many questions like "if the github is deleted, where can users
make sure they are getting the old version of the source code" that are
answered with "there haven't been any crates.io releases since the migration
and history rewrite, just bring in an old version with cargo and you'll have
it".
This could have been potentially avoided if crates.io and cargo provided
better visibility into their internal source control used for packing crates.
At the very least, a link to the source code browser on docs.rs from the
crates.io page for a given release could have made more users aware of the
fact that crates.io/cargo provide such internal source control, and a full on
source code viewer, or even better a version comparison tool, integrated into
crates.io would have made things a _lot_ more manageable while there were
still such questions flying around.
- crates.io metadata is not editable without performing a release
Much of this could have been avoided if the crates.io metadata was
independently editable and included a contact information field (ideally
something like githubs private email solution, where it provides a generated
email address that forwards to something configurable).
At the time of migration, bincode was nowhere _near_ ready for another
release, and being able to independently update the source code link in the
crates.io metadata and provide up to date contact information without having
to roll either a special no-code-changes release off of a branch that only
changed those things, or roll a questionable intermediate release with the
changes, both of which likely would have only raised more concerns from the
community, would have significantly decreased the developer burden of
completing the migration in a public and notorious fashion.

View File

@ -1,131 +0,0 @@
use virtue::prelude::*;
use virtue::utils::{parse_tagged_attribute, ParsedAttribute};
pub struct ContainerAttributes {
pub crate_name: String,
pub bounds: Option<(String, Literal)>,
pub decode_bounds: Option<(String, Literal)>,
pub decode_context: Option<(String, Literal)>,
pub borrow_decode_bounds: Option<(String, Literal)>,
pub encode_bounds: Option<(String, Literal)>,
}
impl Default for ContainerAttributes {
fn default() -> Self {
Self {
crate_name: "::bincode".to_string(),
bounds: None,
decode_bounds: None,
decode_context: None,
encode_bounds: None,
borrow_decode_bounds: None,
}
}
}
impl FromAttribute for ContainerAttributes {
fn parse(group: &Group) -> Result<Option<Self>> {
let attributes = match parse_tagged_attribute(group, "bincode")? {
Some(body) => body,
None => return Ok(None),
};
let mut result = Self::default();
for attribute in attributes {
match attribute {
ParsedAttribute::Property(key, val) if key.to_string() == "crate" => {
let val_string = val.to_string();
if val_string.starts_with('"') && val_string.ends_with('"') {
result.crate_name = val_string[1..val_string.len() - 1].to_string();
} else {
return Err(Error::custom_at("Should be a literal str", val.span()));
}
}
ParsedAttribute::Property(key, val) if key.to_string() == "bounds" => {
let val_string = val.to_string();
if val_string.starts_with('"') && val_string.ends_with('"') {
result.bounds =
Some((val_string[1..val_string.len() - 1].to_string(), val));
} else {
return Err(Error::custom_at("Should be a literal str", val.span()));
}
}
ParsedAttribute::Property(key, val) if key.to_string() == "decode_bounds" => {
let val_string = val.to_string();
if val_string.starts_with('"') && val_string.ends_with('"') {
result.decode_bounds =
Some((val_string[1..val_string.len() - 1].to_string(), val));
} else {
return Err(Error::custom_at("Should be a literal str", val.span()));
}
}
ParsedAttribute::Property(key, val) if key.to_string() == "decode_context" => {
let val_string = val.to_string();
if val_string.starts_with('"') && val_string.ends_with('"') {
result.decode_context =
Some((val_string[1..val_string.len() - 1].to_string(), val));
} else {
return Err(Error::custom_at("Should be a literal str", val.span()));
}
}
ParsedAttribute::Property(key, val) if key.to_string() == "encode_bounds" => {
let val_string = val.to_string();
if val_string.starts_with('"') && val_string.ends_with('"') {
result.encode_bounds =
Some((val_string[1..val_string.len() - 1].to_string(), val));
} else {
return Err(Error::custom_at("Should be a literal str", val.span()));
}
}
ParsedAttribute::Property(key, val)
if key.to_string() == "borrow_decode_bounds" =>
{
let val_string = val.to_string();
if val_string.starts_with('"') && val_string.ends_with('"') {
result.borrow_decode_bounds =
Some((val_string[1..val_string.len() - 1].to_string(), val));
} else {
return Err(Error::custom_at("Should be a literal str", val.span()));
}
}
ParsedAttribute::Tag(i) => {
return Err(Error::custom_at("Unknown field attribute", i.span()))
}
ParsedAttribute::Property(key, _) => {
return Err(Error::custom_at("Unknown field attribute", key.span()))
}
_ => {}
}
}
Ok(Some(result))
}
}
#[derive(Default)]
pub struct FieldAttributes {
pub with_serde: bool,
}
impl FromAttribute for FieldAttributes {
fn parse(group: &Group) -> Result<Option<Self>> {
let attributes = match parse_tagged_attribute(group, "bincode")? {
Some(body) => body,
None => return Ok(None),
};
let mut result = Self::default();
for attribute in attributes {
match attribute {
ParsedAttribute::Tag(i) if i.to_string() == "with_serde" => {
result.with_serde = true;
}
ParsedAttribute::Tag(i) => {
return Err(Error::custom_at("Unknown field attribute", i.span()))
}
ParsedAttribute::Property(key, _) => {
return Err(Error::custom_at("Unknown field attribute", key.span()))
}
_ => {}
}
}
Ok(Some(result))
}
}

View File

@ -1,449 +0,0 @@
use crate::attribute::{ContainerAttributes, FieldAttributes};
use virtue::prelude::*;
const TUPLE_FIELD_PREFIX: &str = "field_";
pub(crate) struct DeriveEnum {
pub variants: Vec<EnumVariant>,
pub attributes: ContainerAttributes,
}
impl DeriveEnum {
fn iter_fields(&self) -> EnumVariantIterator {
EnumVariantIterator {
idx: 0,
variants: &self.variants,
}
}
pub fn generate_encode(self, generator: &mut Generator) -> Result<()> {
let crate_name = self.attributes.crate_name.as_str();
generator
.impl_for(format!("{}::Encode", crate_name))
.modify_generic_constraints(|generics, where_constraints| {
if let Some((bounds, lit)) =
(self.attributes.encode_bounds.as_ref()).or(self.attributes.bounds.as_ref())
{
where_constraints.clear();
where_constraints
.push_parsed_constraint(bounds)
.map_err(|e| e.with_span(lit.span()))?;
} else {
for g in generics.iter_generics() {
where_constraints
.push_constraint(g, format!("{}::Encode", crate_name))
.unwrap();
}
}
Ok(())
})?
.generate_fn("encode")
.with_generic_deps("__E", [format!("{}::enc::Encoder", crate_name)])
.with_self_arg(FnSelfArg::RefSelf)
.with_arg("encoder", "&mut __E")
.with_return_type(format!(
"core::result::Result<(), {}::error::EncodeError>",
crate_name
))
.body(|fn_body| {
fn_body.ident_str("match");
fn_body.ident_str("self");
fn_body.group(Delimiter::Brace, |match_body| {
if self.variants.is_empty() {
self.encode_empty_enum_case(match_body)?;
}
for (variant_index, variant) in self.iter_fields() {
// Self::Variant
match_body.ident_str("Self");
match_body.puncts("::");
match_body.ident(variant.name.clone());
// if we have any fields, declare them here
// Self::Variant { a, b, c }
if let Some(fields) = variant.fields.as_ref() {
let delimiter = fields.delimiter();
match_body.group(delimiter, |field_body| {
for (idx, field_name) in fields.names().into_iter().enumerate() {
if idx != 0 {
field_body.punct(',');
}
field_body.push(
field_name.to_token_tree_with_prefix(TUPLE_FIELD_PREFIX),
);
}
Ok(())
})?;
}
// Arrow
// Self::Variant { a, b, c } =>
match_body.puncts("=>");
// Body of this variant
// Note that the fields are available as locals because of the match destructuring above
// {
// encoder.encode_u32(n)?;
// bincode::Encode::encode(a, encoder)?;
// bincode::Encode::encode(b, encoder)?;
// bincode::Encode::encode(c, encoder)?;
// }
match_body.group(Delimiter::Brace, |body| {
// variant index
body.push_parsed(format!("<u32 as {}::Encode>::encode", crate_name))?;
body.group(Delimiter::Parenthesis, |args| {
args.punct('&');
args.group(Delimiter::Parenthesis, |num| {
num.extend(variant_index);
Ok(())
})?;
args.punct(',');
args.push_parsed("encoder")?;
Ok(())
})?;
body.punct('?');
body.punct(';');
// If we have any fields, encode them all one by one
if let Some(fields) = variant.fields.as_ref() {
for field_name in fields.names() {
let attributes = field_name
.attributes()
.get_attribute::<FieldAttributes>()?
.unwrap_or_default();
if attributes.with_serde {
body.push_parsed(format!(
"{0}::Encode::encode(&{0}::serde::Compat({1}), encoder)?;",
crate_name,
field_name.to_string_with_prefix(TUPLE_FIELD_PREFIX),
))?;
} else {
body.push_parsed(format!(
"{0}::Encode::encode({1}, encoder)?;",
crate_name,
field_name.to_string_with_prefix(TUPLE_FIELD_PREFIX),
))?;
}
}
}
body.push_parsed("core::result::Result::Ok(())")?;
Ok(())
})?;
match_body.punct(',');
}
Ok(())
})?;
Ok(())
})?;
Ok(())
}
/// If we're encoding an empty enum, we need to add an empty case in the form of:
/// `_ => core::unreachable!(),`
fn encode_empty_enum_case(&self, builder: &mut StreamBuilder) -> Result {
builder.push_parsed("_ => core::unreachable!()").map(|_| ())
}
/// Build the catch-all case for an int-to-enum decode implementation
fn invalid_variant_case(&self, enum_name: &str, result: &mut StreamBuilder) -> Result {
let crate_name = self.attributes.crate_name.as_str();
// we'll be generating:
// variant => Err(
// bincode::error::DecodeError::UnexpectedVariant {
// found: variant,
// type_name: <enum_name>
// allowed: ...,
// }
// )
//
// Where allowed is either:
// - bincode::error::AllowedEnumVariants::Range { min: 0, max: <max> }
// if we have no fixed value variants
// - bincode::error::AllowedEnumVariants::Allowed(&[<variant1>, <variant2>, ...])
// if we have fixed value variants
result.ident_str("variant");
result.puncts("=>");
result.push_parsed("core::result::Result::Err")?;
result.group(Delimiter::Parenthesis, |err_inner| {
err_inner.push_parsed(format!(
"{}::error::DecodeError::UnexpectedVariant",
crate_name
))?;
err_inner.group(Delimiter::Brace, |variant_inner| {
variant_inner.ident_str("found");
variant_inner.punct(':');
variant_inner.ident_str("variant");
variant_inner.punct(',');
variant_inner.ident_str("type_name");
variant_inner.punct(':');
variant_inner.lit_str(enum_name);
variant_inner.punct(',');
variant_inner.ident_str("allowed");
variant_inner.punct(':');
if self.variants.iter().any(|i| i.value.is_some()) {
// we have fixed values, implement AllowedEnumVariants::Allowed
variant_inner.push_parsed(format!(
"&{}::error::AllowedEnumVariants::Allowed",
crate_name
))?;
variant_inner.group(Delimiter::Parenthesis, |allowed_inner| {
allowed_inner.punct('&');
allowed_inner.group(Delimiter::Bracket, |allowed_slice| {
for (idx, (ident, _)) in self.iter_fields().enumerate() {
if idx != 0 {
allowed_slice.punct(',');
}
allowed_slice.extend(ident);
}
Ok(())
})?;
Ok(())
})?;
} else {
// no fixed values, implement a range
variant_inner.push_parsed(format!(
"&{0}::error::AllowedEnumVariants::Range {{ min: 0, max: {1} }}",
crate_name,
self.variants.len() - 1
))?;
}
Ok(())
})?;
Ok(())
})?;
Ok(())
}
pub fn generate_decode(self, generator: &mut Generator) -> Result<()> {
let crate_name = self.attributes.crate_name.as_str();
let decode_context = if let Some((decode_context, _)) = &self.attributes.decode_context {
decode_context.as_str()
} else {
"__Context"
};
// Remember to keep this mostly in sync with generate_borrow_decode
let enum_name = generator.target_name().to_string();
let mut impl_for = generator.impl_for(format!("{}::Decode", crate_name));
if self.attributes.decode_context.is_none() {
impl_for = impl_for.with_impl_generics(["__Context"]);
}
impl_for
.with_trait_generics([decode_context])
.modify_generic_constraints(|generics, where_constraints| {
if let Some((bounds, lit)) = (self.attributes.decode_bounds.as_ref()).or(self.attributes.bounds.as_ref()) {
where_constraints.clear();
where_constraints.push_parsed_constraint(bounds).map_err(|e| e.with_span(lit.span()))?;
} else {
for g in generics.iter_generics() {
where_constraints.push_constraint(g, format!("{}::Decode<__Context>", crate_name))?;
}
}
Ok(())
})?
.generate_fn("decode")
.with_generic_deps("__D", [format!("{}::de::Decoder<Context = {}>", crate_name, decode_context)])
.with_arg("decoder", "&mut __D")
.with_return_type(format!("core::result::Result<Self, {}::error::DecodeError>", crate_name))
.body(|fn_builder| {
if self.variants.is_empty() {
fn_builder.push_parsed(format!(
"core::result::Result::Err({}::error::DecodeError::EmptyEnum {{ type_name: core::any::type_name::<Self>() }})",
crate_name
))?;
} else {
fn_builder
.push_parsed(format!(
"let variant_index = <u32 as {}::Decode::<__D::Context>>::decode(decoder)?;",
crate_name
))?;
fn_builder.push_parsed("match variant_index")?;
fn_builder.group(Delimiter::Brace, |variant_case| {
for (mut variant_index, variant) in self.iter_fields() {
// idx => Ok(..)
if variant_index.len() > 1 {
variant_case.push_parsed("x if x == ")?;
variant_case.extend(variant_index);
} else {
variant_case.push(variant_index.remove(0));
}
variant_case.puncts("=>");
variant_case.push_parsed("core::result::Result::Ok")?;
variant_case.group(Delimiter::Parenthesis, |variant_case_body| {
// Self::Variant { }
// Self::Variant { 0: ..., 1: ... 2: ... },
// Self::Variant { a: ..., b: ... c: ... },
variant_case_body.ident_str("Self");
variant_case_body.puncts("::");
variant_case_body.ident(variant.name.clone());
variant_case_body.group(Delimiter::Brace, |variant_body| {
if let Some(fields) = variant.fields.as_ref() {
let is_tuple = matches!(fields, Fields::Tuple(_));
for (idx, field) in fields.names().into_iter().enumerate() {
if is_tuple {
variant_body.lit_usize(idx);
} else {
variant_body.ident(field.unwrap_ident().clone());
}
variant_body.punct(':');
let attributes = field.attributes().get_attribute::<FieldAttributes>()?.unwrap_or_default();
if attributes.with_serde {
variant_body
.push_parsed(format!(
"<{0}::serde::Compat<_> as {0}::Decode::<__D::Context>>::decode(decoder)?.0,",
crate_name
))?;
} else {
variant_body
.push_parsed(format!(
"{}::Decode::<__D::Context>::decode(decoder)?,",
crate_name
))?;
}
}
}
Ok(())
})?;
Ok(())
})?;
variant_case.punct(',');
}
// invalid idx
self.invalid_variant_case(&enum_name, variant_case)
})?;
}
Ok(())
})?;
self.generate_borrow_decode(generator)?;
Ok(())
}
pub fn generate_borrow_decode(self, generator: &mut Generator) -> Result<()> {
let crate_name = &self.attributes.crate_name;
let decode_context = if let Some((decode_context, _)) = &self.attributes.decode_context {
decode_context.as_str()
} else {
"__Context"
};
// Remember to keep this mostly in sync with generate_decode
let enum_name = generator.target_name().to_string();
let mut impl_for = generator
.impl_for_with_lifetimes(format!("{}::BorrowDecode", crate_name), ["__de"])
.with_trait_generics([decode_context]);
if self.attributes.decode_context.is_none() {
impl_for = impl_for.with_impl_generics(["__Context"]);
}
impl_for
.modify_generic_constraints(|generics, where_constraints| {
if let Some((bounds, lit)) = (self.attributes.borrow_decode_bounds.as_ref()).or(self.attributes.bounds.as_ref()) {
where_constraints.clear();
where_constraints.push_parsed_constraint(bounds).map_err(|e| e.with_span(lit.span()))?;
} else {
for g in generics.iter_generics() {
where_constraints.push_constraint(g, format!("{}::de::BorrowDecode<'__de, {}>", crate_name, decode_context)).unwrap();
}
for lt in generics.iter_lifetimes() {
where_constraints.push_parsed_constraint(format!("'__de: '{}", lt.ident))?;
}
}
Ok(())
})?
.generate_fn("borrow_decode")
.with_generic_deps("__D", [format!("{}::de::BorrowDecoder<'__de, Context = {}>", crate_name, decode_context)])
.with_arg("decoder", "&mut __D")
.with_return_type(format!("core::result::Result<Self, {}::error::DecodeError>", crate_name))
.body(|fn_builder| {
if self.variants.is_empty() {
fn_builder.push_parsed(format!(
"core::result::Result::Err({}::error::DecodeError::EmptyEnum {{ type_name: core::any::type_name::<Self>() }})",
crate_name
))?;
} else {
fn_builder
.push_parsed(format!("let variant_index = <u32 as {}::Decode::<__D::Context>>::decode(decoder)?;", crate_name))?;
fn_builder.push_parsed("match variant_index")?;
fn_builder.group(Delimiter::Brace, |variant_case| {
for (mut variant_index, variant) in self.iter_fields() {
// idx => Ok(..)
if variant_index.len() > 1 {
variant_case.push_parsed("x if x == ")?;
variant_case.extend(variant_index);
} else {
variant_case.push(variant_index.remove(0));
}
variant_case.puncts("=>");
variant_case.push_parsed("core::result::Result::Ok")?;
variant_case.group(Delimiter::Parenthesis, |variant_case_body| {
// Self::Variant { }
// Self::Variant { 0: ..., 1: ... 2: ... },
// Self::Variant { a: ..., b: ... c: ... },
variant_case_body.ident_str("Self");
variant_case_body.puncts("::");
variant_case_body.ident(variant.name.clone());
variant_case_body.group(Delimiter::Brace, |variant_body| {
if let Some(fields) = variant.fields.as_ref() {
let is_tuple = matches!(fields, Fields::Tuple(_));
for (idx, field) in fields.names().into_iter().enumerate() {
if is_tuple {
variant_body.lit_usize(idx);
} else {
variant_body.ident(field.unwrap_ident().clone());
}
variant_body.punct(':');
let attributes = field.attributes().get_attribute::<FieldAttributes>()?.unwrap_or_default();
if attributes.with_serde {
variant_body
.push_parsed(format!("<{0}::serde::BorrowCompat<_> as {0}::BorrowDecode::<__D::Context>>::borrow_decode(decoder)?.0,", crate_name))?;
} else {
variant_body.push_parsed(format!("{}::BorrowDecode::<__D::Context>::borrow_decode(decoder)?,", crate_name))?;
}
}
}
Ok(())
})?;
Ok(())
})?;
variant_case.punct(',');
}
// invalid idx
self.invalid_variant_case(&enum_name, variant_case)
})?;
}
Ok(())
})?;
Ok(())
}
}
struct EnumVariantIterator<'a> {
variants: &'a [EnumVariant],
idx: usize,
}
impl<'a> Iterator for EnumVariantIterator<'a> {
type Item = (Vec<TokenTree>, &'a EnumVariant);
fn next(&mut self) -> Option<Self::Item> {
let idx = self.idx;
let variant = self.variants.get(self.idx)?;
self.idx += 1;
let tokens = vec![TokenTree::Literal(Literal::u32_suffixed(idx as u32))];
Some((tokens, variant))
}
}

View File

@ -1,211 +0,0 @@
use crate::attribute::{ContainerAttributes, FieldAttributes};
use virtue::prelude::*;
pub(crate) struct DeriveStruct {
pub fields: Option<Fields>,
pub attributes: ContainerAttributes,
}
impl DeriveStruct {
pub fn generate_encode(self, generator: &mut Generator) -> Result<()> {
let crate_name = &self.attributes.crate_name;
generator
.impl_for(format!("{}::Encode", crate_name))
.modify_generic_constraints(|generics, where_constraints| {
if let Some((bounds, lit)) =
(self.attributes.encode_bounds.as_ref()).or(self.attributes.bounds.as_ref())
{
where_constraints.clear();
where_constraints
.push_parsed_constraint(bounds)
.map_err(|e| e.with_span(lit.span()))?;
} else {
for g in generics.iter_generics() {
where_constraints
.push_constraint(g, format!("{}::Encode", crate_name))
.unwrap();
}
}
Ok(())
})?
.generate_fn("encode")
.with_generic_deps("__E", [format!("{}::enc::Encoder", crate_name)])
.with_self_arg(virtue::generate::FnSelfArg::RefSelf)
.with_arg("encoder", "&mut __E")
.with_return_type(format!(
"core::result::Result<(), {}::error::EncodeError>",
crate_name
))
.body(|fn_body| {
if let Some(fields) = self.fields.as_ref() {
for field in fields.names() {
let attributes = field
.attributes()
.get_attribute::<FieldAttributes>()?
.unwrap_or_default();
if attributes.with_serde {
fn_body.push_parsed(format!(
"{0}::Encode::encode(&{0}::serde::Compat(&self.{1}), encoder)?;",
crate_name, field
))?;
} else {
fn_body.push_parsed(format!(
"{}::Encode::encode(&self.{}, encoder)?;",
crate_name, field
))?;
}
}
}
fn_body.push_parsed("core::result::Result::Ok(())")?;
Ok(())
})?;
Ok(())
}
pub fn generate_decode(self, generator: &mut Generator) -> Result<()> {
// Remember to keep this mostly in sync with generate_borrow_decode
let crate_name = &self.attributes.crate_name;
let decode_context = if let Some((decode_context, _)) = &self.attributes.decode_context {
decode_context.as_str()
} else {
"__Context"
};
let mut impl_for = generator.impl_for(format!("{}::Decode", crate_name));
if self.attributes.decode_context.is_none() {
impl_for = impl_for.with_impl_generics(["__Context"]);
}
impl_for
.with_trait_generics([decode_context])
.modify_generic_constraints(|generics, where_constraints| {
if let Some((bounds, lit)) = (self.attributes.decode_bounds.as_ref()).or(self.attributes.bounds.as_ref()) {
where_constraints.clear();
where_constraints.push_parsed_constraint(bounds).map_err(|e| e.with_span(lit.span()))?;
} else {
for g in generics.iter_generics() {
where_constraints.push_constraint(g, format!("{}::Decode<{}>", crate_name, decode_context)).unwrap();
}
}
Ok(())
})?
.generate_fn("decode")
.with_generic_deps("__D", [format!("{}::de::Decoder<Context = {}>", crate_name, decode_context)])
.with_arg("decoder", "&mut __D")
.with_return_type(format!("core::result::Result<Self, {}::error::DecodeError>", crate_name))
.body(|fn_body| {
// Ok(Self {
fn_body.push_parsed("core::result::Result::Ok")?;
fn_body.group(Delimiter::Parenthesis, |ok_group| {
ok_group.ident_str("Self");
ok_group.group(Delimiter::Brace, |struct_body| {
// Fields
// {
// a: bincode::Decode::decode(decoder)?,
// b: bincode::Decode::decode(decoder)?,
// ...
// }
if let Some(fields) = self.fields.as_ref() {
for field in fields.names() {
let attributes = field.attributes().get_attribute::<FieldAttributes>()?.unwrap_or_default();
if attributes.with_serde {
struct_body
.push_parsed(format!(
"{1}: (<{0}::serde::Compat<_> as {0}::Decode::<{2}>>::decode(decoder)?).0,",
crate_name,
field,
decode_context,
))?;
} else {
struct_body
.push_parsed(format!(
"{1}: {0}::Decode::decode(decoder)?,",
crate_name,
field
))?;
}
}
}
Ok(())
})?;
Ok(())
})?;
Ok(())
})?;
self.generate_borrow_decode(generator)?;
Ok(())
}
pub fn generate_borrow_decode(self, generator: &mut Generator) -> Result<()> {
// Remember to keep this mostly in sync with generate_decode
let crate_name = self.attributes.crate_name;
let decode_context = if let Some((decode_context, _)) = &self.attributes.decode_context {
decode_context.as_str()
} else {
"__Context"
};
let mut impl_for = generator
.impl_for_with_lifetimes(format!("{}::BorrowDecode", crate_name), ["__de"])
.with_trait_generics([decode_context]);
if self.attributes.decode_context.is_none() {
impl_for = impl_for.with_impl_generics(["__Context"]);
}
impl_for
.modify_generic_constraints(|generics, where_constraints| {
if let Some((bounds, lit)) = (self.attributes.borrow_decode_bounds.as_ref()).or(self.attributes.bounds.as_ref()) {
where_constraints.clear();
where_constraints.push_parsed_constraint(bounds).map_err(|e| e.with_span(lit.span()))?;
} else {
for g in generics.iter_generics() {
where_constraints.push_constraint(g, format!("{}::de::BorrowDecode<'__de, {}>", crate_name, decode_context)).unwrap();
}
for lt in generics.iter_lifetimes() {
where_constraints.push_parsed_constraint(format!("'__de: '{}", lt.ident))?;
}
}
Ok(())
})?
.generate_fn("borrow_decode")
.with_generic_deps("__D", [format!("{}::de::BorrowDecoder<'__de, Context = {}>", crate_name, decode_context)])
.with_arg("decoder", "&mut __D")
.with_return_type(format!("core::result::Result<Self, {}::error::DecodeError>", crate_name))
.body(|fn_body| {
// Ok(Self {
fn_body.push_parsed("core::result::Result::Ok")?;
fn_body.group(Delimiter::Parenthesis, |ok_group| {
ok_group.ident_str("Self");
ok_group.group(Delimiter::Brace, |struct_body| {
if let Some(fields) = self.fields.as_ref() {
for field in fields.names() {
let attributes = field.attributes().get_attribute::<FieldAttributes>()?.unwrap_or_default();
if attributes.with_serde {
struct_body
.push_parsed(format!(
"{1}: (<{0}::serde::BorrowCompat<_> as {0}::BorrowDecode::<'_, {2}>>::borrow_decode(decoder)?).0,",
crate_name,
field,
decode_context,
))?;
} else {
struct_body
.push_parsed(format!(
"{1}: {0}::BorrowDecode::<'_, {2}>::borrow_decode(decoder)?,",
crate_name,
field,
decode_context,
))?;
}
}
}
Ok(())
})?;
Ok(())
})?;
Ok(())
})?;
Ok(())
}
}

View File

@ -1,105 +1 @@
mod attribute;
mod derive_enum;
mod derive_struct;
use attribute::ContainerAttributes;
use virtue::prelude::*;
#[proc_macro_derive(Encode, attributes(bincode))]
pub fn derive_encode(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
derive_encode_inner(input).unwrap_or_else(|e| e.into_token_stream())
}
fn derive_encode_inner(input: TokenStream) -> Result<TokenStream> {
let parse = Parse::new(input)?;
let (mut generator, attributes, body) = parse.into_generator();
let attributes = attributes
.get_attribute::<ContainerAttributes>()?
.unwrap_or_default();
match body {
Body::Struct(body) => {
derive_struct::DeriveStruct {
fields: body.fields,
attributes,
}
.generate_encode(&mut generator)?;
}
Body::Enum(body) => {
derive_enum::DeriveEnum {
variants: body.variants,
attributes,
}
.generate_encode(&mut generator)?;
}
}
generator.export_to_file("bincode", "Encode");
generator.finish()
}
#[proc_macro_derive(Decode, attributes(bincode))]
pub fn derive_decode(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
derive_decode_inner(input).unwrap_or_else(|e| e.into_token_stream())
}
fn derive_decode_inner(input: TokenStream) -> Result<TokenStream> {
let parse = Parse::new(input)?;
let (mut generator, attributes, body) = parse.into_generator();
let attributes = attributes
.get_attribute::<ContainerAttributes>()?
.unwrap_or_default();
match body {
Body::Struct(body) => {
derive_struct::DeriveStruct {
fields: body.fields,
attributes,
}
.generate_decode(&mut generator)?;
}
Body::Enum(body) => {
derive_enum::DeriveEnum {
variants: body.variants,
attributes,
}
.generate_decode(&mut generator)?;
}
}
generator.export_to_file("bincode", "Decode");
generator.finish()
}
#[proc_macro_derive(BorrowDecode, attributes(bincode))]
pub fn derive_borrow_decode(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
derive_borrow_decode_inner(input).unwrap_or_else(|e| e.into_token_stream())
}
fn derive_borrow_decode_inner(input: TokenStream) -> Result<TokenStream> {
let parse = Parse::new(input)?;
let (mut generator, attributes, body) = parse.into_generator();
let attributes = attributes
.get_attribute::<ContainerAttributes>()?
.unwrap_or_default();
match body {
Body::Struct(body) => {
derive_struct::DeriveStruct {
fields: body.fields,
attributes,
}
.generate_borrow_decode(&mut generator)?;
}
Body::Enum(body) => {
derive_enum::DeriveEnum {
variants: body.variants,
attributes,
}
.generate_borrow_decode(&mut generator)?;
}
}
generator.export_to_file("bincode", "BorrowDecode");
generator.finish()
}
compile_error!("https://xkcd.com/2347/");

View File

@ -1,116 +0,0 @@
# Migrating from bincode 1 to 2
Bincode 2 now has an optional dependency on `serde`. You can either use `serde`, or use bincode's own `derive` feature and macros.
## From `Options` to `Configuration`
Bincode 1 had the [Options](https://docs.rs/bincode/1/bincode/config/trait.Options.html) trait. This has been replaced with the [Configuration](https://docs.rs/bincode/2/bincode/config/struct.Configuration.html) struct.
If you're using `Options`, you can change it like this:
```rust,ignore
# old
bincode_1::DefaultOptions::new().with_varint_encoding()
# new
bincode_2::config::legacy().with_variable_int_encoding()
```
If you want to be compatible with bincode 1, use the following table:
| Bincode 1 | Bincode 2 |
| ---------------------------------------------------------------------- | ----------------------------------------------- |
| version 1.0 - 1.2 with `bincode_1::DefaultOptions::new().serialize(T)` | `config::legacy()` |
| version 1.3+ with `bincode_1::DefaultOptions::new().serialize(T)` | `config::legacy().with_variable_int_encoding()` |
| No explicit `Options`, e.g. `bincode::serialize(T)` | `config::legacy()` |
If you do not care about compatibility with bincode 1, we recommend using `config::standard()`
The following changes have been made:
- `.with_limit(n)` has been changed to `.with_limit::<n>()`.
- `.with_native_endian()` has been removed. Use `.with_big_endian()` or `with_little_endian()` instead.
- `.with_varint_encoding()` has been renamed to `.with_variable_int_encoding()`.
- `.with_fixint_encoding()` has been renamed to `.with_fixed_int_encoding()`.
- `.reject_trailing_bytes()` has been removed.
- `.allow_trailing_bytes()` has been removed.
- You can no longer (de)serialize from the `Options` trait directly. Use one of the `encode_` or `decode_` methods.
Because of confusion with `Options` defaults in bincode 1, we have made `Configuration` mandatory in all calls in bincode 2.
## Migrating with `serde`
You may wish to stick with `serde` when migrating to bincode 2, for example if you are using serde-exclusive derive features such as `#[serde(deserialize_with)]`.
If so, make sure to include bincode 2 with the `serde` feature enabled, and use the `bincode::serde::*` functions instead of `bincode::*` as described below:
```toml
[dependencies]
bincode = { version = "2.0", features = ["serde"] }
# Optionally you can disable the `derive` feature:
# bincode = { version = "2.0", default-features = false, features = ["std", "serde"] }
```
Then replace the following functions: (`Configuration` is `bincode::config::legacy()` by default)
| Bincode 1 | Bincode 2 |
| ----------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------- |
| `bincode::deserialize(&[u8])` | `bincode::serde::decode_from_slice(&[u8], Configuration)`<br />`bincode::serde::borrow_decode_from_slice(&[u8], Configuration)` |
| `bincode::deserialize_from(std::io::Read)` | `bincode::serde::decode_from_std_read(std::io::Read, Configuration)` |
| `bincode::deserialize_from_custom(BincodeRead)` | `bincode::serde::decode_from_reader(Reader, Configuration)` |
| | |
| `bincode::serialize(T)` | `bincode::serde::encode_to_vec(T, Configuration)`<br />`bincode::serde::encode_into_slice(T, &mut [u8], Configuration)` |
| `bincode::serialize_into(std::io::Write, T)` | `bincode::serde::encode_into_std_write(T, std::io::Write, Configuration)` |
| `bincode::serialized_size(T)` | Currently not implemented |
## Migrating from `serde` to `bincode-derive`
`bincode-derive` is enabled by default. If you're using `default-features = false`, make sure to add `features = ["derive"]` to your `Cargo.toml`.
```toml,ignore
[dependencies]
bincode = "2.0"
# If you need `no_std` with `alloc`:
# bincode = { version = "2.0", default-features = false, features = ["derive", "alloc"] }
# If you need `no_std` and no `alloc`:
# bincode = { version = "2.0", default-features = false, features = ["derive"] }
```
Replace or add the following attributes. You are able to use both `serde-derive` and `bincode-derive` side-by-side.
| serde-derive | bincode-derive |
| ------------------------------- | ---------------------------- |
| `#[derive(serde::Serialize)]` | `#[derive(bincode::Encode)]` |
| `#[derive(serde::Deserialize)]` | `#[derive(bincode::Decode)]` |
**note:** To implement these traits manually, see the documentation of [Encode](https://docs.rs/bincode/2/bincode/enc/trait.Encode.html) and [Decode](https://docs.rs/bincode/2/bincode/de/trait.Decode.html).
**note:** For more information on using `bincode-derive` with external libraries, see [below](#bincode-derive-and-libraries).
Then replace the following functions: (`Configuration` is `bincode::config::legacy()` by default)
| Bincode 1 | Bincode 2 |
| ----------------------------------------------- | ------------------------------------------------------------------------------------------------------------------ |
| `bincode::deserialize(&[u8])` | `bincode::decode_from_slice(&bytes, Configuration)`<br />`bincode::borrow_decode_from_slice(&[u8], Configuration)` |
| `bincode::deserialize_from(std::io::Read)` | `bincode::decode_from_std_read(std::io::Read, Configuration)` |
| `bincode::deserialize_from_custom(BincodeRead)` | `bincode::decode_from_reader(Reader, Configuration)` |
| | |
| `bincode::serialize(T)` | `bincode::encode_to_vec(T, Configuration)`<br />`bincode::encode_into_slice(t: T, &mut [u8], Configuration)` |
| `bincode::serialize_into(std::io::Write, T)` | `bincode::encode_into_std_write(T, std::io::Write, Configuration)` |
| `bincode::serialized_size(T)` | Currently not implemented |
### Bincode derive and libraries
Currently not many libraries support the traits `Encode` and `Decode`. There are a couple of options if you want to use `#[derive(bincode::Encode, bincode::Decode)]`:
- Enable the `serde` feature and add a `#[bincode(with_serde)]` above each field that implements `serde::Serialize/Deserialize` but not `Encode/Decode`
- Enable the `serde` feature and wrap your field in [bincode::serde::Compat](https://docs.rs/bincode/2/bincode/serde/struct.Compat.html) or [bincode::serde::BorrowCompat](https://docs.rs/bincode/2/bincode/serde/struct.BorrowCompat.html)
- Make a pull request to the library:
- Make sure to be respectful, most of the developers are doing this in their free time.
- Add a dependency `bincode = { version = "2.0", default-features = false, optional = true }` to the `Cargo.toml`
- Implement [Encode](https://docs.rs/bincode/2/bincode/enc/trait.Encode.html)
- Implement [Decode](https://docs.rs/bincode/2/bincode/de/trait.Decode.html)
- Make sure both of these implementations have a `#[cfg(feature = "bincode")]` attribute.

View File

@ -1,335 +0,0 @@
# Serialization Specification
_NOTE_: This specification is primarily defined in the context of Rust, but aims to be implementable across different programming languages.
## Definitions
- **Variant**: A specific constructor or case of an enum type.
- **Variant Payload**: The associated data of a specific enum variant.
- **Discriminant**: A unique identifier for an enum variant, typically represented as an integer.
- **Basic Types**: Primitive types that have a direct, well-defined binary representation.
## Endianness
By default, this serialization format uses little-endian byte order for basic numeric types. This means multi-byte values are encoded with their least significant byte first.
Endianness can be configured with the following methods, allowing for big-endian serialization when required:
- [`with_big_endian`](https://docs.rs/bincode/2/bincode/config/struct.Configuration.html#method.with_big_endian)
- [`with_little_endian`](https://docs.rs/bincode/2/bincode/config/struct.Configuration.html#method.with_little_endian)
### Byte Order Considerations
- Multi-byte values (integers, floats) are affected by endianness
- Single-byte values (u8, i8) are not affected
- Struct and collection serialization order is not changed by endianness
## Basic Types
### Boolean Encoding
- Encoded as a single byte
- `false` is represented by `0`
- `true` is represented by `1`
- During deserialization, values other than 0 and 1 will result in an error [`DecodeError::InvalidBooleanValue`](https://docs.rs/bincode/2/bincode/error/enum.DecodeError.html#variant.InvalidBooleanValue)
### Numeric Types
- Encoded based on the configured [IntEncoding](#intencoding)
- Signed integers use 2's complement representation
- Floating point types use IEEE 754-2008 standard
- `f32`: 4 bytes (binary32)
- `f64`: 8 bytes (binary64)
#### Floating Point Special Values
- Subnormal numbers are preserved
- Also known as denormalized numbers
- Maintain their exact bit representation
- `NaN` values are preserved
- Both quiet and signaling `NaN` are kept as-is
- Bit pattern of `NaN` is maintained exactly
- No normalization or transformation of special values occurs
- Serialization and deserialization do not alter the bit-level representation
- Consistent with IEEE 754-2008 standard for floating-point arithmetic
### Character Encoding
- `char` is encoded as a 32-bit unsigned integer representing its Unicode Scalar Value
- Valid Unicode Scalar Value range:
- 0x0000 to 0xD7FF (Basic Multilingual Plane)
- 0xE000 to 0x10FFFF (Supplementary Planes)
- Surrogate code points (0xD800 to 0xDFFF) are not valid
- Invalid Unicode characters can be acquired via unsafe code, this is handled as:
- during serialization: data is written as-is
- during deserialization: an error is raised [`DecodeError::InvalidCharEncoding`](https://docs.rs/bincode/2/bincode/error/enum.DecodeError.html#variant.InvalidCharEncoding)
- No additional metadata or encoding scheme beyond the raw code point value
All tuples have no additional bytes, and are encoded in their specified order, e.g.
```rust
let tuple = (u32::min_value(), i32::max_value()); // 8 bytes
let encoded = bincode::encode_to_vec(tuple, bincode::config::legacy()).unwrap();
assert_eq!(encoded.as_slice(), &[
0, 0, 0, 0, // 4 bytes for first type: u32
255, 255, 255, 127 // 4 bytes for second type: i32
]);
```
## IntEncoding
Bincode currently supports 2 different types of `IntEncoding`. With the default config, `VarintEncoding` is selected.
### VarintEncoding
Encoding an unsigned integer v (of any type excepting u8/i8) works as follows:
1. If `u < 251`, encode it as a single byte with that value.
1. If `251 <= u < 2**16`, encode it as a literal byte 251, followed by a u16 with value `u`.
1. If `2**16 <= u < 2**32`, encode it as a literal byte 252, followed by a u32 with value `u`.
1. If `2**32 <= u < 2**64`, encode it as a literal byte 253, followed by a u64 with value `u`.
1. If `2**64 <= u < 2**128`, encode it as a literal byte 254, followed by a u128 with value `u`.
`usize` is being encoded/decoded as a `u64` and `isize` is being encoded/decoded as a `i64`.
See the documentation of [VarintEncoding](https://docs.rs/bincode/2/bincode/config/struct.Configuration.html#method.with_variable_int_encoding) for more information.
### FixintEncoding
- Fixed size integers are encoded directly
- Enum discriminants are encoded as u32
- Lengths and usize are encoded as u64
See the documentation of [FixintEncoding](https://docs.rs/bincode/2/bincode/config/struct.Configuration.html#method.with_fixed_int_encoding) for more information.
## Enums
Enums are encoded with their variant first, followed by optionally the variant fields. The variant index is based on the `IntEncoding` during serialization.
Both named and unnamed fields are serialized with their values only, and therefore encode to the same value.
```rust
#[derive(bincode::Encode)]
pub enum SomeEnum {
A,
B(u32),
C { value: u32 },
}
// SomeEnum::A
let encoded = bincode::encode_to_vec(SomeEnum::A, bincode::config::legacy()).unwrap();
assert_eq!(encoded.as_slice(), &[
0, 0, 0, 0, // first variant, A
// no extra bytes because A has no fields
]);
// SomeEnum::B(0)
let encoded = bincode::encode_to_vec(SomeEnum::B(0), bincode::config::legacy()).unwrap();
assert_eq!(encoded.as_slice(), &[
1, 0, 0, 0, // second variant, B
0, 0, 0, 0 // B has 1 unnamed field, which is an u32, so 4 bytes
]);
// SomeEnum::C { value: 0u32 }
let encoded = bincode::encode_to_vec(SomeEnum::C { value: 0u32 }, bincode::config::legacy()).unwrap();
assert_eq!(encoded.as_slice(), &[
2, 0, 0, 0, // third variant, C
0, 0, 0, 0 // C has 1 named field which is a u32, so 4 bytes
]);
```
### Options
`Option<T>` is always serialized using a single byte for the discriminant, even in `Fixint` encoding (which normally uses a `u32` for discriminant).
```rust
let data: Option<u32> = Some(123);
let encoded = bincode::encode_to_vec(data, bincode::config::legacy()).unwrap();
assert_eq!(encoded.as_slice(), &[
1, 123, 0, 0, 0 // the Some(..) tag is the leading 1
]);
let data: Option<u32> = None;
let encoded = bincode::encode_to_vec(data, bincode::config::legacy()).unwrap();
assert_eq!(encoded.as_slice(), &[
0 // the None tag is simply 0
]);
```
# Collections
## General Collection Serialization
Collections are encoded with their length value first, followed by each entry of the collection. The length value is based on the configured `IntEncoding`.
### Serialization Considerations
- Length is always serialized first
- Entries are serialized in the order they are returned from the iterator implementation.
- Iteration order depends on the collection type
- Ordered collections (e.g., `Vec`): Iteration from lowest to highest index
- Unordered collections (e.g., `HashMap`): Implementation-defined iteration order
- Duplicate keys are not checked in bincode, but may be resulting in an error when decoding a container from a list of pairs.
### Handling of Specific Collection Types
#### Linear Collections (`Vec`, Arrays, etc.)
- Serialized by iterating from lowest to highest index
- Length prefixed
- Each item serialized sequentially
```rust
let list = vec![0u8, 1u8, 2u8];
let encoded = bincode::encode_to_vec(list, bincode::config::legacy()).unwrap();
assert_eq!(encoded.as_slice(), &[
3, 0, 0, 0, 0, 0, 0, 0, // length of 3u64
0, // entry 0
1, // entry 1
2, // entry 2
]);
```
#### Key-Value Collections (`HashMap`, etc.)
- Serialized as a sequence of key-value pairs
- Iteration order is implementation-defined
- Each entry is a tuple of (key, value)
### Special Collection Considerations
- Bincode will serialize the entries based on the iterator order.
- Deserialization is deterministic but the collection implementation might not guarantee the same order as serialization.
**Note**: Fixed-length arrays do not have their length encoded. See [Arrays](#arrays) for details.
# String and &str
## Encoding Principles
- Strings are encoded as UTF-8 byte sequences
- No null terminator is added
- No Byte Order Mark (BOM) is written
- Unicode non-characters are preserved
### Encoding Details
- Length is encoded first using the configured `IntEncoding`
- Raw UTF-8 bytes follow the length
- Supports the full range of valid UTF-8 sequences
- `U+0000` and other code points can appear freely within the string
### Unicode Handling
- During serialization, the string is encoded as a sequence of the given bytes.
- Rust strings are UTF-8 encoded by default, but this is not enforced by bincode
- No normalization or transformation of text
- If an invalid UTF-8 sequence is encountered during decoding, an [`DecodeError::Utf8`](https://docs.rs/bincode/2/bincode/error/enum.DecodeError.html#variant.Utf8) error is raised
```rust
let str = "Hello 🌍"; // Mixed ASCII and Unicode
let encoded = bincode::encode_to_vec(str, bincode::config::legacy()).unwrap();
assert_eq!(encoded.as_slice(), &[
10, 0, 0, 0, 0, 0, 0, 0, // length of the string, 10 bytes
b'H', b'e', b'l', b'l', b'o', b' ', 0xF0, 0x9F, 0x8C, 0x8D // UTF-8 encoded string
]);
```
### Comparison with Other Types
- Treated similarly to `Vec<u8>` in serialization
- See [Collections](#collections) for more information about length and entry encoding
# Arrays
Array length is never encoded.
Note that `&[T]` is encoded as a [Collection](#collections).
```rust
let arr: [u8; 5] = [10, 20, 30, 40, 50];
let encoded = bincode::encode_to_vec(arr, bincode::config::legacy()).unwrap();
assert_eq!(encoded.as_slice(), &[
10, 20, 30, 40, 50, // the bytes
]);
```
This applies to any type `T` that implements `Encode`/`Decode`
```rust
#[derive(bincode::Encode)]
struct Foo {
first: u8,
second: u8
};
let arr: [Foo; 2] = [
Foo {
first: 10,
second: 20,
},
Foo {
first: 30,
second: 40,
},
];
let encoded = bincode::encode_to_vec(&arr, bincode::config::legacy()).unwrap();
assert_eq!(encoded.as_slice(), &[
10, 20, // First Foo
30, 40, // Second Foo
]);
```
## TupleEncoding
Tuple fields are serialized in first-to-last declaration order, with no additional metadata.
- No length prefix is added
- Fields are encoded sequentially
- No padding or alignment adjustments are made
- Order of serialization is deterministic and matches the tuple's declaration order
## StructEncoding
Struct fields are serialized in first-to-last declaration order, with no metadata representing field names.
- No length prefix is added
- Fields are encoded sequentially
- No padding or alignment adjustments are made
- Order of serialization is deterministic and matches the struct's field declaration order
- Both named and unnamed fields are serialized identically
## EnumEncoding
Enum variants are encoded with a discriminant followed by optional variant payload.
### Discriminant Allocation
- Discriminants are automatically assigned by the derive macro in declaration order
- First variant starts at 0
- Subsequent variants increment by 1
- Explicit discriminant indices are currently not supported
- Discriminant is always represented as a `u32` during serialization. See [Discriminant Representation](#discriminant-representation) for more details.
- Maintains the original enum variant semantics during encoding
### Variant Payload Encoding
- Tuple variants: Fields serialized in declaration order
- Struct variants: Fields serialized in declaration order
- Unit variants: No additional data encoded
### Discriminant Representation
- Always encoded as a `u32`
- Encoding method depends on the configured `IntEncoding`
- `VarintEncoding`: Variable-length encoding
- `FixintEncoding`: Fixed 4-byte representation
### Handling of Variant Payloads
- Payload is serialized immediately after the discriminant
- No additional metadata about field names or types
- Payload structure matches the variant's definition

3
fuzz/.gitignore vendored
View File

@ -1,3 +0,0 @@
target
corpus
artifacts

134
fuzz/Cargo.lock generated
View File

@ -1,134 +0,0 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4
[[package]]
name = "arbitrary"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c38b6b6b79f671c25e1a3e785b7b82d7562ffc9cd3efdc98627e5668a2472490"
[[package]]
name = "bincode"
version = "1.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad"
dependencies = [
"serde",
]
[[package]]
name = "bincode"
version = "2.0.1"
dependencies = [
"bincode_derive",
"serde",
"unty",
]
[[package]]
name = "bincode-fuzz"
version = "0.0.0"
dependencies = [
"bincode 1.3.3",
"bincode 2.0.1",
"libfuzzer-sys",
"serde",
]
[[package]]
name = "bincode_derive"
version = "2.0.1"
dependencies = [
"virtue",
]
[[package]]
name = "cc"
version = "1.0.73"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11"
[[package]]
name = "libfuzzer-sys"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "36a9a84a6e8b55dfefb04235e55edb2b9a2a18488fcae777a6bdaa6f06f1deb3"
dependencies = [
"arbitrary",
"cc",
"once_cell",
]
[[package]]
name = "once_cell"
version = "1.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da32515d9f6e6e489d7bc9d84c71b060db7247dc035bbe44eac88cf87486d8d5"
[[package]]
name = "proc-macro2"
version = "1.0.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c7342d5883fbccae1cc37a2353b09c87c9b0f3afd73f5fb9bba687a1f733b029"
dependencies = [
"unicode-xid",
]
[[package]]
name = "quote"
version = "1.0.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "864d3e96a899863136fc6e99f3d7cae289dafe43bf2c5ac19b70df7210c0a145"
dependencies = [
"proc-macro2",
]
[[package]]
name = "serde"
version = "1.0.136"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ce31e24b01e1e524df96f1c2fdd054405f8d7376249a5110886fb4b658484789"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.136"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08597e7152fcd306f41838ed3e37be9eaeed2b61c42e2117266a554fab4662f9"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "syn"
version = "1.0.86"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a65b3f4ffa0092e9887669db0eae07941f023991ab58ea44da8fe8e2d511c6b"
dependencies = [
"proc-macro2",
"quote",
"unicode-xid",
]
[[package]]
name = "unicode-xid"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
[[package]]
name = "unty"
version = "0.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d49784317cd0d1ee7ec5c716dd598ec5b4483ea832a2dced265471cc0f690ae"
[[package]]
name = "virtue"
version = "0.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "051eb1abcf10076295e815102942cc58f9d5e3b4560e46e53c21e8ff6f3af7b1"

View File

@ -1,33 +0,0 @@
[package]
name = "bincode-fuzz"
version = "0.0.0"
authors = ["Automatically generated"]
publish = false
edition = "2018"
[package.metadata]
cargo-fuzz = true
[dependencies]
libfuzzer-sys = "0.4"
bincodev1 = {package = "bincode", version = "1.3.3"}
serde = { version = "1.0.135", features = ["derive"] }
[dependencies.bincode]
path = ".."
# Prevent this from interfering with workspaces
[workspace]
members = ["."]
[[bin]]
name = "roundtrip"
path = "fuzz_targets/roundtrip.rs"
test = false
doc = false
[[bin]]
name = "compat"
path = "fuzz_targets/compat.rs"
test = false
doc = false

View File

@ -1,77 +0,0 @@
#![no_main]
use libfuzzer_sys::fuzz_target;
use std::collections::{BTreeMap, BTreeSet, VecDeque};
use std::ffi::CString;
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6};
use std::num::{NonZeroI128, NonZeroI32, NonZeroU128, NonZeroU32};
use std::path::PathBuf;
use std::time::{Duration, SystemTime};
#[derive(
bincode::Decode,
bincode::Encode,
PartialEq,
Debug,
serde::Serialize,
serde::Deserialize,
Eq,
PartialOrd,
Ord,
)]
enum AllTypes {
BTreeMap(BTreeMap<u8, AllTypes>),
BTreeSet(BTreeSet<AllTypes>),
VecDeque(VecDeque<AllTypes>),
Vec(Vec<u8>),
String(String),
Box(Box<u8>),
BoxSlice(Box<[u8]>),
CString(CString),
SystemTime(SystemTime),
Duration(Duration),
PathBuf(PathBuf),
IpAddr(IpAddr),
Ipv4Addr(Ipv4Addr),
Ipv6Addr(Ipv6Addr),
SocketAddr(SocketAddr),
SocketAddrV4(SocketAddrV4),
SocketAddrV6(SocketAddrV6),
NonZeroU32(NonZeroU32),
NonZeroI32(NonZeroI32),
NonZeroU128(NonZeroU128),
NonZeroI128(NonZeroI128),
I128(i128),
I8(i8),
U128(u128),
U8(u8),
// Cow(Cow<'static, [u8]>), Blocked, see comment on decode
}
fuzz_target!(|data: &[u8]| {
let config = bincode::config::legacy().with_limit::<1024>();
#[allow(deprecated)]
let mut configv1 = bincodev1::config();
configv1.limit(1024);
let bincode_v1: Result<AllTypes, _> = configv1.deserialize_from(data);
let bincode_v2: Result<(AllTypes, _), _> = bincode::decode_from_slice(data, config);
match (&bincode_v1, &bincode_v2) {
(Err(e), _) if e.to_string() == "the size limit has been reached" => {}
(_, Err(bincode::error::DecodeError::LimitExceeded)) => {}
(Ok(bincode_v1), Ok((bincode_v2, _))) if bincode_v1 != bincode_v2 => {
println!("Bytes: {:?}", data);
println!("Bincode V1: {:?}", bincode_v1);
println!("Bincode V2: {:?}", bincode_v2);
panic!("failed equality check");
}
(Ok(_), Err(_)) | (Err(_), Ok(_)) => {
println!("Bytes: {:?}", data);
println!("Bincode V1: {:?}", bincode_v1);
println!("Bincode V2: {:?}", bincode_v2);
panic!("failed equality check");
}
_ => {}
}
});

View File

@ -1,52 +0,0 @@
#![no_main]
use libfuzzer_sys::fuzz_target;
use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet, VecDeque};
use std::ffi::CString;
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6};
use std::num::{NonZeroI128, NonZeroI32, NonZeroU128, NonZeroU32};
use std::path::PathBuf;
use std::rc::Rc;
use std::sync::Arc;
use std::time::{Duration, SystemTime};
#[derive(bincode::Decode, bincode::Encode, PartialEq, Debug)]
enum AllTypes {
BTreeMap(BTreeMap<u8, u8>),
HashMap(HashMap<u8, u8>),
HashSet(HashSet<u8>),
BTreeSet(BTreeSet<u8>),
VecDeque(VecDeque<AllTypes>),
Vec(Vec<AllTypes>),
String(String),
Box(Box<AllTypes>),
BoxSlice(Box<[AllTypes]>),
Rc(Rc<AllTypes>),
Arc(Arc<AllTypes>),
CString(CString),
SystemTime(SystemTime),
Duration(Duration),
PathBuf(PathBuf),
IpAddr(IpAddr),
Ipv4Addr(Ipv4Addr),
Ipv6Addr(Ipv6Addr),
SocketAddr(SocketAddr),
SocketAddrV4(SocketAddrV4),
SocketAddrV6(SocketAddrV6),
NonZeroU32(NonZeroU32),
NonZeroI32(NonZeroI32),
NonZeroU128(NonZeroU128),
NonZeroI128(NonZeroI128),
// Cow(Cow<'static, [u8]>), Blocked, see comment on decode
}
fuzz_target!(|data: &[u8]| {
let config = bincode::config::standard().with_limit::<1024>();
let result: Result<(AllTypes, _), _> = bincode::decode_from_slice(data, config);
if let Ok((before, _)) = result {
let encoded = bincode::encode_to_vec(&before, config).expect("round trip");
let (after, _) = bincode::decode_from_slice(&encoded, config).unwrap();
assert_eq!(before, after);
}
});

View File

@ -1,15 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="37.239mm" height="45mm" version="1.1" viewBox="0 0 37.239 45" xmlns="http://www.w3.org/2000/svg">
<g transform="translate(-82.272 -105)">
<path d="m103.92 150-21.651-12.5v-27l9.5263-5.5h24.249l3.4641 2v34z" fill="#fff"/>
<g transform="skewY(-30)" stroke-width=".26458" aria-label="1">
<path d="m115.85 204.23q0 1.0273-0.59267 1.62-0.59267 0.55316-1.5804 0.55316h-2.3707q-1.0273 0-1.62-0.55316-0.55316-0.59266-0.55316-1.62v-21.692q0-0.7112 0.47413-1.1458 0.47414-0.43462 0.86925-0.39511 0.39511 0 0.43462 0 0 0 0.31609 0 0.31609-0.0395 0.79022 0.39511 0.47413 0.43463 0.47413 1.1063v7.3096q0 2.0151 0.19756 2.5682 0.19755 0.55315 0.94827 1.3434l0.94826 0.90875q0.79022 0.7112 1.0273 1.3039 0.23707 0.59266 0.23707 2.6472z"/>
</g>
<g transform="skewY(30)" fill="#010101" stroke-width=".26458" aria-label="0">
<path d="m92.053 83.506q0.63218 0 1.0273 0 0.43462 0 0.63218 0 1.1458 0 1.3829-0.19756 0.27658-0.23707 0.27658-1.3039v-14.501q0-0.63218 0-1.0273 0-0.43462 0-0.63218 0-1.1853-0.23707-1.4224-0.19756-0.27658-1.2644-0.27658h-3.5165q-0.63218 0-1.0668 0-0.39511 0-0.59267 0-1.2248 0-1.4619 0.27658-0.23707 0.27658-0.23707 1.5804v14.145q0 0.43462 0 0.86924t0 0.67169q0 1.2644 0.23707 1.5409 0.23707 0.27658 1.4224 0.27658zm-8.3764 0.86924v-21.138q0-0.86924 0.63218-1.5014 0.67169-0.67169 1.5014-0.67169h10.787q0.79022 0 1.4619 0.63218 0.67169 0.63218 0.67169 1.5409v21.138q0 2.1731-2.1731 2.1731h-10.747q-2.1336 0-2.1336-2.1731z" fill="#010101"/>
</g>
<path d="m93.531 106 10.392 6 10.392-6 3.4641 2v8l-3.4641-2-6.9282 4v24l3.4641 2-6.9282 4-6.9282-4 3.4641-2v-24l-6.9282-4-3.4641 2v-8z" fill="#7137c8"/>
<path d="m103.92 116 13.856-8v8l-3.4641-2-6.9282 4v24l3.4641 2-6.9282 4z" fill="#442178"/>
<path d="m103.92 116 13.856-8-3.4641-2-10.392 6-10.392-6-3.4641 2z" fill="#8d5fd3"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.8 KiB

View File

@ -1,226 +0,0 @@
use crate::{de::Decode, enc::Encode, impl_borrow_decode};
use core::sync::atomic::Ordering;
#[cfg(target_has_atomic = "ptr")]
use core::sync::atomic::{AtomicIsize, AtomicUsize};
#[cfg(target_has_atomic = "8")]
use core::sync::atomic::{AtomicBool, AtomicI8, AtomicU8};
#[cfg(target_has_atomic = "16")]
use core::sync::atomic::{AtomicI16, AtomicU16};
#[cfg(target_has_atomic = "32")]
use core::sync::atomic::{AtomicI32, AtomicU32};
#[cfg(target_has_atomic = "64")]
use core::sync::atomic::{AtomicI64, AtomicU64};
#[cfg(target_has_atomic = "8")]
impl Encode for AtomicBool {
fn encode<E: crate::enc::Encoder>(
&self,
encoder: &mut E,
) -> Result<(), crate::error::EncodeError> {
self.load(Ordering::SeqCst).encode(encoder)
}
}
#[cfg(target_has_atomic = "8")]
impl<Context> Decode<Context> for AtomicBool {
fn decode<D: crate::de::Decoder>(decoder: &mut D) -> Result<Self, crate::error::DecodeError> {
Ok(AtomicBool::new(Decode::decode(decoder)?))
}
}
#[cfg(target_has_atomic = "8")]
impl_borrow_decode!(AtomicBool);
#[cfg(target_has_atomic = "8")]
impl Encode for AtomicU8 {
fn encode<E: crate::enc::Encoder>(
&self,
encoder: &mut E,
) -> Result<(), crate::error::EncodeError> {
self.load(Ordering::SeqCst).encode(encoder)
}
}
#[cfg(target_has_atomic = "8")]
impl<Context> Decode<Context> for AtomicU8 {
fn decode<D: crate::de::Decoder>(decoder: &mut D) -> Result<Self, crate::error::DecodeError> {
Ok(AtomicU8::new(Decode::decode(decoder)?))
}
}
#[cfg(target_has_atomic = "8")]
impl_borrow_decode!(AtomicU8);
#[cfg(target_has_atomic = "16")]
impl Encode for AtomicU16 {
fn encode<E: crate::enc::Encoder>(
&self,
encoder: &mut E,
) -> Result<(), crate::error::EncodeError> {
self.load(Ordering::SeqCst).encode(encoder)
}
}
#[cfg(target_has_atomic = "16")]
impl<Context> Decode<Context> for AtomicU16 {
fn decode<D: crate::de::Decoder>(decoder: &mut D) -> Result<Self, crate::error::DecodeError> {
Ok(AtomicU16::new(Decode::decode(decoder)?))
}
}
#[cfg(target_has_atomic = "16")]
impl_borrow_decode!(AtomicU16);
#[cfg(target_has_atomic = "32")]
impl Encode for AtomicU32 {
fn encode<E: crate::enc::Encoder>(
&self,
encoder: &mut E,
) -> Result<(), crate::error::EncodeError> {
self.load(Ordering::SeqCst).encode(encoder)
}
}
#[cfg(target_has_atomic = "32")]
impl<Context> Decode<Context> for AtomicU32 {
fn decode<D: crate::de::Decoder>(decoder: &mut D) -> Result<Self, crate::error::DecodeError> {
Ok(AtomicU32::new(Decode::decode(decoder)?))
}
}
#[cfg(target_has_atomic = "32")]
impl_borrow_decode!(AtomicU32);
#[cfg(target_has_atomic = "64")]
impl Encode for AtomicU64 {
fn encode<E: crate::enc::Encoder>(
&self,
encoder: &mut E,
) -> Result<(), crate::error::EncodeError> {
self.load(Ordering::SeqCst).encode(encoder)
}
}
#[cfg(target_has_atomic = "64")]
impl<Context> Decode<Context> for AtomicU64 {
fn decode<D: crate::de::Decoder>(decoder: &mut D) -> Result<Self, crate::error::DecodeError> {
Ok(AtomicU64::new(Decode::decode(decoder)?))
}
}
#[cfg(target_has_atomic = "64")]
impl_borrow_decode!(AtomicU64);
#[cfg(target_has_atomic = "ptr")]
impl Encode for AtomicUsize {
fn encode<E: crate::enc::Encoder>(
&self,
encoder: &mut E,
) -> Result<(), crate::error::EncodeError> {
self.load(Ordering::SeqCst).encode(encoder)
}
}
#[cfg(target_has_atomic = "ptr")]
impl<Context> Decode<Context> for AtomicUsize {
fn decode<D: crate::de::Decoder>(decoder: &mut D) -> Result<Self, crate::error::DecodeError> {
Ok(AtomicUsize::new(Decode::decode(decoder)?))
}
}
#[cfg(target_has_atomic = "ptr")]
impl_borrow_decode!(AtomicUsize);
#[cfg(target_has_atomic = "8")]
impl Encode for AtomicI8 {
fn encode<E: crate::enc::Encoder>(
&self,
encoder: &mut E,
) -> Result<(), crate::error::EncodeError> {
self.load(Ordering::SeqCst).encode(encoder)
}
}
#[cfg(target_has_atomic = "8")]
impl<Context> Decode<Context> for AtomicI8 {
fn decode<D: crate::de::Decoder>(decoder: &mut D) -> Result<Self, crate::error::DecodeError> {
Ok(AtomicI8::new(Decode::decode(decoder)?))
}
}
#[cfg(target_has_atomic = "8")]
impl_borrow_decode!(AtomicI8);
#[cfg(target_has_atomic = "16")]
impl Encode for AtomicI16 {
fn encode<E: crate::enc::Encoder>(
&self,
encoder: &mut E,
) -> Result<(), crate::error::EncodeError> {
self.load(Ordering::SeqCst).encode(encoder)
}
}
#[cfg(target_has_atomic = "16")]
impl<Context> Decode<Context> for AtomicI16 {
fn decode<D: crate::de::Decoder>(decoder: &mut D) -> Result<Self, crate::error::DecodeError> {
Ok(AtomicI16::new(Decode::decode(decoder)?))
}
}
#[cfg(target_has_atomic = "16")]
impl_borrow_decode!(AtomicI16);
#[cfg(target_has_atomic = "32")]
impl Encode for AtomicI32 {
fn encode<E: crate::enc::Encoder>(
&self,
encoder: &mut E,
) -> Result<(), crate::error::EncodeError> {
self.load(Ordering::SeqCst).encode(encoder)
}
}
#[cfg(target_has_atomic = "32")]
impl<Context> Decode<Context> for AtomicI32 {
fn decode<D: crate::de::Decoder>(decoder: &mut D) -> Result<Self, crate::error::DecodeError> {
Ok(AtomicI32::new(Decode::decode(decoder)?))
}
}
#[cfg(target_has_atomic = "32")]
impl_borrow_decode!(AtomicI32);
#[cfg(target_has_atomic = "64")]
impl Encode for AtomicI64 {
fn encode<E: crate::enc::Encoder>(
&self,
encoder: &mut E,
) -> Result<(), crate::error::EncodeError> {
self.load(Ordering::SeqCst).encode(encoder)
}
}
#[cfg(target_has_atomic = "64")]
impl<Context> Decode<Context> for AtomicI64 {
fn decode<D: crate::de::Decoder>(decoder: &mut D) -> Result<Self, crate::error::DecodeError> {
Ok(AtomicI64::new(Decode::decode(decoder)?))
}
}
#[cfg(target_has_atomic = "64")]
impl_borrow_decode!(AtomicI64);
#[cfg(target_has_atomic = "ptr")]
impl Encode for AtomicIsize {
fn encode<E: crate::enc::Encoder>(
&self,
encoder: &mut E,
) -> Result<(), crate::error::EncodeError> {
self.load(Ordering::SeqCst).encode(encoder)
}
}
#[cfg(target_has_atomic = "ptr")]
impl<Context> Decode<Context> for AtomicIsize {
fn decode<D: crate::de::Decoder>(decoder: &mut D) -> Result<Self, crate::error::DecodeError> {
Ok(AtomicIsize::new(Decode::decode(decoder)?))
}
}
#[cfg(target_has_atomic = "ptr")]
impl_borrow_decode!(AtomicIsize);

View File

@ -1,294 +0,0 @@
//! The config module is used to change the behavior of bincode's encoding and decoding logic.
//!
//! *Important* make sure you use the same config for encoding and decoding, or else bincode will not work properly.
//!
//! To use a config, first create a type of [Configuration]. This type will implement trait [Config] for use with bincode.
//!
//! ```
//! let config = bincode::config::standard()
//! // pick one of:
//! .with_big_endian()
//! .with_little_endian()
//! // pick one of:
//! .with_variable_int_encoding()
//! .with_fixed_int_encoding();
//! ```
//!
//! See [Configuration] for more information on the configuration options.
pub(crate) use self::internal::*;
use core::marker::PhantomData;
/// The Configuration struct is used to build bincode configurations. The [Config] trait is implemented
/// by this struct when a valid configuration has been constructed.
///
/// The following methods are mutually exclusive and will overwrite each other. The last call to one of these methods determines the behavior of the configuration:
///
/// - [with_little_endian] and [with_big_endian]
/// - [with_fixed_int_encoding] and [with_variable_int_encoding]
///
///
/// [with_little_endian]: #method.with_little_endian
/// [with_big_endian]: #method.with_big_endian
/// [with_fixed_int_encoding]: #method.with_fixed_int_encoding
/// [with_variable_int_encoding]: #method.with_variable_int_encoding
#[derive(Copy, Clone, Debug)]
pub struct Configuration<E = LittleEndian, I = Varint, L = NoLimit> {
_e: PhantomData<E>,
_i: PhantomData<I>,
_l: PhantomData<L>,
}
// When adding more features to configuration, follow these steps:
// - Create 2 or more structs that can be used as a type (e.g. Limit and NoLimit)
// - Add an `Internal...Config` to the `internal` module
// - Make sure `Config` and `impl<T> Config for T` extend from this new trait
// - Add a generic to `Configuration`
// - Add this generic to `impl<...> Default for Configuration<...>`
// - Add this generic to `const fn generate<...>()`
// - Add this generic to _every_ function in `Configuration`
// - Add your new methods
/// The default config for bincode 2.0. By default this will be:
/// - Little endian
/// - Variable int encoding
pub const fn standard() -> Configuration {
generate()
}
/// Creates the "legacy" default config. This is the default config that was present in bincode 1.0
/// - Little endian
/// - Fixed int length encoding
pub const fn legacy() -> Configuration<LittleEndian, Fixint, NoLimit> {
generate()
}
impl<E, I, L> Default for Configuration<E, I, L> {
fn default() -> Self {
generate()
}
}
const fn generate<E, I, L>() -> Configuration<E, I, L> {
Configuration {
_e: PhantomData,
_i: PhantomData,
_l: PhantomData,
}
}
impl<E, I, L> Configuration<E, I, L> {
/// Makes bincode encode all integer types in big endian.
pub const fn with_big_endian(self) -> Configuration<BigEndian, I, L> {
generate()
}
/// Makes bincode encode all integer types in little endian.
pub const fn with_little_endian(self) -> Configuration<LittleEndian, I, L> {
generate()
}
/// Makes bincode encode all integer types with a variable integer encoding.
///
/// Encoding an unsigned integer v (of any type excepting u8) works as follows:
///
/// 1. If `u < 251`, encode it as a single byte with that value.
/// 2. If `251 <= u < 2**16`, encode it as a literal byte 251, followed by a u16 with value `u`.
/// 3. If `2**16 <= u < 2**32`, encode it as a literal byte 252, followed by a u32 with value `u`.
/// 4. If `2**32 <= u < 2**64`, encode it as a literal byte 253, followed by a u64 with value `u`.
/// 5. If `2**64 <= u < 2**128`, encode it as a literal byte 254, followed by a u128 with value `u`.
///
/// Then, for signed integers, we first convert to unsigned using the zigzag algorithm,
/// and then encode them as we do for unsigned integers generally. The reason we use this
/// algorithm is that it encodes those values which are close to zero in less bytes; the
/// obvious algorithm, where we encode the cast values, gives a very large encoding for all
/// negative values.
///
/// The zigzag algorithm is defined as follows:
///
/// ```rust
/// # type Signed = i32;
/// # type Unsigned = u32;
/// fn zigzag(v: Signed) -> Unsigned {
/// match v {
/// 0 => 0,
/// // To avoid the edge case of Signed::min_value()
/// // !n is equal to `-n - 1`, so this is:
/// // !n * 2 + 1 = 2(-n - 1) + 1 = -2n - 2 + 1 = -2n - 1
/// v if v < 0 => !(v as Unsigned) * 2 - 1,
/// v if v > 0 => (v as Unsigned) * 2,
/// # _ => unreachable!()
/// }
/// }
/// ```
///
/// And works such that:
///
/// ```rust
/// # let zigzag = |n: i64| -> u64 {
/// # match n {
/// # 0 => 0,
/// # v if v < 0 => !(v as u64) * 2 + 1,
/// # v if v > 0 => (v as u64) * 2,
/// # _ => unreachable!(),
/// # }
/// # };
/// assert_eq!(zigzag(0), 0);
/// assert_eq!(zigzag(-1), 1);
/// assert_eq!(zigzag(1), 2);
/// assert_eq!(zigzag(-2), 3);
/// assert_eq!(zigzag(2), 4);
/// // etc
/// assert_eq!(zigzag(i64::min_value()), u64::max_value());
/// ```
///
/// Note that u256 and the like are unsupported by this format; if and when they are added to the
/// language, they may be supported via the extension point given by the 255 byte.
pub const fn with_variable_int_encoding(self) -> Configuration<E, Varint, L> {
generate()
}
/// Fixed-size integer encoding.
///
/// * Fixed size integers are encoded directly
/// * Enum discriminants are encoded as u32
/// * Lengths and usize are encoded as u64
pub const fn with_fixed_int_encoding(self) -> Configuration<E, Fixint, L> {
generate()
}
/// Sets the byte limit to `limit`.
pub const fn with_limit<const N: usize>(self) -> Configuration<E, I, Limit<N>> {
generate()
}
/// Clear the byte limit.
pub const fn with_no_limit(self) -> Configuration<E, I, NoLimit> {
generate()
}
}
/// Indicates a type is valid for controlling the bincode configuration
pub trait Config:
InternalEndianConfig + InternalIntEncodingConfig + InternalLimitConfig + Copy + Clone
{
/// This configuration's Endianness
fn endianness(&self) -> Endianness;
/// This configuration's Integer Encoding
fn int_encoding(&self) -> IntEncoding;
/// This configuration's byte limit, or `None` if no limit is configured
fn limit(&self) -> Option<usize>;
}
impl<T> Config for T
where
T: InternalEndianConfig + InternalIntEncodingConfig + InternalLimitConfig + Copy + Clone,
{
fn endianness(&self) -> Endianness {
<T as InternalEndianConfig>::ENDIAN
}
fn int_encoding(&self) -> IntEncoding {
<T as InternalIntEncodingConfig>::INT_ENCODING
}
fn limit(&self) -> Option<usize> {
<T as InternalLimitConfig>::LIMIT
}
}
/// Encodes all integer types in big endian.
#[derive(Copy, Clone, Debug)]
pub struct BigEndian;
impl InternalEndianConfig for BigEndian {
const ENDIAN: Endianness = Endianness::Big;
}
/// Encodes all integer types in little endian.
#[derive(Copy, Clone, Debug)]
pub struct LittleEndian;
impl InternalEndianConfig for LittleEndian {
const ENDIAN: Endianness = Endianness::Little;
}
/// Use fixed-size integer encoding.
#[derive(Copy, Clone, Debug)]
pub struct Fixint;
impl InternalIntEncodingConfig for Fixint {
const INT_ENCODING: IntEncoding = IntEncoding::Fixed;
}
/// Use variable integer encoding.
#[derive(Copy, Clone, Debug)]
pub struct Varint;
impl InternalIntEncodingConfig for Varint {
const INT_ENCODING: IntEncoding = IntEncoding::Variable;
}
/// Sets an unlimited byte limit.
#[derive(Copy, Clone, Debug)]
pub struct NoLimit;
impl InternalLimitConfig for NoLimit {
const LIMIT: Option<usize> = None;
}
/// Sets the byte limit to N.
#[derive(Copy, Clone, Debug)]
pub struct Limit<const N: usize>;
impl<const N: usize> InternalLimitConfig for Limit<N> {
const LIMIT: Option<usize> = Some(N);
}
/// Endianness of a `Configuration`.
#[derive(PartialEq, Eq)]
#[non_exhaustive]
pub enum Endianness {
/// Little Endian encoding, see `LittleEndian`.
Little,
/// Big Endian encoding, see `BigEndian`.
Big,
}
/// Integer Encoding of a `Configuration`.
#[derive(PartialEq, Eq)]
#[non_exhaustive]
pub enum IntEncoding {
/// Fixed Integer Encoding, see `Fixint`.
Fixed,
/// Variable Integer Encoding, see `Varint`.
Variable,
}
mod internal {
use super::{Configuration, Endianness, IntEncoding};
pub trait InternalEndianConfig {
const ENDIAN: Endianness;
}
impl<E: InternalEndianConfig, I, L> InternalEndianConfig for Configuration<E, I, L> {
const ENDIAN: Endianness = E::ENDIAN;
}
pub trait InternalIntEncodingConfig {
const INT_ENCODING: IntEncoding;
}
impl<E, I: InternalIntEncodingConfig, L> InternalIntEncodingConfig for Configuration<E, I, L> {
const INT_ENCODING: IntEncoding = I::INT_ENCODING;
}
pub trait InternalLimitConfig {
const LIMIT: Option<usize>;
}
impl<E, I, L: InternalLimitConfig> InternalLimitConfig for Configuration<E, I, L> {
const LIMIT: Option<usize> = L::LIMIT;
}
}

View File

@ -1,142 +0,0 @@
use super::{
read::{BorrowReader, Reader},
BorrowDecoder, Decoder,
};
use crate::{config::Config, error::DecodeError, utils::Sealed};
/// A Decoder that reads bytes from a given reader `R`.
///
/// This struct should rarely be used.
/// In most cases, prefer any of the `decode` functions.
///
/// The ByteOrder that is chosen will impact the endianness that
/// is used to read integers out of the reader.
///
/// ```
/// # let slice: &[u8] = &[0, 0, 0, 0];
/// # let some_reader = bincode::de::read::SliceReader::new(slice);
/// use bincode::de::{DecoderImpl, Decode};
/// let mut context = ();
/// let mut decoder = DecoderImpl::new(some_reader, bincode::config::standard(), &mut context);
/// // this u32 can be any Decode
/// let value = u32::decode(&mut decoder).unwrap();
/// ```
pub struct DecoderImpl<R, C: Config, Context> {
reader: R,
config: C,
bytes_read: usize,
context: Context,
}
impl<R: Reader, C: Config, Context> DecoderImpl<R, C, Context> {
/// Construct a new Decoder
pub fn new(reader: R, config: C, context: Context) -> DecoderImpl<R, C, Context> {
DecoderImpl {
reader,
config,
bytes_read: 0,
context,
}
}
}
impl<R, C: Config, Context> Sealed for DecoderImpl<R, C, Context> {}
impl<'de, R: BorrowReader<'de>, C: Config, Context> BorrowDecoder<'de>
for DecoderImpl<R, C, Context>
{
type BR = R;
fn borrow_reader(&mut self) -> &mut Self::BR {
&mut self.reader
}
}
impl<R: Reader, C: Config, Context> Decoder for DecoderImpl<R, C, Context> {
type R = R;
type C = C;
type Context = Context;
fn reader(&mut self) -> &mut Self::R {
&mut self.reader
}
fn config(&self) -> &Self::C {
&self.config
}
#[inline]
fn claim_bytes_read(&mut self, n: usize) -> Result<(), DecodeError> {
// C::LIMIT is a const so this check should get compiled away
if let Some(limit) = C::LIMIT {
// Make sure we don't accidentally overflow `bytes_read`
self.bytes_read = self
.bytes_read
.checked_add(n)
.ok_or(DecodeError::LimitExceeded)?;
if self.bytes_read > limit {
Err(DecodeError::LimitExceeded)
} else {
Ok(())
}
} else {
Ok(())
}
}
#[inline]
fn unclaim_bytes_read(&mut self, n: usize) {
// C::LIMIT is a const so this check should get compiled away
if C::LIMIT.is_some() {
// We should always be claiming more than we unclaim, so this should never underflow
self.bytes_read -= n;
}
}
fn context(&mut self) -> &mut Self::Context {
&mut self.context
}
}
pub struct WithContext<'a, D: ?Sized, C> {
pub(crate) decoder: &'a mut D,
pub(crate) context: C,
}
impl<C, D: Decoder + ?Sized> Sealed for WithContext<'_, D, C> {}
impl<Context, D: Decoder + ?Sized> Decoder for WithContext<'_, D, Context> {
type R = D::R;
type C = D::C;
type Context = Context;
fn context(&mut self) -> &mut Self::Context {
&mut self.context
}
fn reader(&mut self) -> &mut Self::R {
self.decoder.reader()
}
fn config(&self) -> &Self::C {
self.decoder.config()
}
fn claim_bytes_read(&mut self, n: usize) -> Result<(), DecodeError> {
self.decoder.claim_bytes_read(n)
}
fn unclaim_bytes_read(&mut self, n: usize) {
self.decoder.unclaim_bytes_read(n)
}
}
impl<'de, C, D: BorrowDecoder<'de>> BorrowDecoder<'de> for WithContext<'_, D, C> {
type BR = D::BR;
fn borrow_reader(&mut self) -> &mut Self::BR {
self.decoder.borrow_reader()
}
}

View File

@ -1,186 +0,0 @@
#![allow(unused_unsafe)]
//! Contains implementations for rust core that have not been stabilized
//!
//! Functions in this are expected to be properly peer reviewed by the community
//!
//! Any modifications done are purely to make the code compatible with bincode
use core::mem::{self, MaybeUninit};
/// Pulls `N` items from `iter` and returns them as an array. If the iterator
/// yields fewer than `N` items, `None` is returned and all already yielded
/// items are dropped.
///
/// Since the iterator is passed as a mutable reference and this function calls
/// `next` at most `N` times, the iterator can still be used afterwards to
/// retrieve the remaining items.
///
/// If `iter.next()` panicks, all items already yielded by the iterator are
/// dropped.
#[allow(clippy::while_let_on_iterator)]
pub fn collect_into_array<E, I, T, const N: usize>(iter: &mut I) -> Option<Result<[T; N], E>>
where
I: Iterator<Item = Result<T, E>>,
{
if N == 0 {
// SAFETY: An empty array is always inhabited and has no validity invariants.
return unsafe { Some(Ok(mem::zeroed())) };
}
struct Guard<'a, T, const N: usize> {
array_mut: &'a mut [MaybeUninit<T>; N],
initialized: usize,
}
impl<T, const N: usize> Drop for Guard<'_, T, N> {
fn drop(&mut self) {
debug_assert!(self.initialized <= N);
// SAFETY: this slice will contain only initialized objects.
unsafe {
core::ptr::drop_in_place(slice_assume_init_mut(
self.array_mut.get_unchecked_mut(..self.initialized),
));
}
}
}
let mut array = uninit_array::<T, N>();
let mut guard = Guard {
array_mut: &mut array,
initialized: 0,
};
while let Some(item_rslt) = iter.next() {
let item = match item_rslt {
Err(err) => {
return Some(Err(err));
}
Ok(elem) => elem,
};
// SAFETY: `guard.initialized` starts at 0, is increased by one in the
// loop and the loop is aborted once it reaches N (which is
// `array.len()`).
unsafe {
guard
.array_mut
.get_unchecked_mut(guard.initialized)
.write(item);
}
guard.initialized += 1;
// Check if the whole array was initialized.
if guard.initialized == N {
mem::forget(guard);
// SAFETY: the condition above asserts that all elements are
// initialized.
let out = unsafe { array_assume_init(array) };
return Some(Ok(out));
}
}
// This is only reached if the iterator is exhausted before
// `guard.initialized` reaches `N`. Also note that `guard` is dropped here,
// dropping all already initialized elements.
None
}
/// Assuming all the elements are initialized, get a mutable slice to them.
///
/// # Safety
///
/// It is up to the caller to guarantee that the `MaybeUninit<T>` elements
/// really are in an initialized state.
/// Calling this when the content is not yet fully initialized causes undefined behavior.
///
/// See [`assume_init_mut`] for more details and examples.
///
/// [`assume_init_mut`]: MaybeUninit::assume_init_mut
// #[unstable(feature = "maybe_uninit_slice", issue = "63569")]
// #[rustc_const_unstable(feature = "const_maybe_uninit_assume_init", issue = "none")]
#[inline(always)]
pub unsafe fn slice_assume_init_mut<T>(slice: &mut [MaybeUninit<T>]) -> &mut [T] {
// SAFETY: similar to safety notes for `slice_get_ref`, but we have a
// mutable reference which is also guaranteed to be valid for writes.
unsafe { &mut *(slice as *mut [MaybeUninit<T>] as *mut [T]) }
}
/// Create a new array of `MaybeUninit<T>` items, in an uninitialized state.
///
/// Note: in a future Rust version this method may become unnecessary
/// when Rust allows
/// [inline const expressions](https://github.com/rust-lang/rust/issues/76001).
/// The example below could then use `let mut buf = [const { MaybeUninit::<u8>::uninit() }; 32];`.
///
/// # Examples
///
/// ```ignore
/// #![feature(maybe_uninit_uninit_array, maybe_uninit_extra, maybe_uninit_slice)]
///
/// use std::mem::MaybeUninit;
///
/// extern "C" {
/// fn read_into_buffer(ptr: *mut u8, max_len: usize) -> usize;
/// }
///
/// /// Returns a (possibly smaller) slice of data that was actually read
/// fn read(buf: &mut [MaybeUninit<u8>]) -> &[u8] {
/// unsafe {
/// let len = read_into_buffer(buf.as_mut_ptr() as *mut u8, buf.len());
/// MaybeUninit::slice_assume_init_ref(&buf[..len])
/// }
/// }
///
/// let mut buf: [MaybeUninit<u8>; 32] = MaybeUninit::uninit_array();
/// let data = read(&mut buf);
/// ```
// #[unstable(feature = "maybe_uninit_uninit_array", issue = "none")]
// #[rustc_const_unstable(feature = "maybe_uninit_uninit_array", issue = "none")]
#[inline(always)]
fn uninit_array<T, const LEN: usize>() -> [MaybeUninit<T>; LEN] {
// SAFETY: An uninitialized `[MaybeUninit<_>; LEN]` is valid.
unsafe { MaybeUninit::<[MaybeUninit<T>; LEN]>::uninit().assume_init() }
}
/// Extracts the values from an array of `MaybeUninit` containers.
///
/// # Safety
///
/// It is up to the caller to guarantee that all elements of the array are
/// in an initialized state.
///
/// # Examples
///
/// ```ignore
/// #![feature(maybe_uninit_uninit_array)]
/// #![feature(maybe_uninit_array_assume_init)]
/// use std::mem::MaybeUninit;
///
/// let mut array: [MaybeUninit<i32>; 3] = MaybeUninit::uninit_array();
/// array[0].write(0);
/// array[1].write(1);
/// array[2].write(2);
///
/// // SAFETY: Now safe as we initialised all elements
/// let array = unsafe {
/// MaybeUninit::array_assume_init(array)
/// };
///
/// assert_eq!(array, [0, 1, 2]);
/// ```
// #[unstable(feature = "maybe_uninit_array_assume_init", issue = "80908")]
#[inline(always)]
pub unsafe fn array_assume_init<T, const N: usize>(array: [MaybeUninit<T>; N]) -> [T; N] {
// SAFETY:
// * The caller guarantees that all elements of the array are initialized
// * `MaybeUninit<T>` and T are guaranteed to have the same layout
// * `MaybeUninit` does not drop, so there are no double-frees
// And thus the conversion is safe
unsafe {
// intrinsics::assert_inhabited::<[T; N]>();
(&array as *const _ as *const [T; N]).read()
}
}

View File

@ -1,54 +0,0 @@
use super::{BorrowDecode, BorrowDecoder, Decode, Decoder};
use crate::error::DecodeError;
macro_rules! impl_tuple {
() => {};
($first:ident $(, $extra:ident)*) => {
impl<'de, $first $(, $extra)*, Context> BorrowDecode<'de, Context> for ($first, $($extra, )*)
where
$first: BorrowDecode<'de, Context>,
$(
$extra : BorrowDecode<'de, Context>,
)*
{
fn borrow_decode<BD: BorrowDecoder<'de, Context = Context>>(decoder: &mut BD) -> Result<Self, DecodeError> {
Ok((
$first::borrow_decode(decoder)?,
$($extra :: borrow_decode(decoder)?, )*
))
}
}
impl<Context, $first $(, $extra)*> Decode<Context> for ($first, $($extra, )*)
where
$first: Decode<Context>,
$(
$extra : Decode<Context>,
)*
{
fn decode<DE: Decoder<Context = Context>>(decoder: &mut DE) -> Result<Self, DecodeError> {
Ok((
$first::decode(decoder)?,
$($extra :: decode(decoder)?, )*
))
}
}
}
}
impl_tuple!(A);
impl_tuple!(A, B);
impl_tuple!(A, B, C);
impl_tuple!(A, B, C, D);
impl_tuple!(A, B, C, D, E);
impl_tuple!(A, B, C, D, E, F);
impl_tuple!(A, B, C, D, E, F, G);
impl_tuple!(A, B, C, D, E, F, G, H);
impl_tuple!(A, B, C, D, E, F, G, H, I);
impl_tuple!(A, B, C, D, E, F, G, H, I, J);
impl_tuple!(A, B, C, D, E, F, G, H, I, J, K);
impl_tuple!(A, B, C, D, E, F, G, H, I, J, K, L);
impl_tuple!(A, B, C, D, E, F, G, H, I, J, K, L, M);
impl_tuple!(A, B, C, D, E, F, G, H, I, J, K, L, M, N);
impl_tuple!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O);
impl_tuple!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P);

View File

@ -1,798 +0,0 @@
use super::{
read::{BorrowReader, Reader},
BorrowDecode, BorrowDecoder, Decode, Decoder,
};
use crate::{
config::{Endianness, IntEncoding, InternalEndianConfig, InternalIntEncodingConfig},
error::{DecodeError, IntegerType},
impl_borrow_decode,
};
use core::{
cell::{Cell, RefCell},
cmp::Reverse,
num::{
NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, NonZeroIsize, NonZeroU128,
NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize, Wrapping,
},
ops::{Bound, Range, RangeInclusive},
time::Duration,
};
impl<Context> Decode<Context> for bool {
fn decode<D: Decoder<Context = Context>>(decoder: &mut D) -> Result<Self, DecodeError> {
match u8::decode(decoder)? {
0 => Ok(false),
1 => Ok(true),
x => Err(DecodeError::InvalidBooleanValue(x)),
}
}
}
impl_borrow_decode!(bool);
impl<Context> Decode<Context> for u8 {
#[inline]
fn decode<D: Decoder<Context = Context>>(decoder: &mut D) -> Result<Self, DecodeError> {
decoder.claim_bytes_read(1)?;
if let Some(buf) = decoder.reader().peek_read(1) {
let byte = buf[0];
decoder.reader().consume(1);
Ok(byte)
} else {
let mut bytes = [0u8; 1];
decoder.reader().read(&mut bytes)?;
Ok(bytes[0])
}
}
}
impl_borrow_decode!(u8);
impl<Context> Decode<Context> for NonZeroU8 {
fn decode<D: Decoder<Context = Context>>(decoder: &mut D) -> Result<Self, DecodeError> {
NonZeroU8::new(u8::decode(decoder)?).ok_or(DecodeError::NonZeroTypeIsZero {
non_zero_type: IntegerType::U8,
})
}
}
impl_borrow_decode!(NonZeroU8);
impl<Context> Decode<Context> for u16 {
fn decode<D: Decoder<Context = Context>>(decoder: &mut D) -> Result<Self, DecodeError> {
decoder.claim_bytes_read(2)?;
match D::C::INT_ENCODING {
IntEncoding::Variable => {
crate::varint::varint_decode_u16(decoder.reader(), D::C::ENDIAN)
}
IntEncoding::Fixed => {
let mut bytes = [0u8; 2];
decoder.reader().read(&mut bytes)?;
Ok(match D::C::ENDIAN {
Endianness::Little => u16::from_le_bytes(bytes),
Endianness::Big => u16::from_be_bytes(bytes),
})
}
}
}
}
impl_borrow_decode!(u16);
impl<Context> Decode<Context> for NonZeroU16 {
fn decode<D: Decoder<Context = Context>>(decoder: &mut D) -> Result<Self, DecodeError> {
NonZeroU16::new(u16::decode(decoder)?).ok_or(DecodeError::NonZeroTypeIsZero {
non_zero_type: IntegerType::U16,
})
}
}
impl_borrow_decode!(NonZeroU16);
impl<Context> Decode<Context> for u32 {
fn decode<D: Decoder<Context = Context>>(decoder: &mut D) -> Result<Self, DecodeError> {
decoder.claim_bytes_read(4)?;
match D::C::INT_ENCODING {
IntEncoding::Variable => {
crate::varint::varint_decode_u32(decoder.reader(), D::C::ENDIAN)
}
IntEncoding::Fixed => {
let mut bytes = [0u8; 4];
decoder.reader().read(&mut bytes)?;
Ok(match D::C::ENDIAN {
Endianness::Little => u32::from_le_bytes(bytes),
Endianness::Big => u32::from_be_bytes(bytes),
})
}
}
}
}
impl_borrow_decode!(u32);
impl<Context> Decode<Context> for NonZeroU32 {
fn decode<D: Decoder<Context = Context>>(decoder: &mut D) -> Result<Self, DecodeError> {
NonZeroU32::new(u32::decode(decoder)?).ok_or(DecodeError::NonZeroTypeIsZero {
non_zero_type: IntegerType::U32,
})
}
}
impl_borrow_decode!(NonZeroU32);
impl<Context> Decode<Context> for u64 {
fn decode<D: Decoder<Context = Context>>(decoder: &mut D) -> Result<Self, DecodeError> {
decoder.claim_bytes_read(8)?;
match D::C::INT_ENCODING {
IntEncoding::Variable => {
crate::varint::varint_decode_u64(decoder.reader(), D::C::ENDIAN)
}
IntEncoding::Fixed => {
let mut bytes = [0u8; 8];
decoder.reader().read(&mut bytes)?;
Ok(match D::C::ENDIAN {
Endianness::Little => u64::from_le_bytes(bytes),
Endianness::Big => u64::from_be_bytes(bytes),
})
}
}
}
}
impl_borrow_decode!(u64);
impl<Context> Decode<Context> for NonZeroU64 {
fn decode<D: Decoder<Context = Context>>(decoder: &mut D) -> Result<Self, DecodeError> {
NonZeroU64::new(u64::decode(decoder)?).ok_or(DecodeError::NonZeroTypeIsZero {
non_zero_type: IntegerType::U64,
})
}
}
impl_borrow_decode!(NonZeroU64);
impl<Context> Decode<Context> for u128 {
fn decode<D: Decoder<Context = Context>>(decoder: &mut D) -> Result<Self, DecodeError> {
decoder.claim_bytes_read(16)?;
match D::C::INT_ENCODING {
IntEncoding::Variable => {
crate::varint::varint_decode_u128(decoder.reader(), D::C::ENDIAN)
}
IntEncoding::Fixed => {
let mut bytes = [0u8; 16];
decoder.reader().read(&mut bytes)?;
Ok(match D::C::ENDIAN {
Endianness::Little => u128::from_le_bytes(bytes),
Endianness::Big => u128::from_be_bytes(bytes),
})
}
}
}
}
impl_borrow_decode!(u128);
impl<Context> Decode<Context> for NonZeroU128 {
fn decode<D: Decoder<Context = Context>>(decoder: &mut D) -> Result<Self, DecodeError> {
NonZeroU128::new(u128::decode(decoder)?).ok_or(DecodeError::NonZeroTypeIsZero {
non_zero_type: IntegerType::U128,
})
}
}
impl_borrow_decode!(NonZeroU128);
impl<Context> Decode<Context> for usize {
fn decode<D: Decoder<Context = Context>>(decoder: &mut D) -> Result<Self, DecodeError> {
decoder.claim_bytes_read(8)?;
match D::C::INT_ENCODING {
IntEncoding::Variable => {
crate::varint::varint_decode_usize(decoder.reader(), D::C::ENDIAN)
}
IntEncoding::Fixed => {
let mut bytes = [0u8; 8];
decoder.reader().read(&mut bytes)?;
let value = match D::C::ENDIAN {
Endianness::Little => u64::from_le_bytes(bytes),
Endianness::Big => u64::from_be_bytes(bytes),
};
value
.try_into()
.map_err(|_| DecodeError::OutsideUsizeRange(value))
}
}
}
}
impl_borrow_decode!(usize);
impl<Context> Decode<Context> for NonZeroUsize {
fn decode<D: Decoder<Context = Context>>(decoder: &mut D) -> Result<Self, DecodeError> {
NonZeroUsize::new(usize::decode(decoder)?).ok_or(DecodeError::NonZeroTypeIsZero {
non_zero_type: IntegerType::Usize,
})
}
}
impl_borrow_decode!(NonZeroUsize);
impl<Context> Decode<Context> for i8 {
fn decode<D: Decoder<Context = Context>>(decoder: &mut D) -> Result<Self, DecodeError> {
decoder.claim_bytes_read(1)?;
let mut bytes = [0u8; 1];
decoder.reader().read(&mut bytes)?;
Ok(bytes[0] as i8)
}
}
impl_borrow_decode!(i8);
impl<Context> Decode<Context> for NonZeroI8 {
fn decode<D: Decoder<Context = Context>>(decoder: &mut D) -> Result<Self, DecodeError> {
NonZeroI8::new(i8::decode(decoder)?).ok_or(DecodeError::NonZeroTypeIsZero {
non_zero_type: IntegerType::I8,
})
}
}
impl_borrow_decode!(NonZeroI8);
impl<Context> Decode<Context> for i16 {
fn decode<D: Decoder<Context = Context>>(decoder: &mut D) -> Result<Self, DecodeError> {
decoder.claim_bytes_read(2)?;
match D::C::INT_ENCODING {
IntEncoding::Variable => {
crate::varint::varint_decode_i16(decoder.reader(), D::C::ENDIAN)
}
IntEncoding::Fixed => {
let mut bytes = [0u8; 2];
decoder.reader().read(&mut bytes)?;
Ok(match D::C::ENDIAN {
Endianness::Little => i16::from_le_bytes(bytes),
Endianness::Big => i16::from_be_bytes(bytes),
})
}
}
}
}
impl_borrow_decode!(i16);
impl<Context> Decode<Context> for NonZeroI16 {
fn decode<D: Decoder<Context = Context>>(decoder: &mut D) -> Result<Self, DecodeError> {
NonZeroI16::new(i16::decode(decoder)?).ok_or(DecodeError::NonZeroTypeIsZero {
non_zero_type: IntegerType::I16,
})
}
}
impl_borrow_decode!(NonZeroI16);
impl<Context> Decode<Context> for i32 {
fn decode<D: Decoder<Context = Context>>(decoder: &mut D) -> Result<Self, DecodeError> {
decoder.claim_bytes_read(4)?;
match D::C::INT_ENCODING {
IntEncoding::Variable => {
crate::varint::varint_decode_i32(decoder.reader(), D::C::ENDIAN)
}
IntEncoding::Fixed => {
let mut bytes = [0u8; 4];
decoder.reader().read(&mut bytes)?;
Ok(match D::C::ENDIAN {
Endianness::Little => i32::from_le_bytes(bytes),
Endianness::Big => i32::from_be_bytes(bytes),
})
}
}
}
}
impl_borrow_decode!(i32);
impl<Context> Decode<Context> for NonZeroI32 {
fn decode<D: Decoder<Context = Context>>(decoder: &mut D) -> Result<Self, DecodeError> {
NonZeroI32::new(i32::decode(decoder)?).ok_or(DecodeError::NonZeroTypeIsZero {
non_zero_type: IntegerType::I32,
})
}
}
impl_borrow_decode!(NonZeroI32);
impl<Context> Decode<Context> for i64 {
fn decode<D: Decoder<Context = Context>>(decoder: &mut D) -> Result<Self, DecodeError> {
decoder.claim_bytes_read(8)?;
match D::C::INT_ENCODING {
IntEncoding::Variable => {
crate::varint::varint_decode_i64(decoder.reader(), D::C::ENDIAN)
}
IntEncoding::Fixed => {
let mut bytes = [0u8; 8];
decoder.reader().read(&mut bytes)?;
Ok(match D::C::ENDIAN {
Endianness::Little => i64::from_le_bytes(bytes),
Endianness::Big => i64::from_be_bytes(bytes),
})
}
}
}
}
impl_borrow_decode!(i64);
impl<Context> Decode<Context> for NonZeroI64 {
fn decode<D: Decoder<Context = Context>>(decoder: &mut D) -> Result<Self, DecodeError> {
NonZeroI64::new(i64::decode(decoder)?).ok_or(DecodeError::NonZeroTypeIsZero {
non_zero_type: IntegerType::I64,
})
}
}
impl_borrow_decode!(NonZeroI64);
impl<Context> Decode<Context> for i128 {
fn decode<D: Decoder<Context = Context>>(decoder: &mut D) -> Result<Self, DecodeError> {
decoder.claim_bytes_read(16)?;
match D::C::INT_ENCODING {
IntEncoding::Variable => {
crate::varint::varint_decode_i128(decoder.reader(), D::C::ENDIAN)
}
IntEncoding::Fixed => {
let mut bytes = [0u8; 16];
decoder.reader().read(&mut bytes)?;
Ok(match D::C::ENDIAN {
Endianness::Little => i128::from_le_bytes(bytes),
Endianness::Big => i128::from_be_bytes(bytes),
})
}
}
}
}
impl_borrow_decode!(i128);
impl<Context> Decode<Context> for NonZeroI128 {
fn decode<D: Decoder<Context = Context>>(decoder: &mut D) -> Result<Self, DecodeError> {
NonZeroI128::new(i128::decode(decoder)?).ok_or(DecodeError::NonZeroTypeIsZero {
non_zero_type: IntegerType::I128,
})
}
}
impl_borrow_decode!(NonZeroI128);
impl<Context> Decode<Context> for isize {
fn decode<D: Decoder<Context = Context>>(decoder: &mut D) -> Result<Self, DecodeError> {
decoder.claim_bytes_read(8)?;
match D::C::INT_ENCODING {
IntEncoding::Variable => {
crate::varint::varint_decode_isize(decoder.reader(), D::C::ENDIAN)
}
IntEncoding::Fixed => {
let mut bytes = [0u8; 8];
decoder.reader().read(&mut bytes)?;
Ok(match D::C::ENDIAN {
Endianness::Little => i64::from_le_bytes(bytes),
Endianness::Big => i64::from_be_bytes(bytes),
} as isize)
}
}
}
}
impl_borrow_decode!(isize);
impl<Context> Decode<Context> for NonZeroIsize {
fn decode<D: Decoder<Context = Context>>(decoder: &mut D) -> Result<Self, DecodeError> {
NonZeroIsize::new(isize::decode(decoder)?).ok_or(DecodeError::NonZeroTypeIsZero {
non_zero_type: IntegerType::Isize,
})
}
}
impl_borrow_decode!(NonZeroIsize);
impl<Context> Decode<Context> for f32 {
fn decode<D: Decoder<Context = Context>>(decoder: &mut D) -> Result<Self, DecodeError> {
decoder.claim_bytes_read(4)?;
let mut bytes = [0u8; 4];
decoder.reader().read(&mut bytes)?;
Ok(match D::C::ENDIAN {
Endianness::Little => f32::from_le_bytes(bytes),
Endianness::Big => f32::from_be_bytes(bytes),
})
}
}
impl_borrow_decode!(f32);
impl<Context> Decode<Context> for f64 {
fn decode<D: Decoder<Context = Context>>(decoder: &mut D) -> Result<Self, DecodeError> {
decoder.claim_bytes_read(8)?;
let mut bytes = [0u8; 8];
decoder.reader().read(&mut bytes)?;
Ok(match D::C::ENDIAN {
Endianness::Little => f64::from_le_bytes(bytes),
Endianness::Big => f64::from_be_bytes(bytes),
})
}
}
impl_borrow_decode!(f64);
impl<Context, T: Decode<Context>> Decode<Context> for Wrapping<T> {
fn decode<D: Decoder<Context = Context>>(decoder: &mut D) -> Result<Self, DecodeError> {
Ok(Wrapping(T::decode(decoder)?))
}
}
impl<'de, Context, T: BorrowDecode<'de, Context>> BorrowDecode<'de, Context> for Wrapping<T> {
fn borrow_decode<D: BorrowDecoder<'de, Context = Context>>(
decoder: &mut D,
) -> Result<Self, DecodeError> {
Ok(Wrapping(T::borrow_decode(decoder)?))
}
}
impl<Context, T: Decode<Context>> Decode<Context> for Reverse<T> {
fn decode<D: Decoder<Context = Context>>(decoder: &mut D) -> Result<Self, DecodeError> {
Ok(Reverse(T::decode(decoder)?))
}
}
impl<'de, Context, T: BorrowDecode<'de, Context>> BorrowDecode<'de, Context> for Reverse<T> {
fn borrow_decode<D: BorrowDecoder<'de, Context = Context>>(
decoder: &mut D,
) -> Result<Self, DecodeError> {
Ok(Reverse(T::borrow_decode(decoder)?))
}
}
impl<Context> Decode<Context> for char {
fn decode<D: Decoder<Context = Context>>(decoder: &mut D) -> Result<Self, DecodeError> {
let mut array = [0u8; 4];
// Look at the first byte to see how many bytes must be read
decoder.reader().read(&mut array[..1])?;
let width = utf8_char_width(array[0]);
if width == 0 {
return Err(DecodeError::InvalidCharEncoding(array));
}
// Normally we have to `.claim_bytes_read` before reading, however in this
// case the amount of bytes read from `char` can vary wildly, and it should
// only read up to 4 bytes too much.
decoder.claim_bytes_read(width)?;
if width == 1 {
return Ok(array[0] as char);
}
// read the remaining pain
decoder.reader().read(&mut array[1..width])?;
let res = core::str::from_utf8(&array[..width])
.ok()
.and_then(|s| s.chars().next())
.ok_or(DecodeError::InvalidCharEncoding(array))?;
Ok(res)
}
}
impl_borrow_decode!(char);
impl<'a, 'de: 'a, Context> BorrowDecode<'de, Context> for &'a [u8] {
fn borrow_decode<D: BorrowDecoder<'de, Context = Context>>(
decoder: &mut D,
) -> Result<Self, DecodeError> {
let len = super::decode_slice_len(decoder)?;
decoder.claim_bytes_read(len)?;
decoder.borrow_reader().take_bytes(len)
}
}
impl<'a, 'de: 'a, Context> BorrowDecode<'de, Context> for &'a str {
fn borrow_decode<D: BorrowDecoder<'de, Context = Context>>(
decoder: &mut D,
) -> Result<Self, DecodeError> {
let slice = <&[u8]>::borrow_decode(decoder)?;
core::str::from_utf8(slice).map_err(|inner| DecodeError::Utf8 { inner })
}
}
impl<Context, T, const N: usize> Decode<Context> for [T; N]
where
T: Decode<Context>,
{
fn decode<D: Decoder<Context = Context>>(decoder: &mut D) -> Result<Self, DecodeError> {
decoder.claim_bytes_read(core::mem::size_of::<[T; N]>())?;
if unty::type_equal::<T, u8>() {
let mut buf = [0u8; N];
decoder.reader().read(&mut buf)?;
let ptr = &mut buf as *mut _ as *mut [T; N];
// Safety: we know that T is a u8, so it is perfectly safe to
// translate an array of u8 into an array of T
let res = unsafe { ptr.read() };
Ok(res)
} else {
let result = super::impl_core::collect_into_array(&mut (0..N).map(|_| {
// See the documentation on `unclaim_bytes_read` as to why we're doing this here
decoder.unclaim_bytes_read(core::mem::size_of::<T>());
T::decode(decoder)
}));
// result is only None if N does not match the values of `(0..N)`, which it always should
// So this unwrap should never occur
result.unwrap()
}
}
}
impl<'de, T, const N: usize, Context> BorrowDecode<'de, Context> for [T; N]
where
T: BorrowDecode<'de, Context>,
{
fn borrow_decode<D: BorrowDecoder<'de, Context = Context>>(
decoder: &mut D,
) -> Result<Self, DecodeError> {
decoder.claim_bytes_read(core::mem::size_of::<[T; N]>())?;
if unty::type_equal::<T, u8>() {
let mut buf = [0u8; N];
decoder.reader().read(&mut buf)?;
let ptr = &mut buf as *mut _ as *mut [T; N];
// Safety: we know that T is a u8, so it is perfectly safe to
// translate an array of u8 into an array of T
let res = unsafe { ptr.read() };
Ok(res)
} else {
let result = super::impl_core::collect_into_array(&mut (0..N).map(|_| {
// See the documentation on `unclaim_bytes_read` as to why we're doing this here
decoder.unclaim_bytes_read(core::mem::size_of::<T>());
T::borrow_decode(decoder)
}));
// result is only None if N does not match the values of `(0..N)`, which it always should
// So this unwrap should never occur
result.unwrap()
}
}
}
impl<Context> Decode<Context> for () {
fn decode<D: Decoder<Context = Context>>(_: &mut D) -> Result<Self, DecodeError> {
Ok(())
}
}
impl_borrow_decode!(());
impl<Context, T> Decode<Context> for core::marker::PhantomData<T> {
fn decode<D: Decoder<Context = Context>>(_: &mut D) -> Result<Self, DecodeError> {
Ok(core::marker::PhantomData)
}
}
impl_borrow_decode!(core::marker::PhantomData<T>, T);
impl<Context, T> Decode<Context> for Option<T>
where
T: Decode<Context>,
{
fn decode<D: Decoder<Context = Context>>(decoder: &mut D) -> Result<Self, DecodeError> {
match super::decode_option_variant(decoder, core::any::type_name::<Option<T>>())? {
Some(_) => {
let val = T::decode(decoder)?;
Ok(Some(val))
}
None => Ok(None),
}
}
}
impl<'de, T, Context> BorrowDecode<'de, Context> for Option<T>
where
T: BorrowDecode<'de, Context>,
{
fn borrow_decode<D: BorrowDecoder<'de, Context = Context>>(
decoder: &mut D,
) -> Result<Self, DecodeError> {
match super::decode_option_variant(decoder, core::any::type_name::<Option<T>>())? {
Some(_) => {
let val = T::borrow_decode(decoder)?;
Ok(Some(val))
}
None => Ok(None),
}
}
}
impl<Context, T, U> Decode<Context> for Result<T, U>
where
T: Decode<Context>,
U: Decode<Context>,
{
fn decode<D: Decoder<Context = Context>>(decoder: &mut D) -> Result<Self, DecodeError> {
let is_ok = u32::decode(decoder)?;
match is_ok {
0 => {
let t = T::decode(decoder)?;
Ok(Ok(t))
}
1 => {
let u = U::decode(decoder)?;
Ok(Err(u))
}
x => Err(DecodeError::UnexpectedVariant {
found: x,
allowed: &crate::error::AllowedEnumVariants::Range { max: 1, min: 0 },
type_name: core::any::type_name::<Result<T, U>>(),
}),
}
}
}
impl<'de, T, U, Context> BorrowDecode<'de, Context> for Result<T, U>
where
T: BorrowDecode<'de, Context>,
U: BorrowDecode<'de, Context>,
{
fn borrow_decode<D: BorrowDecoder<'de, Context = Context>>(
decoder: &mut D,
) -> Result<Self, DecodeError> {
let is_ok = u32::decode(decoder)?;
match is_ok {
0 => {
let t = T::borrow_decode(decoder)?;
Ok(Ok(t))
}
1 => {
let u = U::borrow_decode(decoder)?;
Ok(Err(u))
}
x => Err(DecodeError::UnexpectedVariant {
found: x,
allowed: &crate::error::AllowedEnumVariants::Range { max: 1, min: 0 },
type_name: core::any::type_name::<Result<T, U>>(),
}),
}
}
}
impl<Context, T> Decode<Context> for Cell<T>
where
T: Decode<Context>,
{
fn decode<D: Decoder<Context = Context>>(decoder: &mut D) -> Result<Self, DecodeError> {
let t = T::decode(decoder)?;
Ok(Cell::new(t))
}
}
impl<'de, T, Context> BorrowDecode<'de, Context> for Cell<T>
where
T: BorrowDecode<'de, Context>,
{
fn borrow_decode<D: BorrowDecoder<'de, Context = Context>>(
decoder: &mut D,
) -> Result<Self, DecodeError> {
let t = T::borrow_decode(decoder)?;
Ok(Cell::new(t))
}
}
impl<Context, T> Decode<Context> for RefCell<T>
where
T: Decode<Context>,
{
fn decode<D: Decoder<Context = Context>>(decoder: &mut D) -> Result<Self, DecodeError> {
let t = T::decode(decoder)?;
Ok(RefCell::new(t))
}
}
impl<'de, T, Context> BorrowDecode<'de, Context> for RefCell<T>
where
T: BorrowDecode<'de, Context>,
{
fn borrow_decode<D: BorrowDecoder<'de, Context = Context>>(
decoder: &mut D,
) -> Result<Self, DecodeError> {
let t = T::borrow_decode(decoder)?;
Ok(RefCell::new(t))
}
}
impl<Context> Decode<Context> for Duration {
fn decode<D: Decoder<Context = Context>>(decoder: &mut D) -> Result<Self, DecodeError> {
const NANOS_PER_SEC: u64 = 1_000_000_000;
let secs: u64 = Decode::decode(decoder)?;
let nanos: u32 = Decode::decode(decoder)?;
if secs.checked_add(u64::from(nanos) / NANOS_PER_SEC).is_none() {
return Err(DecodeError::InvalidDuration { secs, nanos });
}
Ok(Duration::new(secs, nanos))
}
}
impl_borrow_decode!(Duration);
impl<Context, T> Decode<Context> for Range<T>
where
T: Decode<Context>,
{
fn decode<D: Decoder<Context = Context>>(decoder: &mut D) -> Result<Self, DecodeError> {
let min = T::decode(decoder)?;
let max = T::decode(decoder)?;
Ok(min..max)
}
}
impl<'de, T, Context> BorrowDecode<'de, Context> for Range<T>
where
T: BorrowDecode<'de, Context>,
{
fn borrow_decode<D: BorrowDecoder<'de, Context = Context>>(
decoder: &mut D,
) -> Result<Self, DecodeError> {
let min = T::borrow_decode(decoder)?;
let max = T::borrow_decode(decoder)?;
Ok(min..max)
}
}
impl<Context, T> Decode<Context> for RangeInclusive<T>
where
T: Decode<Context>,
{
fn decode<D: Decoder<Context = Context>>(decoder: &mut D) -> Result<Self, DecodeError> {
let min = T::decode(decoder)?;
let max = T::decode(decoder)?;
Ok(RangeInclusive::new(min, max))
}
}
impl<'de, T, Context> BorrowDecode<'de, Context> for RangeInclusive<T>
where
T: BorrowDecode<'de, Context>,
{
fn borrow_decode<D: BorrowDecoder<'de, Context = Context>>(
decoder: &mut D,
) -> Result<Self, DecodeError> {
let min = T::borrow_decode(decoder)?;
let max = T::borrow_decode(decoder)?;
Ok(RangeInclusive::new(min, max))
}
}
impl<T, Context> Decode<Context> for Bound<T>
where
T: Decode<Context>,
{
fn decode<D: Decoder<Context = Context>>(decoder: &mut D) -> Result<Self, DecodeError> {
match u32::decode(decoder)? {
0 => Ok(Bound::Unbounded),
1 => Ok(Bound::Included(T::decode(decoder)?)),
2 => Ok(Bound::Excluded(T::decode(decoder)?)),
x => Err(DecodeError::UnexpectedVariant {
allowed: &crate::error::AllowedEnumVariants::Range { max: 2, min: 0 },
found: x,
type_name: core::any::type_name::<Bound<T>>(),
}),
}
}
}
impl<'de, T, Context> BorrowDecode<'de, Context> for Bound<T>
where
T: BorrowDecode<'de, Context>,
{
fn borrow_decode<D: BorrowDecoder<'de, Context = Context>>(
decoder: &mut D,
) -> Result<Self, DecodeError> {
match u32::decode(decoder)? {
0 => Ok(Bound::Unbounded),
1 => Ok(Bound::Included(T::borrow_decode(decoder)?)),
2 => Ok(Bound::Excluded(T::borrow_decode(decoder)?)),
x => Err(DecodeError::UnexpectedVariant {
allowed: &crate::error::AllowedEnumVariants::Range { max: 2, min: 0 },
found: x,
type_name: core::any::type_name::<Bound<T>>(),
}),
}
}
}
const UTF8_CHAR_WIDTH: [u8; 256] = [
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, // 0x1F
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, // 0x3F
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, // 0x5F
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, // 0x7F
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, // 0x9F
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, // 0xBF
0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, // 0xDF
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 0xEF
4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xFF
];
// This function is a copy of core::str::utf8_char_width
const fn utf8_char_width(b: u8) -> usize {
UTF8_CHAR_WIDTH[b as usize] as usize
}

View File

@ -1,334 +0,0 @@
//! Decoder-based structs and traits.
mod decoder;
mod impl_core;
mod impl_tuples;
mod impls;
use self::{
decoder::WithContext,
read::{BorrowReader, Reader},
};
use crate::{
config::{Config, InternalLimitConfig},
error::DecodeError,
utils::Sealed,
};
pub mod read;
pub use self::decoder::DecoderImpl;
/// Trait that makes a type able to be decoded, akin to serde's `DeserializeOwned` trait.
///
/// Some types may require specific contexts. For example, to decode arena-based collections, an arena allocator must be provided as a context. In these cases, the context type `Context` should be specified or bounded.
///
/// This trait should be implemented for types which do not have references to data in the reader. For types that contain e.g. `&str` and `&[u8]`, implement [BorrowDecode] instead.
///
/// Whenever you derive `Decode` for your type, the base trait `BorrowDecode` is automatically implemented.
///
/// This trait will be automatically implemented with unbounded `Context` if you enable the `derive` feature and add `#[derive(bincode::Decode)]` to your type. Note that if the type contains any lifetimes, `BorrowDecode` will be implemented instead.
///
/// # Implementing this trait manually
///
/// If you want to implement this trait for your type, the easiest way is to add a `#[derive(bincode::Decode)]`, build and check your `target/generated/bincode/` folder. This should generate a `<Struct name>_Decode.rs` file.
///
/// For this struct:
///
/// ```
/// struct Entity {
/// pub x: f32,
/// pub y: f32,
/// }
/// ```
///
/// It will look something like:
///
/// ```
/// # struct Entity {
/// # pub x: f32,
/// # pub y: f32,
/// # }
/// impl<Context> bincode::Decode<Context> for Entity {
/// fn decode<D: bincode::de::Decoder<Context = Context>>(
/// decoder: &mut D,
/// ) -> core::result::Result<Self, bincode::error::DecodeError> {
/// Ok(Self {
/// x: bincode::Decode::decode(decoder)?,
/// y: bincode::Decode::decode(decoder)?,
/// })
/// }
/// }
/// impl<'de, Context> bincode::BorrowDecode<'de, Context> for Entity {
/// fn borrow_decode<D: bincode::de::BorrowDecoder<'de, Context = Context>>(
/// decoder: &mut D,
/// ) -> core::result::Result<Self, bincode::error::DecodeError> {
/// Ok(Self {
/// x: bincode::BorrowDecode::borrow_decode(decoder)?,
/// y: bincode::BorrowDecode::borrow_decode(decoder)?,
/// })
/// }
/// }
/// ```
///
/// From here you can add/remove fields, or add custom logic.
///
/// To get specific integer types, you can use:
/// ```
/// # struct Foo;
/// # impl<Context> bincode::Decode<Context> for Foo {
/// # fn decode<D: bincode::de::Decoder<Context = Context>>(
/// # decoder: &mut D,
/// # ) -> core::result::Result<Self, bincode::error::DecodeError> {
/// let x: u8 = bincode::Decode::<Context>::decode(decoder)?;
/// let x = <u8 as bincode::Decode::<Context>>::decode(decoder)?;
/// # Ok(Foo)
/// # }
/// # }
/// # bincode::impl_borrow_decode!(Foo);
/// ```
///
/// You can use `Context` to require contexts for decoding a type:
/// ```
/// # /// # use bumpalo::Bump;
/// use bincode::de::Decoder;
/// use bincode::error::DecodeError;
/// struct BytesInArena<'a>(bumpalo::collections::Vec<'a, u8>);
/// impl<'a> bincode::Decode<&'a bumpalo::Bump> for BytesInArena<'a> {
/// fn decode<D: Decoder>(decoder: &mut D) -> Result<Self, DecodeError> {
/// todo!()
/// }
/// # }
/// ```
pub trait Decode<Context>: Sized {
/// Attempt to decode this type with the given [Decode].
fn decode<D: Decoder<Context = Context>>(decoder: &mut D) -> Result<Self, DecodeError>;
}
/// Trait that makes a type able to be decoded, akin to serde's `Deserialize` trait.
///
/// This trait should be implemented for types that contain borrowed data, like `&str` and `&[u8]`. If your type does not have borrowed data, consider implementing [Decode] instead.
///
/// This trait will be automatically implemented if you enable the `derive` feature and add `#[derive(bincode::Decode)]` to a type with a lifetime.
pub trait BorrowDecode<'de, Context>: Sized {
/// Attempt to decode this type with the given [BorrowDecode].
fn borrow_decode<D: BorrowDecoder<'de, Context = Context>>(
decoder: &mut D,
) -> Result<Self, DecodeError>;
}
/// Helper macro to implement `BorrowDecode` for any type that implements `Decode`.
#[macro_export]
macro_rules! impl_borrow_decode {
($ty:ty $(, $param:tt)*) => {
impl<'de $(, $param)*, __Context> $crate::BorrowDecode<'de, __Context> for $ty {
fn borrow_decode<D: $crate::de::BorrowDecoder<'de, Context = __Context>>(
decoder: &mut D,
) -> core::result::Result<Self, $crate::error::DecodeError> {
$crate::Decode::decode(decoder)
}
}
};
}
/// Helper macro to implement `BorrowDecode` for any type that implements `Decode`.
#[macro_export]
macro_rules! impl_borrow_decode_with_context {
($ty:ty, $context:ty $(, $param:tt)*) => {
impl<'de $(, $param)*> $crate::BorrowDecode<'de, $context> for $ty {
fn borrow_decode<D: $crate::de::BorrowDecoder<'de, Context = $context>>(
decoder: &mut D,
) -> core::result::Result<Self, $crate::error::DecodeError> {
$crate::Decode::decode(decoder)
}
}
};
}
/// Any source that can decode basic types. This type is most notably implemented for [Decoder].
pub trait Decoder: Sealed {
/// The concrete [Reader] type
type R: Reader;
/// The concrete [Config] type
type C: Config;
/// The decoding context type
type Context;
/// Returns the decoding context
fn context(&mut self) -> &mut Self::Context;
/// Wraps decoder with a context
fn with_context<C>(&mut self, context: C) -> WithContext<Self, C> {
WithContext {
decoder: self,
context,
}
}
/// Returns a mutable reference to the reader
fn reader(&mut self) -> &mut Self::R;
/// Returns a reference to the config
fn config(&self) -> &Self::C;
/// Claim that `n` bytes are going to be read from the decoder.
/// This can be used to validate `Configuration::Limit<N>()`.
fn claim_bytes_read(&mut self, n: usize) -> Result<(), DecodeError>;
/// Claim that we're going to read a container which contains `len` entries of `T`.
/// This will correctly handle overflowing if `len * size_of::<T>() > usize::max_value`
fn claim_container_read<T>(&mut self, len: usize) -> Result<(), DecodeError> {
if <Self::C as InternalLimitConfig>::LIMIT.is_some() {
match len.checked_mul(core::mem::size_of::<T>()) {
Some(val) => self.claim_bytes_read(val),
None => Err(DecodeError::LimitExceeded),
}
} else {
Ok(())
}
}
/// Notify the decoder that `n` bytes are being reclaimed.
///
/// When decoding container types, a typical implementation would claim to read `len * size_of::<T>()` bytes.
/// This is to ensure that bincode won't allocate several GB of memory while constructing the container.
///
/// Because the implementation claims `len * size_of::<T>()`, but then has to decode each `T`, this would be marked
/// as double. This function allows us to un-claim each `T` that gets decoded.
///
/// We cannot check if `len * size_of::<T>()` is valid without claiming it, because this would mean that if you have
/// a nested container (e.g. `Vec<Vec<T>>`), it does not know how much memory is already claimed, and could easily
/// allocate much more than the user intends.
/// ```
/// # use bincode::de::{Decode, Decoder};
/// # use bincode::error::DecodeError;
/// # struct Container<T>(Vec<T>);
/// # impl<T> Container<T> {
/// # fn with_capacity(cap: usize) -> Self {
/// # Self(Vec::with_capacity(cap))
/// # }
/// #
/// # fn push(&mut self, t: T) {
/// # self.0.push(t);
/// # }
/// # }
/// impl<Context, T: Decode<Context>> Decode<Context> for Container<T> {
/// fn decode<D: Decoder<Context = Context>>(decoder: &mut D) -> Result<Self, DecodeError> {
/// let len = u64::decode(decoder)?;
/// let len: usize = len.try_into().map_err(|_| DecodeError::OutsideUsizeRange(len))?;
/// // Make sure we don't allocate too much memory
/// decoder.claim_bytes_read(len * core::mem::size_of::<T>());
///
/// let mut result = Container::with_capacity(len);
/// for _ in 0..len {
/// // un-claim the memory
/// decoder.unclaim_bytes_read(core::mem::size_of::<T>());
/// result.push(T::decode(decoder)?)
/// }
/// Ok(result)
/// }
/// }
/// impl<'de, Context, T: bincode::BorrowDecode<'de, Context>> bincode::BorrowDecode<'de, Context> for Container<T> {
/// fn borrow_decode<D: bincode::de::BorrowDecoder<'de, Context = Context>>(
/// decoder: &mut D,
/// ) -> core::result::Result<Self, bincode::error::DecodeError> {
/// let len = u64::borrow_decode(decoder)?;
/// let len: usize = len.try_into().map_err(|_| DecodeError::OutsideUsizeRange(len))?;
/// // Make sure we don't allocate too much memory
/// decoder.claim_bytes_read(len * core::mem::size_of::<T>());
///
/// let mut result = Container::with_capacity(len);
/// for _ in 0..len {
/// // un-claim the memory
/// decoder.unclaim_bytes_read(core::mem::size_of::<T>());
/// result.push(T::borrow_decode(decoder)?)
/// }
/// Ok(result)
/// }
/// }
/// ```
fn unclaim_bytes_read(&mut self, n: usize);
}
/// Any source that can decode basic types. This type is most notably implemented for [Decoder].
///
/// This is an extension of [Decode] that can also return borrowed data.
pub trait BorrowDecoder<'de>: Decoder {
/// The concrete [BorrowReader] type
type BR: BorrowReader<'de>;
/// Returns a mutable reference to the borrow reader
fn borrow_reader(&mut self) -> &mut Self::BR;
}
impl<T> Decoder for &mut T
where
T: Decoder,
{
type R = T::R;
type C = T::C;
type Context = T::Context;
fn reader(&mut self) -> &mut Self::R {
T::reader(self)
}
fn config(&self) -> &Self::C {
T::config(self)
}
#[inline]
fn claim_bytes_read(&mut self, n: usize) -> Result<(), DecodeError> {
T::claim_bytes_read(self, n)
}
#[inline]
fn unclaim_bytes_read(&mut self, n: usize) {
T::unclaim_bytes_read(self, n)
}
fn context(&mut self) -> &mut Self::Context {
T::context(self)
}
}
impl<'de, T> BorrowDecoder<'de> for &mut T
where
T: BorrowDecoder<'de>,
{
type BR = T::BR;
fn borrow_reader(&mut self) -> &mut Self::BR {
T::borrow_reader(self)
}
}
/// Decodes only the option variant from the decoder. Will not read any more data than that.
#[inline]
pub(crate) fn decode_option_variant<D: Decoder>(
decoder: &mut D,
type_name: &'static str,
) -> Result<Option<()>, DecodeError> {
let is_some = u8::decode(decoder)?;
match is_some {
0 => Ok(None),
1 => Ok(Some(())),
x => Err(DecodeError::UnexpectedVariant {
found: x as u32,
allowed: &crate::error::AllowedEnumVariants::Range { max: 1, min: 0 },
type_name,
}),
}
}
/// Decodes the length of any slice, container, etc from the decoder
#[inline]
pub(crate) fn decode_slice_len<D: Decoder>(decoder: &mut D) -> Result<usize, DecodeError> {
let v = u64::decode(decoder)?;
v.try_into().map_err(|_| DecodeError::OutsideUsizeRange(v))
}

View File

@ -1,112 +0,0 @@
//! This module contains reader-based structs and traits.
//!
//! Because `std::io::Read` is only limited to `std` and not `core`, we provide 2 alternative readers.
//!
//! [Reader] is a reader for sources that do not own their data. It is assumed that the reader's data is dropped after the `read` method is called. This reader is incapable of reading borrowed data, like `&str` and `&[u8]`.
//!
//! [BorrowReader] is an extension of `Reader` that also allows returning borrowed data. A `BorrowReader` allows reading `&str` and `&[u8]`.
//!
//! Specifically the `Reader` trait is used by [Decode] and the `BorrowReader` trait is used by `[BorrowDecode]`.
//!
//! [Decode]: ../trait.Decode.html
//! [BorrowDecode]: ../trait.BorrowDecode.html
use crate::error::DecodeError;
/// A reader for owned data. See the module documentation for more information.
pub trait Reader {
/// Fill the given `bytes` argument with values. Exactly the length of the given slice must be filled, or else an error must be returned.
fn read(&mut self, bytes: &mut [u8]) -> Result<(), DecodeError>;
/// If this reader wraps a buffer of any kind, this function lets callers access contents of
/// the buffer without passing data through a buffer first.
#[inline]
fn peek_read(&mut self, _: usize) -> Option<&[u8]> {
None
}
/// If an implementation of `peek_read` is provided, an implementation of this function
/// must be provided so that subsequent reads or peek-reads do not return the same bytes
#[inline]
fn consume(&mut self, _: usize) {}
}
impl<T> Reader for &mut T
where
T: Reader,
{
#[inline]
fn read(&mut self, bytes: &mut [u8]) -> Result<(), DecodeError> {
(**self).read(bytes)
}
#[inline]
fn peek_read(&mut self, n: usize) -> Option<&[u8]> {
(**self).peek_read(n)
}
#[inline]
fn consume(&mut self, n: usize) {
(*self).consume(n)
}
}
/// A reader for borrowed data. Implementers of this must also implement the [Reader] trait. See the module documentation for more information.
pub trait BorrowReader<'storage>: Reader {
/// Read exactly `length` bytes and return a slice to this data. If not enough bytes could be read, an error should be returned.
///
/// *note*: Exactly `length` bytes must be returned. If less bytes are returned, bincode may panic. If more bytes are returned, the excess bytes may be discarded.
fn take_bytes(&mut self, length: usize) -> Result<&'storage [u8], DecodeError>;
}
/// A reader type for `&[u8]` slices. Implements both [Reader] and [BorrowReader], and thus can be used for borrowed data.
pub struct SliceReader<'storage> {
pub(crate) slice: &'storage [u8],
}
impl<'storage> SliceReader<'storage> {
/// Constructs a slice reader
pub const fn new(bytes: &'storage [u8]) -> SliceReader<'storage> {
SliceReader { slice: bytes }
}
}
impl<'storage> Reader for SliceReader<'storage> {
#[inline(always)]
fn read(&mut self, bytes: &mut [u8]) -> Result<(), DecodeError> {
if bytes.len() > self.slice.len() {
return Err(DecodeError::UnexpectedEnd {
additional: bytes.len() - self.slice.len(),
});
}
let (read_slice, remaining) = self.slice.split_at(bytes.len());
bytes.copy_from_slice(read_slice);
self.slice = remaining;
Ok(())
}
#[inline]
fn peek_read(&mut self, n: usize) -> Option<&'storage [u8]> {
self.slice.get(..n)
}
#[inline]
fn consume(&mut self, n: usize) {
self.slice = self.slice.get(n..).unwrap_or_default();
}
}
impl<'storage> BorrowReader<'storage> for SliceReader<'storage> {
#[inline(always)]
fn take_bytes(&mut self, length: usize) -> Result<&'storage [u8], DecodeError> {
if length > self.slice.len() {
return Err(DecodeError::UnexpectedEnd {
additional: length - self.slice.len(),
});
}
let (read_slice, remaining) = self.slice.split_at(length);
self.slice = remaining;
Ok(read_slice)
}
}

View File

@ -1,57 +0,0 @@
use super::{write::Writer, Encoder};
use crate::{config::Config, utils::Sealed};
/// An Encoder that writes bytes into a given writer `W`.
///
/// This struct should rarely be used.
/// In most cases, prefer any of the `encode` functions.
///
/// The ByteOrder that is chosen will impact the endianness that
/// is used to write integers to the writer.
///
/// ```
/// # use bincode::enc::{write::SliceWriter, EncoderImpl, Encode};
/// let slice: &mut [u8] = &mut [0, 0, 0, 0];
/// let config = bincode::config::legacy().with_big_endian();
///
/// let mut encoder = EncoderImpl::new(SliceWriter::new(slice), config);
/// // this u32 can be any Encodable
/// 5u32.encode(&mut encoder).unwrap();
/// assert_eq!(encoder.into_writer().bytes_written(), 4);
/// assert_eq!(slice, [0, 0, 0, 5]);
/// ```
pub struct EncoderImpl<W: Writer, C: Config> {
writer: W,
config: C,
}
impl<W: Writer, C: Config> EncoderImpl<W, C> {
/// Create a new Encoder
pub const fn new(writer: W, config: C) -> EncoderImpl<W, C> {
EncoderImpl { writer, config }
}
/// Return the underlying writer
#[inline]
pub fn into_writer(self) -> W {
self.writer
}
}
impl<W: Writer, C: Config> Encoder for EncoderImpl<W, C> {
type W = W;
type C = C;
#[inline]
fn writer(&mut self) -> &mut Self::W {
&mut self.writer
}
#[inline]
fn config(&self) -> &Self::C {
&self.config
}
}
impl<W: Writer, C: Config> Sealed for EncoderImpl<W, C> {}

View File

@ -1,404 +0,0 @@
use super::{Encode, Encoder};
use crate::error::EncodeError;
impl<A> Encode for (A,)
where
A: Encode,
{
fn encode<_E: Encoder>(&self, encoder: &mut _E) -> Result<(), EncodeError> {
self.0.encode(encoder)?;
Ok(())
}
}
impl<A, B> Encode for (A, B)
where
A: Encode,
B: Encode,
{
fn encode<_E: Encoder>(&self, encoder: &mut _E) -> Result<(), EncodeError> {
self.0.encode(encoder)?;
self.1.encode(encoder)?;
Ok(())
}
}
impl<A, B, C> Encode for (A, B, C)
where
A: Encode,
B: Encode,
C: Encode,
{
fn encode<_E: Encoder>(&self, encoder: &mut _E) -> Result<(), EncodeError> {
self.0.encode(encoder)?;
self.1.encode(encoder)?;
self.2.encode(encoder)?;
Ok(())
}
}
impl<A, B, C, D> Encode for (A, B, C, D)
where
A: Encode,
B: Encode,
C: Encode,
D: Encode,
{
fn encode<_E: Encoder>(&self, encoder: &mut _E) -> Result<(), EncodeError> {
self.0.encode(encoder)?;
self.1.encode(encoder)?;
self.2.encode(encoder)?;
self.3.encode(encoder)?;
Ok(())
}
}
impl<A, B, C, D, E> Encode for (A, B, C, D, E)
where
A: Encode,
B: Encode,
C: Encode,
D: Encode,
E: Encode,
{
fn encode<_E: Encoder>(&self, encoder: &mut _E) -> Result<(), EncodeError> {
self.0.encode(encoder)?;
self.1.encode(encoder)?;
self.2.encode(encoder)?;
self.3.encode(encoder)?;
self.4.encode(encoder)?;
Ok(())
}
}
impl<A, B, C, D, E, F> Encode for (A, B, C, D, E, F)
where
A: Encode,
B: Encode,
C: Encode,
D: Encode,
E: Encode,
F: Encode,
{
fn encode<_E: Encoder>(&self, encoder: &mut _E) -> Result<(), EncodeError> {
self.0.encode(encoder)?;
self.1.encode(encoder)?;
self.2.encode(encoder)?;
self.3.encode(encoder)?;
self.4.encode(encoder)?;
self.5.encode(encoder)?;
Ok(())
}
}
impl<A, B, C, D, E, F, G> Encode for (A, B, C, D, E, F, G)
where
A: Encode,
B: Encode,
C: Encode,
D: Encode,
E: Encode,
F: Encode,
G: Encode,
{
fn encode<_E: Encoder>(&self, encoder: &mut _E) -> Result<(), EncodeError> {
self.0.encode(encoder)?;
self.1.encode(encoder)?;
self.2.encode(encoder)?;
self.3.encode(encoder)?;
self.4.encode(encoder)?;
self.5.encode(encoder)?;
self.6.encode(encoder)?;
Ok(())
}
}
impl<A, B, C, D, E, F, G, H> Encode for (A, B, C, D, E, F, G, H)
where
A: Encode,
B: Encode,
C: Encode,
D: Encode,
E: Encode,
F: Encode,
G: Encode,
H: Encode,
{
fn encode<_E: Encoder>(&self, encoder: &mut _E) -> Result<(), EncodeError> {
self.0.encode(encoder)?;
self.1.encode(encoder)?;
self.2.encode(encoder)?;
self.3.encode(encoder)?;
self.4.encode(encoder)?;
self.5.encode(encoder)?;
self.6.encode(encoder)?;
self.7.encode(encoder)?;
Ok(())
}
}
impl<A, B, C, D, E, F, G, H, I> Encode for (A, B, C, D, E, F, G, H, I)
where
A: Encode,
B: Encode,
C: Encode,
D: Encode,
E: Encode,
F: Encode,
G: Encode,
H: Encode,
I: Encode,
{
fn encode<_E: Encoder>(&self, encoder: &mut _E) -> Result<(), EncodeError> {
self.0.encode(encoder)?;
self.1.encode(encoder)?;
self.2.encode(encoder)?;
self.3.encode(encoder)?;
self.4.encode(encoder)?;
self.5.encode(encoder)?;
self.6.encode(encoder)?;
self.7.encode(encoder)?;
self.8.encode(encoder)?;
Ok(())
}
}
impl<A, B, C, D, E, F, G, H, I, J> Encode for (A, B, C, D, E, F, G, H, I, J)
where
A: Encode,
B: Encode,
C: Encode,
D: Encode,
E: Encode,
F: Encode,
G: Encode,
H: Encode,
I: Encode,
J: Encode,
{
fn encode<_E: Encoder>(&self, encoder: &mut _E) -> Result<(), EncodeError> {
self.0.encode(encoder)?;
self.1.encode(encoder)?;
self.2.encode(encoder)?;
self.3.encode(encoder)?;
self.4.encode(encoder)?;
self.5.encode(encoder)?;
self.6.encode(encoder)?;
self.7.encode(encoder)?;
self.8.encode(encoder)?;
self.9.encode(encoder)?;
Ok(())
}
}
impl<A, B, C, D, E, F, G, H, I, J, K> Encode for (A, B, C, D, E, F, G, H, I, J, K)
where
A: Encode,
B: Encode,
C: Encode,
D: Encode,
E: Encode,
F: Encode,
G: Encode,
H: Encode,
I: Encode,
J: Encode,
K: Encode,
{
fn encode<_E: Encoder>(&self, encoder: &mut _E) -> Result<(), EncodeError> {
self.0.encode(encoder)?;
self.1.encode(encoder)?;
self.2.encode(encoder)?;
self.3.encode(encoder)?;
self.4.encode(encoder)?;
self.5.encode(encoder)?;
self.6.encode(encoder)?;
self.7.encode(encoder)?;
self.8.encode(encoder)?;
self.9.encode(encoder)?;
self.10.encode(encoder)?;
Ok(())
}
}
impl<A, B, C, D, E, F, G, H, I, J, K, L> Encode for (A, B, C, D, E, F, G, H, I, J, K, L)
where
A: Encode,
B: Encode,
C: Encode,
D: Encode,
E: Encode,
F: Encode,
G: Encode,
H: Encode,
I: Encode,
J: Encode,
K: Encode,
L: Encode,
{
fn encode<_E: Encoder>(&self, encoder: &mut _E) -> Result<(), EncodeError> {
self.0.encode(encoder)?;
self.1.encode(encoder)?;
self.2.encode(encoder)?;
self.3.encode(encoder)?;
self.4.encode(encoder)?;
self.5.encode(encoder)?;
self.6.encode(encoder)?;
self.7.encode(encoder)?;
self.8.encode(encoder)?;
self.9.encode(encoder)?;
self.10.encode(encoder)?;
self.11.encode(encoder)?;
Ok(())
}
}
impl<A, B, C, D, E, F, G, H, I, J, K, L, M> Encode for (A, B, C, D, E, F, G, H, I, J, K, L, M)
where
A: Encode,
B: Encode,
C: Encode,
D: Encode,
E: Encode,
F: Encode,
G: Encode,
H: Encode,
I: Encode,
J: Encode,
K: Encode,
L: Encode,
M: Encode,
{
fn encode<_E: Encoder>(&self, encoder: &mut _E) -> Result<(), EncodeError> {
self.0.encode(encoder)?;
self.1.encode(encoder)?;
self.2.encode(encoder)?;
self.3.encode(encoder)?;
self.4.encode(encoder)?;
self.5.encode(encoder)?;
self.6.encode(encoder)?;
self.7.encode(encoder)?;
self.8.encode(encoder)?;
self.9.encode(encoder)?;
self.10.encode(encoder)?;
self.11.encode(encoder)?;
self.12.encode(encoder)?;
Ok(())
}
}
impl<A, B, C, D, E, F, G, H, I, J, K, L, M, N> Encode for (A, B, C, D, E, F, G, H, I, J, K, L, M, N)
where
A: Encode,
B: Encode,
C: Encode,
D: Encode,
E: Encode,
F: Encode,
G: Encode,
H: Encode,
I: Encode,
J: Encode,
K: Encode,
L: Encode,
M: Encode,
N: Encode,
{
fn encode<_E: Encoder>(&self, encoder: &mut _E) -> Result<(), EncodeError> {
self.0.encode(encoder)?;
self.1.encode(encoder)?;
self.2.encode(encoder)?;
self.3.encode(encoder)?;
self.4.encode(encoder)?;
self.5.encode(encoder)?;
self.6.encode(encoder)?;
self.7.encode(encoder)?;
self.8.encode(encoder)?;
self.9.encode(encoder)?;
self.10.encode(encoder)?;
self.11.encode(encoder)?;
self.12.encode(encoder)?;
self.13.encode(encoder)?;
Ok(())
}
}
impl<A, B, C, D, E, F, G, H, I, J, K, L, M, N, O> Encode
for (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O)
where
A: Encode,
B: Encode,
C: Encode,
D: Encode,
E: Encode,
F: Encode,
G: Encode,
H: Encode,
I: Encode,
J: Encode,
K: Encode,
L: Encode,
M: Encode,
N: Encode,
O: Encode,
{
fn encode<_E: Encoder>(&self, encoder: &mut _E) -> Result<(), EncodeError> {
self.0.encode(encoder)?;
self.1.encode(encoder)?;
self.2.encode(encoder)?;
self.3.encode(encoder)?;
self.4.encode(encoder)?;
self.5.encode(encoder)?;
self.6.encode(encoder)?;
self.7.encode(encoder)?;
self.8.encode(encoder)?;
self.9.encode(encoder)?;
self.10.encode(encoder)?;
self.11.encode(encoder)?;
self.12.encode(encoder)?;
self.13.encode(encoder)?;
self.14.encode(encoder)?;
Ok(())
}
}
impl<A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P> Encode
for (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P)
where
A: Encode,
B: Encode,
C: Encode,
D: Encode,
E: Encode,
F: Encode,
G: Encode,
H: Encode,
I: Encode,
J: Encode,
K: Encode,
L: Encode,
M: Encode,
N: Encode,
O: Encode,
P: Encode,
{
fn encode<_E: Encoder>(&self, encoder: &mut _E) -> Result<(), EncodeError> {
self.0.encode(encoder)?;
self.1.encode(encoder)?;
self.2.encode(encoder)?;
self.3.encode(encoder)?;
self.4.encode(encoder)?;
self.5.encode(encoder)?;
self.6.encode(encoder)?;
self.7.encode(encoder)?;
self.8.encode(encoder)?;
self.9.encode(encoder)?;
self.10.encode(encoder)?;
self.11.encode(encoder)?;
self.12.encode(encoder)?;
self.13.encode(encoder)?;
self.14.encode(encoder)?;
self.15.encode(encoder)?;
Ok(())
}
}

View File

@ -1,491 +0,0 @@
use super::{write::Writer, Encode, Encoder};
use crate::{
config::{Endianness, IntEncoding, InternalEndianConfig, InternalIntEncodingConfig},
error::EncodeError,
};
use core::cmp::Reverse;
use core::{
cell::{Cell, RefCell},
marker::PhantomData,
num::{
NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, NonZeroIsize, NonZeroU128,
NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize, Wrapping,
},
ops::{Bound, Range, RangeInclusive},
time::Duration,
};
impl Encode for () {
fn encode<E: Encoder>(&self, _: &mut E) -> Result<(), EncodeError> {
Ok(())
}
}
impl<T> Encode for PhantomData<T> {
fn encode<E: Encoder>(&self, _: &mut E) -> Result<(), EncodeError> {
Ok(())
}
}
impl Encode for bool {
fn encode<E: Encoder>(&self, encoder: &mut E) -> Result<(), EncodeError> {
u8::from(*self).encode(encoder)
}
}
impl Encode for u8 {
fn encode<E: Encoder>(&self, encoder: &mut E) -> Result<(), EncodeError> {
encoder.writer().write(&[*self])
}
}
impl Encode for NonZeroU8 {
fn encode<E: Encoder>(&self, encoder: &mut E) -> Result<(), EncodeError> {
self.get().encode(encoder)
}
}
impl Encode for u16 {
fn encode<E: Encoder>(&self, encoder: &mut E) -> Result<(), EncodeError> {
match E::C::INT_ENCODING {
IntEncoding::Variable => {
crate::varint::varint_encode_u16(encoder.writer(), E::C::ENDIAN, *self)
}
IntEncoding::Fixed => match E::C::ENDIAN {
Endianness::Big => encoder.writer().write(&self.to_be_bytes()),
Endianness::Little => encoder.writer().write(&self.to_le_bytes()),
},
}
}
}
impl Encode for NonZeroU16 {
fn encode<E: Encoder>(&self, encoder: &mut E) -> Result<(), EncodeError> {
self.get().encode(encoder)
}
}
impl Encode for u32 {
fn encode<E: Encoder>(&self, encoder: &mut E) -> Result<(), EncodeError> {
match E::C::INT_ENCODING {
IntEncoding::Variable => {
crate::varint::varint_encode_u32(encoder.writer(), E::C::ENDIAN, *self)
}
IntEncoding::Fixed => match E::C::ENDIAN {
Endianness::Big => encoder.writer().write(&self.to_be_bytes()),
Endianness::Little => encoder.writer().write(&self.to_le_bytes()),
},
}
}
}
impl Encode for NonZeroU32 {
fn encode<E: Encoder>(&self, encoder: &mut E) -> Result<(), EncodeError> {
self.get().encode(encoder)
}
}
impl Encode for u64 {
fn encode<E: Encoder>(&self, encoder: &mut E) -> Result<(), EncodeError> {
match E::C::INT_ENCODING {
IntEncoding::Variable => {
crate::varint::varint_encode_u64(encoder.writer(), E::C::ENDIAN, *self)
}
IntEncoding::Fixed => match E::C::ENDIAN {
Endianness::Big => encoder.writer().write(&self.to_be_bytes()),
Endianness::Little => encoder.writer().write(&self.to_le_bytes()),
},
}
}
}
impl Encode for NonZeroU64 {
fn encode<E: Encoder>(&self, encoder: &mut E) -> Result<(), EncodeError> {
self.get().encode(encoder)
}
}
impl Encode for u128 {
fn encode<E: Encoder>(&self, encoder: &mut E) -> Result<(), EncodeError> {
match E::C::INT_ENCODING {
IntEncoding::Variable => {
crate::varint::varint_encode_u128(encoder.writer(), E::C::ENDIAN, *self)
}
IntEncoding::Fixed => match E::C::ENDIAN {
Endianness::Big => encoder.writer().write(&self.to_be_bytes()),
Endianness::Little => encoder.writer().write(&self.to_le_bytes()),
},
}
}
}
impl Encode for NonZeroU128 {
fn encode<E: Encoder>(&self, encoder: &mut E) -> Result<(), EncodeError> {
self.get().encode(encoder)
}
}
impl Encode for usize {
fn encode<E: Encoder>(&self, encoder: &mut E) -> Result<(), EncodeError> {
match E::C::INT_ENCODING {
IntEncoding::Variable => {
crate::varint::varint_encode_usize(encoder.writer(), E::C::ENDIAN, *self)
}
IntEncoding::Fixed => match E::C::ENDIAN {
Endianness::Big => encoder.writer().write(&(*self as u64).to_be_bytes()),
Endianness::Little => encoder.writer().write(&(*self as u64).to_le_bytes()),
},
}
}
}
impl Encode for NonZeroUsize {
fn encode<E: Encoder>(&self, encoder: &mut E) -> Result<(), EncodeError> {
self.get().encode(encoder)
}
}
impl Encode for i8 {
fn encode<E: Encoder>(&self, encoder: &mut E) -> Result<(), EncodeError> {
encoder.writer().write(&[*self as u8])
}
}
impl Encode for NonZeroI8 {
fn encode<E: Encoder>(&self, encoder: &mut E) -> Result<(), EncodeError> {
self.get().encode(encoder)
}
}
impl Encode for i16 {
fn encode<E: Encoder>(&self, encoder: &mut E) -> Result<(), EncodeError> {
match E::C::INT_ENCODING {
IntEncoding::Variable => {
crate::varint::varint_encode_i16(encoder.writer(), E::C::ENDIAN, *self)
}
IntEncoding::Fixed => match E::C::ENDIAN {
Endianness::Big => encoder.writer().write(&self.to_be_bytes()),
Endianness::Little => encoder.writer().write(&self.to_le_bytes()),
},
}
}
}
impl Encode for NonZeroI16 {
fn encode<E: Encoder>(&self, encoder: &mut E) -> Result<(), EncodeError> {
self.get().encode(encoder)
}
}
impl Encode for i32 {
fn encode<E: Encoder>(&self, encoder: &mut E) -> Result<(), EncodeError> {
match E::C::INT_ENCODING {
IntEncoding::Variable => {
crate::varint::varint_encode_i32(encoder.writer(), E::C::ENDIAN, *self)
}
IntEncoding::Fixed => match E::C::ENDIAN {
Endianness::Big => encoder.writer().write(&self.to_be_bytes()),
Endianness::Little => encoder.writer().write(&self.to_le_bytes()),
},
}
}
}
impl Encode for NonZeroI32 {
fn encode<E: Encoder>(&self, encoder: &mut E) -> Result<(), EncodeError> {
self.get().encode(encoder)
}
}
impl Encode for i64 {
fn encode<E: Encoder>(&self, encoder: &mut E) -> Result<(), EncodeError> {
match E::C::INT_ENCODING {
IntEncoding::Variable => {
crate::varint::varint_encode_i64(encoder.writer(), E::C::ENDIAN, *self)
}
IntEncoding::Fixed => match E::C::ENDIAN {
Endianness::Big => encoder.writer().write(&self.to_be_bytes()),
Endianness::Little => encoder.writer().write(&self.to_le_bytes()),
},
}
}
}
impl Encode for NonZeroI64 {
fn encode<E: Encoder>(&self, encoder: &mut E) -> Result<(), EncodeError> {
self.get().encode(encoder)
}
}
impl Encode for i128 {
fn encode<E: Encoder>(&self, encoder: &mut E) -> Result<(), EncodeError> {
match E::C::INT_ENCODING {
IntEncoding::Variable => {
crate::varint::varint_encode_i128(encoder.writer(), E::C::ENDIAN, *self)
}
IntEncoding::Fixed => match E::C::ENDIAN {
Endianness::Big => encoder.writer().write(&self.to_be_bytes()),
Endianness::Little => encoder.writer().write(&self.to_le_bytes()),
},
}
}
}
impl Encode for NonZeroI128 {
fn encode<E: Encoder>(&self, encoder: &mut E) -> Result<(), EncodeError> {
self.get().encode(encoder)
}
}
impl Encode for isize {
fn encode<E: Encoder>(&self, encoder: &mut E) -> Result<(), EncodeError> {
match E::C::INT_ENCODING {
IntEncoding::Variable => {
crate::varint::varint_encode_isize(encoder.writer(), E::C::ENDIAN, *self)
}
IntEncoding::Fixed => match E::C::ENDIAN {
Endianness::Big => encoder.writer().write(&(*self as i64).to_be_bytes()),
Endianness::Little => encoder.writer().write(&(*self as i64).to_le_bytes()),
},
}
}
}
impl Encode for NonZeroIsize {
fn encode<E: Encoder>(&self, encoder: &mut E) -> Result<(), EncodeError> {
self.get().encode(encoder)
}
}
impl Encode for f32 {
fn encode<E: Encoder>(&self, encoder: &mut E) -> Result<(), EncodeError> {
match E::C::ENDIAN {
Endianness::Big => encoder.writer().write(&self.to_be_bytes()),
Endianness::Little => encoder.writer().write(&self.to_le_bytes()),
}
}
}
impl Encode for f64 {
fn encode<E: Encoder>(&self, encoder: &mut E) -> Result<(), EncodeError> {
match E::C::ENDIAN {
Endianness::Big => encoder.writer().write(&self.to_be_bytes()),
Endianness::Little => encoder.writer().write(&self.to_le_bytes()),
}
}
}
impl<T: Encode> Encode for Wrapping<T> {
fn encode<E: Encoder>(&self, encoder: &mut E) -> Result<(), EncodeError> {
self.0.encode(encoder)
}
}
impl<T: Encode> Encode for Reverse<T> {
fn encode<E: Encoder>(&self, encoder: &mut E) -> Result<(), EncodeError> {
self.0.encode(encoder)
}
}
impl Encode for char {
fn encode<E: Encoder>(&self, encoder: &mut E) -> Result<(), EncodeError> {
encode_utf8(encoder.writer(), *self)
}
}
impl<T> Encode for [T]
where
T: Encode,
{
fn encode<E: Encoder>(&self, encoder: &mut E) -> Result<(), EncodeError> {
super::encode_slice_len(encoder, self.len())?;
if unty::type_equal::<T, u8>() {
// Safety: T = u8
let t: &[u8] = unsafe { core::mem::transmute(self) };
encoder.writer().write(t)?;
return Ok(());
}
for item in self {
item.encode(encoder)?;
}
Ok(())
}
}
const TAG_CONT: u8 = 0b1000_0000;
const TAG_TWO_B: u8 = 0b1100_0000;
const TAG_THREE_B: u8 = 0b1110_0000;
const TAG_FOUR_B: u8 = 0b1111_0000;
const MAX_ONE_B: u32 = 0x80;
const MAX_TWO_B: u32 = 0x800;
const MAX_THREE_B: u32 = 0x10000;
fn encode_utf8(writer: &mut impl Writer, c: char) -> Result<(), EncodeError> {
let code = c as u32;
if code < MAX_ONE_B {
writer.write(&[c as u8])
} else if code < MAX_TWO_B {
let mut buf = [0u8; 2];
buf[0] = ((code >> 6) & 0x1F) as u8 | TAG_TWO_B;
buf[1] = (code & 0x3F) as u8 | TAG_CONT;
writer.write(&buf)
} else if code < MAX_THREE_B {
let mut buf = [0u8; 3];
buf[0] = ((code >> 12) & 0x0F) as u8 | TAG_THREE_B;
buf[1] = ((code >> 6) & 0x3F) as u8 | TAG_CONT;
buf[2] = (code & 0x3F) as u8 | TAG_CONT;
writer.write(&buf)
} else {
let mut buf = [0u8; 4];
buf[0] = ((code >> 18) & 0x07) as u8 | TAG_FOUR_B;
buf[1] = ((code >> 12) & 0x3F) as u8 | TAG_CONT;
buf[2] = ((code >> 6) & 0x3F) as u8 | TAG_CONT;
buf[3] = (code & 0x3F) as u8 | TAG_CONT;
writer.write(&buf)
}
}
impl Encode for str {
fn encode<E: Encoder>(&self, encoder: &mut E) -> Result<(), EncodeError> {
self.as_bytes().encode(encoder)
}
}
impl<T, const N: usize> Encode for [T; N]
where
T: Encode,
{
fn encode<E: Encoder>(&self, encoder: &mut E) -> Result<(), EncodeError> {
if unty::type_equal::<T, u8>() {
// Safety: this is &[u8; N]
let array_slice: &[u8] =
unsafe { core::slice::from_raw_parts(self.as_ptr().cast(), N) };
encoder.writer().write(array_slice)
} else {
for item in self.iter() {
item.encode(encoder)?;
}
Ok(())
}
}
}
impl<T> Encode for Option<T>
where
T: Encode,
{
fn encode<E: Encoder>(&self, encoder: &mut E) -> Result<(), EncodeError> {
super::encode_option_variant(encoder, self)?;
if let Some(val) = self {
val.encode(encoder)?;
}
Ok(())
}
}
impl<T, U> Encode for Result<T, U>
where
T: Encode,
U: Encode,
{
fn encode<E: Encoder>(&self, encoder: &mut E) -> Result<(), EncodeError> {
match self {
Ok(val) => {
0u32.encode(encoder)?;
val.encode(encoder)
}
Err(err) => {
1u32.encode(encoder)?;
err.encode(encoder)
}
}
}
}
impl<T> Encode for Cell<T>
where
T: Encode + Copy,
{
fn encode<E: Encoder>(&self, encoder: &mut E) -> Result<(), EncodeError> {
T::encode(&self.get(), encoder)
}
}
impl<T> Encode for RefCell<T>
where
T: Encode + ?Sized,
{
fn encode<E: Encoder>(&self, encoder: &mut E) -> Result<(), EncodeError> {
let borrow_guard = self
.try_borrow()
.map_err(|e| EncodeError::RefCellAlreadyBorrowed {
inner: e,
type_name: core::any::type_name::<RefCell<T>>(),
})?;
T::encode(&borrow_guard, encoder)
}
}
impl Encode for Duration {
fn encode<E: Encoder>(&self, encoder: &mut E) -> Result<(), EncodeError> {
self.as_secs().encode(encoder)?;
self.subsec_nanos().encode(encoder)?;
Ok(())
}
}
impl<T> Encode for Range<T>
where
T: Encode,
{
fn encode<E: Encoder>(&self, encoder: &mut E) -> Result<(), EncodeError> {
self.start.encode(encoder)?;
self.end.encode(encoder)?;
Ok(())
}
}
impl<T> Encode for RangeInclusive<T>
where
T: Encode,
{
fn encode<E: Encoder>(&self, encoder: &mut E) -> Result<(), EncodeError> {
self.start().encode(encoder)?;
self.end().encode(encoder)?;
Ok(())
}
}
impl<T> Encode for Bound<T>
where
T: Encode,
{
fn encode<E: Encoder>(&self, encoder: &mut E) -> Result<(), EncodeError> {
match self {
Self::Unbounded => {
0u32.encode(encoder)?;
}
Self::Included(val) => {
1u32.encode(encoder)?;
val.encode(encoder)?;
}
Self::Excluded(val) => {
2u32.encode(encoder)?;
val.encode(encoder)?;
}
}
Ok(())
}
}
impl<T> Encode for &T
where
T: Encode + ?Sized,
{
fn encode<E: Encoder>(&self, encoder: &mut E) -> Result<(), EncodeError> {
T::encode(self, encoder)
}
}

View File

@ -1,103 +0,0 @@
//! Encoder-based structs and traits.
mod encoder;
mod impl_tuples;
mod impls;
use self::write::Writer;
use crate::{config::Config, error::EncodeError, utils::Sealed};
pub mod write;
pub use self::encoder::EncoderImpl;
/// Any source that can be encoded. This trait should be implemented for all types that you want to be able to use with any of the `encode_with` methods.
///
/// This trait will be automatically implemented if you enable the `derive` feature and add `#[derive(bincode::Encode)]` to your trait.
///
/// # Implementing this trait manually
///
/// If you want to implement this trait for your type, the easiest way is to add a `#[derive(bincode::Encode)]`, build and check your `target/generated/bincode/` folder. This should generate a `<Struct name>_Encode.rs` file.
///
/// For this struct:
///
/// ```
/// struct Entity {
/// pub x: f32,
/// pub y: f32,
/// }
/// ```
/// It will look something like:
///
/// ```
/// # struct Entity {
/// # pub x: f32,
/// # pub y: f32,
/// # }
/// impl bincode::Encode for Entity {
/// fn encode<E: bincode::enc::Encoder>(
/// &self,
/// encoder: &mut E,
/// ) -> core::result::Result<(), bincode::error::EncodeError> {
/// bincode::Encode::encode(&self.x, encoder)?;
/// bincode::Encode::encode(&self.y, encoder)?;
/// Ok(())
/// }
/// }
/// ```
///
/// From here you can add/remove fields, or add custom logic.
pub trait Encode {
/// Encode a given type.
fn encode<E: Encoder>(&self, encoder: &mut E) -> Result<(), EncodeError>;
}
/// Helper trait to encode basic types into.
pub trait Encoder: Sealed {
/// The concrete [Writer] type
type W: Writer;
/// The concrete [Config] type
type C: Config;
/// Returns a mutable reference to the writer
fn writer(&mut self) -> &mut Self::W;
/// Returns a reference to the config
fn config(&self) -> &Self::C;
}
impl<T> Encoder for &mut T
where
T: Encoder,
{
type W = T::W;
type C = T::C;
fn writer(&mut self) -> &mut Self::W {
T::writer(self)
}
fn config(&self) -> &Self::C {
T::config(self)
}
}
/// Encode the variant of the given option. Will not encode the option itself.
#[inline]
pub(crate) fn encode_option_variant<E: Encoder, T>(
encoder: &mut E,
value: &Option<T>,
) -> Result<(), EncodeError> {
match value {
None => 0u8.encode(encoder),
Some(_) => 1u8.encode(encoder),
}
}
/// Encodes the length of any slice, container, etc into the given encoder
#[inline]
pub(crate) fn encode_slice_len<E: Encoder>(encoder: &mut E, len: usize) -> Result<(), EncodeError> {
(len as u64).encode(encoder)
}

View File

@ -1,82 +0,0 @@
//! This module contains writer-based structs and traits.
//!
//! Because `std::io::Write` is only limited to `std` and not `core`, we provide our own [Writer].
use crate::error::EncodeError;
/// Trait that indicates that a struct can be used as a destination to encode data too. This is used by [Encode]
///
/// [Encode]: ../trait.Encode.html
pub trait Writer {
/// Write `bytes` to the underlying writer. Exactly `bytes.len()` bytes must be written, or else an error should be returned.
fn write(&mut self, bytes: &[u8]) -> Result<(), EncodeError>;
}
impl<T: Writer> Writer for &mut T {
#[inline]
fn write(&mut self, bytes: &[u8]) -> Result<(), EncodeError> {
(**self).write(bytes)
}
}
/// A helper struct that implements `Writer` for a `&[u8]` slice.
///
/// ```
/// use bincode::enc::write::{Writer, SliceWriter};
///
/// let destination = &mut [0u8; 100];
/// let mut writer = SliceWriter::new(destination);
/// writer.write(&[1, 2, 3, 4, 5]).unwrap();
///
/// assert_eq!(writer.bytes_written(), 5);
/// assert_eq!(destination[0..6], [1, 2, 3, 4, 5, 0]);
/// ```
pub struct SliceWriter<'storage> {
slice: &'storage mut [u8],
original_length: usize,
}
impl<'storage> SliceWriter<'storage> {
/// Create a new instance of `SliceWriter` with the given byte array.
pub fn new(bytes: &'storage mut [u8]) -> SliceWriter<'storage> {
let original = bytes.len();
SliceWriter {
slice: bytes,
original_length: original,
}
}
/// Return the amount of bytes written so far.
pub fn bytes_written(&self) -> usize {
self.original_length - self.slice.len()
}
}
impl Writer for SliceWriter<'_> {
#[inline(always)]
fn write(&mut self, bytes: &[u8]) -> Result<(), EncodeError> {
if bytes.len() > self.slice.len() {
return Err(EncodeError::UnexpectedEnd);
}
let (a, b) = core::mem::take(&mut self.slice).split_at_mut(bytes.len());
a.copy_from_slice(bytes);
self.slice = b;
Ok(())
}
}
/// A writer that counts how many bytes were written. This is useful for e.g. pre-allocating buffers before writing to them.
#[derive(Default)]
pub struct SizeWriter {
/// the amount of bytes that were written so far
pub bytes_written: usize,
}
impl Writer for SizeWriter {
#[inline(always)]
fn write(&mut self, bytes: &[u8]) -> Result<(), EncodeError> {
self.bytes_written += bytes.len();
Ok(())
}
}

View File

@ -1,286 +0,0 @@
//! Errors that can be encountering by Encoding and Decoding.
/// Errors that can be encountered by encoding a type
#[non_exhaustive]
#[derive(Debug)]
pub enum EncodeError {
/// The writer ran out of storage.
UnexpectedEnd,
/// The `RefCell<T>` is already borrowed
RefCellAlreadyBorrowed {
/// The inner borrow error
inner: core::cell::BorrowError,
/// the type name of the RefCell being encoded that is currently borrowed.
type_name: &'static str,
},
/// An uncommon error occurred, see the inner text for more information
Other(&'static str),
/// An uncommon error occurred, see the inner text for more information
#[cfg(feature = "alloc")]
OtherString(alloc::string::String),
/// A `std::path::Path` was being encoded but did not contain a valid `&str` representation
#[cfg(feature = "std")]
InvalidPathCharacters,
/// The targeted writer encountered an `std::io::Error`
#[cfg(feature = "std")]
Io {
/// The encountered error
inner: std::io::Error,
/// The amount of bytes that were written before the error occurred
index: usize,
},
/// The encoder tried to encode a `Mutex` or `RwLock`, but the locking failed
#[cfg(feature = "std")]
LockFailed {
/// The type name of the mutex for debugging purposes
type_name: &'static str,
},
/// The encoder tried to encode a `SystemTime`, but it was before `SystemTime::UNIX_EPOCH`
#[cfg(feature = "std")]
InvalidSystemTime {
/// The error that was thrown by the SystemTime
inner: std::time::SystemTimeError,
/// The SystemTime that caused the error
time: std::boxed::Box<std::time::SystemTime>,
},
#[cfg(feature = "serde")]
/// A serde-specific error that occurred while decoding.
Serde(crate::features::serde::EncodeError),
}
impl core::fmt::Display for EncodeError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
// TODO: Improve this?
write!(f, "{:?}", self)
}
}
impl core::error::Error for EncodeError {
fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
match self {
Self::RefCellAlreadyBorrowed { inner, .. } => Some(inner),
#[cfg(feature = "std")]
Self::Io { inner, .. } => Some(inner),
#[cfg(feature = "std")]
Self::InvalidSystemTime { inner, .. } => Some(inner),
_ => None,
}
}
}
impl core::error::Error for DecodeError {
fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
match self {
Self::Utf8 { inner } => Some(inner),
_ => None,
}
}
}
/// Errors that can be encountered by decoding a type
#[non_exhaustive]
#[derive(Debug)]
pub enum DecodeError {
/// The reader reached its end but more bytes were expected.
UnexpectedEnd {
/// Gives an estimate of how many extra bytes are needed.
///
/// **Note**: this is only an estimate and not indicative of the actual bytes needed.
///
/// **Note**: Bincode has no look-ahead mechanism. This means that this will only return the amount of bytes to be read for the current action, and not take into account the entire data structure being read.
additional: usize,
},
/// The given configuration limit was exceeded
LimitExceeded,
/// Invalid type was found. The decoder tried to read type `expected`, but found type `found` instead.
InvalidIntegerType {
/// The type that was being read from the reader
expected: IntegerType,
/// The type that was encoded in the data
found: IntegerType,
},
/// The decoder tried to decode any of the `NonZero*` types but the value is zero
NonZeroTypeIsZero {
/// The type that was being read from the reader
non_zero_type: IntegerType,
},
/// Invalid enum variant was found. The decoder tried to decode variant index `found`, but the variant index should be between `min` and `max`.
UnexpectedVariant {
/// The type name that was being decoded.
type_name: &'static str,
/// The variants that are allowed
allowed: &'static AllowedEnumVariants,
/// The index of the enum that the decoder encountered
found: u32,
},
/// The decoder tried to decode a `str`, but an utf8 error was encountered.
Utf8 {
/// The inner error
inner: core::str::Utf8Error,
},
/// The decoder tried to decode a `char` and failed. The given buffer contains the bytes that are read at the moment of failure.
InvalidCharEncoding([u8; 4]),
/// The decoder tried to decode a `bool` and failed. The given value is what is actually read.
InvalidBooleanValue(u8),
/// The decoder tried to decode an array of length `required`, but the binary data contained an array of length `found`.
ArrayLengthMismatch {
/// The length of the array required by the rust type.
required: usize,
/// The length of the array found in the binary format.
found: usize,
},
/// The encoded value is outside of the range of the target usize type.
///
/// This can happen if an usize was encoded on an architecture with a larger
/// usize type and then decoded on an architecture with a smaller one. For
/// example going from a 64 bit architecture to a 32 or 16 bit one may
/// cause this error.
OutsideUsizeRange(u64),
/// Tried to decode an enum with no variants
EmptyEnum {
/// The type that was being decoded
type_name: &'static str,
},
/// The decoder tried to decode a Duration and overflowed the number of seconds.
InvalidDuration {
/// The number of seconds in the duration.
secs: u64,
/// The number of nanoseconds in the duration, which when converted to seconds and added to
/// `secs`, overflows a `u64`.
nanos: u32,
},
/// The decoder tried to decode a SystemTime and overflowed
InvalidSystemTime {
/// The duration which could not have been added to
/// [`UNIX_EPOCH`](std::time::SystemTime::UNIX_EPOCH)
duration: core::time::Duration,
},
/// The decoder tried to decode a `CString`, but the incoming data contained a 0 byte
#[cfg(feature = "std")]
CStringNulError {
/// Nul byte position
position: usize,
},
/// The reader encountered an IO error but more bytes were expected.
#[cfg(feature = "std")]
Io {
/// The IO error expected
inner: std::io::Error,
/// Gives an estimate of how many extra bytes are needed.
///
/// **Note**: this is only an estimate and not indicative of the actual bytes needed.
///
/// **Note**: Bincode has no look-ahead mechanism. This means that this will only return the amount of bytes to be read for the current action, and not take into account the entire data structure being read.
additional: usize,
},
/// An uncommon error occurred, see the inner text for more information
Other(&'static str),
/// An uncommon error occurred, see the inner text for more information
#[cfg(feature = "alloc")]
OtherString(alloc::string::String),
#[cfg(feature = "serde")]
/// A serde-specific error that occurred while decoding.
Serde(crate::features::serde::DecodeError),
}
impl core::fmt::Display for DecodeError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
// TODO: Improve this?
write!(f, "{:?}", self)
}
}
impl DecodeError {
/// If the current error is `InvalidIntegerType`, change the `expected` and
/// `found` values from `Ux` to `Ix`. This is needed to have correct error
/// reporting in src/varint/decode_signed.rs since this calls
/// src/varint/decode_unsigned.rs and needs to correct the `expected` and
/// `found` types.
pub(crate) fn change_integer_type_to_signed(self) -> DecodeError {
match self {
Self::InvalidIntegerType { expected, found } => Self::InvalidIntegerType {
expected: expected.into_signed(),
found: found.into_signed(),
},
other => other,
}
}
}
/// Indicates which enum variants are allowed
#[non_exhaustive]
#[derive(Debug, PartialEq, Eq)]
pub enum AllowedEnumVariants {
/// All values between `min` and `max` (inclusive) are allowed
#[allow(missing_docs)]
Range { min: u32, max: u32 },
/// Each one of these values is allowed
Allowed(&'static [u32]),
}
/// Integer types. Used by [DecodeError]. These types have no purpose other than being shown in errors.
#[non_exhaustive]
#[derive(Debug, PartialEq, Eq)]
#[allow(missing_docs)]
pub enum IntegerType {
U8,
U16,
U32,
U64,
U128,
Usize,
I8,
I16,
I32,
I64,
I128,
Isize,
Reserved,
}
impl IntegerType {
/// Change the `Ux` value to the associated `Ix` value.
/// Returns the old value if `self` is already `Ix`.
pub(crate) const fn into_signed(self) -> Self {
match self {
Self::U8 => Self::I8,
Self::U16 => Self::I16,
Self::U32 => Self::I32,
Self::U64 => Self::I64,
Self::U128 => Self::I128,
Self::Usize => Self::Isize,
other => other,
}
}
}

View File

@ -1,2 +0,0 @@
#[cfg_attr(docsrs, doc(cfg(feature = "derive")))]
pub use bincode_derive::{BorrowDecode, Decode, Encode};

View File

@ -1,603 +0,0 @@
use crate::{
de::{read::Reader, BorrowDecoder, Decode, Decoder},
enc::{
self,
write::{SizeWriter, Writer},
Encode, Encoder,
},
error::{DecodeError, EncodeError},
impl_borrow_decode, BorrowDecode, Config,
};
use alloc::{
borrow::{Cow, ToOwned},
boxed::Box,
collections::*,
rc::Rc,
string::String,
vec::Vec,
};
#[cfg(target_has_atomic = "ptr")]
use alloc::sync::Arc;
#[derive(Default)]
pub(crate) struct VecWriter {
inner: Vec<u8>,
}
impl VecWriter {
/// Create a new vec writer with the given capacity
pub fn with_capacity(cap: usize) -> Self {
Self {
inner: Vec::with_capacity(cap),
}
}
// May not be used in all feature combinations
#[allow(dead_code)]
pub(crate) fn collect(self) -> Vec<u8> {
self.inner
}
}
impl enc::write::Writer for VecWriter {
#[inline(always)]
fn write(&mut self, bytes: &[u8]) -> Result<(), EncodeError> {
self.inner.extend_from_slice(bytes);
Ok(())
}
}
/// Encode the given value into a `Vec<u8>` with the given `Config`. See the [config] module for more information.
///
/// [config]: config/index.html
#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
pub fn encode_to_vec<E: enc::Encode, C: Config>(val: E, config: C) -> Result<Vec<u8>, EncodeError> {
let size = {
let mut size_writer = enc::EncoderImpl::<_, C>::new(SizeWriter::default(), config);
val.encode(&mut size_writer)?;
size_writer.into_writer().bytes_written
};
let writer = VecWriter::with_capacity(size);
let mut encoder = enc::EncoderImpl::<_, C>::new(writer, config);
val.encode(&mut encoder)?;
Ok(encoder.into_writer().inner)
}
impl<Context, T> Decode<Context> for BinaryHeap<T>
where
T: Decode<Context> + Ord,
{
fn decode<D: Decoder<Context = Context>>(decoder: &mut D) -> Result<Self, DecodeError> {
Ok(Vec::<T>::decode(decoder)?.into())
}
}
impl<'de, T, Context> BorrowDecode<'de, Context> for BinaryHeap<T>
where
T: BorrowDecode<'de, Context> + Ord,
{
fn borrow_decode<D: BorrowDecoder<'de, Context = Context>>(
decoder: &mut D,
) -> Result<Self, DecodeError> {
Ok(Vec::<T>::borrow_decode(decoder)?.into())
}
}
impl<T> Encode for BinaryHeap<T>
where
T: Encode + Ord,
{
fn encode<E: Encoder>(&self, encoder: &mut E) -> Result<(), EncodeError> {
// BLOCKEDTODO(https://github.com/rust-lang/rust/issues/83659): we can u8 optimize this with `.as_slice()`
crate::enc::encode_slice_len(encoder, self.len())?;
for val in self.iter() {
val.encode(encoder)?;
}
Ok(())
}
}
impl<Context, K, V> Decode<Context> for BTreeMap<K, V>
where
K: Decode<Context> + Ord,
V: Decode<Context>,
{
fn decode<D: Decoder<Context = Context>>(decoder: &mut D) -> Result<Self, DecodeError> {
let len = crate::de::decode_slice_len(decoder)?;
decoder.claim_container_read::<(K, V)>(len)?;
let mut map = BTreeMap::new();
for _ in 0..len {
// See the documentation on `unclaim_bytes_read` as to why we're doing this here
decoder.unclaim_bytes_read(core::mem::size_of::<(K, V)>());
let key = K::decode(decoder)?;
let value = V::decode(decoder)?;
map.insert(key, value);
}
Ok(map)
}
}
impl<'de, K, V, Context> BorrowDecode<'de, Context> for BTreeMap<K, V>
where
K: BorrowDecode<'de, Context> + Ord,
V: BorrowDecode<'de, Context>,
{
fn borrow_decode<D: BorrowDecoder<'de, Context = Context>>(
decoder: &mut D,
) -> Result<Self, DecodeError> {
let len = crate::de::decode_slice_len(decoder)?;
decoder.claim_container_read::<(K, V)>(len)?;
let mut map = BTreeMap::new();
for _ in 0..len {
// See the documentation on `unclaim_bytes_read` as to why we're doing this here
decoder.unclaim_bytes_read(core::mem::size_of::<(K, V)>());
let key = K::borrow_decode(decoder)?;
let value = V::borrow_decode(decoder)?;
map.insert(key, value);
}
Ok(map)
}
}
impl<K, V> Encode for BTreeMap<K, V>
where
K: Encode + Ord,
V: Encode,
{
fn encode<E: Encoder>(&self, encoder: &mut E) -> Result<(), EncodeError> {
crate::enc::encode_slice_len(encoder, self.len())?;
for (key, val) in self.iter() {
key.encode(encoder)?;
val.encode(encoder)?;
}
Ok(())
}
}
impl<Context, T> Decode<Context> for BTreeSet<T>
where
T: Decode<Context> + Ord,
{
fn decode<D: Decoder<Context = Context>>(decoder: &mut D) -> Result<Self, DecodeError> {
let len = crate::de::decode_slice_len(decoder)?;
decoder.claim_container_read::<T>(len)?;
let mut map = BTreeSet::new();
for _ in 0..len {
// See the documentation on `unclaim_bytes_read` as to why we're doing this here
decoder.unclaim_bytes_read(core::mem::size_of::<T>());
let key = T::decode(decoder)?;
map.insert(key);
}
Ok(map)
}
}
impl<'de, T, Context> BorrowDecode<'de, Context> for BTreeSet<T>
where
T: BorrowDecode<'de, Context> + Ord,
{
fn borrow_decode<D: BorrowDecoder<'de, Context = Context>>(
decoder: &mut D,
) -> Result<Self, DecodeError> {
let len = crate::de::decode_slice_len(decoder)?;
decoder.claim_container_read::<T>(len)?;
let mut map = BTreeSet::new();
for _ in 0..len {
// See the documentation on `unclaim_bytes_read` as to why we're doing this here
decoder.unclaim_bytes_read(core::mem::size_of::<T>());
let key = T::borrow_decode(decoder)?;
map.insert(key);
}
Ok(map)
}
}
impl<T> Encode for BTreeSet<T>
where
T: Encode + Ord,
{
fn encode<E: Encoder>(&self, encoder: &mut E) -> Result<(), EncodeError> {
crate::enc::encode_slice_len(encoder, self.len())?;
for item in self.iter() {
item.encode(encoder)?;
}
Ok(())
}
}
impl<Context, T> Decode<Context> for VecDeque<T>
where
T: Decode<Context>,
{
fn decode<D: Decoder<Context = Context>>(decoder: &mut D) -> Result<Self, DecodeError> {
Ok(Vec::<T>::decode(decoder)?.into())
}
}
impl<'de, T, Context> BorrowDecode<'de, Context> for VecDeque<T>
where
T: BorrowDecode<'de, Context>,
{
fn borrow_decode<D: BorrowDecoder<'de, Context = Context>>(
decoder: &mut D,
) -> Result<Self, DecodeError> {
Ok(Vec::<T>::borrow_decode(decoder)?.into())
}
}
impl<T> Encode for VecDeque<T>
where
T: Encode,
{
fn encode<E: Encoder>(&self, encoder: &mut E) -> Result<(), EncodeError> {
crate::enc::encode_slice_len(encoder, self.len())?;
if unty::type_equal::<T, u8>() {
let slices: (&[T], &[T]) = self.as_slices();
// Safety: T is u8 so turning this into `&[u8]` is okay
let slices: (&[u8], &[u8]) = unsafe {
(
core::slice::from_raw_parts(slices.0.as_ptr().cast(), slices.0.len()),
core::slice::from_raw_parts(slices.1.as_ptr().cast(), slices.1.len()),
)
};
encoder.writer().write(slices.0)?;
encoder.writer().write(slices.1)?;
} else {
for item in self.iter() {
item.encode(encoder)?;
}
}
Ok(())
}
}
impl<Context, T> Decode<Context> for Vec<T>
where
T: Decode<Context>,
{
fn decode<D: Decoder<Context = Context>>(decoder: &mut D) -> Result<Self, DecodeError> {
let len = crate::de::decode_slice_len(decoder)?;
if unty::type_equal::<T, u8>() {
decoder.claim_container_read::<T>(len)?;
// optimize for reading u8 vecs
let mut vec = alloc::vec![0u8; len];
decoder.reader().read(&mut vec)?;
// Safety: Vec<T> is Vec<u8>
Ok(unsafe { core::mem::transmute::<Vec<u8>, Vec<T>>(vec) })
} else {
decoder.claim_container_read::<T>(len)?;
let mut vec = Vec::with_capacity(len);
for _ in 0..len {
// See the documentation on `unclaim_bytes_read` as to why we're doing this here
decoder.unclaim_bytes_read(core::mem::size_of::<T>());
vec.push(T::decode(decoder)?);
}
Ok(vec)
}
}
}
impl<'de, T, Context> BorrowDecode<'de, Context> for Vec<T>
where
T: BorrowDecode<'de, Context>,
{
fn borrow_decode<D: BorrowDecoder<'de, Context = Context>>(
decoder: &mut D,
) -> Result<Self, DecodeError> {
let len = crate::de::decode_slice_len(decoder)?;
if unty::type_equal::<T, u8>() {
decoder.claim_container_read::<T>(len)?;
// optimize for reading u8 vecs
let mut vec = alloc::vec![0u8; len];
decoder.reader().read(&mut vec)?;
// Safety: Vec<T> is Vec<u8>
Ok(unsafe { core::mem::transmute::<Vec<u8>, Vec<T>>(vec) })
} else {
decoder.claim_container_read::<T>(len)?;
let mut vec = Vec::with_capacity(len);
for _ in 0..len {
// See the documentation on `unclaim_bytes_read` as to why we're doing this here
decoder.unclaim_bytes_read(core::mem::size_of::<T>());
vec.push(T::borrow_decode(decoder)?);
}
Ok(vec)
}
}
}
impl<T> Encode for Vec<T>
where
T: Encode,
{
fn encode<E: Encoder>(&self, encoder: &mut E) -> Result<(), EncodeError> {
crate::enc::encode_slice_len(encoder, self.len())?;
if unty::type_equal::<T, u8>() {
// Safety: T == u8
let slice: &[u8] = unsafe { core::mem::transmute(self.as_slice()) };
encoder.writer().write(slice)?;
Ok(())
} else {
for item in self.iter() {
item.encode(encoder)?;
}
Ok(())
}
}
}
impl<Context> Decode<Context> for String {
fn decode<D: Decoder<Context = Context>>(decoder: &mut D) -> Result<Self, DecodeError> {
let bytes = Vec::<u8>::decode(decoder)?;
String::from_utf8(bytes).map_err(|e| DecodeError::Utf8 {
inner: e.utf8_error(),
})
}
}
impl_borrow_decode!(String);
impl<Context> Decode<Context> for Box<str> {
fn decode<D: Decoder>(decoder: &mut D) -> Result<Self, DecodeError> {
String::decode(decoder).map(String::into_boxed_str)
}
}
impl_borrow_decode!(Box<str>);
impl Encode for String {
fn encode<E: Encoder>(&self, encoder: &mut E) -> Result<(), EncodeError> {
self.as_bytes().encode(encoder)
}
}
impl<Context, T> Decode<Context> for Box<T>
where
T: Decode<Context>,
{
fn decode<D: Decoder<Context = Context>>(decoder: &mut D) -> Result<Self, DecodeError> {
let t = T::decode(decoder)?;
Ok(Box::new(t))
}
}
impl<'de, T, Context> BorrowDecode<'de, Context> for Box<T>
where
T: BorrowDecode<'de, Context>,
{
fn borrow_decode<D: BorrowDecoder<'de, Context = Context>>(
decoder: &mut D,
) -> Result<Self, DecodeError> {
let t = T::borrow_decode(decoder)?;
Ok(Box::new(t))
}
}
impl<T> Encode for Box<T>
where
T: Encode + ?Sized,
{
fn encode<E: Encoder>(&self, encoder: &mut E) -> Result<(), EncodeError> {
T::encode(self, encoder)
}
}
impl<Context, T> Decode<Context> for Box<[T]>
where
T: Decode<Context> + 'static,
{
fn decode<D: Decoder<Context = Context>>(decoder: &mut D) -> Result<Self, DecodeError> {
let vec = Vec::decode(decoder)?;
Ok(vec.into_boxed_slice())
}
}
impl<'de, T, Context> BorrowDecode<'de, Context> for Box<[T]>
where
T: BorrowDecode<'de, Context> + 'de,
{
fn borrow_decode<D: BorrowDecoder<'de, Context = Context>>(
decoder: &mut D,
) -> Result<Self, DecodeError> {
let vec = Vec::borrow_decode(decoder)?;
Ok(vec.into_boxed_slice())
}
}
impl<Context, T> Decode<Context> for Cow<'_, T>
where
T: ToOwned + ?Sized,
<T as ToOwned>::Owned: Decode<Context>,
{
fn decode<D: Decoder<Context = Context>>(decoder: &mut D) -> Result<Self, DecodeError> {
let t = <T as ToOwned>::Owned::decode(decoder)?;
Ok(Cow::Owned(t))
}
}
impl<'cow, T, Context> BorrowDecode<'cow, Context> for Cow<'cow, T>
where
T: ToOwned + ?Sized,
&'cow T: BorrowDecode<'cow, Context>,
{
fn borrow_decode<D: BorrowDecoder<'cow, Context = Context>>(
decoder: &mut D,
) -> Result<Self, DecodeError> {
let t = <&T>::borrow_decode(decoder)?;
Ok(Cow::Borrowed(t))
}
}
impl<T> Encode for Cow<'_, T>
where
T: ToOwned + ?Sized,
for<'a> &'a T: Encode,
{
fn encode<E: Encoder>(&self, encoder: &mut E) -> Result<(), EncodeError> {
self.as_ref().encode(encoder)
}
}
#[test]
fn test_cow_round_trip() {
let start = Cow::Borrowed("Foo");
let encoded = crate::encode_to_vec(&start, crate::config::standard()).unwrap();
let (end, _) =
crate::borrow_decode_from_slice::<Cow<str>, _>(&encoded, crate::config::standard())
.unwrap();
assert_eq!(start, end);
let (end, _) =
crate::decode_from_slice::<Cow<str>, _>(&encoded, crate::config::standard()).unwrap();
assert_eq!(start, end);
}
impl<Context, T> Decode<Context> for Rc<T>
where
T: Decode<Context>,
{
fn decode<D: Decoder<Context = Context>>(decoder: &mut D) -> Result<Self, DecodeError> {
let t = T::decode(decoder)?;
Ok(Rc::new(t))
}
}
impl<Context> Decode<Context> for Rc<str> {
fn decode<D: Decoder<Context = Context>>(decoder: &mut D) -> Result<Self, DecodeError> {
let decoded = String::decode(decoder)?;
Ok(decoded.into())
}
}
impl<'de, T, Context> BorrowDecode<'de, Context> for Rc<T>
where
T: BorrowDecode<'de, Context>,
{
fn borrow_decode<D: BorrowDecoder<'de, Context = Context>>(
decoder: &mut D,
) -> Result<Self, DecodeError> {
let t = T::borrow_decode(decoder)?;
Ok(Rc::new(t))
}
}
impl<'de, Context> BorrowDecode<'de, Context> for Rc<str> {
fn borrow_decode<D: BorrowDecoder<'de, Context = Context>>(
decoder: &mut D,
) -> Result<Self, DecodeError> {
let decoded = String::decode(decoder)?;
Ok(decoded.into())
}
}
impl<T> Encode for Rc<T>
where
T: Encode + ?Sized,
{
fn encode<E: Encoder>(&self, encoder: &mut E) -> Result<(), EncodeError> {
T::encode(self, encoder)
}
}
impl<Context, T> Decode<Context> for Rc<[T]>
where
T: Decode<Context> + 'static,
{
fn decode<D: Decoder<Context = Context>>(decoder: &mut D) -> Result<Self, DecodeError> {
let vec = Vec::decode(decoder)?;
Ok(vec.into())
}
}
impl<'de, T, Context> BorrowDecode<'de, Context> for Rc<[T]>
where
T: BorrowDecode<'de, Context> + 'de,
{
fn borrow_decode<D: BorrowDecoder<'de, Context = Context>>(
decoder: &mut D,
) -> Result<Self, DecodeError> {
let vec = Vec::borrow_decode(decoder)?;
Ok(vec.into())
}
}
#[cfg(target_has_atomic = "ptr")]
impl<Context, T> Decode<Context> for Arc<T>
where
T: Decode<Context>,
{
fn decode<D: Decoder<Context = Context>>(decoder: &mut D) -> Result<Self, DecodeError> {
let t = T::decode(decoder)?;
Ok(Arc::new(t))
}
}
#[cfg(target_has_atomic = "ptr")]
impl<Context> Decode<Context> for Arc<str> {
fn decode<D: Decoder<Context = Context>>(decoder: &mut D) -> Result<Self, DecodeError> {
let decoded = String::decode(decoder)?;
Ok(decoded.into())
}
}
#[cfg(target_has_atomic = "ptr")]
impl<'de, T, Context> BorrowDecode<'de, Context> for Arc<T>
where
T: BorrowDecode<'de, Context>,
{
fn borrow_decode<D: BorrowDecoder<'de, Context = Context>>(
decoder: &mut D,
) -> Result<Self, DecodeError> {
let t = T::borrow_decode(decoder)?;
Ok(Arc::new(t))
}
}
#[cfg(target_has_atomic = "ptr")]
impl<'de, Context> BorrowDecode<'de, Context> for Arc<str> {
fn borrow_decode<D: BorrowDecoder<'de, Context = Context>>(
decoder: &mut D,
) -> Result<Self, DecodeError> {
let decoded = String::decode(decoder)?;
Ok(decoded.into())
}
}
#[cfg(target_has_atomic = "ptr")]
impl<T> Encode for Arc<T>
where
T: Encode + ?Sized,
{
fn encode<E: Encoder>(&self, encoder: &mut E) -> Result<(), EncodeError> {
T::encode(self, encoder)
}
}
#[cfg(target_has_atomic = "ptr")]
impl<Context, T> Decode<Context> for Arc<[T]>
where
T: Decode<Context> + 'static,
{
fn decode<D: Decoder<Context = Context>>(decoder: &mut D) -> Result<Self, DecodeError> {
let vec = Vec::decode(decoder)?;
Ok(vec.into())
}
}
#[cfg(target_has_atomic = "ptr")]
impl<'de, T, Context> BorrowDecode<'de, Context> for Arc<[T]>
where
T: BorrowDecode<'de, Context> + 'de,
{
fn borrow_decode<D: BorrowDecoder<'de, Context = Context>>(
decoder: &mut D,
) -> Result<Self, DecodeError> {
let vec = Vec::borrow_decode(decoder)?;
Ok(vec.into())
}
}

View File

@ -1,535 +0,0 @@
use crate::{
config::Config,
de::{read::Reader, BorrowDecode, BorrowDecoder, Decode, Decoder, DecoderImpl},
enc::{write::Writer, Encode, Encoder, EncoderImpl},
error::{DecodeError, EncodeError},
impl_borrow_decode,
};
use core::time::Duration;
use std::{
collections::{HashMap, HashSet},
ffi::{CStr, CString},
hash::Hash,
io::Read,
net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6},
path::{Path, PathBuf},
sync::{Mutex, RwLock},
time::SystemTime,
};
/// Decode type `D` from the given reader with the given `Config`. The reader can be any type that implements `std::io::Read`, e.g. `std::fs::File`.
///
/// See the [config] module for more information about config options.
///
/// [config]: config/index.html
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
pub fn decode_from_std_read<D: Decode<()>, C: Config, R: std::io::Read>(
src: &mut R,
config: C,
) -> Result<D, DecodeError> {
decode_from_std_read_with_context(src, config, ())
}
/// Decode type `D` from the given reader with the given `Config` and `Context`. The reader can be any type that implements `std::io::Read`, e.g. `std::fs::File`.
///
/// See the [config] module for more information about config options.
///
/// [config]: config/index.html
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
pub fn decode_from_std_read_with_context<
Context,
D: Decode<Context>,
C: Config,
R: std::io::Read,
>(
src: &mut R,
config: C,
context: Context,
) -> Result<D, DecodeError> {
let reader = IoReader::new(src);
let mut decoder = DecoderImpl::<_, C, Context>::new(reader, config, context);
D::decode(&mut decoder)
}
pub(crate) struct IoReader<R> {
reader: R,
}
impl<R> IoReader<R> {
pub const fn new(reader: R) -> Self {
Self { reader }
}
}
impl<R> Reader for IoReader<R>
where
R: std::io::Read,
{
#[inline(always)]
fn read(&mut self, bytes: &mut [u8]) -> Result<(), DecodeError> {
self.reader
.read_exact(bytes)
.map_err(|inner| DecodeError::Io {
inner,
additional: bytes.len(),
})
}
}
impl<R> Reader for std::io::BufReader<R>
where
R: std::io::Read,
{
fn read(&mut self, bytes: &mut [u8]) -> Result<(), DecodeError> {
self.read_exact(bytes).map_err(|inner| DecodeError::Io {
inner,
additional: bytes.len(),
})
}
#[inline]
fn peek_read(&mut self, n: usize) -> Option<&[u8]> {
self.buffer().get(..n)
}
#[inline]
fn consume(&mut self, n: usize) {
<Self as std::io::BufRead>::consume(self, n);
}
}
/// Encode the given value into any type that implements `std::io::Write`, e.g. `std::fs::File`, with the given `Config`.
/// See the [config] module for more information.
/// Returns the amount of bytes written.
///
/// [config]: config/index.html
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
pub fn encode_into_std_write<E: Encode, C: Config, W: std::io::Write>(
val: E,
dst: &mut W,
config: C,
) -> Result<usize, EncodeError> {
let writer = IoWriter::new(dst);
let mut encoder = EncoderImpl::<_, C>::new(writer, config);
val.encode(&mut encoder)?;
Ok(encoder.into_writer().bytes_written())
}
pub(crate) struct IoWriter<'a, W: std::io::Write> {
writer: &'a mut W,
bytes_written: usize,
}
impl<'a, W: std::io::Write> IoWriter<'a, W> {
pub fn new(writer: &'a mut W) -> Self {
Self {
writer,
bytes_written: 0,
}
}
pub const fn bytes_written(&self) -> usize {
self.bytes_written
}
}
impl<W: std::io::Write> Writer for IoWriter<'_, W> {
#[inline(always)]
fn write(&mut self, bytes: &[u8]) -> Result<(), EncodeError> {
self.writer
.write_all(bytes)
.map_err(|inner| EncodeError::Io {
inner,
index: self.bytes_written,
})?;
self.bytes_written += bytes.len();
Ok(())
}
}
impl Encode for &CStr {
fn encode<E: Encoder>(&self, encoder: &mut E) -> Result<(), EncodeError> {
self.to_bytes().encode(encoder)
}
}
impl Encode for CString {
fn encode<E: Encoder>(&self, encoder: &mut E) -> Result<(), EncodeError> {
self.as_bytes().encode(encoder)
}
}
impl<Context> Decode<Context> for CString {
fn decode<D: Decoder<Context = Context>>(decoder: &mut D) -> Result<Self, DecodeError> {
let vec = std::vec::Vec::decode(decoder)?;
CString::new(vec).map_err(|inner| DecodeError::CStringNulError {
position: inner.nul_position(),
})
}
}
impl_borrow_decode!(CString);
impl<T> Encode for Mutex<T>
where
T: Encode,
{
fn encode<E: Encoder>(&self, encoder: &mut E) -> Result<(), EncodeError> {
let t = self.lock().map_err(|_| EncodeError::LockFailed {
type_name: core::any::type_name::<Mutex<T>>(),
})?;
t.encode(encoder)
}
}
impl<Context, T> Decode<Context> for Mutex<T>
where
T: Decode<Context>,
{
fn decode<D: Decoder<Context = Context>>(decoder: &mut D) -> Result<Self, DecodeError> {
let t = T::decode(decoder)?;
Ok(Mutex::new(t))
}
}
impl<'de, T, Context> BorrowDecode<'de, Context> for Mutex<T>
where
T: BorrowDecode<'de, Context>,
{
fn borrow_decode<D: BorrowDecoder<'de, Context = Context>>(
decoder: &mut D,
) -> Result<Self, DecodeError> {
let t = T::borrow_decode(decoder)?;
Ok(Mutex::new(t))
}
}
impl<T> Encode for RwLock<T>
where
T: Encode,
{
fn encode<E: Encoder>(&self, encoder: &mut E) -> Result<(), EncodeError> {
let t = self.read().map_err(|_| EncodeError::LockFailed {
type_name: core::any::type_name::<RwLock<T>>(),
})?;
t.encode(encoder)
}
}
impl<Context, T> Decode<Context> for RwLock<T>
where
T: Decode<Context>,
{
fn decode<D: Decoder<Context = Context>>(decoder: &mut D) -> Result<Self, DecodeError> {
let t = T::decode(decoder)?;
Ok(RwLock::new(t))
}
}
impl<'de, T, Context> BorrowDecode<'de, Context> for RwLock<T>
where
T: BorrowDecode<'de, Context>,
{
fn borrow_decode<D: BorrowDecoder<'de, Context = Context>>(
decoder: &mut D,
) -> Result<Self, DecodeError> {
let t = T::borrow_decode(decoder)?;
Ok(RwLock::new(t))
}
}
impl Encode for SystemTime {
fn encode<E: Encoder>(&self, encoder: &mut E) -> Result<(), EncodeError> {
let duration = self.duration_since(SystemTime::UNIX_EPOCH).map_err(|e| {
EncodeError::InvalidSystemTime {
inner: e,
time: std::boxed::Box::new(*self),
}
})?;
duration.encode(encoder)
}
}
impl<Context> Decode<Context> for SystemTime {
fn decode<D: Decoder<Context = Context>>(decoder: &mut D) -> Result<Self, DecodeError> {
let duration = Duration::decode(decoder)?;
match SystemTime::UNIX_EPOCH.checked_add(duration) {
Some(t) => Ok(t),
None => Err(DecodeError::InvalidSystemTime { duration }),
}
}
}
impl_borrow_decode!(SystemTime);
impl Encode for &'_ Path {
fn encode<E: Encoder>(&self, encoder: &mut E) -> Result<(), EncodeError> {
match self.to_str() {
Some(str) => str.encode(encoder),
None => Err(EncodeError::InvalidPathCharacters),
}
}
}
impl<'de, Context> BorrowDecode<'de, Context> for &'de Path {
fn borrow_decode<D: BorrowDecoder<'de, Context = Context>>(
decoder: &mut D,
) -> Result<Self, DecodeError> {
let str = <&'de str>::borrow_decode(decoder)?;
Ok(Path::new(str))
}
}
impl Encode for PathBuf {
fn encode<E: Encoder>(&self, encoder: &mut E) -> Result<(), EncodeError> {
self.as_path().encode(encoder)
}
}
impl<Context> Decode<Context> for PathBuf {
fn decode<D: Decoder<Context = Context>>(decoder: &mut D) -> Result<Self, DecodeError> {
let string = std::string::String::decode(decoder)?;
Ok(string.into())
}
}
impl_borrow_decode!(PathBuf);
impl Encode for IpAddr {
fn encode<E: Encoder>(&self, encoder: &mut E) -> Result<(), EncodeError> {
match self {
IpAddr::V4(v4) => {
0u32.encode(encoder)?;
v4.encode(encoder)
}
IpAddr::V6(v6) => {
1u32.encode(encoder)?;
v6.encode(encoder)
}
}
}
}
impl<Context> Decode<Context> for IpAddr {
fn decode<D: Decoder<Context = Context>>(decoder: &mut D) -> Result<Self, DecodeError> {
match u32::decode(decoder)? {
0 => Ok(IpAddr::V4(Ipv4Addr::decode(decoder)?)),
1 => Ok(IpAddr::V6(Ipv6Addr::decode(decoder)?)),
found => Err(DecodeError::UnexpectedVariant {
allowed: &crate::error::AllowedEnumVariants::Range { min: 0, max: 1 },
found,
type_name: core::any::type_name::<IpAddr>(),
}),
}
}
}
impl_borrow_decode!(IpAddr);
impl Encode for Ipv4Addr {
fn encode<E: Encoder>(&self, encoder: &mut E) -> Result<(), EncodeError> {
encoder.writer().write(&self.octets())
}
}
impl<Context> Decode<Context> for Ipv4Addr {
fn decode<D: Decoder<Context = Context>>(decoder: &mut D) -> Result<Self, DecodeError> {
let mut buff = [0u8; 4];
decoder.reader().read(&mut buff)?;
Ok(Self::from(buff))
}
}
impl_borrow_decode!(Ipv4Addr);
impl Encode for Ipv6Addr {
fn encode<E: Encoder>(&self, encoder: &mut E) -> Result<(), EncodeError> {
encoder.writer().write(&self.octets())
}
}
impl<Context> Decode<Context> for Ipv6Addr {
fn decode<D: Decoder<Context = Context>>(decoder: &mut D) -> Result<Self, DecodeError> {
let mut buff = [0u8; 16];
decoder.reader().read(&mut buff)?;
Ok(Self::from(buff))
}
}
impl_borrow_decode!(Ipv6Addr);
impl Encode for SocketAddr {
fn encode<E: Encoder>(&self, encoder: &mut E) -> Result<(), EncodeError> {
match self {
SocketAddr::V4(v4) => {
0u32.encode(encoder)?;
v4.encode(encoder)
}
SocketAddr::V6(v6) => {
1u32.encode(encoder)?;
v6.encode(encoder)
}
}
}
}
impl<Context> Decode<Context> for SocketAddr {
fn decode<D: Decoder<Context = Context>>(decoder: &mut D) -> Result<Self, DecodeError> {
match u32::decode(decoder)? {
0 => Ok(SocketAddr::V4(SocketAddrV4::decode(decoder)?)),
1 => Ok(SocketAddr::V6(SocketAddrV6::decode(decoder)?)),
found => Err(DecodeError::UnexpectedVariant {
allowed: &crate::error::AllowedEnumVariants::Range { min: 0, max: 1 },
found,
type_name: core::any::type_name::<SocketAddr>(),
}),
}
}
}
impl_borrow_decode!(SocketAddr);
impl Encode for SocketAddrV4 {
fn encode<E: Encoder>(&self, encoder: &mut E) -> Result<(), EncodeError> {
self.ip().encode(encoder)?;
self.port().encode(encoder)
}
}
impl<Context> Decode<Context> for SocketAddrV4 {
fn decode<D: Decoder<Context = Context>>(decoder: &mut D) -> Result<Self, DecodeError> {
let ip = Ipv4Addr::decode(decoder)?;
let port = u16::decode(decoder)?;
Ok(Self::new(ip, port))
}
}
impl_borrow_decode!(SocketAddrV4);
impl Encode for SocketAddrV6 {
fn encode<E: Encoder>(&self, encoder: &mut E) -> Result<(), EncodeError> {
self.ip().encode(encoder)?;
self.port().encode(encoder)
}
}
impl<Context> Decode<Context> for SocketAddrV6 {
fn decode<D: Decoder<Context = Context>>(decoder: &mut D) -> Result<Self, DecodeError> {
let ip = Ipv6Addr::decode(decoder)?;
let port = u16::decode(decoder)?;
Ok(Self::new(ip, port, 0, 0))
}
}
impl_borrow_decode!(SocketAddrV6);
impl<K, V, S> Encode for HashMap<K, V, S>
where
K: Encode,
V: Encode,
{
fn encode<E: Encoder>(&self, encoder: &mut E) -> Result<(), EncodeError> {
crate::enc::encode_slice_len(encoder, self.len())?;
for (k, v) in self.iter() {
Encode::encode(k, encoder)?;
Encode::encode(v, encoder)?;
}
Ok(())
}
}
impl<Context, K, V, S> Decode<Context> for HashMap<K, V, S>
where
K: Decode<Context> + Eq + std::hash::Hash,
V: Decode<Context>,
S: std::hash::BuildHasher + Default,
{
fn decode<D: Decoder<Context = Context>>(decoder: &mut D) -> Result<Self, DecodeError> {
let len = crate::de::decode_slice_len(decoder)?;
decoder.claim_container_read::<(K, V)>(len)?;
let hash_builder: S = Default::default();
let mut map = HashMap::with_capacity_and_hasher(len, hash_builder);
for _ in 0..len {
// See the documentation on `unclaim_bytes_read` as to why we're doing this here
decoder.unclaim_bytes_read(core::mem::size_of::<(K, V)>());
let k = K::decode(decoder)?;
let v = V::decode(decoder)?;
map.insert(k, v);
}
Ok(map)
}
}
impl<'de, K, V, S, Context> BorrowDecode<'de, Context> for HashMap<K, V, S>
where
K: BorrowDecode<'de, Context> + Eq + std::hash::Hash,
V: BorrowDecode<'de, Context>,
S: std::hash::BuildHasher + Default,
{
fn borrow_decode<D: BorrowDecoder<'de, Context = Context>>(
decoder: &mut D,
) -> Result<Self, DecodeError> {
let len = crate::de::decode_slice_len(decoder)?;
decoder.claim_container_read::<(K, V)>(len)?;
let hash_builder: S = Default::default();
let mut map = HashMap::with_capacity_and_hasher(len, hash_builder);
for _ in 0..len {
// See the documentation on `unclaim_bytes_read` as to why we're doing this here
decoder.unclaim_bytes_read(core::mem::size_of::<(K, V)>());
let k = K::borrow_decode(decoder)?;
let v = V::borrow_decode(decoder)?;
map.insert(k, v);
}
Ok(map)
}
}
impl<Context, T, S> Decode<Context> for HashSet<T, S>
where
T: Decode<Context> + Eq + Hash,
S: std::hash::BuildHasher + Default,
{
fn decode<D: Decoder<Context = Context>>(decoder: &mut D) -> Result<Self, DecodeError> {
let len = crate::de::decode_slice_len(decoder)?;
decoder.claim_container_read::<T>(len)?;
let hash_builder: S = Default::default();
let mut map: HashSet<T, S> = HashSet::with_capacity_and_hasher(len, hash_builder);
for _ in 0..len {
// See the documentation on `unclaim_bytes_read` as to why we're doing this here
decoder.unclaim_bytes_read(core::mem::size_of::<T>());
let key = T::decode(decoder)?;
map.insert(key);
}
Ok(map)
}
}
impl<'de, T, S, Context> BorrowDecode<'de, Context> for HashSet<T, S>
where
T: BorrowDecode<'de, Context> + Eq + Hash,
S: std::hash::BuildHasher + Default,
{
fn borrow_decode<D: BorrowDecoder<'de, Context = Context>>(
decoder: &mut D,
) -> Result<Self, DecodeError> {
let len = crate::de::decode_slice_len(decoder)?;
decoder.claim_container_read::<T>(len)?;
let mut map = HashSet::with_capacity_and_hasher(len, S::default());
for _ in 0..len {
// See the documentation on `unclaim_bytes_read` as to why we're doing this here
decoder.unclaim_bytes_read(core::mem::size_of::<T>());
let key = T::borrow_decode(decoder)?;
map.insert(key);
}
Ok(map)
}
}
impl<T, S> Encode for HashSet<T, S>
where
T: Encode,
{
fn encode<E: Encoder>(&self, encoder: &mut E) -> Result<(), EncodeError> {
crate::enc::encode_slice_len(encoder, self.len())?;
for item in self.iter() {
item.encode(encoder)?;
}
Ok(())
}
}

View File

@ -1,18 +0,0 @@
#[cfg(feature = "alloc")]
mod impl_alloc;
#[cfg(feature = "alloc")]
pub use self::impl_alloc::*;
#[cfg(feature = "std")]
mod impl_std;
#[cfg(feature = "std")]
pub use self::impl_std::*;
#[cfg(feature = "derive")]
mod derive;
#[cfg(feature = "derive")]
pub use self::derive::*;
#[cfg(feature = "serde")]
#[cfg_attr(docsrs, doc(cfg(feature = "serde")))]
pub mod serde;

View File

@ -1,496 +0,0 @@
use super::DecodeError as SerdeDecodeError;
use crate::{
config::Config,
de::{read::SliceReader, BorrowDecode, BorrowDecoder, Decode, DecoderImpl},
error::DecodeError,
};
use core::marker::PhantomData;
use serde::de::*;
/// Serde decoder encapsulating a borrowed reader.
pub struct BorrowedSerdeDecoder<'de, DE: BorrowDecoder<'de>> {
pub(super) de: DE,
pub(super) pd: PhantomData<&'de ()>,
}
impl<'de, DE: BorrowDecoder<'de>> BorrowedSerdeDecoder<'de, DE> {
/// Return a type implementing `serde::Deserializer`.
pub fn as_deserializer<'a>(
&'a mut self,
) -> impl serde::Deserializer<'de, Error = DecodeError> + 'a {
SerdeDecoder {
de: &mut self.de,
pd: PhantomData,
}
}
}
impl<'de, C: Config, Context> BorrowedSerdeDecoder<'de, DecoderImpl<SliceReader<'de>, C, Context>> {
/// Creates the decoder from a borrowed slice.
pub fn from_slice(
slice: &'de [u8],
config: C,
context: Context,
) -> BorrowedSerdeDecoder<'de, DecoderImpl<SliceReader<'de>, C, Context>>
where
C: Config,
{
let reader = SliceReader::new(slice);
let decoder = DecoderImpl::new(reader, config, context);
Self {
de: decoder,
pd: PhantomData,
}
}
}
/// Attempt to decode a given type `D` from the given slice. Returns the decoded output and the amount of bytes read.
///
/// See the [config](../config/index.html) module for more information on configurations.
pub fn borrow_decode_from_slice<'de, D, C>(
slice: &'de [u8],
config: C,
) -> Result<(D, usize), DecodeError>
where
D: Deserialize<'de>,
C: Config,
{
let mut serde_decoder =
BorrowedSerdeDecoder::<DecoderImpl<SliceReader<'de>, C, ()>>::from_slice(slice, config, ());
let result = D::deserialize(serde_decoder.as_deserializer())?;
let bytes_read = slice.len() - serde_decoder.de.borrow_reader().slice.len();
Ok((result, bytes_read))
}
/// Decode a borrowed type from the given slice using a seed. Some parts of the decoded type are expected to be referring to the given slice
pub fn seed_decode_from_slice<'de, D, C>(
seed: D,
slice: &'de [u8],
config: C,
) -> Result<(D::Value, usize), DecodeError>
where
D: DeserializeSeed<'de>,
C: Config,
{
let mut serde_decoder =
BorrowedSerdeDecoder::<DecoderImpl<SliceReader<'de>, C, ()>>::from_slice(slice, config, ());
let result = seed.deserialize(serde_decoder.as_deserializer())?;
let bytes_read = slice.len() - serde_decoder.de.borrow_reader().slice.len();
Ok((result, bytes_read))
}
pub(super) struct SerdeDecoder<'a, 'de, DE: BorrowDecoder<'de>> {
pub(super) de: &'a mut DE,
pub(super) pd: PhantomData<&'de ()>,
}
impl<'de, DE: BorrowDecoder<'de>> Deserializer<'de> for SerdeDecoder<'_, 'de, DE> {
type Error = DecodeError;
fn deserialize_any<V>(self, _: V) -> Result<V::Value, Self::Error>
where
V: serde::de::Visitor<'de>,
{
Err(SerdeDecodeError::AnyNotSupported.into())
}
fn deserialize_bool<V>(mut self, visitor: V) -> Result<V::Value, Self::Error>
where
V: serde::de::Visitor<'de>,
{
visitor.visit_bool(Decode::decode(&mut self.de)?)
}
fn deserialize_i8<V>(mut self, visitor: V) -> Result<V::Value, Self::Error>
where
V: serde::de::Visitor<'de>,
{
visitor.visit_i8(Decode::decode(&mut self.de)?)
}
fn deserialize_i16<V>(mut self, visitor: V) -> Result<V::Value, Self::Error>
where
V: serde::de::Visitor<'de>,
{
visitor.visit_i16(Decode::decode(&mut self.de)?)
}
fn deserialize_i32<V>(mut self, visitor: V) -> Result<V::Value, Self::Error>
where
V: serde::de::Visitor<'de>,
{
visitor.visit_i32(Decode::decode(&mut self.de)?)
}
fn deserialize_i64<V>(mut self, visitor: V) -> Result<V::Value, Self::Error>
where
V: serde::de::Visitor<'de>,
{
visitor.visit_i64(Decode::decode(&mut self.de)?)
}
serde::serde_if_integer128! {
fn deserialize_i128<V>(mut self, visitor: V) -> Result<V::Value, Self::Error>
where
V: serde::de::Visitor<'de>,
{
visitor.visit_i128(Decode::decode(&mut self.de)?)
}
}
fn deserialize_u8<V>(mut self, visitor: V) -> Result<V::Value, Self::Error>
where
V: serde::de::Visitor<'de>,
{
visitor.visit_u8(Decode::decode(&mut self.de)?)
}
fn deserialize_u16<V>(mut self, visitor: V) -> Result<V::Value, Self::Error>
where
V: serde::de::Visitor<'de>,
{
visitor.visit_u16(Decode::decode(&mut self.de)?)
}
fn deserialize_u32<V>(mut self, visitor: V) -> Result<V::Value, Self::Error>
where
V: serde::de::Visitor<'de>,
{
visitor.visit_u32(Decode::decode(&mut self.de)?)
}
fn deserialize_u64<V>(mut self, visitor: V) -> Result<V::Value, Self::Error>
where
V: serde::de::Visitor<'de>,
{
visitor.visit_u64(Decode::decode(&mut self.de)?)
}
serde::serde_if_integer128! {
fn deserialize_u128<V>(mut self, visitor: V) -> Result<V::Value, Self::Error>
where
V: serde::de::Visitor<'de>,
{
visitor.visit_u128(Decode::decode(&mut self.de)?)
}
}
fn deserialize_f32<V>(mut self, visitor: V) -> Result<V::Value, Self::Error>
where
V: serde::de::Visitor<'de>,
{
visitor.visit_f32(Decode::decode(&mut self.de)?)
}
fn deserialize_f64<V>(mut self, visitor: V) -> Result<V::Value, Self::Error>
where
V: serde::de::Visitor<'de>,
{
visitor.visit_f64(Decode::decode(&mut self.de)?)
}
fn deserialize_char<V>(mut self, visitor: V) -> Result<V::Value, Self::Error>
where
V: serde::de::Visitor<'de>,
{
visitor.visit_char(Decode::decode(&mut self.de)?)
}
fn deserialize_str<V>(mut self, visitor: V) -> Result<V::Value, Self::Error>
where
V: serde::de::Visitor<'de>,
{
let str = <&'de str>::borrow_decode(&mut self.de)?;
visitor.visit_borrowed_str(str)
}
#[cfg(not(feature = "alloc"))]
fn deserialize_string<V>(self, _: V) -> Result<V::Value, Self::Error>
where
V: serde::de::Visitor<'de>,
{
Err(SerdeDecodeError::CannotBorrowOwnedData.into())
}
#[cfg(feature = "alloc")]
fn deserialize_string<V>(mut self, visitor: V) -> Result<V::Value, Self::Error>
where
V: serde::de::Visitor<'de>,
{
visitor.visit_string(Decode::decode(&mut self.de)?)
}
fn deserialize_bytes<V>(mut self, visitor: V) -> Result<V::Value, Self::Error>
where
V: serde::de::Visitor<'de>,
{
let bytes = <&'de [u8]>::borrow_decode(&mut self.de)?;
visitor.visit_borrowed_bytes(bytes)
}
#[cfg(not(feature = "alloc"))]
fn deserialize_byte_buf<V>(self, _: V) -> Result<V::Value, Self::Error>
where
V: serde::de::Visitor<'de>,
{
Err(SerdeDecodeError::CannotBorrowOwnedData.into())
}
#[cfg(feature = "alloc")]
fn deserialize_byte_buf<V>(mut self, visitor: V) -> Result<V::Value, Self::Error>
where
V: serde::de::Visitor<'de>,
{
visitor.visit_byte_buf(Decode::decode(&mut self.de)?)
}
fn deserialize_option<V>(mut self, visitor: V) -> Result<V::Value, Self::Error>
where
V: serde::de::Visitor<'de>,
{
let variant = crate::de::decode_option_variant(&mut self.de, "Option<T>")?;
if variant.is_some() {
visitor.visit_some(self)
} else {
visitor.visit_none()
}
}
fn deserialize_unit<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: serde::de::Visitor<'de>,
{
visitor.visit_unit()
}
fn deserialize_unit_struct<V>(
self,
_name: &'static str,
visitor: V,
) -> Result<V::Value, Self::Error>
where
V: serde::de::Visitor<'de>,
{
visitor.visit_unit()
}
fn deserialize_newtype_struct<V>(
self,
_name: &'static str,
visitor: V,
) -> Result<V::Value, Self::Error>
where
V: serde::de::Visitor<'de>,
{
visitor.visit_newtype_struct(self)
}
fn deserialize_seq<V>(mut self, visitor: V) -> Result<V::Value, Self::Error>
where
V: serde::de::Visitor<'de>,
{
let len = usize::decode(&mut self.de)?;
self.deserialize_tuple(len, visitor)
}
fn deserialize_tuple<V>(mut self, len: usize, visitor: V) -> Result<V::Value, Self::Error>
where
V: serde::de::Visitor<'de>,
{
struct Access<'a, 'b, 'de, DE: BorrowDecoder<'de>> {
deserializer: &'a mut SerdeDecoder<'b, 'de, DE>,
len: usize,
}
impl<'de, 'a, 'b: 'a, DE: BorrowDecoder<'de> + 'b> SeqAccess<'de> for Access<'a, 'b, 'de, DE> {
type Error = DecodeError;
fn next_element_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>, DecodeError>
where
T: DeserializeSeed<'de>,
{
if self.len > 0 {
self.len -= 1;
let value = DeserializeSeed::deserialize(
seed,
SerdeDecoder {
de: self.deserializer.de,
pd: PhantomData,
},
)?;
Ok(Some(value))
} else {
Ok(None)
}
}
fn size_hint(&self) -> Option<usize> {
Some(self.len)
}
}
visitor.visit_seq(Access {
deserializer: &mut self,
len,
})
}
fn deserialize_tuple_struct<V>(
self,
_name: &'static str,
len: usize,
visitor: V,
) -> Result<V::Value, Self::Error>
where
V: serde::de::Visitor<'de>,
{
self.deserialize_tuple(len, visitor)
}
fn deserialize_map<V>(mut self, visitor: V) -> Result<V::Value, Self::Error>
where
V: serde::de::Visitor<'de>,
{
struct Access<'a, 'b, 'de, DE: BorrowDecoder<'de>> {
deserializer: &'a mut SerdeDecoder<'b, 'de, DE>,
len: usize,
}
impl<'de, 'a, 'b: 'a, DE: BorrowDecoder<'de> + 'b> MapAccess<'de> for Access<'a, 'b, 'de, DE> {
type Error = DecodeError;
fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>, DecodeError>
where
K: DeserializeSeed<'de>,
{
if self.len > 0 {
self.len -= 1;
let key = DeserializeSeed::deserialize(
seed,
SerdeDecoder {
de: self.deserializer.de,
pd: PhantomData,
},
)?;
Ok(Some(key))
} else {
Ok(None)
}
}
fn next_value_seed<V>(&mut self, seed: V) -> Result<V::Value, DecodeError>
where
V: DeserializeSeed<'de>,
{
let value = DeserializeSeed::deserialize(
seed,
SerdeDecoder {
de: self.deserializer.de,
pd: PhantomData,
},
)?;
Ok(value)
}
fn size_hint(&self) -> Option<usize> {
Some(self.len)
}
}
let len = usize::decode(&mut self.de)?;
visitor.visit_map(Access {
deserializer: &mut self,
len,
})
}
fn deserialize_struct<V>(
self,
_name: &'static str,
fields: &'static [&'static str],
visitor: V,
) -> Result<V::Value, Self::Error>
where
V: serde::de::Visitor<'de>,
{
self.deserialize_tuple(fields.len(), visitor)
}
fn deserialize_enum<V>(
self,
_name: &'static str,
_variants: &'static [&'static str],
visitor: V,
) -> Result<V::Value, Self::Error>
where
V: serde::de::Visitor<'de>,
{
visitor.visit_enum(self)
}
fn deserialize_identifier<V>(self, _visitor: V) -> Result<V::Value, Self::Error>
where
V: serde::de::Visitor<'de>,
{
Err(SerdeDecodeError::IdentifierNotSupported.into())
}
fn deserialize_ignored_any<V>(self, _: V) -> Result<V::Value, Self::Error>
where
V: serde::de::Visitor<'de>,
{
Err(SerdeDecodeError::IgnoredAnyNotSupported.into())
}
fn is_human_readable(&self) -> bool {
false
}
}
impl<'de, DE: BorrowDecoder<'de>> EnumAccess<'de> for SerdeDecoder<'_, 'de, DE> {
type Error = DecodeError;
type Variant = Self;
fn variant_seed<V>(mut self, seed: V) -> Result<(V::Value, Self::Variant), Self::Error>
where
V: DeserializeSeed<'de>,
{
let idx = u32::decode(&mut self.de)?;
let val = seed.deserialize(idx.into_deserializer())?;
Ok((val, self))
}
}
impl<'de, DE: BorrowDecoder<'de>> VariantAccess<'de> for SerdeDecoder<'_, 'de, DE> {
type Error = DecodeError;
fn unit_variant(self) -> Result<(), Self::Error> {
Ok(())
}
fn newtype_variant_seed<T>(self, seed: T) -> Result<T::Value, Self::Error>
where
T: DeserializeSeed<'de>,
{
DeserializeSeed::deserialize(seed, self)
}
fn tuple_variant<V>(self, len: usize, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
Deserializer::deserialize_tuple(self, len, visitor)
}
fn struct_variant<V>(
self,
fields: &'static [&'static str],
visitor: V,
) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
Deserializer::deserialize_tuple(self, fields.len(), visitor)
}
}

View File

@ -1,545 +0,0 @@
use super::{de_borrowed::borrow_decode_from_slice, DecodeError as SerdeDecodeError};
use crate::{
config::Config,
de::{read::Reader, Decode, Decoder, DecoderImpl},
error::DecodeError,
};
use serde::de::*;
#[cfg(feature = "std")]
use crate::features::IoReader;
/// Serde decoder encapsulating an owned reader.
pub struct OwnedSerdeDecoder<DE: Decoder> {
pub(super) de: DE,
}
impl<DE: Decoder> OwnedSerdeDecoder<DE> {
/// Return a type implementing `serde::Deserializer`.
pub fn as_deserializer<'a>(
&'a mut self,
) -> impl for<'de> serde::Deserializer<'de, Error = DecodeError> + 'a {
SerdeDecoder { de: &mut self.de }
}
}
#[cfg(feature = "std")]
impl<'r, C: Config, R: std::io::Read> OwnedSerdeDecoder<DecoderImpl<IoReader<&'r mut R>, C, ()>> {
/// Creates the decoder from an `std::io::Read` implementor.
pub fn from_std_read(
src: &'r mut R,
config: C,
) -> OwnedSerdeDecoder<DecoderImpl<IoReader<&'r mut R>, C, ()>>
where
C: Config,
{
let reader = IoReader::new(src);
let decoder = DecoderImpl::new(reader, config, ());
Self { de: decoder }
}
}
impl<C: Config, R: Reader> OwnedSerdeDecoder<DecoderImpl<R, C, ()>> {
/// Creates the decoder from a [`Reader`] implementor.
pub fn from_reader(reader: R, config: C) -> OwnedSerdeDecoder<DecoderImpl<R, C, ()>>
where
C: Config,
{
let decoder = DecoderImpl::new(reader, config, ());
Self { de: decoder }
}
}
/// Attempt to decode a given type `D` from the given slice. Returns the decoded output and the amount of bytes read.
///
/// Note that this does not work with borrowed types like `&str` or `&[u8]`. For that use [borrow_decode_from_slice].
///
/// See the [config] module for more information on configurations.
///
/// [borrow_decode_from_slice]: fn.borrow_decode_from_slice.html
/// [config]: ../config/index.html
pub fn decode_from_slice<D, C>(slice: &[u8], config: C) -> Result<(D, usize), DecodeError>
where
D: DeserializeOwned,
C: Config,
{
borrow_decode_from_slice(slice, config)
}
/// Decode type `D` from the given reader with the given `Config`. The reader can be any type that implements `std::io::Read`, e.g. `std::fs::File`.
///
/// See the [config] module for more information about config options.
///
/// [config]: ../config/index.html
#[cfg(feature = "std")]
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
pub fn decode_from_std_read<'r, D: DeserializeOwned, C: Config, R: std::io::Read>(
src: &'r mut R,
config: C,
) -> Result<D, DecodeError> {
let mut serde_decoder =
OwnedSerdeDecoder::<DecoderImpl<IoReader<&'r mut R>, C, ()>>::from_std_read(src, config);
D::deserialize(serde_decoder.as_deserializer())
}
/// Attempt to decode a given type `D` from the given [Reader].
///
/// See the [config] module for more information on configurations.
///
/// [config]: ../config/index.html
pub fn decode_from_reader<D: DeserializeOwned, R: Reader, C: Config>(
reader: R,
config: C,
) -> Result<D, DecodeError> {
let mut serde_decoder = OwnedSerdeDecoder::<DecoderImpl<R, C, ()>>::from_reader(reader, config);
D::deserialize(serde_decoder.as_deserializer())
}
/// Decode from the given reader with the given `Config` using a seed. The reader can be any type that implements `std::io::Read`, e.g. `std::fs::File`.
///
/// See the [config] module for more information about config options.
///
/// [config]: ../config/index.html
#[cfg(feature = "std")]
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
pub fn seed_decode_from_std_read<'de, 'r, D, C, R>(
seed: D,
src: &'r mut R,
config: C,
) -> Result<D::Value, DecodeError>
where
D: DeserializeSeed<'de>,
C: Config,
R: std::io::Read,
{
let mut serde_decoder =
OwnedSerdeDecoder::<DecoderImpl<IoReader<&'r mut R>, C, ()>>::from_std_read(src, config);
seed.deserialize(serde_decoder.as_deserializer())
}
pub(super) struct SerdeDecoder<'a, DE: Decoder> {
pub(super) de: &'a mut DE,
}
impl<'de, DE: Decoder> Deserializer<'de> for SerdeDecoder<'_, DE> {
type Error = DecodeError;
fn deserialize_any<V>(self, _: V) -> Result<V::Value, Self::Error>
where
V: serde::de::Visitor<'de>,
{
Err(SerdeDecodeError::AnyNotSupported.into())
}
fn deserialize_bool<V>(mut self, visitor: V) -> Result<V::Value, Self::Error>
where
V: serde::de::Visitor<'de>,
{
visitor.visit_bool(Decode::decode(&mut self.de)?)
}
fn deserialize_i8<V>(mut self, visitor: V) -> Result<V::Value, Self::Error>
where
V: serde::de::Visitor<'de>,
{
visitor.visit_i8(Decode::decode(&mut self.de)?)
}
fn deserialize_i16<V>(mut self, visitor: V) -> Result<V::Value, Self::Error>
where
V: serde::de::Visitor<'de>,
{
visitor.visit_i16(Decode::decode(&mut self.de)?)
}
fn deserialize_i32<V>(mut self, visitor: V) -> Result<V::Value, Self::Error>
where
V: serde::de::Visitor<'de>,
{
visitor.visit_i32(Decode::decode(&mut self.de)?)
}
fn deserialize_i64<V>(mut self, visitor: V) -> Result<V::Value, Self::Error>
where
V: serde::de::Visitor<'de>,
{
visitor.visit_i64(Decode::decode(&mut self.de)?)
}
serde::serde_if_integer128! {
fn deserialize_i128<V>(mut self, visitor: V) -> Result<V::Value, Self::Error>
where
V: serde::de::Visitor<'de>,
{
visitor.visit_i128(Decode::decode(&mut self.de)?)
}
}
fn deserialize_u8<V>(mut self, visitor: V) -> Result<V::Value, Self::Error>
where
V: serde::de::Visitor<'de>,
{
visitor.visit_u8(Decode::decode(&mut self.de)?)
}
fn deserialize_u16<V>(mut self, visitor: V) -> Result<V::Value, Self::Error>
where
V: serde::de::Visitor<'de>,
{
visitor.visit_u16(Decode::decode(&mut self.de)?)
}
fn deserialize_u32<V>(mut self, visitor: V) -> Result<V::Value, Self::Error>
where
V: serde::de::Visitor<'de>,
{
visitor.visit_u32(Decode::decode(&mut self.de)?)
}
fn deserialize_u64<V>(mut self, visitor: V) -> Result<V::Value, Self::Error>
where
V: serde::de::Visitor<'de>,
{
visitor.visit_u64(Decode::decode(&mut self.de)?)
}
serde::serde_if_integer128! {
fn deserialize_u128<V>(mut self, visitor: V) -> Result<V::Value, Self::Error>
where
V: serde::de::Visitor<'de>,
{
visitor.visit_u128(Decode::decode(&mut self.de)?)
}
}
fn deserialize_f32<V>(mut self, visitor: V) -> Result<V::Value, Self::Error>
where
V: serde::de::Visitor<'de>,
{
visitor.visit_f32(Decode::decode(&mut self.de)?)
}
fn deserialize_f64<V>(mut self, visitor: V) -> Result<V::Value, Self::Error>
where
V: serde::de::Visitor<'de>,
{
visitor.visit_f64(Decode::decode(&mut self.de)?)
}
fn deserialize_char<V>(mut self, visitor: V) -> Result<V::Value, Self::Error>
where
V: serde::de::Visitor<'de>,
{
visitor.visit_char(Decode::decode(&mut self.de)?)
}
#[cfg(feature = "alloc")]
fn deserialize_str<V>(mut self, visitor: V) -> Result<V::Value, Self::Error>
where
V: serde::de::Visitor<'de>,
{
visitor.visit_string(Decode::decode(&mut self.de)?)
}
#[cfg(not(feature = "alloc"))]
fn deserialize_str<V>(self, _: V) -> Result<V::Value, Self::Error>
where
V: serde::de::Visitor<'de>,
{
Err(SerdeDecodeError::CannotBorrowOwnedData.into())
}
#[cfg(feature = "alloc")]
fn deserialize_string<V>(mut self, visitor: V) -> Result<V::Value, Self::Error>
where
V: serde::de::Visitor<'de>,
{
visitor.visit_string(Decode::decode(&mut self.de)?)
}
#[cfg(not(feature = "alloc"))]
fn deserialize_string<V>(self, _: V) -> Result<V::Value, Self::Error>
where
V: serde::de::Visitor<'de>,
{
Err(SerdeDecodeError::CannotAllocate.into())
}
#[cfg(feature = "alloc")]
fn deserialize_bytes<V>(mut self, visitor: V) -> Result<V::Value, Self::Error>
where
V: serde::de::Visitor<'de>,
{
visitor.visit_byte_buf(Decode::decode(&mut self.de)?)
}
#[cfg(not(feature = "alloc"))]
fn deserialize_bytes<V>(self, _visitor: V) -> Result<V::Value, Self::Error>
where
V: serde::de::Visitor<'de>,
{
Err(SerdeDecodeError::CannotBorrowOwnedData.into())
}
#[cfg(feature = "alloc")]
fn deserialize_byte_buf<V>(mut self, visitor: V) -> Result<V::Value, Self::Error>
where
V: serde::de::Visitor<'de>,
{
visitor.visit_byte_buf(Decode::decode(&mut self.de)?)
}
#[cfg(not(feature = "alloc"))]
fn deserialize_byte_buf<V>(self, _: V) -> Result<V::Value, Self::Error>
where
V: serde::de::Visitor<'de>,
{
Err(SerdeDecodeError::CannotAllocate.into())
}
fn deserialize_option<V>(mut self, visitor: V) -> Result<V::Value, Self::Error>
where
V: serde::de::Visitor<'de>,
{
let variant = crate::de::decode_option_variant(&mut self.de, "Option<T>")?;
if variant.is_some() {
visitor.visit_some(self)
} else {
visitor.visit_none()
}
}
fn deserialize_unit<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: serde::de::Visitor<'de>,
{
visitor.visit_unit()
}
fn deserialize_unit_struct<V>(
self,
_name: &'static str,
visitor: V,
) -> Result<V::Value, Self::Error>
where
V: serde::de::Visitor<'de>,
{
visitor.visit_unit()
}
fn deserialize_newtype_struct<V>(
self,
_name: &'static str,
visitor: V,
) -> Result<V::Value, Self::Error>
where
V: serde::de::Visitor<'de>,
{
visitor.visit_newtype_struct(self)
}
fn deserialize_seq<V>(mut self, visitor: V) -> Result<V::Value, Self::Error>
where
V: serde::de::Visitor<'de>,
{
let len = usize::decode(&mut self.de)?;
self.deserialize_tuple(len, visitor)
}
fn deserialize_tuple<V>(mut self, len: usize, visitor: V) -> Result<V::Value, Self::Error>
where
V: serde::de::Visitor<'de>,
{
struct Access<'a, 'b, DE: Decoder> {
deserializer: &'a mut SerdeDecoder<'b, DE>,
len: usize,
}
impl<'de, 'a, 'b: 'a, DE: Decoder + 'b> SeqAccess<'de> for Access<'a, 'b, DE> {
type Error = DecodeError;
fn next_element_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>, DecodeError>
where
T: DeserializeSeed<'de>,
{
if self.len > 0 {
self.len -= 1;
let value = DeserializeSeed::deserialize(
seed,
SerdeDecoder {
de: self.deserializer.de,
},
)?;
Ok(Some(value))
} else {
Ok(None)
}
}
fn size_hint(&self) -> Option<usize> {
Some(self.len)
}
}
visitor.visit_seq(Access {
deserializer: &mut self,
len,
})
}
fn deserialize_tuple_struct<V>(
self,
_name: &'static str,
len: usize,
visitor: V,
) -> Result<V::Value, Self::Error>
where
V: serde::de::Visitor<'de>,
{
self.deserialize_tuple(len, visitor)
}
fn deserialize_map<V>(mut self, visitor: V) -> Result<V::Value, Self::Error>
where
V: serde::de::Visitor<'de>,
{
struct Access<'a, 'b, DE: Decoder> {
deserializer: &'a mut SerdeDecoder<'b, DE>,
len: usize,
}
impl<'de, 'a, 'b: 'a, DE: Decoder + 'b> MapAccess<'de> for Access<'a, 'b, DE> {
type Error = DecodeError;
fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>, DecodeError>
where
K: DeserializeSeed<'de>,
{
if self.len > 0 {
self.len -= 1;
let key = DeserializeSeed::deserialize(
seed,
SerdeDecoder {
de: self.deserializer.de,
},
)?;
Ok(Some(key))
} else {
Ok(None)
}
}
fn next_value_seed<V>(&mut self, seed: V) -> Result<V::Value, DecodeError>
where
V: DeserializeSeed<'de>,
{
let value = DeserializeSeed::deserialize(
seed,
SerdeDecoder {
de: self.deserializer.de,
},
)?;
Ok(value)
}
fn size_hint(&self) -> Option<usize> {
Some(self.len)
}
}
let len = usize::decode(&mut self.de)?;
visitor.visit_map(Access {
deserializer: &mut self,
len,
})
}
fn deserialize_struct<V>(
self,
_name: &'static str,
fields: &'static [&'static str],
visitor: V,
) -> Result<V::Value, Self::Error>
where
V: serde::de::Visitor<'de>,
{
self.deserialize_tuple(fields.len(), visitor)
}
fn deserialize_enum<V>(
self,
_name: &'static str,
_variants: &'static [&'static str],
visitor: V,
) -> Result<V::Value, Self::Error>
where
V: serde::de::Visitor<'de>,
{
visitor.visit_enum(self)
}
fn deserialize_identifier<V>(self, _visitor: V) -> Result<V::Value, Self::Error>
where
V: serde::de::Visitor<'de>,
{
Err(SerdeDecodeError::IdentifierNotSupported.into())
}
fn deserialize_ignored_any<V>(self, _: V) -> Result<V::Value, Self::Error>
where
V: serde::de::Visitor<'de>,
{
Err(SerdeDecodeError::IgnoredAnyNotSupported.into())
}
fn is_human_readable(&self) -> bool {
false
}
}
impl<'de, DE: Decoder> EnumAccess<'de> for SerdeDecoder<'_, DE> {
type Error = DecodeError;
type Variant = Self;
fn variant_seed<V>(mut self, seed: V) -> Result<(V::Value, Self::Variant), Self::Error>
where
V: DeserializeSeed<'de>,
{
let idx = u32::decode(&mut self.de)?;
let val = seed.deserialize(idx.into_deserializer())?;
Ok((val, self))
}
}
impl<'de, DE: Decoder> VariantAccess<'de> for SerdeDecoder<'_, DE> {
type Error = DecodeError;
fn unit_variant(self) -> Result<(), Self::Error> {
Ok(())
}
fn newtype_variant_seed<T>(self, seed: T) -> Result<T::Value, Self::Error>
where
T: DeserializeSeed<'de>,
{
DeserializeSeed::deserialize(seed, self)
}
fn tuple_variant<V>(self, len: usize, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
Deserializer::deserialize_tuple(self, len, visitor)
}
fn struct_variant<V>(
self,
fields: &'static [&'static str],
visitor: V,
) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
Deserializer::deserialize_tuple(self, fields.len(), visitor)
}
}

View File

@ -1,297 +0,0 @@
//! Support for serde integration. Enable this with the `serde` feature.
//!
//! To encode/decode type that implement serde's trait, you can use:
//! - [borrow_decode_from_slice]
//! - [decode_from_slice]
//! - [encode_into_slice]
//! - [encode_to_vec]
//!
//! For interop with bincode's [Decode]/[Encode], you can use:
//! - [Compat]
//! - [BorrowCompat]
//!
//! For interop with bincode's `derive` feature, you can use the `#[bincode(with_serde)]` attribute on each field that implements serde's traits.
//!
//! ```
//! # #[cfg(feature = "derive")]
//! # mod foo {
//! # use bincode::{Decode, Encode};
//! # use serde_derive::{Deserialize, Serialize};
//! #[derive(Serialize, Deserialize)]
//! pub struct SerdeType {
//! // ...
//! }
//!
//! #[derive(Decode, Encode)]
//! pub struct StructWithSerde {
//! #[bincode(with_serde)]
//! pub serde: SerdeType,
//! }
//!
//! #[derive(Decode, Encode)]
//! pub enum EnumWithSerde {
//! Unit(#[bincode(with_serde)] SerdeType),
//! Struct {
//! #[bincode(with_serde)]
//! serde: SerdeType,
//! },
//! }
//! # }
//! ```
//!
//! # Known issues
//!
//! Because bincode is a format without meta data, there are several known issues with serde's attributes. Please do not use any of the following attributes if you plan on using bincode, or use bincode's own `derive` macros.
//! - `#[serde(flatten)]`
//! - `#[serde(skip)]`
//! - `#[serde(skip_deserializing)]`
//! - `#[serde(skip_serializing)]`
//! - `#[serde(skip_serializing_if = "path")]`
//! - `#[serde(tag = "...")]`
//! - `#[serde(untagged)]`
//!
//! **Using any of the above attributes can and will cause issues with bincode and will result in lost data**. Consider using bincode's own derive macro instead.
//!
//! # Why move away from serde?
//!
//! Serde is a great library, but it has some issues that makes us want to be decoupled from serde:
//! - The issues documented above with attributes.
//! - Serde has chosen to not have a MSRV ([source](https://github.com/serde-rs/serde/pull/2257)). We think MSRV is important, bincode 1 still compiles with rust 1.18.
//! - Before serde we had rustc-serializer. Serde has more than replaced rustc-serializer, but we can imagine a future where serde is replaced by something else.
//! - We believe that less dependencies is better, and that you should be able to choose your own dependencies. If you disable all features, bincode 2 only has 1 dependency. ([`unty`], a micro crate we manage ourselves)
//!
//! **note:** just because we're making serde an optional dependency, it does not mean we're dropping support for serde. Serde will still be fully supported, we're just giving you the option to not use it.
//!
//! [Decode]: ../de/trait.Decode.html
//! [Encode]: ../enc/trait.Encode.html
//! [`unty`]: https://crates.io/crates/unty
mod de_borrowed;
mod de_owned;
mod ser;
pub use self::de_borrowed::*;
pub use self::de_owned::*;
pub use self::ser::*;
/// A serde-specific error that occurred while decoding.
#[derive(Debug)]
#[non_exhaustive]
pub enum DecodeError {
/// Bincode does not support serde's `any` decoding feature.
///
/// See the "known issues" list in the serde module for more information on this.
AnyNotSupported,
/// Bincode does not support serde identifiers
IdentifierNotSupported,
/// Bincode does not support serde's `ignored_any`.
///
/// See the "known issues" list in the serde module for more information on this.
IgnoredAnyNotSupported,
/// Serde tried decoding a borrowed value from an owned reader. Use `serde_decode_borrowed_from_*` instead
CannotBorrowOwnedData,
/// Could not allocate data like `String` and `Vec<u8>`
#[cfg(not(feature = "alloc"))]
CannotAllocate,
/// Custom serde error but bincode is unable to allocate a string. Set a breakpoint where this is thrown for more information.
#[cfg(not(feature = "alloc"))]
CustomError,
}
#[cfg(feature = "alloc")]
impl serde::de::Error for crate::error::DecodeError {
fn custom<T>(msg: T) -> Self
where
T: core::fmt::Display,
{
use alloc::string::ToString;
Self::OtherString(msg.to_string())
}
}
#[cfg(not(feature = "alloc"))]
impl serde::de::Error for crate::error::DecodeError {
fn custom<T>(_: T) -> Self
where
T: core::fmt::Display,
{
DecodeError::CustomError.into()
}
}
#[allow(clippy::from_over_into)]
impl Into<crate::error::DecodeError> for DecodeError {
fn into(self) -> crate::error::DecodeError {
crate::error::DecodeError::Serde(self)
}
}
/// A serde-specific error that occurred while encoding.
#[derive(Debug)]
#[non_exhaustive]
pub enum EncodeError {
/// Serde provided bincode with a sequence without a length, which is not supported in bincode
SequenceMustHaveLength,
/// [Serializer::collect_str] got called but bincode was unable to allocate memory.
#[cfg(not(feature = "alloc"))]
CannotCollectStr,
/// Custom serde error but bincode is unable to allocate a string. Set a breakpoint where this is thrown for more information.
#[cfg(not(feature = "alloc"))]
CustomError,
}
#[allow(clippy::from_over_into)]
impl Into<crate::error::EncodeError> for EncodeError {
fn into(self) -> crate::error::EncodeError {
crate::error::EncodeError::Serde(self)
}
}
#[cfg(feature = "alloc")]
impl serde::ser::Error for crate::error::EncodeError {
fn custom<T>(msg: T) -> Self
where
T: core::fmt::Display,
{
use alloc::string::ToString;
Self::OtherString(msg.to_string())
}
}
#[cfg(not(feature = "alloc"))]
impl serde::ser::Error for crate::error::EncodeError {
fn custom<T>(_: T) -> Self
where
T: core::fmt::Display,
{
EncodeError::CustomError.into()
}
}
/// Wrapper struct that implements [Decode] and [Encode] on any type that implements serde's [DeserializeOwned] and [Serialize] respectively.
///
/// This works for most types, but if you're dealing with borrowed data consider using [BorrowCompat] instead.
///
/// [Decode]: ../de/trait.Decode.html
/// [Encode]: ../enc/trait.Encode.html
/// [DeserializeOwned]: https://docs.rs/serde/1/serde/de/trait.DeserializeOwned.html
/// [Serialize]: https://docs.rs/serde/1/serde/trait.Serialize.html
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub struct Compat<T>(pub T);
impl<Context, T> crate::Decode<Context> for Compat<T>
where
T: serde::de::DeserializeOwned,
{
fn decode<D: crate::de::Decoder>(decoder: &mut D) -> Result<Self, crate::error::DecodeError> {
let serde_decoder = de_owned::SerdeDecoder { de: decoder };
T::deserialize(serde_decoder).map(Compat)
}
}
impl<'de, T, Context> crate::BorrowDecode<'de, Context> for Compat<T>
where
T: serde::de::DeserializeOwned,
{
fn borrow_decode<D: crate::de::BorrowDecoder<'de>>(
decoder: &mut D,
) -> Result<Self, crate::error::DecodeError> {
let serde_decoder = de_owned::SerdeDecoder { de: decoder };
T::deserialize(serde_decoder).map(Compat)
}
}
impl<T> crate::Encode for Compat<T>
where
T: serde::Serialize,
{
fn encode<E: crate::enc::Encoder>(
&self,
encoder: &mut E,
) -> Result<(), crate::error::EncodeError> {
let serializer = ser::SerdeEncoder { enc: encoder };
self.0.serialize(serializer)?;
Ok(())
}
}
impl<T> core::fmt::Debug for Compat<T>
where
T: core::fmt::Debug,
{
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_tuple("Compat").field(&self.0).finish()
}
}
impl<T> core::fmt::Display for Compat<T>
where
T: core::fmt::Display,
{
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
self.0.fmt(f)
}
}
/// Wrapper struct that implements [BorrowDecode] and [Encode] on any type that implements serde's [Deserialize] and [Serialize] respectively. This is mostly used on `&[u8]` and `&str`, for other types consider using [Compat] instead.
///
/// [BorrowDecode]: ../de/trait.BorrowDecode.html
/// [Encode]: ../enc/trait.Encode.html
/// [Deserialize]: https://docs.rs/serde/1/serde/de/trait.Deserialize.html
/// [Serialize]: https://docs.rs/serde/1/serde/trait.Serialize.html
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub struct BorrowCompat<T>(pub T);
impl<'de, T, Context> crate::de::BorrowDecode<'de, Context> for BorrowCompat<T>
where
T: serde::de::Deserialize<'de>,
{
fn borrow_decode<D: crate::de::BorrowDecoder<'de>>(
decoder: &mut D,
) -> Result<Self, crate::error::DecodeError> {
let serde_decoder = de_borrowed::SerdeDecoder {
de: decoder,
pd: core::marker::PhantomData,
};
T::deserialize(serde_decoder).map(BorrowCompat)
}
}
impl<T> crate::Encode for BorrowCompat<T>
where
T: serde::Serialize,
{
fn encode<E: crate::enc::Encoder>(
&self,
encoder: &mut E,
) -> Result<(), crate::error::EncodeError> {
let serializer = ser::SerdeEncoder { enc: encoder };
self.0.serialize(serializer)?;
Ok(())
}
}
impl<T> core::fmt::Debug for BorrowCompat<T>
where
T: core::fmt::Debug,
{
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_tuple("BorrowCompat").field(&self.0).finish()
}
}
impl<T> core::fmt::Display for BorrowCompat<T>
where
T: core::fmt::Display,
{
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
self.0.fmt(f)
}
}

View File

@ -1,406 +0,0 @@
use super::EncodeError as SerdeEncodeError;
use crate::{
config::Config,
enc::{write::Writer, Encode, Encoder},
error::EncodeError,
};
#[cfg(feature = "alloc")]
use alloc::vec::Vec;
use serde::ser::*;
/// Encode the given value into a `Vec<u8>` with the given `Config`. See the [config] module for more information.
///
/// [config]: ../config/index.html
#[cfg(feature = "alloc")]
#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
pub fn encode_to_vec<E, C>(val: E, config: C) -> Result<Vec<u8>, EncodeError>
where
E: Serialize,
C: Config,
{
let mut encoder = crate::enc::EncoderImpl::new(crate::VecWriter::default(), config);
let serializer = SerdeEncoder { enc: &mut encoder };
val.serialize(serializer)?;
Ok(encoder.into_writer().collect())
}
/// Encode the given value into the given slice. Returns the amount of bytes that have been written.
///
/// See the [config] module for more information on configurations.
///
/// [config]: ../config/index.html
pub fn encode_into_slice<E, C>(val: E, dst: &mut [u8], config: C) -> Result<usize, EncodeError>
where
E: Serialize,
C: Config,
{
let mut encoder =
crate::enc::EncoderImpl::new(crate::enc::write::SliceWriter::new(dst), config);
let serializer = SerdeEncoder { enc: &mut encoder };
val.serialize(serializer)?;
Ok(encoder.into_writer().bytes_written())
}
/// Encode the given value into a custom [Writer].
///
/// See the [config] module for more information on configurations.
///
/// [config]: ../config/index.html
pub fn encode_into_writer<E: Serialize, W: Writer, C: Config>(
val: E,
writer: W,
config: C,
) -> Result<(), EncodeError> {
let mut encoder = crate::enc::EncoderImpl::<_, C>::new(writer, config);
let serializer = SerdeEncoder { enc: &mut encoder };
val.serialize(serializer)?;
Ok(())
}
/// Encode the given value into any type that implements `std::io::Write`, e.g. `std::fs::File`, with the given `Config`.
/// See the [config] module for more information.
///
/// [config]: ../config/index.html
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
#[cfg(feature = "std")]
pub fn encode_into_std_write<E: Serialize, C: Config, W: std::io::Write>(
val: E,
dst: &mut W,
config: C,
) -> Result<usize, EncodeError> {
let writer = crate::IoWriter::new(dst);
let mut encoder = crate::enc::EncoderImpl::<_, C>::new(writer, config);
let serializer = SerdeEncoder { enc: &mut encoder };
val.serialize(serializer)?;
Ok(encoder.into_writer().bytes_written())
}
pub(super) struct SerdeEncoder<'a, ENC: Encoder> {
pub(super) enc: &'a mut ENC,
}
impl<ENC> Serializer for SerdeEncoder<'_, ENC>
where
ENC: Encoder,
{
type Ok = ();
type Error = EncodeError;
type SerializeSeq = Self;
type SerializeTuple = Self;
type SerializeTupleStruct = Self;
type SerializeTupleVariant = Self;
type SerializeMap = Self;
type SerializeStruct = Self;
type SerializeStructVariant = Self;
fn serialize_bool(self, v: bool) -> Result<Self::Ok, Self::Error> {
v.encode(self.enc)
}
fn serialize_i8(self, v: i8) -> Result<Self::Ok, Self::Error> {
v.encode(self.enc)
}
fn serialize_i16(self, v: i16) -> Result<Self::Ok, Self::Error> {
v.encode(self.enc)
}
fn serialize_i32(self, v: i32) -> Result<Self::Ok, Self::Error> {
v.encode(self.enc)
}
fn serialize_i64(self, v: i64) -> Result<Self::Ok, Self::Error> {
v.encode(self.enc)
}
serde::serde_if_integer128! {
fn serialize_i128(self, v: i128) -> Result<Self::Ok, Self::Error> {
v.encode(self.enc)
}
}
fn serialize_u8(self, v: u8) -> Result<Self::Ok, Self::Error> {
v.encode(self.enc)
}
fn serialize_u16(self, v: u16) -> Result<Self::Ok, Self::Error> {
v.encode(self.enc)
}
fn serialize_u32(self, v: u32) -> Result<Self::Ok, Self::Error> {
v.encode(self.enc)
}
fn serialize_u64(self, v: u64) -> Result<Self::Ok, Self::Error> {
v.encode(self.enc)
}
serde::serde_if_integer128! {
fn serialize_u128(self, v: u128) -> Result<Self::Ok, Self::Error> {
v.encode(self.enc)
}
}
fn serialize_f32(self, v: f32) -> Result<Self::Ok, Self::Error> {
v.encode(self.enc)
}
fn serialize_f64(self, v: f64) -> Result<Self::Ok, Self::Error> {
v.encode(self.enc)
}
fn serialize_char(self, v: char) -> Result<Self::Ok, Self::Error> {
v.encode(self.enc)
}
fn serialize_str(self, v: &str) -> Result<Self::Ok, Self::Error> {
v.encode(self.enc)
}
fn serialize_bytes(self, v: &[u8]) -> Result<Self::Ok, Self::Error> {
v.encode(self.enc)
}
fn serialize_none(self) -> Result<Self::Ok, Self::Error> {
0u8.encode(self.enc)
}
fn serialize_some<T>(mut self, value: &T) -> Result<Self::Ok, Self::Error>
where
T: Serialize + ?Sized,
{
1u8.encode(&mut self.enc)?;
value.serialize(self)
}
fn serialize_unit(self) -> Result<Self::Ok, Self::Error> {
Ok(())
}
fn serialize_unit_struct(self, _name: &'static str) -> Result<Self::Ok, Self::Error> {
Ok(())
}
fn serialize_unit_variant(
self,
_name: &'static str,
variant_index: u32,
_variant: &'static str,
) -> Result<Self::Ok, Self::Error> {
variant_index.encode(self.enc)
}
fn serialize_newtype_struct<T>(
self,
_name: &'static str,
value: &T,
) -> Result<Self::Ok, Self::Error>
where
T: Serialize + ?Sized,
{
value.serialize(self)
}
fn serialize_newtype_variant<T>(
mut self,
_name: &'static str,
variant_index: u32,
_variant: &'static str,
value: &T,
) -> Result<Self::Ok, Self::Error>
where
T: Serialize + ?Sized,
{
variant_index.encode(&mut self.enc)?;
value.serialize(self)
}
fn serialize_seq(mut self, len: Option<usize>) -> Result<Self::SerializeSeq, Self::Error> {
let len = len.ok_or_else(|| SerdeEncodeError::SequenceMustHaveLength.into())?;
len.encode(&mut self.enc)?;
Ok(Compound { enc: self.enc })
}
fn serialize_tuple(self, _: usize) -> Result<Self::SerializeTuple, Self::Error> {
Ok(self)
}
fn serialize_tuple_struct(
self,
_name: &'static str,
_len: usize,
) -> Result<Self::SerializeTupleStruct, Self::Error> {
Ok(Compound { enc: self.enc })
}
fn serialize_tuple_variant(
mut self,
_name: &'static str,
variant_index: u32,
_variant: &'static str,
_len: usize,
) -> Result<Self::SerializeTupleVariant, Self::Error> {
variant_index.encode(&mut self.enc)?;
Ok(Compound { enc: self.enc })
}
fn serialize_map(mut self, len: Option<usize>) -> Result<Self::SerializeMap, Self::Error> {
let len = len.ok_or_else(|| SerdeEncodeError::SequenceMustHaveLength.into())?;
len.encode(&mut self.enc)?;
Ok(Compound { enc: self.enc })
}
fn serialize_struct(
self,
_name: &'static str,
_len: usize,
) -> Result<Self::SerializeStruct, Self::Error> {
Ok(Compound { enc: self.enc })
}
fn serialize_struct_variant(
mut self,
_name: &'static str,
variant_index: u32,
_variant: &'static str,
_len: usize,
) -> Result<Self::SerializeStructVariant, Self::Error> {
variant_index.encode(&mut self.enc)?;
Ok(Compound { enc: self.enc })
}
#[cfg(not(feature = "alloc"))]
fn collect_str<T>(self, _: &T) -> Result<Self::Ok, Self::Error>
where
T: core::fmt::Display + ?Sized,
{
Err(SerdeEncodeError::CannotCollectStr.into())
}
fn is_human_readable(&self) -> bool {
false
}
}
type Compound<'a, ENC> = SerdeEncoder<'a, ENC>;
impl<ENC: Encoder> SerializeSeq for Compound<'_, ENC> {
type Ok = ();
type Error = EncodeError;
fn serialize_element<T>(&mut self, value: &T) -> Result<(), Self::Error>
where
T: Serialize + ?Sized,
{
value.serialize(SerdeEncoder { enc: self.enc })
}
fn end(self) -> Result<Self::Ok, Self::Error> {
Ok(())
}
}
impl<ENC: Encoder> SerializeTuple for Compound<'_, ENC> {
type Ok = ();
type Error = EncodeError;
fn serialize_element<T>(&mut self, value: &T) -> Result<(), Self::Error>
where
T: Serialize + ?Sized,
{
value.serialize(SerdeEncoder { enc: self.enc })
}
fn end(self) -> Result<Self::Ok, Self::Error> {
Ok(())
}
}
impl<ENC: Encoder> SerializeTupleStruct for Compound<'_, ENC> {
type Ok = ();
type Error = EncodeError;
fn serialize_field<T>(&mut self, value: &T) -> Result<(), Self::Error>
where
T: Serialize + ?Sized,
{
value.serialize(SerdeEncoder { enc: self.enc })
}
fn end(self) -> Result<Self::Ok, Self::Error> {
Ok(())
}
}
impl<ENC: Encoder> SerializeTupleVariant for Compound<'_, ENC> {
type Ok = ();
type Error = EncodeError;
fn serialize_field<T>(&mut self, value: &T) -> Result<(), Self::Error>
where
T: Serialize + ?Sized,
{
value.serialize(SerdeEncoder { enc: self.enc })
}
fn end(self) -> Result<Self::Ok, Self::Error> {
Ok(())
}
}
impl<ENC: Encoder> SerializeMap for Compound<'_, ENC> {
type Ok = ();
type Error = EncodeError;
fn serialize_key<T>(&mut self, key: &T) -> Result<(), Self::Error>
where
T: Serialize + ?Sized,
{
key.serialize(SerdeEncoder { enc: self.enc })
}
fn serialize_value<T>(&mut self, value: &T) -> Result<(), Self::Error>
where
T: Serialize + ?Sized,
{
value.serialize(SerdeEncoder { enc: self.enc })
}
fn end(self) -> Result<Self::Ok, Self::Error> {
Ok(())
}
}
impl<ENC: Encoder> SerializeStruct for Compound<'_, ENC> {
type Ok = ();
type Error = EncodeError;
fn serialize_field<T>(&mut self, _key: &'static str, value: &T) -> Result<(), Self::Error>
where
T: Serialize + ?Sized,
{
value.serialize(SerdeEncoder { enc: self.enc })
}
fn end(self) -> Result<Self::Ok, Self::Error> {
Ok(())
}
}
impl<ENC: Encoder> SerializeStructVariant for Compound<'_, ENC> {
type Ok = ();
type Error = EncodeError;
fn serialize_field<T>(&mut self, _key: &'static str, value: &T) -> Result<(), Self::Error>
where
T: Serialize + ?Sized,
{
value.serialize(SerdeEncoder { enc: self.enc })
}
fn end(self) -> Result<Self::Ok, Self::Error> {
Ok(())
}
}

View File

@ -1,237 +1 @@
#![no_std]
#![warn(missing_docs, unused_lifetimes)]
#![cfg_attr(docsrs, feature(doc_cfg))]
//! Bincode is a crate for encoding and decoding using a tiny binary
//! serialization strategy. Using it, you can easily go from having
//! an object in memory, quickly serialize it to bytes, and then
//! deserialize it back just as fast!
//!
//! If you're coming from bincode 1, check out our [migration guide](migration_guide/index.html)
//!
//! # Serde
//!
//! Starting from bincode 2, serde is now an optional dependency. If you want to use serde, please enable the `serde` feature. See [Features](#features) for more information.
//!
//! # Features
//!
//! |Name |Default?|Affects MSRV?|Supported types for Encode/Decode|Enabled methods |Other|
//! |------|--------|-------------|-----------------------------------------|-----------------------------------------------------------------|-----|
//! |std | Yes | No |`HashMap` and `HashSet`|`decode_from_std_read` and `encode_into_std_write`|
//! |alloc | Yes | No |All common containers in alloc, like `Vec`, `String`, `Box`|`encode_to_vec`|
//! |atomic| Yes | No |All `Atomic*` integer types, e.g. `AtomicUsize`, and `AtomicBool`||
//! |derive| Yes | No |||Enables the `BorrowDecode`, `Decode` and `Encode` derive macros|
//! |serde | No | Yes (MSRV reliant on serde)|`Compat` and `BorrowCompat`, which will work for all types that implement serde's traits|serde-specific encode/decode functions in the [serde] module|Note: There are several [known issues](serde/index.html#known-issues) when using serde and bincode|
//!
//! # Which functions to use
//!
//! Bincode has a couple of pairs of functions that are used in different situations.
//!
//! |Situation|Encode|Decode|
//! |---|---|---
//! |You're working with [`fs::File`] or [`net::TcpStream`]|[`encode_into_std_write`]|[`decode_from_std_read`]|
//! |you're working with in-memory buffers|[`encode_to_vec`]|[`decode_from_slice`]|
//! |You want to use a custom [Reader] and [Writer]|[`encode_into_writer`]|[`decode_from_reader`]|
//! |You're working with pre-allocated buffers or on embedded targets|[`encode_into_slice`]|[`decode_from_slice`]|
//!
//! **Note:** If you're using `serde`, use `bincode::serde::...` instead of `bincode::...`
//!
//! # Example
//!
//! ```rust
//! let mut slice = [0u8; 100];
//!
//! // You can encode any type that implements `Encode`.
//! // You can automatically implement this trait on custom types with the `derive` feature.
//! let input = (
//! 0u8,
//! 10u32,
//! 10000i128,
//! 'a',
//! [0u8, 1u8, 2u8, 3u8]
//! );
//!
//! let length = bincode::encode_into_slice(
//! input,
//! &mut slice,
//! bincode::config::standard()
//! ).unwrap();
//!
//! let slice = &slice[..length];
//! println!("Bytes written: {:?}", slice);
//!
//! // Decoding works the same as encoding.
//! // The trait used is `Decode`, and can also be automatically implemented with the `derive` feature.
//! let decoded: (u8, u32, i128, char, [u8; 4]) = bincode::decode_from_slice(slice, bincode::config::standard()).unwrap().0;
//!
//! assert_eq!(decoded, input);
//! ```
//!
//! [`fs::File`]: std::fs::File
//! [`net::TcpStream`]: std::net::TcpStream
//!
#![doc(html_root_url = "https://docs.rs/bincode/2.0.1")]
#![crate_name = "bincode"]
#![crate_type = "rlib"]
#[cfg(feature = "alloc")]
extern crate alloc;
#[cfg(any(feature = "std", test))]
extern crate std;
mod atomic;
mod features;
pub(crate) mod utils;
pub(crate) mod varint;
use de::{read::Reader, Decoder};
use enc::write::Writer;
#[cfg(any(
feature = "alloc",
feature = "std",
feature = "derive",
feature = "serde"
))]
pub use features::*;
pub mod config;
#[macro_use]
pub mod de;
pub mod enc;
pub mod error;
pub use de::{BorrowDecode, Decode};
pub use enc::Encode;
use config::Config;
/// Encode the given value into the given slice. Returns the amount of bytes that have been written.
///
/// See the [config] module for more information on configurations.
///
/// [config]: config/index.html
pub fn encode_into_slice<E: enc::Encode, C: Config>(
val: E,
dst: &mut [u8],
config: C,
) -> Result<usize, error::EncodeError> {
let writer = enc::write::SliceWriter::new(dst);
let mut encoder = enc::EncoderImpl::<_, C>::new(writer, config);
val.encode(&mut encoder)?;
Ok(encoder.into_writer().bytes_written())
}
/// Encode the given value into a custom [Writer].
///
/// See the [config] module for more information on configurations.
///
/// [config]: config/index.html
pub fn encode_into_writer<E: enc::Encode, W: Writer, C: Config>(
val: E,
writer: W,
config: C,
) -> Result<(), error::EncodeError> {
let mut encoder = enc::EncoderImpl::<_, C>::new(writer, config);
val.encode(&mut encoder)?;
Ok(())
}
/// Attempt to decode a given type `D` from the given slice. Returns the decoded output and the amount of bytes read.
///
/// Note that this does not work with borrowed types like `&str` or `&[u8]`. For that use [borrow_decode_from_slice].
///
/// See the [config] module for more information on configurations.
///
/// [config]: config/index.html
pub fn decode_from_slice<D: de::Decode<()>, C: Config>(
src: &[u8],
config: C,
) -> Result<(D, usize), error::DecodeError> {
decode_from_slice_with_context(src, config, ())
}
/// Attempt to decode a given type `D` from the given slice with `Context`. Returns the decoded output and the amount of bytes read.
///
/// Note that this does not work with borrowed types like `&str` or `&[u8]`. For that use [borrow_decode_from_slice].
///
/// See the [config] module for more information on configurations.
///
/// [config]: config/index.html
pub fn decode_from_slice_with_context<Context, D: de::Decode<Context>, C: Config>(
src: &[u8],
config: C,
context: Context,
) -> Result<(D, usize), error::DecodeError> {
let reader = de::read::SliceReader::new(src);
let mut decoder = de::DecoderImpl::<_, C, Context>::new(reader, config, context);
let result = D::decode(&mut decoder)?;
let bytes_read = src.len() - decoder.reader().slice.len();
Ok((result, bytes_read))
}
/// Attempt to decode a given type `D` from the given slice. Returns the decoded output and the amount of bytes read.
///
/// See the [config] module for more information on configurations.
///
/// [config]: config/index.html
pub fn borrow_decode_from_slice<'a, D: de::BorrowDecode<'a, ()>, C: Config>(
src: &'a [u8],
config: C,
) -> Result<(D, usize), error::DecodeError> {
borrow_decode_from_slice_with_context(src, config, ())
}
/// Attempt to decode a given type `D` from the given slice with `Context`. Returns the decoded output and the amount of bytes read.
///
/// See the [config] module for more information on configurations.
///
/// [config]: config/index.html
pub fn borrow_decode_from_slice_with_context<
'a,
Context,
D: de::BorrowDecode<'a, Context>,
C: Config,
>(
src: &'a [u8],
config: C,
context: Context,
) -> Result<(D, usize), error::DecodeError> {
let reader = de::read::SliceReader::new(src);
let mut decoder = de::DecoderImpl::<_, C, Context>::new(reader, config, context);
let result = D::borrow_decode(&mut decoder)?;
let bytes_read = src.len() - decoder.reader().slice.len();
Ok((result, bytes_read))
}
/// Attempt to decode a given type `D` from the given [Reader].
///
/// See the [config] module for more information on configurations.
///
/// [config]: config/index.html
pub fn decode_from_reader<D: de::Decode<()>, R: Reader, C: Config>(
reader: R,
config: C,
) -> Result<D, error::DecodeError> {
let mut decoder = de::DecoderImpl::<_, C, ()>::new(reader, config, ());
D::decode(&mut decoder)
}
// TODO: Currently our doctests fail when trying to include the specs because the specs depend on `derive` and `alloc`.
// But we want to have the specs in the docs always
#[cfg(all(feature = "alloc", feature = "derive", doc))]
pub mod spec {
#![doc = include_str!("../docs/spec.md")]
}
#[cfg(doc)]
pub mod migration_guide {
#![doc = include_str!("../docs/migration_guide.md")]
}
// Test the examples in readme.md
#[cfg(all(feature = "alloc", feature = "derive", doctest))]
mod readme {
#![doc = include_str!("../readme.md")]
}
compile_error!("https://xkcd.com/2347/");

View File

@ -1,3 +0,0 @@
pub trait Sealed {}
impl<T> Sealed for &mut T where T: Sealed {}

View File

@ -1,92 +0,0 @@
use crate::{
config::Endianness,
de::read::Reader,
error::{DecodeError, IntegerType},
};
pub fn varint_decode_i16<R: Reader>(read: &mut R, endian: Endianness) -> Result<i16, DecodeError> {
let n = super::varint_decode_u16(read, endian)
.map_err(DecodeError::change_integer_type_to_signed)?;
Ok(if n % 2 == 0 {
// positive number
(n / 2) as _
} else {
// negative number
// !m * 2 + 1 = n
// !m * 2 = n - 1
// !m = (n - 1) / 2
// m = !((n - 1) / 2)
// since we have n is odd, we have floor(n / 2) = floor((n - 1) / 2)
!(n / 2) as _
})
}
pub fn varint_decode_i32<R: Reader>(read: &mut R, endian: Endianness) -> Result<i32, DecodeError> {
let n = super::varint_decode_u32(read, endian)
.map_err(DecodeError::change_integer_type_to_signed)?;
Ok(if n % 2 == 0 {
// positive number
(n / 2) as _
} else {
// negative number
// !m * 2 + 1 = n
// !m * 2 = n - 1
// !m = (n - 1) / 2
// m = !((n - 1) / 2)
// since we have n is odd, we have floor(n / 2) = floor((n - 1) / 2)
!(n / 2) as _
})
}
pub fn varint_decode_i64<R: Reader>(read: &mut R, endian: Endianness) -> Result<i64, DecodeError> {
let n = super::varint_decode_u64(read, endian)
.map_err(DecodeError::change_integer_type_to_signed)?;
Ok(if n % 2 == 0 {
// positive number
(n / 2) as _
} else {
// negative number
// !m * 2 + 1 = n
// !m * 2 = n - 1
// !m = (n - 1) / 2
// m = !((n - 1) / 2)
// since we have n is odd, we have floor(n / 2) = floor((n - 1) / 2)
!(n / 2) as _
})
}
pub fn varint_decode_i128<R: Reader>(
read: &mut R,
endian: Endianness,
) -> Result<i128, DecodeError> {
let n = super::varint_decode_u128(read, endian)
.map_err(DecodeError::change_integer_type_to_signed)?;
Ok(if n % 2 == 0 {
// positive number
(n / 2) as _
} else {
// negative number
// !m * 2 + 1 = n
// !m * 2 = n - 1
// !m = (n - 1) / 2
// m = !((n - 1) / 2)
// since we have n is odd, we have floor(n / 2) = floor((n - 1) / 2)
!(n / 2) as _
})
}
pub fn varint_decode_isize<R: Reader>(
read: &mut R,
endian: Endianness,
) -> Result<isize, DecodeError> {
match varint_decode_i64(read, endian) {
Ok(val) => Ok(val as isize),
Err(DecodeError::InvalidIntegerType { found, .. }) => {
Err(DecodeError::InvalidIntegerType {
expected: IntegerType::Isize,
found: found.into_signed(),
})
}
Err(e) => Err(e),
}
}

View File

@ -1,710 +0,0 @@
use core::convert::TryInto;
use super::{SINGLE_BYTE_MAX, U128_BYTE, U16_BYTE, U32_BYTE, U64_BYTE};
use crate::{
config::Endianness,
de::read::Reader,
error::{DecodeError, IntegerType},
};
#[inline(never)]
#[cold]
fn deserialize_varint_cold_u16<R>(read: &mut R, endian: Endianness) -> Result<u16, DecodeError>
where
R: Reader,
{
let mut bytes = [0u8; 1];
read.read(&mut bytes)?;
match bytes[0] {
byte @ 0..=SINGLE_BYTE_MAX => Ok(byte as u16),
U16_BYTE => {
let mut bytes = [0u8; 2];
read.read(&mut bytes)?;
Ok(match endian {
Endianness::Big => u16::from_be_bytes(bytes),
Endianness::Little => u16::from_le_bytes(bytes),
})
}
U32_BYTE => invalid_varint_discriminant(IntegerType::U16, IntegerType::U32),
U64_BYTE => invalid_varint_discriminant(IntegerType::U16, IntegerType::U64),
U128_BYTE => invalid_varint_discriminant(IntegerType::U16, IntegerType::U128),
_ => invalid_varint_discriminant(IntegerType::U16, IntegerType::Reserved),
}
}
#[inline(never)]
#[cold]
fn deserialize_varint_cold_u32<R>(read: &mut R, endian: Endianness) -> Result<u32, DecodeError>
where
R: Reader,
{
let mut bytes = [0u8; 1];
read.read(&mut bytes)?;
match bytes[0] {
byte @ 0..=SINGLE_BYTE_MAX => Ok(byte as u32),
U16_BYTE => {
let mut bytes = [0u8; 2];
read.read(&mut bytes)?;
Ok(match endian {
Endianness::Big => u16::from_be_bytes(bytes) as u32,
Endianness::Little => u16::from_le_bytes(bytes) as u32,
})
}
U32_BYTE => {
let mut bytes = [0u8; 4];
read.read(&mut bytes)?;
Ok(match endian {
Endianness::Big => u32::from_be_bytes(bytes),
Endianness::Little => u32::from_le_bytes(bytes),
})
}
U64_BYTE => invalid_varint_discriminant(IntegerType::U32, IntegerType::U64),
U128_BYTE => invalid_varint_discriminant(IntegerType::U32, IntegerType::U128),
_ => invalid_varint_discriminant(IntegerType::U32, IntegerType::Reserved),
}
}
#[inline(never)]
#[cold]
fn deserialize_varint_cold_u64<R>(read: &mut R, endian: Endianness) -> Result<u64, DecodeError>
where
R: Reader,
{
let mut bytes = [0u8; 1];
read.read(&mut bytes)?;
match bytes[0] {
byte @ 0..=SINGLE_BYTE_MAX => Ok(byte as u64),
U16_BYTE => {
let mut bytes = [0u8; 2];
read.read(&mut bytes)?;
Ok(match endian {
Endianness::Big => u16::from_be_bytes(bytes) as u64,
Endianness::Little => u16::from_le_bytes(bytes) as u64,
})
}
U32_BYTE => {
let mut bytes = [0u8; 4];
read.read(&mut bytes)?;
Ok(match endian {
Endianness::Big => u32::from_be_bytes(bytes) as u64,
Endianness::Little => u32::from_le_bytes(bytes) as u64,
})
}
U64_BYTE => {
let mut bytes = [0u8; 8];
read.read(&mut bytes)?;
Ok(match endian {
Endianness::Big => u64::from_be_bytes(bytes),
Endianness::Little => u64::from_le_bytes(bytes),
})
}
U128_BYTE => invalid_varint_discriminant(IntegerType::U64, IntegerType::U128),
_ => invalid_varint_discriminant(IntegerType::U64, IntegerType::Reserved),
}
}
#[inline(never)]
#[cold]
fn deserialize_varint_cold_usize<R>(read: &mut R, endian: Endianness) -> Result<usize, DecodeError>
where
R: Reader,
{
let mut bytes = [0u8; 1];
read.read(&mut bytes)?;
match bytes[0] {
byte @ 0..=SINGLE_BYTE_MAX => Ok(byte as usize),
U16_BYTE => {
let mut bytes = [0u8; 2];
read.read(&mut bytes)?;
Ok(match endian {
Endianness::Big => u16::from_be_bytes(bytes) as usize,
Endianness::Little => u16::from_le_bytes(bytes) as usize,
})
}
U32_BYTE => {
let mut bytes = [0u8; 4];
read.read(&mut bytes)?;
Ok(match endian {
Endianness::Big => u32::from_be_bytes(bytes) as usize,
Endianness::Little => u32::from_le_bytes(bytes) as usize,
})
}
U64_BYTE => {
let mut bytes = [0u8; 8];
read.read(&mut bytes)?;
Ok(match endian {
Endianness::Big => u64::from_be_bytes(bytes) as usize,
Endianness::Little => u64::from_le_bytes(bytes) as usize,
})
}
U128_BYTE => invalid_varint_discriminant(IntegerType::Usize, IntegerType::U128),
_ => invalid_varint_discriminant(IntegerType::Usize, IntegerType::Reserved),
}
}
#[inline(never)]
#[cold]
fn deserialize_varint_cold_u128<R>(read: &mut R, endian: Endianness) -> Result<u128, DecodeError>
where
R: Reader,
{
let mut bytes = [0u8; 1];
read.read(&mut bytes)?;
match bytes[0] {
byte @ 0..=SINGLE_BYTE_MAX => Ok(byte as u128),
U16_BYTE => {
let mut bytes = [0u8; 2];
read.read(&mut bytes)?;
Ok(match endian {
Endianness::Big => u16::from_be_bytes(bytes) as u128,
Endianness::Little => u16::from_le_bytes(bytes) as u128,
})
}
U32_BYTE => {
let mut bytes = [0u8; 4];
read.read(&mut bytes)?;
Ok(match endian {
Endianness::Big => u32::from_be_bytes(bytes) as u128,
Endianness::Little => u32::from_le_bytes(bytes) as u128,
})
}
U64_BYTE => {
let mut bytes = [0u8; 8];
read.read(&mut bytes)?;
Ok(match endian {
Endianness::Big => u64::from_be_bytes(bytes) as u128,
Endianness::Little => u64::from_le_bytes(bytes) as u128,
})
}
U128_BYTE => {
let mut bytes = [0u8; 16];
read.read(&mut bytes)?;
Ok(match endian {
Endianness::Big => u128::from_be_bytes(bytes),
Endianness::Little => u128::from_le_bytes(bytes),
})
}
_ => invalid_varint_discriminant(IntegerType::U128, IntegerType::Reserved),
}
}
#[inline(never)]
#[cold]
const fn invalid_varint_discriminant<T>(
expected: IntegerType,
found: IntegerType,
) -> Result<T, DecodeError> {
Err(DecodeError::InvalidIntegerType { expected, found })
}
pub fn varint_decode_u16<R: Reader>(read: &mut R, endian: Endianness) -> Result<u16, DecodeError> {
if let Some(bytes) = read.peek_read(3) {
let (discriminant, bytes) = bytes.split_at(1);
let (out, used) = match discriminant[0] {
byte @ 0..=SINGLE_BYTE_MAX => (byte as u16, 1),
U16_BYTE => {
let val = match endian {
Endianness::Big => u16::from_be_bytes(bytes[..2].try_into().unwrap()),
Endianness::Little => u16::from_le_bytes(bytes[..2].try_into().unwrap()),
};
(val, 3)
}
U32_BYTE => return invalid_varint_discriminant(IntegerType::U16, IntegerType::U32),
U64_BYTE => return invalid_varint_discriminant(IntegerType::U16, IntegerType::U64),
U128_BYTE => return invalid_varint_discriminant(IntegerType::U16, IntegerType::U128),
_ => return invalid_varint_discriminant(IntegerType::U16, IntegerType::Reserved),
};
read.consume(used);
Ok(out)
} else {
deserialize_varint_cold_u16(read, endian)
}
}
pub fn varint_decode_u32<R: Reader>(read: &mut R, endian: Endianness) -> Result<u32, DecodeError> {
if let Some(bytes) = read.peek_read(5) {
let (discriminant, bytes) = bytes.split_at(1);
let (out, used) = match discriminant[0] {
byte @ 0..=SINGLE_BYTE_MAX => (byte as u32, 1),
U16_BYTE => {
let val = match endian {
Endianness::Big => u16::from_be_bytes(bytes[..2].try_into().unwrap()),
Endianness::Little => u16::from_le_bytes(bytes[..2].try_into().unwrap()),
};
(val as u32, 3)
}
U32_BYTE => {
let val = match endian {
Endianness::Big => u32::from_be_bytes(bytes[..4].try_into().unwrap()),
Endianness::Little => u32::from_le_bytes(bytes[..4].try_into().unwrap()),
};
(val, 5)
}
U64_BYTE => return invalid_varint_discriminant(IntegerType::U32, IntegerType::U64),
U128_BYTE => return invalid_varint_discriminant(IntegerType::U32, IntegerType::U128),
_ => return invalid_varint_discriminant(IntegerType::U32, IntegerType::Reserved),
};
read.consume(used);
Ok(out)
} else {
deserialize_varint_cold_u32(read, endian)
}
}
pub fn varint_decode_u64<R: Reader>(read: &mut R, endian: Endianness) -> Result<u64, DecodeError> {
if let Some(bytes) = read.peek_read(9) {
let (discriminant, bytes) = bytes.split_at(1);
let (out, used) = match discriminant[0] {
byte @ 0..=SINGLE_BYTE_MAX => (byte as u64, 1),
U16_BYTE => {
let val = match endian {
Endianness::Big => u16::from_be_bytes(bytes[..2].try_into().unwrap()),
Endianness::Little => u16::from_le_bytes(bytes[..2].try_into().unwrap()),
};
(val as u64, 3)
}
U32_BYTE => {
let val = match endian {
Endianness::Big => u32::from_be_bytes(bytes[..4].try_into().unwrap()),
Endianness::Little => u32::from_le_bytes(bytes[..4].try_into().unwrap()),
};
(val as u64, 5)
}
U64_BYTE => {
let val = match endian {
Endianness::Big => u64::from_be_bytes(bytes[..8].try_into().unwrap()),
Endianness::Little => u64::from_le_bytes(bytes[..8].try_into().unwrap()),
};
(val, 9)
}
U128_BYTE => return invalid_varint_discriminant(IntegerType::U32, IntegerType::U128),
_ => return invalid_varint_discriminant(IntegerType::U32, IntegerType::Reserved),
};
read.consume(used);
Ok(out)
} else {
deserialize_varint_cold_u64(read, endian)
}
}
pub fn varint_decode_usize<R: Reader>(
read: &mut R,
endian: Endianness,
) -> Result<usize, DecodeError> {
if let Some(bytes) = read.peek_read(9) {
let (discriminant, bytes) = bytes.split_at(1);
let (out, used) = match discriminant[0] {
byte @ 0..=SINGLE_BYTE_MAX => (byte as usize, 1),
U16_BYTE => {
let val = match endian {
Endianness::Big => u16::from_be_bytes(bytes[..2].try_into().unwrap()),
Endianness::Little => u16::from_le_bytes(bytes[..2].try_into().unwrap()),
};
(val as usize, 3)
}
U32_BYTE => {
let val = match endian {
Endianness::Big => u32::from_be_bytes(bytes[..4].try_into().unwrap()),
Endianness::Little => u32::from_le_bytes(bytes[..4].try_into().unwrap()),
};
(val as usize, 5)
}
U64_BYTE => {
let val = match endian {
Endianness::Big => u64::from_be_bytes(bytes[..8].try_into().unwrap()),
Endianness::Little => u64::from_le_bytes(bytes[..8].try_into().unwrap()),
};
(val as usize, 9)
}
U128_BYTE => return invalid_varint_discriminant(IntegerType::Usize, IntegerType::U128),
_ => return invalid_varint_discriminant(IntegerType::Usize, IntegerType::Reserved),
};
read.consume(used);
Ok(out)
} else {
deserialize_varint_cold_usize(read, endian)
}
}
pub fn varint_decode_u128<R: Reader>(
read: &mut R,
endian: Endianness,
) -> Result<u128, DecodeError> {
if let Some(bytes) = read.peek_read(17) {
let (discriminant, bytes) = bytes.split_at(1);
let (out, used) = match discriminant[0] {
byte @ 0..=SINGLE_BYTE_MAX => (byte as u128, 1),
U16_BYTE => {
let val = match endian {
Endianness::Big => u16::from_be_bytes(bytes[..2].try_into().unwrap()),
Endianness::Little => u16::from_le_bytes(bytes[..2].try_into().unwrap()),
};
(val as u128, 3)
}
U32_BYTE => {
let val = match endian {
Endianness::Big => u32::from_be_bytes(bytes[..4].try_into().unwrap()),
Endianness::Little => u32::from_le_bytes(bytes[..4].try_into().unwrap()),
};
(val as u128, 5)
}
U64_BYTE => {
let val = match endian {
Endianness::Big => u64::from_be_bytes(bytes[..8].try_into().unwrap()),
Endianness::Little => u64::from_le_bytes(bytes[..8].try_into().unwrap()),
};
(val as u128, 9)
}
U128_BYTE => {
let val = match endian {
Endianness::Big => u128::from_be_bytes(bytes[..16].try_into().unwrap()),
Endianness::Little => u128::from_le_bytes(bytes[..16].try_into().unwrap()),
};
(val, 17)
}
_ => return invalid_varint_discriminant(IntegerType::Usize, IntegerType::Reserved),
};
read.consume(used);
Ok(out)
} else {
deserialize_varint_cold_u128(read, endian)
}
}
#[test]
fn test_decode_u16() {
let cases: &[(&[u8], u16, u16)] = &[
(&[0], 0, 0),
(&[10], 10, 10),
(&[U16_BYTE, 0, 10], 2560, 10),
];
for &(slice, expected_le, expected_be) in cases {
let mut reader = crate::de::read::SliceReader::new(slice);
let found = varint_decode_u16(&mut reader, Endianness::Little).unwrap();
assert_eq!(expected_le, found);
let mut reader = crate::de::read::SliceReader::new(slice);
let found = varint_decode_u16(&mut reader, Endianness::Big).unwrap();
assert_eq!(expected_be, found);
}
let errors: &[(&[u8], DecodeError)] = &[
(
&[U32_BYTE],
DecodeError::InvalidIntegerType {
expected: IntegerType::U16,
found: IntegerType::U32,
},
),
(
&[U64_BYTE],
DecodeError::InvalidIntegerType {
expected: IntegerType::U16,
found: IntegerType::U64,
},
),
(
&[U128_BYTE],
DecodeError::InvalidIntegerType {
expected: IntegerType::U16,
found: IntegerType::U128,
},
),
(&[U16_BYTE], DecodeError::UnexpectedEnd { additional: 2 }),
(&[U16_BYTE, 0], DecodeError::UnexpectedEnd { additional: 1 }),
];
for (slice, expected) in errors {
let mut reader = crate::de::read::SliceReader::new(slice);
let found = varint_decode_u16(&mut reader, Endianness::Little).unwrap_err();
assert_eq!(std::format!("{:?}", expected), std::format!("{:?}", found));
}
}
#[test]
fn test_decode_u32() {
let cases: &[(&[u8], u32, u32)] = &[
(&[0], 0, 0),
(&[10], 10, 10),
(&[U16_BYTE, 0, 10], 2560, 10),
(&[U32_BYTE, 0, 0, 0, 10], 167_772_160, 10),
];
for &(slice, expected_le, expected_be) in cases {
let mut reader = crate::de::read::SliceReader::new(slice);
let found = varint_decode_u32(&mut reader, Endianness::Little).unwrap();
assert_eq!(expected_le, found);
let mut reader = crate::de::read::SliceReader::new(slice);
let found = varint_decode_u32(&mut reader, Endianness::Big).unwrap();
assert_eq!(expected_be, found);
}
let errors: &[(&[u8], DecodeError)] = &[
(
&[U64_BYTE],
DecodeError::InvalidIntegerType {
expected: IntegerType::U32,
found: IntegerType::U64,
},
),
(
&[U128_BYTE],
DecodeError::InvalidIntegerType {
expected: IntegerType::U32,
found: IntegerType::U128,
},
),
(&[U16_BYTE], DecodeError::UnexpectedEnd { additional: 2 }),
(&[U16_BYTE, 0], DecodeError::UnexpectedEnd { additional: 1 }),
(&[U32_BYTE], DecodeError::UnexpectedEnd { additional: 4 }),
(&[U32_BYTE, 0], DecodeError::UnexpectedEnd { additional: 3 }),
(
&[U32_BYTE, 0, 0],
DecodeError::UnexpectedEnd { additional: 2 },
),
(
&[U32_BYTE, 0, 0, 0],
DecodeError::UnexpectedEnd { additional: 1 },
),
];
for (slice, expected) in errors {
let mut reader = crate::de::read::SliceReader::new(slice);
let found = varint_decode_u32(&mut reader, Endianness::Little).unwrap_err();
assert_eq!(std::format!("{:?}", expected), std::format!("{:?}", found));
}
}
#[test]
fn test_decode_u64() {
let cases: &[(&[u8], u64, u64)] = &[
(&[0], 0, 0),
(&[10], 10, 10),
(&[U16_BYTE, 0, 10], 2560, 10),
(&[U32_BYTE, 0, 0, 0, 10], 167_772_160, 10),
(
&[U64_BYTE, 0, 0, 0, 0, 0, 0, 0, 10],
720_575_940_379_279_360,
10,
),
];
for &(slice, expected_le, expected_be) in cases {
let mut reader = crate::de::read::SliceReader::new(slice);
let found = varint_decode_u64(&mut reader, Endianness::Little).unwrap();
assert_eq!(expected_le, found);
let mut reader = crate::de::read::SliceReader::new(slice);
let found = varint_decode_u64(&mut reader, Endianness::Big).unwrap();
assert_eq!(expected_be, found);
}
let errors: &[(&[u8], DecodeError)] = &[
(
&[U128_BYTE],
DecodeError::InvalidIntegerType {
expected: IntegerType::U64,
found: IntegerType::U128,
},
),
(&[U16_BYTE], DecodeError::UnexpectedEnd { additional: 2 }),
(&[U16_BYTE, 0], DecodeError::UnexpectedEnd { additional: 1 }),
(&[U32_BYTE], DecodeError::UnexpectedEnd { additional: 4 }),
(&[U32_BYTE, 0], DecodeError::UnexpectedEnd { additional: 3 }),
(
&[U32_BYTE, 0, 0],
DecodeError::UnexpectedEnd { additional: 2 },
),
(
&[U32_BYTE, 0, 0, 0],
DecodeError::UnexpectedEnd { additional: 1 },
),
(&[U64_BYTE], DecodeError::UnexpectedEnd { additional: 8 }),
(&[U64_BYTE, 0], DecodeError::UnexpectedEnd { additional: 7 }),
(
&[U64_BYTE, 0, 0],
DecodeError::UnexpectedEnd { additional: 6 },
),
(
&[U64_BYTE, 0, 0, 0],
DecodeError::UnexpectedEnd { additional: 5 },
),
(
&[U64_BYTE, 0, 0, 0, 0],
DecodeError::UnexpectedEnd { additional: 4 },
),
(
&[U64_BYTE, 0, 0, 0, 0, 0],
DecodeError::UnexpectedEnd { additional: 3 },
),
(
&[U64_BYTE, 0, 0, 0, 0, 0, 0],
DecodeError::UnexpectedEnd { additional: 2 },
),
(
&[U64_BYTE, 0, 0, 0, 0, 0, 0, 0],
DecodeError::UnexpectedEnd { additional: 1 },
),
];
for (slice, expected) in errors {
let mut reader = crate::de::read::SliceReader::new(slice);
let found = varint_decode_u64(&mut reader, Endianness::Little).unwrap_err();
assert_eq!(std::format!("{:?}", expected), std::format!("{:?}", found));
}
}
#[test]
fn test_decode_u128() {
let cases: &[(&[u8], u128, u128)] = &[
(&[0], 0, 0),
(&[10], 10, 10),
(&[U16_BYTE, 0, 10], 2560, 10),
(&[U32_BYTE, 0, 0, 0, 10], 167_772_160, 10),
(
&[U64_BYTE, 0, 0, 0, 0, 0, 0, 0, 10],
720_575_940_379_279_360,
10,
),
(
&[U128_BYTE, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10],
13_292_279_957_849_158_729_038_070_602_803_445_760,
10,
),
];
for &(slice, expected_le, expected_be) in cases {
let mut reader = crate::de::read::SliceReader::new(slice);
let found = varint_decode_u128(&mut reader, Endianness::Little).unwrap();
assert_eq!(expected_le, found);
let mut reader = crate::de::read::SliceReader::new(slice);
let found = varint_decode_u128(&mut reader, Endianness::Big).unwrap();
assert_eq!(expected_be, found);
}
let errors: &[(&[u8], DecodeError)] = &[
(&[U16_BYTE], DecodeError::UnexpectedEnd { additional: 2 }),
(&[U16_BYTE, 0], DecodeError::UnexpectedEnd { additional: 1 }),
(&[U32_BYTE], DecodeError::UnexpectedEnd { additional: 4 }),
(&[U32_BYTE, 0], DecodeError::UnexpectedEnd { additional: 3 }),
(
&[U32_BYTE, 0, 0],
DecodeError::UnexpectedEnd { additional: 2 },
),
(
&[U32_BYTE, 0, 0, 0],
DecodeError::UnexpectedEnd { additional: 1 },
),
(&[U64_BYTE], DecodeError::UnexpectedEnd { additional: 8 }),
(&[U64_BYTE, 0], DecodeError::UnexpectedEnd { additional: 7 }),
(
&[U64_BYTE, 0, 0],
DecodeError::UnexpectedEnd { additional: 6 },
),
(
&[U64_BYTE, 0, 0, 0],
DecodeError::UnexpectedEnd { additional: 5 },
),
(
&[U64_BYTE, 0, 0, 0, 0],
DecodeError::UnexpectedEnd { additional: 4 },
),
(
&[U64_BYTE, 0, 0, 0, 0, 0],
DecodeError::UnexpectedEnd { additional: 3 },
),
(
&[U64_BYTE, 0, 0, 0, 0, 0, 0],
DecodeError::UnexpectedEnd { additional: 2 },
),
(
&[U64_BYTE, 0, 0, 0, 0, 0, 0, 0],
DecodeError::UnexpectedEnd { additional: 1 },
),
(&[U128_BYTE], DecodeError::UnexpectedEnd { additional: 16 }),
(
&[U128_BYTE, 0],
DecodeError::UnexpectedEnd { additional: 15 },
),
(
&[U128_BYTE, 0, 0],
DecodeError::UnexpectedEnd { additional: 14 },
),
(
&[U128_BYTE, 0, 0, 0],
DecodeError::UnexpectedEnd { additional: 13 },
),
(
&[U128_BYTE, 0, 0, 0, 0],
DecodeError::UnexpectedEnd { additional: 12 },
),
(
&[U128_BYTE, 0, 0, 0, 0, 0],
DecodeError::UnexpectedEnd { additional: 11 },
),
(
&[U128_BYTE, 0, 0, 0, 0, 0, 0],
DecodeError::UnexpectedEnd { additional: 10 },
),
(
&[U128_BYTE, 0, 0, 0, 0, 0, 0, 0],
DecodeError::UnexpectedEnd { additional: 9 },
),
(
&[U128_BYTE, 0, 0, 0, 0, 0, 0, 0, 0],
DecodeError::UnexpectedEnd { additional: 8 },
),
(
&[U128_BYTE, 0, 0, 0, 0, 0, 0, 0, 0, 0],
DecodeError::UnexpectedEnd { additional: 7 },
),
(
&[U128_BYTE, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
DecodeError::UnexpectedEnd { additional: 6 },
),
(
&[U128_BYTE, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
DecodeError::UnexpectedEnd { additional: 5 },
),
(
&[U128_BYTE, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
DecodeError::UnexpectedEnd { additional: 4 },
),
(
&[U128_BYTE, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
DecodeError::UnexpectedEnd { additional: 3 },
),
(
&[U128_BYTE, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
DecodeError::UnexpectedEnd { additional: 2 },
),
(
&[U128_BYTE, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
DecodeError::UnexpectedEnd { additional: 1 },
),
];
for (slice, expected) in errors {
let mut reader = crate::de::read::SliceReader::new(slice);
let found = varint_decode_u128(&mut reader, Endianness::Little).unwrap_err();
std::dbg!(slice);
assert_eq!(std::format!("{:?}", expected), std::format!("{:?}", found));
}
}

View File

@ -1,318 +0,0 @@
use super::{varint_encode_u128, varint_encode_u16, varint_encode_u32, varint_encode_u64};
use crate::{config::Endianness, enc::write::Writer, error::EncodeError};
pub fn varint_encode_i16<W: Writer>(
writer: &mut W,
endian: Endianness,
val: i16,
) -> Result<(), EncodeError> {
varint_encode_u16(
writer,
endian,
if val < 0 {
// let's avoid the edge case of i16::min_value()
// !n is equal to `-n - 1`, so this is:
// !n * 2 + 1 = 2(-n - 1) + 1 = -2n - 2 + 1 = -2n - 1
!(val as u16) * 2 + 1
} else {
(val as u16) * 2
},
)
}
pub fn varint_encode_i32<W: Writer>(
writer: &mut W,
endian: Endianness,
val: i32,
) -> Result<(), EncodeError> {
varint_encode_u32(
writer,
endian,
if val < 0 {
// let's avoid the edge case of i32::min_value()
// !n is equal to `-n - 1`, so this is:
// !n * 2 + 1 = 2(-n - 1) + 1 = -2n - 2 + 1 = -2n - 1
!(val as u32) * 2 + 1
} else {
(val as u32) * 2
},
)
}
pub fn varint_encode_i64<W: Writer>(
writer: &mut W,
endian: Endianness,
val: i64,
) -> Result<(), EncodeError> {
varint_encode_u64(
writer,
endian,
if val < 0 {
// let's avoid the edge case of i64::min_value()
// !n is equal to `-n - 1`, so this is:
// !n * 2 + 1 = 2(-n - 1) + 1 = -2n - 2 + 1 = -2n - 1
!(val as u64) * 2 + 1
} else {
(val as u64) * 2
},
)
}
pub fn varint_encode_i128<W: Writer>(
writer: &mut W,
endian: Endianness,
val: i128,
) -> Result<(), EncodeError> {
varint_encode_u128(
writer,
endian,
if val < 0 {
// let's avoid the edge case of i128::min_value()
// !n is equal to `-n - 1`, so this is:
// !n * 2 + 1 = 2(-n - 1) + 1 = -2n - 2 + 1 = -2n - 1
!(val as u128) * 2 + 1
} else {
(val as u128) * 2
},
)
}
pub fn varint_encode_isize<W: Writer>(
writer: &mut W,
endian: Endianness,
val: isize,
) -> Result<(), EncodeError> {
// isize is being encoded as a i64
varint_encode_i64(writer, endian, val as i64)
}
#[test]
fn test_encode_i16() {
let cases: &[(i16, &[u8], &[u8])] = &[
(0, &[0], &[0]),
(2, &[4], &[4]),
(256, &[super::U16_BYTE, 0, 2], &[super::U16_BYTE, 2, 0]),
(
16_000,
&[super::U16_BYTE, 0, 125],
&[super::U16_BYTE, 125, 0],
),
(
i16::MAX - 1,
&[super::U16_BYTE, 252, 255],
&[super::U16_BYTE, 255, 252],
),
(
i16::MAX,
&[super::U16_BYTE, 254, 255],
&[super::U16_BYTE, 255, 254],
),
];
use crate::enc::write::SliceWriter;
let mut buffer = [0u8; 20];
for &(value, expected_le, expected_be) in cases {
std::dbg!(value);
// Little endian
let mut writer = SliceWriter::new(&mut buffer);
varint_encode_i16(&mut writer, Endianness::Little, value).unwrap();
assert_eq!(writer.bytes_written(), expected_le.len());
assert_eq!(&buffer[..expected_le.len()], expected_le);
// Big endian
let mut writer = SliceWriter::new(&mut buffer);
varint_encode_i16(&mut writer, Endianness::Big, value).unwrap();
assert_eq!(writer.bytes_written(), expected_be.len());
assert_eq!(&buffer[..expected_be.len()], expected_be);
}
}
#[test]
fn test_encode_i32() {
let cases: &[(i32, &[u8], &[u8])] = &[
(0, &[0], &[0]),
(2, &[4], &[4]),
(256, &[super::U16_BYTE, 0, 2], &[super::U16_BYTE, 2, 0]),
(
16_000,
&[super::U16_BYTE, 0, 125],
&[super::U16_BYTE, 125, 0],
),
(
40_000,
&[super::U32_BYTE, 128, 56, 1, 0],
&[super::U32_BYTE, 0, 1, 56, 128],
),
(
i32::MAX - 1,
&[super::U32_BYTE, 252, 255, 255, 255],
&[super::U32_BYTE, 255, 255, 255, 252],
),
(
i32::MAX,
&[super::U32_BYTE, 254, 255, 255, 255],
&[super::U32_BYTE, 255, 255, 255, 254],
),
];
use crate::enc::write::SliceWriter;
let mut buffer = [0u8; 20];
for &(value, expected_le, expected_be) in cases {
std::dbg!(value);
// Little endian
let mut writer = SliceWriter::new(&mut buffer);
varint_encode_i32(&mut writer, Endianness::Little, value).unwrap();
assert_eq!(writer.bytes_written(), expected_le.len());
assert_eq!(&buffer[..expected_le.len()], expected_le);
// Big endian
let mut writer = SliceWriter::new(&mut buffer);
varint_encode_i32(&mut writer, Endianness::Big, value).unwrap();
assert_eq!(writer.bytes_written(), expected_be.len());
assert_eq!(&buffer[..expected_be.len()], expected_be);
}
}
#[test]
fn test_encode_i64() {
let cases: &[(i64, &[u8], &[u8])] = &[
(0, &[0], &[0]),
(2, &[4], &[4]),
(256, &[super::U16_BYTE, 0, 2], &[super::U16_BYTE, 2, 0]),
(
16_000,
&[super::U16_BYTE, 0, 125],
&[super::U16_BYTE, 125, 0],
),
(
40_000,
&[super::U32_BYTE, 128, 56, 1, 0],
&[super::U32_BYTE, 0, 1, 56, 128],
),
(
3_000_000_000,
&[super::U64_BYTE, 0, 188, 160, 101, 1, 0, 0, 0],
&[super::U64_BYTE, 0, 0, 0, 1, 101, 160, 188, 0],
),
(
i64::MAX - 1,
&[super::U64_BYTE, 252, 255, 255, 255, 255, 255, 255, 255],
&[super::U64_BYTE, 255, 255, 255, 255, 255, 255, 255, 252],
),
(
i64::MAX,
&[super::U64_BYTE, 254, 255, 255, 255, 255, 255, 255, 255],
&[super::U64_BYTE, 255, 255, 255, 255, 255, 255, 255, 254],
),
];
use crate::enc::write::SliceWriter;
let mut buffer = [0u8; 20];
for &(value, expected_le, expected_be) in cases {
std::dbg!(value);
// Little endian
let mut writer = SliceWriter::new(&mut buffer);
varint_encode_i64(&mut writer, Endianness::Little, value).unwrap();
assert_eq!(writer.bytes_written(), expected_le.len());
assert_eq!(&buffer[..expected_le.len()], expected_le);
// Big endian
let mut writer = SliceWriter::new(&mut buffer);
varint_encode_i64(&mut writer, Endianness::Big, value).unwrap();
assert_eq!(writer.bytes_written(), expected_be.len());
assert_eq!(&buffer[..expected_be.len()], expected_be);
}
}
#[test]
fn test_encode_i128() {
#[rustfmt::skip]
let cases: &[(i128, &[u8], &[u8])] = &[
(0, &[0], &[0]),
(2, &[4], &[4]),
(256, &[super::U16_BYTE, 0, 2], &[super::U16_BYTE, 2, 0]),
(
16_000,
&[super::U16_BYTE, 0, 125],
&[super::U16_BYTE, 125, 0],
),
(
40_000,
&[super::U32_BYTE, 128, 56, 1, 0],
&[super::U32_BYTE, 0, 1, 56, 128],
),
(
3_000_000_000,
&[super::U64_BYTE, 0, 188, 160, 101, 1, 0, 0, 0],
&[super::U64_BYTE, 0, 0, 0, 1, 101, 160, 188, 0],
),
(
11_000_000_000_000_000_000,
&[
super::U128_BYTE,
0, 0, 152, 98, 112, 179, 79, 49,
1, 0, 0, 0, 0, 0, 0, 0,
],
&[
super::U128_BYTE,
0, 0, 0, 0, 0, 0, 0, 1,
49, 79, 179, 112, 98, 152, 0, 0,
],
),
(
i128::MAX - 1,
&[
super::U128_BYTE,
252, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255,
],
&[
super::U128_BYTE,
255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 252,
],
),
(
i128::MAX,
&[
super::U128_BYTE,
254, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255,
],
&[
super::U128_BYTE,
255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 254,
],
),
];
use crate::enc::write::SliceWriter;
let mut buffer = [0u8; 20];
for &(value, expected_le, expected_be) in cases {
std::dbg!(value);
// Little endian
let mut writer = SliceWriter::new(&mut buffer);
varint_encode_i128(&mut writer, Endianness::Little, value).unwrap();
assert_eq!(writer.bytes_written(), expected_le.len());
assert_eq!(&buffer[..expected_le.len()], expected_le);
// Big endian
let mut writer = SliceWriter::new(&mut buffer);
varint_encode_i128(&mut writer, Endianness::Big, value).unwrap();
assert_eq!(writer.bytes_written(), expected_be.len());
assert_eq!(&buffer[..expected_be.len()], expected_be);
}
}

View File

@ -1,383 +0,0 @@
use super::{SINGLE_BYTE_MAX, U128_BYTE, U16_BYTE, U32_BYTE, U64_BYTE};
use crate::{config::Endianness, enc::write::Writer, error::EncodeError};
pub fn varint_encode_u16<W: Writer>(
writer: &mut W,
endian: Endianness,
val: u16,
) -> Result<(), EncodeError> {
if val <= SINGLE_BYTE_MAX as _ {
writer.write(&[val as u8])
} else {
writer.write(&[U16_BYTE])?;
match endian {
Endianness::Big => writer.write(&val.to_be_bytes()),
Endianness::Little => writer.write(&val.to_le_bytes()),
}
}
}
pub fn varint_encode_u32<W: Writer>(
writer: &mut W,
endian: Endianness,
val: u32,
) -> Result<(), EncodeError> {
if val <= SINGLE_BYTE_MAX as _ {
writer.write(&[val as u8])
} else if val <= u16::MAX as _ {
writer.write(&[U16_BYTE])?;
match endian {
Endianness::Big => writer.write(&(val as u16).to_be_bytes()),
Endianness::Little => writer.write(&(val as u16).to_le_bytes()),
}
} else {
writer.write(&[U32_BYTE])?;
match endian {
Endianness::Big => writer.write(&val.to_be_bytes()),
Endianness::Little => writer.write(&val.to_le_bytes()),
}
}
}
pub fn varint_encode_u64<W: Writer>(
writer: &mut W,
endian: Endianness,
val: u64,
) -> Result<(), EncodeError> {
if val <= SINGLE_BYTE_MAX as _ {
writer.write(&[val as u8])
} else if val <= u16::MAX as _ {
writer.write(&[U16_BYTE])?;
match endian {
Endianness::Big => writer.write(&(val as u16).to_be_bytes()),
Endianness::Little => writer.write(&(val as u16).to_le_bytes()),
}
} else if val <= u32::MAX as _ {
writer.write(&[U32_BYTE])?;
match endian {
Endianness::Big => writer.write(&(val as u32).to_be_bytes()),
Endianness::Little => writer.write(&(val as u32).to_le_bytes()),
}
} else {
writer.write(&[U64_BYTE])?;
match endian {
Endianness::Big => writer.write(&val.to_be_bytes()),
Endianness::Little => writer.write(&val.to_le_bytes()),
}
}
}
pub fn varint_encode_u128<W: Writer>(
writer: &mut W,
endian: Endianness,
val: u128,
) -> Result<(), EncodeError> {
if val <= SINGLE_BYTE_MAX as _ {
writer.write(&[val as u8])
} else if val <= u16::MAX as _ {
writer.write(&[U16_BYTE])?;
match endian {
Endianness::Big => writer.write(&(val as u16).to_be_bytes()),
Endianness::Little => writer.write(&(val as u16).to_le_bytes()),
}
} else if val <= u32::MAX as _ {
writer.write(&[U32_BYTE])?;
match endian {
Endianness::Big => writer.write(&(val as u32).to_be_bytes()),
Endianness::Little => writer.write(&(val as u32).to_le_bytes()),
}
} else if val <= u64::MAX as _ {
writer.write(&[U64_BYTE])?;
match endian {
Endianness::Big => writer.write(&(val as u64).to_be_bytes()),
Endianness::Little => writer.write(&(val as u64).to_le_bytes()),
}
} else {
writer.write(&[U128_BYTE])?;
match endian {
Endianness::Big => writer.write(&val.to_be_bytes()),
Endianness::Little => writer.write(&val.to_le_bytes()),
}
}
}
pub fn varint_encode_usize<W: Writer>(
writer: &mut W,
endian: Endianness,
val: usize,
) -> Result<(), EncodeError> {
// usize is being encoded as a u64
varint_encode_u64(writer, endian, val as u64)
}
#[test]
fn test_encode_u16() {
use crate::enc::write::SliceWriter;
let mut buffer = [0u8; 20];
// these should all encode to a single byte
for i in 0u16..=SINGLE_BYTE_MAX as u16 {
let mut writer = SliceWriter::new(&mut buffer);
varint_encode_u16(&mut writer, Endianness::Big, i).unwrap();
assert_eq!(writer.bytes_written(), 1);
assert_eq!(buffer[0] as u16, i);
// Assert endianness doesn't matter
let mut writer = SliceWriter::new(&mut buffer);
varint_encode_u16(&mut writer, Endianness::Little, i).unwrap();
assert_eq!(writer.bytes_written(), 1);
assert_eq!(buffer[0] as u16, i);
}
// these values should encode in 3 bytes (leading byte + 2 bytes)
// Values chosen at random, add new cases as needed
for i in [
SINGLE_BYTE_MAX as u16 + 1,
300,
500,
700,
888,
1234,
u16::MAX,
] {
let mut writer = SliceWriter::new(&mut buffer);
varint_encode_u16(&mut writer, Endianness::Big, i).unwrap();
assert_eq!(writer.bytes_written(), 3);
assert_eq!(buffer[0], U16_BYTE);
assert_eq!(&buffer[1..3], &i.to_be_bytes());
let mut writer = SliceWriter::new(&mut buffer);
varint_encode_u16(&mut writer, Endianness::Little, i).unwrap();
assert_eq!(writer.bytes_written(), 3);
assert_eq!(buffer[0], U16_BYTE);
assert_eq!(&buffer[1..3], &i.to_le_bytes());
}
}
#[test]
fn test_encode_u32() {
use crate::enc::write::SliceWriter;
let mut buffer = [0u8; 20];
// these should all encode to a single byte
for i in 0u32..=SINGLE_BYTE_MAX as u32 {
let mut writer = SliceWriter::new(&mut buffer);
varint_encode_u32(&mut writer, Endianness::Big, i).unwrap();
assert_eq!(writer.bytes_written(), 1);
assert_eq!(buffer[0] as u32, i);
// Assert endianness doesn't matter
let mut writer = SliceWriter::new(&mut buffer);
varint_encode_u32(&mut writer, Endianness::Little, i).unwrap();
assert_eq!(writer.bytes_written(), 1);
assert_eq!(buffer[0] as u32, i);
}
// these values should encode in 3 bytes (leading byte + 2 bytes)
// Values chosen at random, add new cases as needed
for i in [
SINGLE_BYTE_MAX as u32 + 1,
300,
500,
700,
888,
1234,
u16::MAX as u32,
] {
let mut writer = SliceWriter::new(&mut buffer);
varint_encode_u32(&mut writer, Endianness::Big, i).unwrap();
assert_eq!(writer.bytes_written(), 3);
assert_eq!(buffer[0], U16_BYTE);
assert_eq!(&buffer[1..3], &(i as u16).to_be_bytes());
let mut writer = SliceWriter::new(&mut buffer);
varint_encode_u32(&mut writer, Endianness::Little, i).unwrap();
assert_eq!(writer.bytes_written(), 3);
assert_eq!(buffer[0], U16_BYTE);
assert_eq!(&buffer[1..3], &(i as u16).to_le_bytes());
}
// these values should encode in 5 bytes (leading byte + 4 bytes)
// Values chosen at random, add new cases as needed
for i in [u16::MAX as u32 + 1, 100_000, 1_000_000, u32::MAX] {
let mut writer = SliceWriter::new(&mut buffer);
varint_encode_u32(&mut writer, Endianness::Big, i).unwrap();
assert_eq!(writer.bytes_written(), 5);
assert_eq!(buffer[0], U32_BYTE);
assert_eq!(&buffer[1..5], &i.to_be_bytes());
let mut writer = SliceWriter::new(&mut buffer);
varint_encode_u32(&mut writer, Endianness::Little, i).unwrap();
assert_eq!(writer.bytes_written(), 5);
assert_eq!(buffer[0], U32_BYTE);
assert_eq!(&buffer[1..5], &i.to_le_bytes());
}
}
#[test]
fn test_encode_u64() {
use crate::enc::write::SliceWriter;
let mut buffer = [0u8; 20];
// these should all encode to a single byte
for i in 0u64..=SINGLE_BYTE_MAX as u64 {
let mut writer = SliceWriter::new(&mut buffer);
varint_encode_u64(&mut writer, Endianness::Big, i).unwrap();
assert_eq!(writer.bytes_written(), 1);
assert_eq!(buffer[0] as u64, i);
// Assert endianness doesn't matter
let mut writer = SliceWriter::new(&mut buffer);
varint_encode_u64(&mut writer, Endianness::Little, i).unwrap();
assert_eq!(writer.bytes_written(), 1);
assert_eq!(buffer[0] as u64, i);
}
// these values should encode in 3 bytes (leading byte + 2 bytes)
// Values chosen at random, add new cases as needed
for i in [
SINGLE_BYTE_MAX as u64 + 1,
300,
500,
700,
888,
1234,
u16::MAX as u64,
] {
let mut writer = SliceWriter::new(&mut buffer);
varint_encode_u64(&mut writer, Endianness::Big, i).unwrap();
assert_eq!(writer.bytes_written(), 3);
assert_eq!(buffer[0], U16_BYTE);
assert_eq!(&buffer[1..3], &(i as u16).to_be_bytes());
let mut writer = SliceWriter::new(&mut buffer);
varint_encode_u64(&mut writer, Endianness::Little, i).unwrap();
assert_eq!(writer.bytes_written(), 3);
assert_eq!(buffer[0], U16_BYTE);
assert_eq!(&buffer[1..3], &(i as u16).to_le_bytes());
}
// these values should encode in 5 bytes (leading byte + 4 bytes)
// Values chosen at random, add new cases as needed
for i in [u16::MAX as u64 + 1, 100_000, 1_000_000, u32::MAX as u64] {
let mut writer = SliceWriter::new(&mut buffer);
varint_encode_u64(&mut writer, Endianness::Big, i).unwrap();
assert_eq!(writer.bytes_written(), 5);
assert_eq!(buffer[0], U32_BYTE);
assert_eq!(&buffer[1..5], &(i as u32).to_be_bytes());
let mut writer = SliceWriter::new(&mut buffer);
varint_encode_u64(&mut writer, Endianness::Little, i).unwrap();
assert_eq!(writer.bytes_written(), 5);
assert_eq!(buffer[0], U32_BYTE);
assert_eq!(&buffer[1..5], &(i as u32).to_le_bytes());
}
// these values should encode in 9 bytes (leading byte + 8 bytes)
// Values chosen at random, add new cases as needed
for i in [u32::MAX as u64 + 1, 5_000_000_000, u64::MAX] {
let mut writer = SliceWriter::new(&mut buffer);
varint_encode_u64(&mut writer, Endianness::Big, i).unwrap();
assert_eq!(writer.bytes_written(), 9);
assert_eq!(buffer[0], U64_BYTE);
assert_eq!(&buffer[1..9], &i.to_be_bytes());
let mut writer = SliceWriter::new(&mut buffer);
varint_encode_u64(&mut writer, Endianness::Little, i).unwrap();
assert_eq!(writer.bytes_written(), 9);
assert_eq!(buffer[0], U64_BYTE);
assert_eq!(&buffer[1..9], &i.to_le_bytes());
}
}
#[test]
fn test_encode_u128() {
use crate::enc::write::SliceWriter;
let mut buffer = [0u8; 20];
// these should all encode to a single byte
for i in 0u128..=SINGLE_BYTE_MAX as u128 {
let mut writer = SliceWriter::new(&mut buffer);
varint_encode_u128(&mut writer, Endianness::Big, i).unwrap();
assert_eq!(writer.bytes_written(), 1);
assert_eq!(buffer[0] as u128, i);
// Assert endianness doesn't matter
let mut writer = SliceWriter::new(&mut buffer);
varint_encode_u128(&mut writer, Endianness::Little, i).unwrap();
assert_eq!(writer.bytes_written(), 1);
assert_eq!(buffer[0] as u128, i);
}
// these values should encode in 3 bytes (leading byte + 2 bytes)
// Values chosen at random, add new cases as needed
for i in [
SINGLE_BYTE_MAX as u128 + 1,
300,
500,
700,
888,
1234,
u16::MAX as u128,
] {
let mut writer = SliceWriter::new(&mut buffer);
varint_encode_u128(&mut writer, Endianness::Big, i).unwrap();
assert_eq!(writer.bytes_written(), 3);
assert_eq!(buffer[0], U16_BYTE);
assert_eq!(&buffer[1..3], &(i as u16).to_be_bytes());
let mut writer = SliceWriter::new(&mut buffer);
varint_encode_u128(&mut writer, Endianness::Little, i).unwrap();
assert_eq!(writer.bytes_written(), 3);
assert_eq!(buffer[0], U16_BYTE);
assert_eq!(&buffer[1..3], &(i as u16).to_le_bytes());
}
// these values should encode in 5 bytes (leading byte + 4 bytes)
// Values chosen at random, add new cases as needed
for i in [u16::MAX as u128 + 1, 100_000, 1_000_000, u32::MAX as u128] {
let mut writer = SliceWriter::new(&mut buffer);
varint_encode_u128(&mut writer, Endianness::Big, i).unwrap();
assert_eq!(writer.bytes_written(), 5);
assert_eq!(buffer[0], U32_BYTE);
assert_eq!(&buffer[1..5], &(i as u32).to_be_bytes());
let mut writer = SliceWriter::new(&mut buffer);
varint_encode_u128(&mut writer, Endianness::Little, i).unwrap();
assert_eq!(writer.bytes_written(), 5);
assert_eq!(buffer[0], U32_BYTE);
assert_eq!(&buffer[1..5], &(i as u32).to_le_bytes());
}
// these values should encode in 9 bytes (leading byte + 8 bytes)
// Values chosen at random, add new cases as needed
for i in [u32::MAX as u128 + 1, 5_000_000_000, u64::MAX as u128] {
let mut writer = SliceWriter::new(&mut buffer);
varint_encode_u128(&mut writer, Endianness::Big, i).unwrap();
assert_eq!(writer.bytes_written(), 9);
assert_eq!(buffer[0], U64_BYTE);
assert_eq!(&buffer[1..9], &(i as u64).to_be_bytes());
let mut writer = SliceWriter::new(&mut buffer);
varint_encode_u128(&mut writer, Endianness::Little, i).unwrap();
assert_eq!(writer.bytes_written(), 9);
assert_eq!(buffer[0], U64_BYTE);
assert_eq!(&buffer[1..9], &(i as u64).to_le_bytes());
}
// these values should encode in 17 bytes (leading byte + 16 bytes)
// Values chosen at random, add new cases as needed
for i in [u64::MAX as u128 + 1, u128::MAX] {
let mut writer = SliceWriter::new(&mut buffer);
varint_encode_u128(&mut writer, Endianness::Big, i).unwrap();
assert_eq!(writer.bytes_written(), 17);
assert_eq!(buffer[0], U128_BYTE);
assert_eq!(&buffer[1..17], &i.to_be_bytes());
let mut writer = SliceWriter::new(&mut buffer);
varint_encode_u128(&mut writer, Endianness::Little, i).unwrap();
assert_eq!(writer.bytes_written(), 17);
assert_eq!(buffer[0], U128_BYTE);
assert_eq!(&buffer[1..17], &i.to_le_bytes());
}
}

View File

@ -1,29 +0,0 @@
mod decode_signed;
mod decode_unsigned;
mod encode_signed;
mod encode_unsigned;
pub use self::{
decode_signed::{
varint_decode_i128, varint_decode_i16, varint_decode_i32, varint_decode_i64,
varint_decode_isize,
},
decode_unsigned::{
varint_decode_u128, varint_decode_u16, varint_decode_u32, varint_decode_u64,
varint_decode_usize,
},
encode_signed::{
varint_encode_i128, varint_encode_i16, varint_encode_i32, varint_encode_i64,
varint_encode_isize,
},
encode_unsigned::{
varint_encode_u128, varint_encode_u16, varint_encode_u32, varint_encode_u64,
varint_encode_usize,
},
};
const SINGLE_BYTE_MAX: u8 = 250;
const U16_BYTE: u8 = 251;
const U32_BYTE: u8 = 252;
const U64_BYTE: u8 = 253;
const U128_BYTE: u8 = 254;

View File

@ -1,197 +0,0 @@
#![allow(clippy::disallowed_names)]
#![cfg(feature = "alloc")]
extern crate alloc;
mod utils;
use alloc::borrow::Cow;
use alloc::collections::*;
#[cfg(not(feature = "serde"))]
use alloc::rc::Rc;
#[cfg(all(target_has_atomic = "ptr", not(feature = "serde")))]
use alloc::sync::Arc;
use utils::{the_same, the_same_with_comparer};
struct Foo {
pub a: u32,
pub b: u32,
}
impl bincode::Encode for Foo {
fn encode<E: bincode::enc::Encoder>(
&self,
encoder: &mut E,
) -> Result<(), bincode::error::EncodeError> {
self.a.encode(encoder)?;
self.b.encode(encoder)?;
Ok(())
}
}
impl<Context> bincode::Decode<Context> for Foo {
fn decode<D: bincode::de::Decoder>(
decoder: &mut D,
) -> Result<Self, bincode::error::DecodeError> {
Ok(Self {
a: bincode::Decode::decode(decoder)?,
b: bincode::Decode::decode(decoder)?,
})
}
}
bincode::impl_borrow_decode!(Foo);
#[test]
fn test_vec() {
let vec = bincode::encode_to_vec(Foo { a: 5, b: 10 }, bincode::config::standard()).unwrap();
assert_eq!(vec, &[5, 10]);
let (foo, len): (Foo, usize) =
bincode::decode_from_slice(&vec, bincode::config::standard()).unwrap();
assert_eq!(foo.a, 5);
assert_eq!(foo.b, 10);
assert_eq!(len, 2);
let vec: Vec<u8> = bincode::decode_from_slice(
&[4, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4],
bincode::config::legacy(),
)
.unwrap()
.0;
assert_eq!(vec, &[1, 2, 3, 4]);
let vec: Vec<Cow<'static, u8>> = bincode::decode_from_slice(
&[4, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4],
bincode::config::legacy(),
)
.unwrap()
.0;
assert_eq!(
vec,
&[
Cow::Borrowed(&1),
Cow::Borrowed(&2),
Cow::Borrowed(&3),
Cow::Borrowed(&4)
]
);
}
#[test]
fn test_alloc_commons() {
the_same::<Vec<u32>>(vec![1, 2, 3, 4, 5]);
the_same(String::from("Hello world"));
the_same(Box::<u32>::new(5));
the_same(Box::<[u32]>::from(vec![1, 2, 3, 4, 5]));
the_same(Cow::<u32>::Owned(5));
the_same(Cow::<u32>::Borrowed(&5));
#[cfg(not(feature = "serde"))]
{
// Serde doesn't support Rc or Arc
the_same(Rc::<u32>::new(5));
the_same(Rc::<[u32]>::from(vec![1, 2, 3, 4, 5]));
#[cfg(target_has_atomic = "ptr")]
{
the_same(Arc::<u32>::new(5));
the_same(Arc::<[u32]>::from(vec![1, 2, 3, 4, 5]));
}
}
the_same_with_comparer(
{
let mut map = BinaryHeap::<u32>::new();
map.push(1);
map.push(2);
map.push(3);
map.push(4);
map.push(5);
map
},
|a, b| a.iter().collect::<Vec<_>>() == b.iter().collect::<Vec<_>>(),
);
the_same({
let mut map = BTreeMap::<u32, i32>::new();
map.insert(5, -5);
map
});
the_same({
let mut set = BTreeSet::<u32>::new();
set.insert(5);
set
});
the_same({
let mut set = VecDeque::<u32>::new();
set.push_back(15);
set.push_front(5);
set
});
}
#[test]
fn test_container_limits() {
use bincode::{error::DecodeError, BorrowDecode, Decode};
const DECODE_LIMIT: usize = 100_000;
// for this test we'll create a malformed package of a lot of bytes
let test_cases = &[
// u64::max_value(), should overflow
#[cfg(target_pointer_width = "64")]
bincode::encode_to_vec(u64::MAX, bincode::config::standard()).unwrap(),
#[cfg(target_pointer_width = "32")]
bincode::encode_to_vec(u32::MAX, bincode::config::standard()).unwrap(),
// A high value which doesn't overflow, but exceeds the decode limit
bincode::encode_to_vec(DECODE_LIMIT as u64, bincode::config::standard()).unwrap(),
];
fn validate_fail<T: Decode<()> + for<'de> BorrowDecode<'de, ()> + core::fmt::Debug>(
slice: &[u8],
) {
let result = bincode::decode_from_slice::<T, _>(
slice,
bincode::config::standard().with_limit::<DECODE_LIMIT>(),
);
let name = core::any::type_name::<T>();
match result {
Ok(_) => panic!("Decoding {} should fail, it instead succeeded", name),
Err(DecodeError::OutsideUsizeRange(_)) if cfg!(target_pointer_width = "32") => {},
Err(DecodeError::LimitExceeded) => {},
Err(e) => panic!("Expected OutsideUsizeRange (on 32 bit platforms) or LimitExceeded whilst decoding {}, got {:?}", name, e),
}
}
for slice in test_cases {
validate_fail::<BinaryHeap<i32>>(slice);
validate_fail::<BTreeMap<i32, i32>>(slice);
validate_fail::<BTreeSet<i32>>(slice);
validate_fail::<VecDeque<i32>>(slice);
validate_fail::<Vec<i32>>(slice);
validate_fail::<String>(slice);
#[cfg(feature = "std")]
{
validate_fail::<std::collections::HashMap<i32, i32>>(slice);
validate_fail::<std::collections::HashSet<i32>>(slice);
}
}
}
#[cfg(target_has_atomic = "ptr")]
#[test]
fn test_arc_str() {
use alloc::sync::Arc;
let start: Arc<str> = Arc::from("Example String");
let mut target = [0u8; 100];
let config = bincode::config::standard();
let len = {
let start: Arc<str> = Arc::clone(&start);
bincode::encode_into_slice(start, &mut target, config).unwrap()
};
let slice = &target[..len];
let decoded: Arc<str> = bincode::borrow_decode_from_slice(slice, config).unwrap().0;
assert_eq!(decoded, start);
}

View File

@ -1,66 +0,0 @@
mod utils;
use core::sync::atomic::Ordering;
#[cfg(target_has_atomic = "8")]
use core::sync::atomic::{AtomicBool, AtomicI8, AtomicU8};
#[cfg(target_has_atomic = "16")]
use core::sync::atomic::{AtomicI16, AtomicU16};
#[cfg(target_has_atomic = "32")]
use core::sync::atomic::{AtomicI32, AtomicU32};
#[cfg(target_has_atomic = "64")]
use core::sync::atomic::{AtomicI64, AtomicU64};
#[cfg(target_has_atomic = "ptr")]
use core::sync::atomic::{AtomicIsize, AtomicUsize};
use utils::the_same_with_comparer;
#[test]
fn test_atomic_commons() {
#[cfg(target_has_atomic = "8")]
the_same_with_comparer(AtomicBool::new(true), |a, b| {
a.load(Ordering::SeqCst) == b.load(Ordering::SeqCst)
});
#[cfg(target_has_atomic = "8")]
the_same_with_comparer(AtomicBool::new(false), |a, b| {
a.load(Ordering::SeqCst) == b.load(Ordering::SeqCst)
});
#[cfg(target_has_atomic = "8")]
the_same_with_comparer(AtomicU8::new(0), |a, b| {
a.load(Ordering::SeqCst) == b.load(Ordering::SeqCst)
});
#[cfg(target_has_atomic = "16")]
the_same_with_comparer(AtomicU16::new(0), |a, b| {
a.load(Ordering::SeqCst) == b.load(Ordering::SeqCst)
});
#[cfg(target_has_atomic = "32")]
the_same_with_comparer(AtomicU32::new(0), |a, b| {
a.load(Ordering::SeqCst) == b.load(Ordering::SeqCst)
});
#[cfg(target_has_atomic = "64")]
the_same_with_comparer(AtomicU64::new(0), |a, b| {
a.load(Ordering::SeqCst) == b.load(Ordering::SeqCst)
});
#[cfg(target_has_atomic = "ptr")]
the_same_with_comparer(AtomicUsize::new(0), |a, b| {
a.load(Ordering::SeqCst) == b.load(Ordering::SeqCst)
});
#[cfg(target_has_atomic = "8")]
the_same_with_comparer(AtomicI8::new(0), |a, b| {
a.load(Ordering::SeqCst) == b.load(Ordering::SeqCst)
});
#[cfg(target_has_atomic = "16")]
the_same_with_comparer(AtomicI16::new(0), |a, b| {
a.load(Ordering::SeqCst) == b.load(Ordering::SeqCst)
});
#[cfg(target_has_atomic = "32")]
the_same_with_comparer(AtomicI32::new(0), |a, b| {
a.load(Ordering::SeqCst) == b.load(Ordering::SeqCst)
});
#[cfg(target_has_atomic = "64")]
the_same_with_comparer(AtomicI64::new(0), |a, b| {
a.load(Ordering::SeqCst) == b.load(Ordering::SeqCst)
});
#[cfg(target_has_atomic = "ptr")]
the_same_with_comparer(AtomicIsize::new(0), |a, b| {
a.load(Ordering::SeqCst) == b.load(Ordering::SeqCst)
});
}

View File

@ -1,310 +0,0 @@
mod utils;
use bincode::error::DecodeError;
use core::cell::{Cell, RefCell};
use core::cmp::Reverse;
use core::ops::Bound;
use core::time::Duration;
use std::num::*;
use utils::{the_same, the_same_with_comparer};
#[test]
fn test_numbers() {
// integer types
the_same(5u8);
the_same(5u16);
the_same(5u32);
the_same(5u64);
the_same(5u128);
the_same(5usize);
the_same(5i8);
the_same(5i16);
the_same(5i32);
the_same(5i64);
the_same(5i128);
the_same(5isize);
println!("Test {:?}", 5.0f32);
the_same_with_comparer(5.0f32, |a, b| (a - b).abs() <= f32::EPSILON);
the_same_with_comparer(5.0f64, |a, b| (a - b).abs() <= f64::EPSILON);
// bool
the_same(true);
the_same(false);
// utf8 characters
for char in "aÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö文😀😁😂😃".chars()
{
the_same(char);
}
// tuples, up to 8
the_same((1u8,));
the_same((1u8, 2u8));
the_same((1u8, 2u8, 3u8));
the_same((1u8, 2u8, 3u8, 4u8));
the_same((1u8, 2u8, 3u8, 4u8, 5u8));
the_same((1u8, 2u8, 3u8, 4u8, 5u8, 6u8));
the_same((1u8, 2u8, 3u8, 4u8, 5u8, 6u8, 7u8));
the_same((1u8, 2u8, 3u8, 4u8, 5u8, 6u8, 7u8, 8u8));
// arrays
#[rustfmt::skip]
#[cfg(not(feature = "serde"))] // serde doesn't support arrays this big
the_same([
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32,
33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64,
65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80,
81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96,
97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112,
113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128,
129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144,
145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160,
161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176,
177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192,
193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208,
209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224,
225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240,
241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255
]);
// Common types
the_same(Option::<u32>::None);
the_same(Option::<u32>::Some(1234));
the_same(Result::<u32, u8>::Ok(1555));
the_same(Result::<u32, u8>::Err(15));
the_same(Cell::<u32>::new(15));
the_same(RefCell::<u32>::new(15));
the_same(Duration::new(5, 730023852));
the_same(5u8..10u8);
the_same(5u8..=10u8);
the_same(Bound::<usize>::Unbounded);
the_same(Bound::<usize>::Included(105));
the_same(Bound::<usize>::Excluded(5));
// NonZero* types
the_same(NonZeroU8::new(0));
the_same(NonZeroU8::new(123));
the_same(NonZeroU16::new(0));
the_same(NonZeroU16::new(12345));
the_same(NonZeroU32::new(0));
the_same(NonZeroU32::new(12345));
the_same(NonZeroU64::new(0));
the_same(NonZeroU64::new(12345));
the_same(NonZeroU128::new(0));
the_same(NonZeroU128::new(12345));
the_same(NonZeroUsize::new(0));
the_same(NonZeroUsize::new(12345));
the_same(NonZeroI8::new(0));
the_same(NonZeroI8::new(123));
the_same(NonZeroI16::new(0));
the_same(NonZeroI16::new(12345));
the_same(NonZeroI32::new(0));
the_same(NonZeroI32::new(12345));
the_same(NonZeroI64::new(0));
the_same(NonZeroI64::new(12345));
the_same(NonZeroI128::new(0));
the_same(NonZeroI128::new(12345));
the_same(NonZeroIsize::new(0));
the_same(NonZeroIsize::new(12345));
// Wrapping types
the_same(Wrapping(5u8));
the_same(Wrapping(5u16));
the_same(Wrapping(5u32));
the_same(Wrapping(5u64));
the_same(Wrapping(5u128));
the_same(Wrapping(5usize));
the_same(Wrapping(5i8));
the_same(Wrapping(5i16));
the_same(Wrapping(5i32));
the_same(Wrapping(5i64));
the_same(Wrapping(5i128));
the_same(Wrapping(5isize));
// Reverse types
the_same(Reverse(5u8));
the_same(Reverse(5u16));
the_same(Reverse(5u32));
the_same(Reverse(5u64));
the_same(Reverse(5u128));
the_same(Reverse(5usize));
the_same(Reverse(5i8));
the_same(Reverse(5i16));
the_same(Reverse(5i32));
the_same(Reverse(5i64));
the_same(Reverse(5i128));
the_same(Reverse(5isize));
}
#[test]
fn test_refcell_already_borrowed() {
let cell = RefCell::new(5u32);
// first get a mutable reference to the cell
let _mutable_guard = cell.borrow_mut();
// now try to encode it
let mut slice = [0u8; 10];
let result = bincode::encode_into_slice(&cell, &mut slice, bincode::config::standard())
.expect_err("Encoding a borrowed refcell should fail");
match result {
bincode::error::EncodeError::RefCellAlreadyBorrowed { .. } => {} // ok
x => panic!("Expected a RefCellAlreadyBorrowed error, found {:?}", x),
}
}
#[test]
fn test_slice() {
let mut buffer = [0u8; 32];
let input: &[u8] = &[1, 2, 3, 4, 5, 6, 7];
bincode::encode_into_slice(input, &mut buffer, bincode::config::standard()).unwrap();
assert_eq!(&buffer[..8], &[7, 1, 2, 3, 4, 5, 6, 7]);
let (output, len): (&[u8], usize) =
bincode::borrow_decode_from_slice(&buffer[..8], bincode::config::standard()).unwrap();
assert_eq!(input, output);
assert_eq!(len, 8);
}
#[test]
fn test_option_slice() {
let mut buffer = [0u8; 32];
let input: Option<&[u8]> = Some(&[1, 2, 3, 4, 5, 6, 7]);
let n = bincode::encode_into_slice(input, &mut buffer, bincode::config::standard()).unwrap();
assert_eq!(&buffer[..n], &[1, 7, 1, 2, 3, 4, 5, 6, 7]);
let (output, len): (Option<&[u8]>, usize) =
bincode::borrow_decode_from_slice(&buffer[..n], bincode::config::standard()).unwrap();
assert_eq!(input, output);
assert_eq!(len, n);
let mut buffer = [0u8; 32];
let input: Option<&[u8]> = None;
let n = bincode::encode_into_slice(input, &mut buffer, bincode::config::standard()).unwrap();
assert_eq!(&buffer[..n], &[0]);
let (output, len): (Option<&[u8]>, usize) =
bincode::borrow_decode_from_slice(&buffer[..n], bincode::config::standard()).unwrap();
assert_eq!(input, output);
assert_eq!(len, n);
}
#[test]
fn test_str() {
let mut buffer = [0u8; 32];
let input: &str = "Hello world";
bincode::encode_into_slice(input, &mut buffer, bincode::config::standard()).unwrap();
assert_eq!(
&buffer[..12],
&[11, 72, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100]
);
let (output, len): (&str, usize) =
bincode::borrow_decode_from_slice(&buffer[..12], bincode::config::standard()).unwrap();
assert_eq!(input, output);
assert_eq!(len, 12);
}
#[test]
fn test_option_str() {
let mut buffer = [0u8; 32];
let input: Option<&str> = Some("Hello world");
let n = bincode::encode_into_slice(input, &mut buffer, bincode::config::standard()).unwrap();
assert_eq!(
&buffer[..n],
&[1, 11, 72, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100]
);
let (output, len): (Option<&str>, usize) =
bincode::borrow_decode_from_slice(&buffer[..n], bincode::config::standard()).unwrap();
assert_eq!(input, output);
assert_eq!(len, n);
let mut buffer = [0u8; 32];
let input: Option<&str> = None;
let n = bincode::encode_into_slice(input, &mut buffer, bincode::config::standard()).unwrap();
assert_eq!(&buffer[..n], &[0]);
let (output, len): (Option<&str>, usize) =
bincode::borrow_decode_from_slice(&buffer[..n], bincode::config::standard()).unwrap();
assert_eq!(input, output);
assert_eq!(len, n);
}
#[test]
fn test_array() {
let mut buffer = [0u8; 32];
let input: [u8; 10] = [10, 20, 30, 40, 50, 60, 70, 80, 90, 100];
bincode::encode_into_slice(input, &mut buffer, bincode::config::standard()).unwrap();
assert_eq!(&buffer[..10], &[10, 20, 30, 40, 50, 60, 70, 80, 90, 100]);
let (output, len): ([u8; 10], usize) =
bincode::decode_from_slice(&buffer[..11], bincode::config::standard()).unwrap();
assert_eq!(input, output);
assert_eq!(len, 10);
let mut buffer = [0u8; 32];
let input: [u8; 1] = [1];
let config = bincode::config::standard()
.with_fixed_int_encoding()
.with_little_endian();
let len = bincode::encode_into_slice(input, &mut buffer, config).unwrap();
assert_eq!(len, 1);
assert_eq!(&buffer[..1], &[1]);
let (output, len): ([u8; 1], usize) = bincode::decode_from_slice(&buffer[..9], config).unwrap();
assert_eq!(len, 1);
assert_eq!(input, output);
}
#[test]
fn test_duration_out_of_range() {
let mut input = [0u8; 14];
bincode::encode_into_slice(
(u64::MAX, u32::MAX),
&mut input,
bincode::config::standard(),
)
.unwrap();
let result: Result<(std::time::Duration, usize), _> =
bincode::decode_from_slice(&input, bincode::config::standard());
match result {
Err(DecodeError::InvalidDuration {
secs: u64::MAX,
nanos: u32::MAX,
}) => {}
Err(e) => panic!("Expected InvalidDuration, got {:?}", e),
Ok(_) => panic!("Expected the decode to fail"),
}
}
#[test]
fn test_duration_wrapping() {
let mut input = [0u8; 14];
bincode::encode_into_slice(
(u64::MAX - 4, u32::MAX),
&mut input,
bincode::config::standard(),
)
.unwrap();
let (result, _): (std::time::Duration, _) =
bincode::decode_from_slice(&input, bincode::config::standard()).unwrap();
assert_eq!(result.as_secs(), u64::MAX);
assert_eq!(result.subsec_nanos(), 294967295);
}

View File

@ -1,105 +0,0 @@
#![cfg(all(feature = "alloc", feature = "derive"))]
use bincode::{
config, de::BorrowDecoder, decode_from_slice, decode_from_slice_with_context, encode_to_vec,
error::DecodeError, BorrowDecode, Decode, Encode,
};
use bumpalo::{collections::Vec, vec, Bump};
#[derive(PartialEq, Eq, Debug)]
struct CodableVec<'bump, T: 'bump>(Vec<'bump, T>);
impl<'bump, T: Encode> Encode for CodableVec<'bump, T> {
fn encode<E: bincode::enc::Encoder>(
&self,
encoder: &mut E,
) -> Result<(), bincode::error::EncodeError> {
self.0.as_slice().encode(encoder)
}
}
impl<'bump, T: Decode<&'bump Bump>> Decode<&'bump Bump> for CodableVec<'bump, T> {
fn decode<D: bincode::de::Decoder<Context = &'bump Bump>>(
decoder: &mut D,
) -> Result<Self, bincode::error::DecodeError> {
let len = u64::decode(decoder)?;
let len = usize::try_from(len).map_err(|_| DecodeError::OutsideUsizeRange(len))?;
decoder.claim_container_read::<T>(len)?;
let mut vec = Vec::with_capacity_in(len, decoder.context());
for _ in 0..len {
decoder.unclaim_bytes_read(core::mem::size_of::<T>());
vec.push(T::decode(decoder)?);
}
Ok(Self(vec))
}
}
impl<'de, 'bump, T: BorrowDecode<'de, &'bump Bump>> BorrowDecode<'de, &'bump Bump>
for CodableVec<'bump, T>
{
fn borrow_decode<D: BorrowDecoder<'de, Context = &'bump Bump>>(
decoder: &mut D,
) -> Result<Self, DecodeError> {
let len = u64::decode(decoder)?;
let len = usize::try_from(len).map_err(|_| DecodeError::OutsideUsizeRange(len))?;
decoder.claim_container_read::<T>(len)?;
let mut vec = Vec::with_capacity_in(len, decoder.context());
for _ in 0..len {
// See the documentation on `unclaim_bytes_read` as to why we're doing this here
decoder.unclaim_bytes_read(core::mem::size_of::<T>());
vec.push(T::borrow_decode(decoder)?);
}
Ok(Self(vec))
}
}
#[derive(Encode, Decode, PartialEq, Eq, Debug)]
#[bincode(decode_context = "&'bump Bump")]
struct Container<'bump> {
vec: CodableVec<'bump, u32>,
}
#[derive(Encode, Decode, PartialEq, Eq, Debug)]
#[bincode(decode_context = "&'bump Bump")]
enum _EnumContainer<'bump> {
Vec(CodableVec<'bump, u32>),
}
#[ouroboros::self_referencing]
struct SelfReferencing {
bump: Bump,
#[borrows(bump)]
#[not_covariant]
container: Container<'this>,
}
impl<Context> Decode<Context> for SelfReferencing {
fn decode<D: bincode::de::Decoder<Context = Context>>(
decoder: &mut D,
) -> Result<Self, DecodeError> {
SelfReferencing::try_new(Bump::new(), |bump| {
Container::decode(&mut decoder.with_context(bump))
})
}
}
#[test]
fn decode_with_context() {
let config = config::standard();
let bump = Bump::new();
let container = Container {
vec: CodableVec(vec![in &bump; 1, 2, 3]),
};
let bytes = encode_to_vec(&container, config).unwrap();
let (decoded_container, _) =
decode_from_slice_with_context::<_, Container, _>(&bytes, config, &bump).unwrap();
assert_eq!(container, decoded_container);
let self_referencing: SelfReferencing = decode_from_slice(&bytes, config).unwrap().0;
self_referencing.with_container(|c| assert_eq!(&container, c))
}

View File

@ -1,467 +0,0 @@
#![cfg(feature = "derive")]
use bincode::error::DecodeError;
#[derive(bincode::Encode, PartialEq, Debug)]
pub(crate) struct Test<T> {
a: T,
b: u32,
c: u8,
}
#[test]
fn test_encode() {
let start = Test {
a: 5i32,
b: 10u32,
c: 20u8,
};
let mut slice = [0u8; 1024];
let bytes_written =
bincode::encode_into_slice(start, &mut slice, bincode::config::standard()).unwrap();
assert_eq!(bytes_written, 3);
assert_eq!(&slice[..bytes_written], &[10, 10, 20]);
}
#[derive(PartialEq, Debug, Eq)]
pub struct Test2<T> {
a: T,
b: u32,
c: u32,
}
impl<T, Context> ::bincode::Decode<Context> for Test2<T>
where
T: ::bincode::Decode<Context>,
{
fn decode<D: ::bincode::de::Decoder<Context = Context>>(
decoder: &mut D,
) -> core::result::Result<Self, ::bincode::error::DecodeError> {
Ok(Self {
a: ::bincode::Decode::decode(decoder)?,
b: ::bincode::Decode::decode(decoder)?,
c: ::bincode::Decode::decode(decoder)?,
})
}
}
impl<'__de, T, Context> ::bincode::BorrowDecode<'__de, Context> for Test2<T>
where
T: ::bincode::BorrowDecode<'__de, Context> + '__de,
{
fn borrow_decode<D: ::bincode::de::BorrowDecoder<'__de, Context = Context>>(
decoder: &mut D,
) -> core::result::Result<Self, ::bincode::error::DecodeError> {
Ok(Self {
a: ::bincode::BorrowDecode::borrow_decode(decoder)?,
b: ::bincode::BorrowDecode::borrow_decode(decoder)?,
c: ::bincode::BorrowDecode::borrow_decode(decoder)?,
})
}
}
#[test]
fn test_decode() {
let start = Test2 {
a: 5u32,
b: 10u32,
c: 1024u32,
};
let slice = [5, 10, 251, 0, 4];
let (result, len): (Test2<u32>, usize) =
bincode::decode_from_slice(&slice, bincode::config::standard()).unwrap();
assert_eq!(result, start);
assert_eq!(len, 5);
}
#[derive(bincode::BorrowDecode, bincode::Encode, PartialEq, Debug, Eq)]
pub struct Test3<'a> {
a: &'a str,
b: u32,
c: u32,
d: Option<&'a [u8]>,
}
#[test]
fn test_encode_decode_str() {
let start = Test3 {
a: "Foo bar",
b: 10u32,
c: 1024u32,
d: Some(b"Foo bar"),
};
let mut slice = [0u8; 100];
let len = bincode::encode_into_slice(&start, &mut slice, bincode::config::standard()).unwrap();
assert_eq!(len, 21);
let (end, len): (Test3, usize) =
bincode::borrow_decode_from_slice(&slice[..len], bincode::config::standard()).unwrap();
assert_eq!(end, start);
assert_eq!(len, 21);
}
#[derive(bincode::Encode, bincode::Decode, PartialEq, Debug, Eq)]
pub struct TestTupleStruct(u32, u32, u32);
#[test]
fn test_encode_tuple() {
let start = TestTupleStruct(5, 10, 1024);
let mut slice = [0u8; 1024];
let bytes_written =
bincode::encode_into_slice(start, &mut slice, bincode::config::standard()).unwrap();
assert_eq!(bytes_written, 5);
assert_eq!(&slice[..bytes_written], &[5, 10, 251, 0, 4]);
}
#[test]
fn test_decode_tuple() {
let start = TestTupleStruct(5, 10, 1024);
let slice = [5, 10, 251, 0, 4];
let (result, len): (TestTupleStruct, usize) =
bincode::decode_from_slice(&slice, bincode::config::standard()).unwrap();
assert_eq!(result, start);
assert_eq!(len, 5);
}
#[derive(bincode::Encode, bincode::Decode, PartialEq, Debug, Eq)]
pub enum TestEnum {
Foo,
Bar { name: u32 },
Baz(u32, u32, u32),
}
#[test]
fn test_encode_enum_struct_variant() {
let start = TestEnum::Bar { name: 5u32 };
let mut slice = [0u8; 1024];
let bytes_written =
bincode::encode_into_slice(start, &mut slice, bincode::config::standard()).unwrap();
assert_eq!(bytes_written, 2);
assert_eq!(&slice[..bytes_written], &[1, 5]);
}
#[test]
fn test_decode_enum_struct_variant() {
let start = TestEnum::Bar { name: 5u32 };
let slice = [1, 5];
let (result, len): (TestEnum, usize) =
bincode::decode_from_slice(&slice, bincode::config::standard()).unwrap();
assert_eq!(result, start);
assert_eq!(len, 2);
}
#[test]
fn test_decode_enum_unit_variant() {
let start = TestEnum::Foo;
let slice = [0];
let (result, len): (TestEnum, usize) =
bincode::decode_from_slice(&slice, bincode::config::standard()).unwrap();
assert_eq!(result, start);
assert_eq!(len, 1);
}
#[test]
fn test_encode_enum_unit_variant() {
let start = TestEnum::Foo;
let mut slice = [0u8; 1024];
let bytes_written =
bincode::encode_into_slice(start, &mut slice, bincode::config::standard()).unwrap();
assert_eq!(bytes_written, 1);
assert_eq!(&slice[..bytes_written], &[0]);
}
#[test]
fn test_encode_enum_tuple_variant() {
let start = TestEnum::Baz(5, 10, 1024);
let mut slice = [0u8; 1024];
let bytes_written =
bincode::encode_into_slice(start, &mut slice, bincode::config::standard()).unwrap();
assert_eq!(bytes_written, 6);
assert_eq!(&slice[..bytes_written], &[2, 5, 10, 251, 0, 4]);
}
#[test]
fn test_decode_enum_tuple_variant() {
let start = TestEnum::Baz(5, 10, 1024);
let slice = [2, 5, 10, 251, 0, 4];
let (result, len): (TestEnum, usize) =
bincode::decode_from_slice(&slice, bincode::config::standard()).unwrap();
assert_eq!(result, start);
assert_eq!(len, 6);
}
#[derive(bincode::Encode, bincode::BorrowDecode, PartialEq, Debug, Eq)]
pub enum TestEnum2<'a> {
Foo,
Bar { name: &'a str },
Baz(u32, u32, u32),
}
#[test]
fn test_encode_borrowed_enum_struct_variant() {
let start = TestEnum2::Bar { name: "foo" };
let mut slice = [0u8; 1024];
let bytes_written =
bincode::encode_into_slice(start, &mut slice, bincode::config::standard()).unwrap();
assert_eq!(bytes_written, 5);
assert_eq!(&slice[..bytes_written], &[1, 3, 102, 111, 111]);
}
#[test]
fn test_decode_borrowed_enum_struct_variant() {
let start = TestEnum2::Bar { name: "foo" };
let slice = [1, 3, 102, 111, 111];
let (result, len): (TestEnum2, usize) =
bincode::borrow_decode_from_slice(&slice, bincode::config::standard()).unwrap();
assert_eq!(result, start);
assert_eq!(len, 5);
}
#[test]
fn test_decode_borrowed_enum_unit_variant() {
let start = TestEnum2::Foo;
let slice = [0];
let (result, len): (TestEnum2, usize) =
bincode::borrow_decode_from_slice(&slice, bincode::config::standard()).unwrap();
assert_eq!(result, start);
assert_eq!(len, 1);
}
#[test]
fn test_encode_borrowed_enum_unit_variant() {
let start = TestEnum2::Foo;
let mut slice = [0u8; 1024];
let bytes_written =
bincode::encode_into_slice(start, &mut slice, bincode::config::standard()).unwrap();
assert_eq!(bytes_written, 1);
assert_eq!(&slice[..bytes_written], &[0]);
}
#[test]
fn test_encode_borrowed_enum_tuple_variant() {
let start = TestEnum2::Baz(5, 10, 1024);
let mut slice = [0u8; 1024];
let bytes_written =
bincode::encode_into_slice(start, &mut slice, bincode::config::standard()).unwrap();
assert_eq!(bytes_written, 6);
assert_eq!(&slice[..bytes_written], &[2, 5, 10, 251, 0, 4]);
}
#[test]
fn test_decode_borrowed_enum_tuple_variant() {
let start = TestEnum2::Baz(5, 10, 1024);
let slice = [2, 5, 10, 251, 0, 4];
let (result, len): (TestEnum2, usize) =
bincode::borrow_decode_from_slice(&slice, bincode::config::standard()).unwrap();
assert_eq!(result, start);
assert_eq!(len, 6);
}
#[derive(bincode::Decode, bincode::Encode, PartialEq, Eq, Debug)]
enum CStyleEnum {
A = -1,
B = 2,
C,
D = 5,
E,
}
#[test]
fn test_c_style_enum() {
fn ser(e: CStyleEnum) -> u8 {
let mut slice = [0u8; 10];
let bytes_written =
bincode::encode_into_slice(e, &mut slice, bincode::config::standard()).unwrap();
assert_eq!(bytes_written, 1);
slice[0]
}
assert_eq!(ser(CStyleEnum::A), 0);
assert_eq!(ser(CStyleEnum::B), 1);
assert_eq!(ser(CStyleEnum::C), 2);
assert_eq!(ser(CStyleEnum::D), 3);
assert_eq!(ser(CStyleEnum::E), 4);
fn assert_de_successfully(num: u8, expected: CStyleEnum) {
match bincode::decode_from_slice::<CStyleEnum, _>(&[num], bincode::config::standard()) {
Ok((result, len)) => {
assert_eq!(len, 1);
assert_eq!(result, expected)
}
Err(e) => panic!("Could not deserialize CStyleEnum idx {num}: {e:?}"),
}
}
fn assert_de_fails(num: u8) {
match bincode::decode_from_slice::<CStyleEnum, _>(&[num], bincode::config::standard()) {
Ok(_) => {
panic!("Expected to not be able to decode CStyleEnum index {num}, but it succeeded")
}
Err(DecodeError::UnexpectedVariant {
type_name: "CStyleEnum",
allowed: &bincode::error::AllowedEnumVariants::Allowed(&[0, 1, 2, 3, 4]),
found,
}) if found == num as u32 => {}
Err(e) => panic!("Expected DecodeError::UnexpectedVariant, got {e:?}"),
}
}
assert_de_successfully(0, CStyleEnum::A);
assert_de_successfully(1, CStyleEnum::B);
assert_de_successfully(2, CStyleEnum::C);
assert_de_successfully(3, CStyleEnum::D);
assert_de_successfully(4, CStyleEnum::E);
assert_de_fails(5);
}
macro_rules! macro_newtype {
($name:ident) => {
#[derive(bincode::Encode, bincode::Decode, PartialEq, Eq, Debug)]
pub struct $name(pub usize);
};
}
macro_newtype!(MacroNewType);
#[test]
fn test_macro_newtype() {
for val in [0, 100, usize::MAX] {
let mut usize_slice = [0u8; 10];
let usize_len =
bincode::encode_into_slice(val, &mut usize_slice, bincode::config::standard()).unwrap();
let mut newtype_slice = [0u8; 10];
let newtype_len = bincode::encode_into_slice(
MacroNewType(val),
&mut newtype_slice,
bincode::config::standard(),
)
.unwrap();
assert_eq!(usize_len, newtype_len);
assert_eq!(usize_slice, newtype_slice);
let (newtype, len) = bincode::decode_from_slice::<MacroNewType, _>(
&newtype_slice,
bincode::config::standard(),
)
.unwrap();
assert_eq!(newtype, MacroNewType(val));
assert_eq!(len, newtype_len);
}
}
#[derive(bincode::Encode, bincode::Decode, Debug)]
pub enum EmptyEnum {}
#[derive(bincode::Encode, bincode::BorrowDecode, Debug)]
pub enum BorrowedEmptyEnum {}
#[test]
fn test_empty_enum_decode() {
match bincode::decode_from_slice::<EmptyEnum, _>(&[], bincode::config::standard()) {
Ok(_) => panic!("We successfully decoded an empty slice, this should never happen"),
Err(DecodeError::EmptyEnum {
type_name: "derive::EmptyEnum",
}) => {}
Err(e) => panic!("Expected DecodeError::EmptyEnum, got {e:?}"),
}
}
#[derive(bincode::Encode, bincode::Decode, PartialEq, Debug, Eq)]
pub enum TestWithGeneric<T> {
Foo,
Bar(T),
}
#[test]
fn test_enum_with_generics_roundtrip() {
let start = TestWithGeneric::Bar(1234);
let mut slice = [0u8; 10];
let bytes_written =
bincode::encode_into_slice(&start, &mut slice, bincode::config::standard()).unwrap();
assert_eq!(
&slice[..bytes_written],
&[
1, // variant 1
251, // u16
210, 4 // 1234
]
);
let decoded: TestWithGeneric<u32> =
bincode::decode_from_slice(&slice[..bytes_written], bincode::config::standard())
.unwrap()
.0;
assert_eq!(start, decoded);
let start = TestWithGeneric::<()>::Foo;
let mut slice = [0u8; 10];
let bytes_written =
bincode::encode_into_slice(&start, &mut slice, bincode::config::standard()).unwrap();
assert_eq!(&slice[..bytes_written], &[0]);
let decoded: TestWithGeneric<()> =
bincode::decode_from_slice(&slice[..bytes_written], bincode::config::standard())
.unwrap()
.0;
assert_eq!(start, decoded);
}
mod derive_with_polluted_scope {
#[allow(dead_code)]
#[allow(non_snake_case)]
fn Ok() {}
#[allow(dead_code)]
#[allow(non_snake_case)]
fn Err() {}
#[derive(bincode::Encode, bincode::Decode)]
struct A {
a: u32,
}
#[derive(bincode::Encode, bincode::Decode)]
enum B {
A,
B,
}
}
#[cfg(feature = "alloc")]
mod zoxide {
extern crate alloc;
use alloc::borrow::Cow;
use bincode::{Decode, Encode};
pub type Rank = f64;
pub type Epoch = u64;
#[derive(Encode, Decode)]
pub struct Dir<'a> {
pub path: Cow<'a, str>,
pub rank: Rank,
pub last_accessed: Epoch,
}
#[test]
fn test() {
let dirs = vec![
Dir {
path: Cow::Borrowed("Foo"),
rank: 1.23,
last_accessed: 5,
},
Dir {
path: Cow::Owned(String::from("Bar")),
rank: 2.34,
last_accessed: 10,
},
];
let config = bincode::config::standard();
let slice = bincode::encode_to_vec(dirs, config).unwrap();
let decoded: Vec<Dir> = bincode::borrow_decode_from_slice(&slice, config).unwrap().0;
assert_eq!(decoded.len(), 2);
assert!(matches!(decoded[0].path, Cow::Borrowed("Foo")));
assert!(matches!(decoded[1].path, Cow::Borrowed("Bar")));
}
}

View File

@ -1,14 +0,0 @@
#![cfg(feature = "derive")]
extern crate bincode as bincode_new;
// Make sure that the `bincode` crate exists, just symlink it to `core.
extern crate core as bincode;
#[derive(bincode_new::Encode)]
#[bincode(crate = "bincode_new")]
#[allow(dead_code)]
struct DeriveRenameTest {
a: u32,
b: u32,
}

View File

@ -1,15 +0,0 @@
#![cfg(target_pointer_width = "64")]
#[test]
fn decode_error_size() {
assert_eq!(std::mem::size_of::<bincode::error::DecodeError>(), 32);
}
#[test]
fn encode_error_size() {
#[cfg(feature = "std")]
assert_eq!(std::mem::size_of::<bincode::error::EncodeError>(), 32);
#[cfg(not(feature = "std"))]
assert_eq!(std::mem::size_of::<bincode::error::EncodeError>(), 24);
}

View File

@ -1,40 +0,0 @@
#![no_std]
#[path = "issues/issue_431.rs"]
mod issue_431;
#[path = "issues/issue_427.rs"]
mod issue_427;
#[path = "issues/issue_467.rs"]
mod issue_467;
#[path = "issues/issue_459.rs"]
mod issue_459;
#[path = "issues/issue_474.rs"]
mod issue_474;
#[path = "issues/issue_498.rs"]
mod issue_498;
#[path = "issues/issue_500.rs"]
mod issue_500;
#[path = "issues/issue_523.rs"]
mod issue_523;
#[path = "issues/issue_537.rs"]
mod issue_537;
#[path = "issues/issue_547.rs"]
mod issue_547;
#[path = "issues/issue_570.rs"]
mod issue_570;
#[path = "issues/issue_592.rs"]
mod issue_592;
#[path = "issues/issue_614.rs"]
mod issue_614;

View File

@ -1,69 +0,0 @@
#![cfg(feature = "derive")]
/// HID-IO Packet Buffer Struct
///
/// # Remarks
/// Used to store HID-IO data chunks. Will be chunked into individual packets on transmission.
#[repr(C)]
#[derive(PartialEq, Eq, Clone, Debug, bincode::Encode)]
pub struct HidIoPacketBuffer<const H: usize> {
/// Type of packet (Continued is automatically set if needed)
pub ptype: u32,
/// Packet Id
pub id: u32,
/// Packet length for serialization (in bytes)
pub max_len: u32,
/// Payload data, chunking is done automatically by serializer
pub data: [u8; H],
/// Set False if buffer is not complete, True if it is
pub done: bool,
}
#[repr(u32)]
#[derive(PartialEq, Eq, Clone, Copy, Debug, bincode::Encode)]
#[allow(dead_code)]
/// Requests for to perform a specific action
pub enum HidIoCommandId {
SupportedIds = 0x00,
GetInfo = 0x01,
TestPacket = 0x02,
ResetHidIo = 0x03,
Reserved = 0x04, // ... 0x0F
GetProperties = 0x10,
KeyState = 0x11,
KeyboardLayout = 0x12,
KeyLayout = 0x13,
KeyShapes = 0x14,
LedLayout = 0x15,
FlashMode = 0x16,
UnicodeText = 0x17,
UnicodeState = 0x18,
HostMacro = 0x19,
SleepMode = 0x1A,
KllState = 0x20,
PixelSetting = 0x21,
PixelSet1c8b = 0x22,
PixelSet3c8b = 0x23,
PixelSet1c16b = 0x24,
PixelSet3c16b = 0x25,
OpenUrl = 0x30,
TerminalCmd = 0x31,
GetInputLayout = 0x32,
SetInputLayout = 0x33,
TerminalOut = 0x34,
HidKeyboard = 0x40,
HidKeyboardLed = 0x41,
HidMouse = 0x42,
HidJoystick = 0x43,
HidSystemCtrl = 0x44,
HidConsumerCtrl = 0x45,
ManufacturingTest = 0x50,
ManufacturingResult = 0x51,
Unused = 0xFFFF,
}

View File

@ -1,42 +0,0 @@
#![cfg(all(feature = "std", feature = "derive"))]
extern crate std;
use bincode::{Decode, Encode};
use std::borrow::Cow;
use std::string::String;
#[derive(Decode, Encode, PartialEq, Debug)]
#[bincode(
decode_context = "()",
borrow_decode_bounds = "&'__de U<'a, A>: ::bincode::de::BorrowDecode<'__de, ()> + '__de, '__de: 'a"
)]
struct T<'a, A: Clone + Encode + Decode<()>> {
t: Cow<'a, U<'a, A>>,
}
#[derive(Clone, Decode, Encode, PartialEq, Debug)]
#[bincode(
decode_context = "()",
borrow_decode_bounds = "&'__de A: ::bincode::de::BorrowDecode<'__de, ()> + '__de, '__de: 'a"
)]
struct U<'a, A: Clone + Encode + Decode<()>> {
u: Cow<'a, A>,
}
#[test]
fn test() {
let u = U {
u: Cow::Owned(String::from("Hello world")),
};
let t = T {
t: Cow::Borrowed(&u),
};
let vec = bincode::encode_to_vec(&t, bincode::config::standard()).unwrap();
let (decoded, len): (T<String>, usize) =
bincode::decode_from_slice(&vec, bincode::config::standard()).unwrap();
assert_eq!(t, decoded);
assert_eq!(len, 12);
}

View File

@ -1,13 +0,0 @@
#![cfg(all(feature = "std", feature = "derive"))]
extern crate std;
use std::collections::BTreeMap;
#[derive(bincode::Encode)]
struct AllTypes(BTreeMap<u8, AllTypes>);
#[test]
fn test_issue_459() {
let _result = bincode::encode_to_vec(AllTypes(BTreeMap::new()), bincode::config::standard());
}

View File

@ -1,14 +0,0 @@
#![cfg(all(feature = "std", feature = "derive"))]
extern crate std;
use std::collections::BTreeMap;
#[derive(bincode::Decode, bincode::Encode)]
struct AllTypes(BTreeMap<u8, AllTypes>);
#[test]
fn test_issue_467() {
let _result: Result<(AllTypes, _), _> =
bincode::decode_from_slice(&[], bincode::config::standard().with_limit::<1024>());
}

View File

@ -1,94 +0,0 @@
#![cfg(all(feature = "serde", feature = "std"))]
extern crate std;
use chrono::{DateTime, Utc};
use serde::de::DeserializeOwned;
use std::collections::HashMap;
use std::prelude::rust_2021::*;
use uuid::Uuid;
#[derive(serde_derive::Serialize, serde_derive::Deserialize, PartialEq, Eq, Debug)]
pub struct MyStruct {
name: String,
}
#[derive(serde_derive::Serialize, serde_derive::Deserialize, PartialEq, Eq, Debug)]
pub struct CustomerTest {
pub id: Option<Uuid>,
pub email_address: Option<String>,
pub is_active: Option<bool>,
pub date_stamp: Option<DateTime<Utc>>,
}
#[test]
fn test() {
let test = MyStruct {
name: "Test Value".into(),
};
let cache_id = Uuid::nil();
let cache = MemCache::default();
cache.set_data::<MyStruct>(&cache_id, &test, 5).unwrap();
let model = cache.get_data::<MyStruct>(&cache_id).unwrap();
assert_eq!(test, model);
let test = CustomerTest {
id: Some(Uuid::nil()),
email_address: Some("foo@bar".into()),
is_active: None,
date_stamp: Some(Utc::now()),
};
cache.set_data::<CustomerTest>(&cache_id, &test, 5).unwrap();
let model = cache.get_data::<CustomerTest>(&cache_id).unwrap();
assert_eq!(test, model);
}
#[derive(Default)]
struct MemCache {
cache: std::sync::RwLock<HashMap<Uuid, CacheItem>>,
}
impl MemCache {
fn set_data<T>(
&self,
key: &Uuid,
cache_data: &T,
expire_seconds: i64,
) -> Result<(), bincode::error::EncodeError>
where
T: Send + Sync + serde::Serialize,
{
let config = bincode::config::standard();
let mut guard = self.cache.write().unwrap();
let encoded = bincode::serde::encode_to_vec(cache_data, config)?;
let cache_item = CacheItem::new(encoded, expire_seconds);
guard.insert(*key, cache_item);
Ok(())
}
fn get_data<T>(&self, key: &Uuid) -> Result<T, bincode::error::DecodeError>
where
T: Send + Sync + DeserializeOwned,
{
let config = bincode::config::standard();
let guard = self.cache.read().unwrap();
let cache_item = guard.get(key).unwrap();
let (decoded, _len): (T, usize) =
bincode::serde::decode_from_slice(&cache_item.payload[..], config)?;
Ok(decoded)
}
}
struct CacheItem {
payload: Vec<u8>,
}
impl CacheItem {
fn new(payload: Vec<u8>, _expire_seconds: i64) -> Self {
Self { payload }
}
}

View File

@ -1,17 +0,0 @@
#![cfg(feature = "std")]
extern crate std;
use std::ffi::CString;
#[test]
fn test_issue_498() {
let bytes = [1, 0, 0, 0, 0, 0, 0, 0, 0];
let out: Result<(CString, _), _> =
bincode::decode_from_slice(&bytes, bincode::config::legacy().with_limit::<1024>());
match out.unwrap_err() {
bincode::error::DecodeError::CStringNulError { position: _ } => {}
err => panic!("Expected CStringNullErr, found {:?}", err),
}
}

View File

@ -1,37 +0,0 @@
#![cfg(all(feature = "serde", feature = "derive", feature = "std"))]
extern crate std;
type NodeId = u64;
use std::collections::BTreeSet;
#[derive(
bincode::Encode,
bincode::Decode,
serde_derive::Serialize,
serde_derive::Deserialize,
Debug,
PartialEq,
Eq,
)]
pub struct Membership {
/// learners set
learners: BTreeSet<NodeId>,
}
#[test]
fn test() {
let mut start = Membership {
learners: BTreeSet::new(),
};
start.learners.insert(1);
let config = bincode::config::legacy();
let encoded = bincode::encode_to_vec(&start, config).unwrap();
std::dbg!(&encoded);
let decoded: Membership = bincode::serde::decode_from_slice(&encoded, config)
.unwrap()
.0;
assert_eq!(start, decoded);
}

View File

@ -1,9 +0,0 @@
#![cfg(all(feature = "derive", feature = "std"))]
extern crate std;
use bincode::{Decode, Encode};
use std::borrow::Cow;
#[derive(Clone, Encode, Decode)]
pub struct Foo<'a>(Cow<'a, str>);

View File

@ -1,8 +0,0 @@
#![cfg(all(feature = "derive", feature = "std"))]
use bincode::{Decode, Encode};
#[derive(Encode, Decode)]
struct Foo<Bar = ()> {
x: Bar,
}

View File

@ -1,24 +0,0 @@
#![cfg(all(feature = "serde", feature = "std"))]
use glam::vec3;
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Debug, PartialEq)]
struct Instance {
position: glam::Vec3,
}
#[test]
fn test() {
let instance = Instance {
position: vec3(2.0, 2.0, 2.0),
};
let m = bincode::serde::encode_to_vec(&instance, bincode::config::standard()).unwrap();
let instance2: Instance = bincode::serde::decode_from_slice(&m, bincode::config::standard())
.unwrap()
.0;
assert_eq!(instance, instance2);
}

View File

@ -1,6 +0,0 @@
#![cfg(feature = "derive")]
#[derive(bincode::Encode, bincode::Decode)]
pub struct Eg<D, E> {
data: (D, E),
}

View File

@ -1,8 +0,0 @@
#![cfg(all(feature = "derive", feature = "std"))]
use bincode::{Decode, Encode};
#[derive(Encode, Decode)]
pub enum TypeOfFile {
Unknown = -1,
}

View File

@ -1,22 +0,0 @@
#![cfg(feature = "derive")]
use bincode::{Decode, Encode};
#[derive(Encode, Decode, Clone)]
pub struct A;
#[derive(Encode, Decode, Clone)]
pub struct B<T>
where
T: Clone + Encode + Decode<()>,
{
pub t: T,
}
#[derive(Encode, Decode)]
pub struct MyStruct<T>
where
T: Clone + Encode + Decode<()>,
{
pub a: A,
pub b: B<T>,
}

View File

@ -1,253 +0,0 @@
#![cfg(all(feature = "serde", feature = "alloc", feature = "derive"))]
extern crate alloc;
use serde_derive::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, bincode::Encode, bincode::Decode)]
pub struct SerdeRoundtrip {
pub a: u32,
#[serde(skip)]
pub b: u32,
pub c: TupleS,
}
#[derive(Serialize, Deserialize, bincode::Encode, bincode::Decode, PartialEq, Debug)]
pub struct TupleS(f32, f32, f32);
#[test]
fn test_serde_round_trip() {
// validate serde attribute working
let json = serde_json::to_string(&SerdeRoundtrip {
a: 5,
b: 5,
c: TupleS(2.0, 3.0, 4.0),
})
.unwrap();
assert_eq!("{\"a\":5,\"c\":[2.0,3.0,4.0]}", json);
let result: SerdeRoundtrip = serde_json::from_str(&json).unwrap();
assert_eq!(result.a, 5);
assert_eq!(result.b, 0);
// validate bincode working
let bytes = bincode::serde::encode_to_vec(
SerdeRoundtrip {
a: 15,
b: 15,
c: TupleS(2.0, 3.0, 4.0),
},
bincode::config::standard(),
)
.unwrap();
assert_eq!(bytes, &[15, 0, 0, 0, 64, 0, 0, 64, 64, 0, 0, 128, 64]);
let (result, len): (SerdeRoundtrip, usize) =
bincode::serde::decode_from_slice(&bytes, bincode::config::standard()).unwrap();
assert_eq!(result.a, 15);
assert_eq!(result.b, 0); // remember: b is skipped
assert_eq!(result.c, TupleS(2.0, 3.0, 4.0));
assert_eq!(len, 13);
}
#[derive(Serialize, Deserialize, PartialEq, Eq, Debug)]
pub struct SerdeWithBorrowedData<'a> {
pub a: u32,
#[serde(skip)]
pub b: u32,
pub str: &'a str,
}
#[test]
fn test_serialize_deserialize_borrowed_data() {
let input = SerdeWithBorrowedData {
a: 5,
b: 5,
str: "Hello world",
};
#[rustfmt::skip]
let expected = &[
5, // a
// b is skipped
11, // str length
b'H', b'e', b'l', b'l', b'o', b' ', b'w', b'o', b'r', b'l', b'd' // str
];
let mut result = [0u8; 20];
let len = bincode::serde::encode_into_slice(&input, &mut result, bincode::config::standard())
.unwrap();
let result = &result[..len];
assert_eq!(result, expected);
let result = bincode::serde::encode_to_vec(&input, bincode::config::standard()).unwrap();
assert_eq!(result, expected);
let (output, len): (SerdeWithBorrowedData, usize) =
bincode::serde::borrow_decode_from_slice(&result, bincode::config::standard()).unwrap();
assert_eq!(
SerdeWithBorrowedData {
b: 0, // remember: b is skipped
..input
},
output
);
assert_eq!(len, 13);
}
#[derive(Serialize, Deserialize, PartialEq, Eq, Debug)]
pub struct SerdeWithOwnedData {
pub a: u32,
#[serde(skip)]
pub b: u32,
pub str: String,
}
#[test]
fn test_serialize_deserialize_owned_data() {
let input = SerdeWithOwnedData {
a: 5,
b: 5,
str: String::from("Hello world"),
};
#[rustfmt::skip]
let expected = &[
5, // a
// b is skipped
11, // str length
b'H', b'e', b'l', b'l', b'o', b' ', b'w', b'o', b'r', b'l', b'd' // str
];
let mut result = [0u8; 20];
let len = bincode::serde::encode_into_slice(&input, &mut result, bincode::config::standard())
.unwrap();
let result = &result[..len];
assert_eq!(result, expected);
let result = bincode::serde::encode_to_vec(&input, bincode::config::standard()).unwrap();
assert_eq!(result, expected);
let (output, len): (SerdeWithOwnedData, usize) =
bincode::serde::decode_from_slice(&result, bincode::config::standard()).unwrap();
assert_eq!(
SerdeWithOwnedData {
b: 0, // remember: b is skipped
..input
},
output
);
assert_eq!(len, 13);
}
#[cfg(feature = "derive")]
mod derive {
use bincode::{
serde::{BorrowCompat, Compat},
Decode, Encode,
};
use serde_derive::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, PartialEq, Eq, Debug)]
pub struct SerdeType {
pub a: u32,
}
#[derive(Decode, Encode, PartialEq, Eq, Debug)]
pub struct StructWithSerde {
#[bincode(with_serde)]
pub serde: SerdeType,
}
#[derive(Decode, Encode, PartialEq, Eq, Debug)]
pub enum EnumWithSerde {
Unit(#[bincode(with_serde)] SerdeType),
Struct {
#[bincode(with_serde)]
serde: SerdeType,
},
}
#[test]
fn test_serde_derive() {
fn test_encode_decode<T>(start: T, expected_len: usize)
where
T: bincode::Encode + bincode::Decode<()> + PartialEq + core::fmt::Debug,
{
let mut slice = [0u8; 100];
let len = bincode::encode_into_slice(&start, &mut slice, bincode::config::standard())
.unwrap();
assert_eq!(len, expected_len);
let slice = &slice[..len];
let (result, len): (T, usize) =
bincode::decode_from_slice(slice, bincode::config::standard()).unwrap();
assert_eq!(start, result);
assert_eq!(len, expected_len);
}
test_encode_decode(
StructWithSerde {
serde: SerdeType { a: 5 },
},
1,
);
test_encode_decode(EnumWithSerde::Unit(SerdeType { a: 5 }), 2);
test_encode_decode(
EnumWithSerde::Struct {
serde: SerdeType { a: 5 },
},
2,
);
}
#[test]
fn test_vec_compat_debug() {
let compat = Compat(vec![0, 1, 2, 3]);
let debug_view = format!("{:?}", compat);
assert_eq!(debug_view, "Compat([0, 1, 2, 3])")
}
#[test]
fn test_i32_compat_debug() {
let compat = Compat(1337_i32);
let debug_view = format!("{:?}", compat);
assert_eq!(debug_view, "Compat(1337)")
}
#[test]
fn test_i32_compat_display() {
let compat = Compat(1337_i32);
let debug_view = format!("{}", compat);
assert_eq!(debug_view, "1337")
}
#[test]
fn test_f32_compat_display() {
let compat = Compat(1.5_f32);
let debug_view = format!("{}", compat);
assert_eq!(debug_view, "1.5")
}
#[test]
fn test_vec_borrow_compat_debug() {
let vector = vec![0, 1, 2, 3];
let borrow_compat = BorrowCompat(&vector);
let debug_view = format!("{:?}", borrow_compat);
assert_eq!(debug_view, "BorrowCompat([0, 1, 2, 3])")
}
#[test]
fn test_str_borrow_compat_debug() {
let borrow_compat = BorrowCompat("Hello World!");
let debug_view = format!("{:?}", borrow_compat);
assert_eq!(debug_view, "BorrowCompat(\"Hello World!\")")
}
#[test]
fn test_str_borrow_compat_display() {
let borrow_compat = BorrowCompat("Hello World!");
let debug_view = format!("{}", borrow_compat);
assert_eq!(debug_view, "Hello World!")
}
}

View File

@ -1,203 +0,0 @@
#![allow(clippy::disallowed_names)]
#![cfg(feature = "std")]
mod utils;
use bincode::error::DecodeError;
use std::{
ffi::CString,
io::{Cursor, Seek, SeekFrom},
net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6},
path::{Path, PathBuf},
sync::{Mutex, RwLock},
};
use utils::the_same;
use crate::utils::the_same_with_comparer;
struct Foo {
pub a: u32,
pub b: u32,
}
impl bincode::Encode for Foo {
fn encode<E: bincode::enc::Encoder>(
&self,
encoder: &mut E,
) -> Result<(), bincode::error::EncodeError> {
self.a.encode(encoder)?;
self.b.encode(encoder)?;
Ok(())
}
}
impl<Context> bincode::Decode<Context> for Foo {
fn decode<D: bincode::de::Decoder>(
decoder: &mut D,
) -> Result<Self, bincode::error::DecodeError> {
Ok(Self {
a: bincode::Decode::decode(decoder)?,
b: bincode::Decode::decode(decoder)?,
})
}
}
#[test]
fn test_std_cursor() {
let mut cursor = Cursor::<&[u8]>::new(&[5, 10]);
let foo: Foo = bincode::decode_from_std_read(&mut cursor, bincode::config::standard()).unwrap();
assert_eq!(foo.a, 5);
assert_eq!(foo.b, 10);
}
#[test]
#[cfg_attr(miri, ignore)] // miri does not like `tempfile`
fn test_std_file() {
let mut file = tempfile::tempfile().expect("Could not create temp file");
let bytes_written = bincode::encode_into_std_write(
Foo { a: 30, b: 50 },
&mut file,
bincode::config::standard(),
)
.unwrap();
assert_eq!(bytes_written, 2);
file.seek(SeekFrom::Start(0)).unwrap();
let foo: Foo = bincode::decode_from_std_read(&mut file, bincode::config::standard()).unwrap();
assert_eq!(foo.a, 30);
assert_eq!(foo.b, 50);
}
#[test]
fn test_std_commons() {
the_same(CString::new("Hello world").unwrap());
the_same(PathBuf::from("C:/Program Files/Foo"));
the_same(Ipv4Addr::LOCALHOST);
the_same(Ipv6Addr::LOCALHOST);
the_same(IpAddr::V4(Ipv4Addr::LOCALHOST));
the_same(IpAddr::V6(Ipv6Addr::LOCALHOST));
the_same(SocketAddrV4::new(Ipv4Addr::LOCALHOST, 12345));
the_same(SocketAddrV6::new(Ipv6Addr::LOCALHOST, 12345, 0, 0));
the_same(SocketAddr::V4(SocketAddrV4::new(
Ipv4Addr::LOCALHOST,
12345,
)));
the_same(SocketAddr::V6(SocketAddrV6::new(
Ipv6Addr::LOCALHOST,
12345,
0,
0,
)));
the_same_with_comparer(Mutex::new("Hello world".to_string()), |a, b| {
*a.lock().unwrap() == *b.lock().unwrap()
});
the_same_with_comparer(RwLock::new("Hello world".to_string()), |a, b| {
*a.read().unwrap() == *b.read().unwrap()
});
let mut map = std::collections::HashMap::new();
map.insert("Hello".to_owned(), "world".to_owned());
map.insert("How".to_owned(), "are".to_owned());
map.insert("you".to_owned(), "doing?".to_owned());
the_same(map);
let mut set = std::collections::HashSet::new();
set.insert("Hello".to_string());
set.insert("World".to_string());
the_same(set);
// HashMap and HashSet with custom hash algorithm
type MyBuildHasher = std::hash::BuildHasherDefault<ExampleCustomHasher>;
let mut custom_map: std::collections::HashMap<String, String, MyBuildHasher> =
Default::default();
custom_map.insert("Hello".to_owned(), "world".to_owned());
custom_map.insert("How".to_owned(), "are".to_owned());
custom_map.insert("you".to_owned(), "doing?".to_owned());
the_same(custom_map);
let mut custom_set: std::collections::HashSet<String, MyBuildHasher> = Default::default();
custom_set.insert("Hello".to_string());
custom_set.insert("World".to_string());
the_same(custom_set);
// Borrowed values
let config = bincode::config::standard();
let mut buffer = [0u8; 1024];
// &CStr
let cstr = c"Hello world";
let len = bincode::encode_into_slice(cstr, &mut buffer, config).unwrap();
let (decoded, len): (CString, usize) =
bincode::decode_from_slice(&buffer[..len], config).unwrap();
assert_eq!(cstr, decoded.as_c_str());
assert_eq!(len, 12);
// Path
let path = Path::new("C:/Program Files/Foo");
let len = bincode::encode_into_slice(path, &mut buffer, config).unwrap();
let (decoded, len): (&Path, usize) =
bincode::borrow_decode_from_slice(&buffer[..len], config).unwrap();
assert_eq!(path, decoded);
assert_eq!(len, 21);
}
#[test]
fn test_system_time_out_of_range() {
let input = [0xfd, 0x90, 0x0c, 0xfd, 0xfd, 0x90, 0x0c, 0xfd, 0x90, 0x90];
let result: Result<(std::time::SystemTime, usize), _> =
bincode::decode_from_slice(&input, bincode::config::standard());
match result {
Ok(_) => panic!("Expected the decode to fail, but it succeeded"),
Err(DecodeError::InvalidSystemTime { duration }) => {
assert_eq!(
duration,
std::time::Duration::new(10447520527445462160, 144)
)
}
Err(e) => panic!("Expected DecodeError::InvalidSystemTime, got {e:?}"),
}
}
/// Simple example of user-defined hasher to test encoding/decoding HashMap and HashSet with custom hash algorithms.
#[derive(Copy, Clone, Default)]
pub struct ExampleCustomHasher {
pub hash: u64,
}
impl std::hash::Hasher for ExampleCustomHasher {
fn write(&mut self, value: &[u8]) {
for (index, &item) in value.iter().enumerate() {
self.hash ^= u64::from(item) << ((index % 8) * 8);
}
}
fn finish(&self) -> u64 {
self.hash
}
}
#[test]
fn test_decode_borrow_str_in_array() {
let (strs, _): (Vec<&str>, usize) = bincode::borrow_decode_from_slice(
&[
3, 3, b'a', b'b', b'c', 3, b'd', b'e', b'f', 3, b'g', b'h', b'i',
],
bincode::config::standard(),
)
.unwrap();
assert_eq!(strs, vec!["abc", "def", "ghi"]);
let (strs, _): ([&str; 3], usize) = bincode::borrow_decode_from_slice(
&[
3, b'a', b'b', b'c', 3, b'd', b'e', b'f', 3, b'g', b'h', b'i',
],
bincode::config::standard(),
)
.unwrap();
assert_eq!(strs, ["abc", "def", "ghi"]);
}

View File

@ -1,158 +0,0 @@
use core::fmt::Debug;
fn the_same_with_config<V, C, CMP>(element: &V, config: C, cmp: CMP)
where
V: TheSameTrait,
C: bincode::config::Config,
CMP: Fn(&V, &V) -> bool,
{
let mut buffer = [0u8; 2048];
let len = bincode::encode_into_slice(element, &mut buffer, config).unwrap();
println!(
"{:?} ({}): {:?} ({:?})",
element,
core::any::type_name::<V>(),
&buffer[..len],
core::any::type_name::<C>()
);
let (decoded, decoded_len): (V, usize) = bincode::decode_from_slice(&buffer, config).unwrap();
assert!(
cmp(element, &decoded),
"Comparison failed\nDecoded: {:?}\nExpected: {:?}\nBytes: {:?}",
decoded,
element,
&buffer[..len],
);
assert_eq!(len, decoded_len);
#[cfg(feature = "serde")]
the_same_with_config_serde(element, config, cmp)
}
#[cfg(feature = "serde")]
fn the_same_with_config_serde<V, C, CMP>(element: &V, config: C, cmp: CMP)
where
V: TheSameTrait,
C: bincode::config::Config,
CMP: Fn(&V, &V) -> bool,
{
let mut buffer = [0u8; 2048];
let len = bincode::serde::encode_into_slice(element, &mut buffer, config);
let decoded = bincode::serde::decode_from_slice(&buffer, config);
let len = len.unwrap();
let (decoded, decoded_len): (V, usize) = decoded.unwrap();
println!(
"{:?} ({}): {:?} ({:?})",
element,
core::any::type_name::<V>(),
&buffer[..len],
core::any::type_name::<C>()
);
assert!(
cmp(element, &decoded),
"Comparison failed\nDecoded: {:?}\nExpected: {:?}\nBytes: {:?}",
decoded,
element,
&buffer[..len],
);
assert_eq!(len, decoded_len);
}
pub fn the_same_with_comparer<V, CMP>(element: V, cmp: CMP)
where
V: TheSameTrait,
CMP: Fn(&V, &V) -> bool,
{
// A matrix of each different config option possible
the_same_with_config(
&element,
bincode::config::standard()
.with_little_endian()
.with_fixed_int_encoding(),
&cmp,
);
the_same_with_config(
&element,
bincode::config::standard()
.with_big_endian()
.with_fixed_int_encoding(),
&cmp,
);
the_same_with_config(
&element,
bincode::config::standard()
.with_little_endian()
.with_variable_int_encoding(),
&cmp,
);
the_same_with_config(
&element,
bincode::config::standard()
.with_big_endian()
.with_variable_int_encoding(),
&cmp,
);
the_same_with_config(
&element,
bincode::config::standard()
.with_little_endian()
.with_fixed_int_encoding(),
&cmp,
);
the_same_with_config(
&element,
bincode::config::standard()
.with_big_endian()
.with_fixed_int_encoding(),
&cmp,
);
the_same_with_config(
&element,
bincode::config::standard()
.with_little_endian()
.with_variable_int_encoding(),
&cmp,
);
the_same_with_config(
&element,
bincode::config::standard()
.with_big_endian()
.with_variable_int_encoding(),
&cmp,
);
}
#[cfg(feature = "serde")]
pub trait TheSameTrait:
bincode::Encode
+ bincode::Decode<()>
+ serde::de::DeserializeOwned
+ serde::Serialize
+ Debug
+ 'static
{
}
#[cfg(feature = "serde")]
impl<T> TheSameTrait for T where
T: bincode::Encode
+ bincode::Decode<()>
+ serde::de::DeserializeOwned
+ serde::Serialize
+ Debug
+ 'static
{
}
#[cfg(not(feature = "serde"))]
pub trait TheSameTrait: bincode::Encode + bincode::Decode<()> + Debug + 'static {}
#[cfg(not(feature = "serde"))]
impl<T> TheSameTrait for T where T: bincode::Encode + bincode::Decode<()> + Debug + 'static {}
#[allow(dead_code)] // This is not used in every test
pub fn the_same<V: TheSameTrait + PartialEq>(element: V) {
the_same_with_comparer(element, |a, b| a == b);
}