From b1c472d10310e1e641ac8fa2642e0f42faf0ad8a Mon Sep 17 00:00:00 2001 From: Martin Geisler Date: Tue, 9 Apr 2024 20:01:13 +0200 Subject: Import 'bincode' crate Request Document: go/android-rust-importing-crates For CL Reviewers: go/android3p#cl-review For Build Team: go/ab-third-party-imports Bug: http://b/330683225 Test: m libbincode Change-Id: I4c077729d734537bfa80a53e7c9a2ca8069353e5 --- .cargo_vcs_info.json | 5 + .github/workflows/rust.yml | 175 ++++++++ .github/workflows/security.yml | 26 ++ .mailmap | 3 + Android.bp | 20 + Cargo.lock | 71 ++++ Cargo.toml | 37 ++ LICENSE | 1 + LICENSE.md | 21 + METADATA | 20 + MODULE_LICENSE_MIT | 0 OWNERS | 2 + cargo_embargo.json | 3 + readme.md | 112 +++++ src/byteorder.rs | 385 ++++++++++++++++++ src/config/endian.rs | 27 ++ src/config/int.rs | 682 +++++++++++++++++++++++++++++++ src/config/legacy.rs | 253 ++++++++++++ src/config/limit.rs | 49 +++ src/config/mod.rs | 408 +++++++++++++++++++ src/config/trailing.rs | 37 ++ src/de/mod.rs | 515 +++++++++++++++++++++++ src/de/read.rs | 202 +++++++++ src/error.rs | 115 ++++++ src/internal.rs | 124 ++++++ src/lib.rs | 201 +++++++++ src/ser/mod.rs | 772 +++++++++++++++++++++++++++++++++++ tests/test.rs | 899 +++++++++++++++++++++++++++++++++++++++++ 28 files changed, 5165 insertions(+) create mode 100644 .cargo_vcs_info.json create mode 100644 .github/workflows/rust.yml create mode 100644 .github/workflows/security.yml create mode 100644 .mailmap create mode 100644 Android.bp create mode 100644 Cargo.lock create mode 100644 Cargo.toml create mode 120000 LICENSE create mode 100644 LICENSE.md create mode 100644 METADATA create mode 100644 MODULE_LICENSE_MIT create mode 100644 OWNERS create mode 100644 cargo_embargo.json create mode 100644 readme.md create mode 100644 src/byteorder.rs create mode 100644 src/config/endian.rs create mode 100644 src/config/int.rs create mode 100644 src/config/legacy.rs create mode 100644 src/config/limit.rs create mode 100644 src/config/mod.rs create mode 100644 src/config/trailing.rs create mode 100644 src/de/mod.rs create mode 100644 src/de/read.rs create mode 100644 src/error.rs create mode 100644 src/internal.rs create mode 100644 src/lib.rs create mode 100644 src/ser/mod.rs create mode 100644 tests/test.rs diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json new file mode 100644 index 0000000..dc4c924 --- /dev/null +++ b/.cargo_vcs_info.json @@ -0,0 +1,5 @@ +{ + "git": { + "sha1": "c44b5e364e7084cdbabf9f94b63a3c7f32b8fb68" + } +} diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml new file mode 100644 index 0000000..841f124 --- /dev/null +++ b/.github/workflows/rust.yml @@ -0,0 +1,175 @@ +{ + "name": "CI", + "on": { + "push": { + "branches": [ + "trunk", + "v*.x" + ] + }, + "pull_request": { + "branches": [ + "trunk", + "v*.x" + ] + } + }, + "jobs": { + "check": { + "name": "Check", + "runs-on": "ubuntu-latest", + "strategy": { + "fail-fast": false, + "matrix": { + "rust": [ + "stable", + "beta", + "nightly", + "1.18.0" + ] + } + }, + "steps": [ + { + "uses": "actions/checkout@v2", + "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" + }, + "name": "Run `cargo check`" + }, + { + "uses": "actions-rs/cargo@v1", + "with": { + "command": "check", + "args": "--examples" + }, + "name": "Check examples", + "if": "matrix.rust != '1.18.0'" + } + ] + }, + "test": { + "name": "Test", + "runs-on": "ubuntu-latest", + "strategy": { + "matrix": { + "rust": [ + "stable", + "beta", + "nightly" + ] + } + }, + "steps": [ + { + "uses": "actions/checkout@v2", + "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": "test" + }, + "name": "Run `cargo test`" + } + ] + }, + "lints": { + "name": "Lints", + "runs-on": "ubuntu-latest", + "steps": [ + { + "uses": "actions/checkout@v2", + "name": "Checkout" + }, + { + "uses": "actions-rs/toolchain@v1", + "with": { + "profile": "minimal", + "toolchain": "stable", + "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": "-- -D warnings" + }, + "name": "Run `cargo clippy`" + } + ] + }, + "coverage": { + "name": "Code Coverage", + "runs-on": "ubuntu-latest", + "steps": [ + { + "uses": "actions/checkout@v2", + "name": "Checkout" + }, + { + "uses": "actions-rs/toolchain@v1", + "with": { + "profile": "minimal", + "toolchain": "nightly", + "override": true + }, + "name": "Install Rust nightly" + }, + { + "name": "Run cargo-tarpaulin", + "uses": "actions-rs/tarpaulin@v0.1", + "with": { + "version": "0.12.3", + "args": "--ignore-tests -- --test-threads 1" + } + }, + { + "name": "Upload to codecov.io", + "uses": "codecov/codecov-action@v1" + }, + { + "name": "Archive code coverage results", + "uses": "actions/upload-artifact@v1", + "with": { + "name": "code-coverage-report", + "path": "cobertura.xml" + } + } + ] + } + } +} diff --git a/.github/workflows/security.yml b/.github/workflows/security.yml new file mode 100644 index 0000000..704c5f0 --- /dev/null +++ b/.github/workflows/security.yml @@ -0,0 +1,26 @@ +{ + "name": "Security audit", + "on": { + "schedule": [ + { + "cron": "0 0 * * *" + } + ] + }, + "jobs": { + "audit": { + "runs-on": "ubuntu-latest", + "steps": [ + { + "uses": "actions/checkout@v1" + }, + { + "uses": "actions-rs/audit-check@v1", + "with": { + "token": "${{ secrets.GITHUB_TOKEN }}" + } + } + ] + } + } +} diff --git a/.mailmap b/.mailmap new file mode 100644 index 0000000..85e4fe3 --- /dev/null +++ b/.mailmap @@ -0,0 +1,3 @@ +Ty Overby +Ty Overby +Zoey Riordan diff --git a/Android.bp b/Android.bp new file mode 100644 index 0000000..dd8a014 --- /dev/null +++ b/Android.bp @@ -0,0 +1,20 @@ +// This file is generated by cargo_embargo. +// Do not modify this file as changes will be overridden on upgrade. + +// TODO: Add license. +rust_library { + name: "libbincode", + host_supported: true, + crate_name: "bincode", + cargo_env_compat: true, + cargo_pkg_version: "1.3.3", + srcs: ["src/lib.rs"], + edition: "2015", + rustlibs: ["libserde"], + apex_available: [ + "//apex_available:platform", + "//apex_available:anyapex", + ], + product_available: true, + vendor_available: true, +} diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..86e0ba6 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,71 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "bincode" +version = "1.3.3" +dependencies = [ + "serde", + "serde_bytes", + "serde_derive", +] + +[[package]] +name = "proc-macro2" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "quote" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "serde" +version = "1.0.123" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92d5161132722baa40d802cc70b15262b98258453e85e5d1d365c757c73869ae" + +[[package]] +name = "serde_bytes" +version = "0.11.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16ae07dd2f88a366f15bd0632ba725227018c69a1c8550a927324f8eb8368bb9" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_derive" +version = "1.0.123" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9391c295d64fc0abb2c556bad848f33cb8296276b1ad2677d1ae1ace4f258f31" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "syn" +version = "1.0.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c700597eca8a5a762beb35753ef6b94df201c81cca676604f547495a0d7f0081" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "unicode-xid" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..4c81bfc --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,37 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "bincode" +version = "1.3.3" +authors = ["Ty Overby ", "Francesco Mazzoli ", "David Tolnay ", "Zoey Riordan "] +exclude = ["logo.png", "examples/*", ".gitignore", ".travis.yml"] +publish = true +description = "A binary serialization / deserialization strategy that uses Serde for transforming structs into bytes and vice versa!" +documentation = "https://docs.rs/bincode" +readme = "./readme.md" +keywords = ["binary", "encode", "decode", "serialize", "deserialize"] +categories = ["encoding", "network-programming"] +license = "MIT" +repository = "https://github.com/servo/bincode" +[dependencies.serde] +version = "1.0.63" +[dev-dependencies.serde_bytes] +version = "0.11" + +[dev-dependencies.serde_derive] +version = "1.0.27" + +[features] +i128 = [] +[badges.travis-ci] +repository = "servo/bincode" diff --git a/LICENSE b/LICENSE new file mode 120000 index 0000000..f0c4298 --- /dev/null +++ b/LICENSE @@ -0,0 +1 @@ +LICENSE.md \ No newline at end of file diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..3db1f01 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2014 Ty Overby + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/METADATA b/METADATA new file mode 100644 index 0000000..26541e1 --- /dev/null +++ b/METADATA @@ -0,0 +1,20 @@ +name: "bincode" +description: "A binary serialization / deserialization strategy that uses Serde for transforming structs into bytes and vice versa!" +third_party { + identifier { + type: "crates.io" + value: "bincode" + } + identifier { + type: "Archive" + value: "https://static.crates.io/crates/bincode/bincode-1.3.3.crate" + primary_source: true + } + version: "1.3.3" + license_type: NOTICE + last_upgrade_date { + year: 2024 + month: 3 + day: 21 + } +} diff --git a/MODULE_LICENSE_MIT b/MODULE_LICENSE_MIT new file mode 100644 index 0000000..e69de29 diff --git a/OWNERS b/OWNERS new file mode 100644 index 0000000..48bea6e --- /dev/null +++ b/OWNERS @@ -0,0 +1,2 @@ +# Bug component: 688011 +include platform/prebuilts/rust:main:/OWNERS diff --git a/cargo_embargo.json b/cargo_embargo.json new file mode 100644 index 0000000..cb908d7 --- /dev/null +++ b/cargo_embargo.json @@ -0,0 +1,3 @@ +{ + "run_cargo": false +} diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..e916512 --- /dev/null +++ b/readme.md @@ -0,0 +1,112 @@ +# Bincode + + + +![CI](https://github.com/servo/bincode/workflows/CI/badge.svg) +[![](https://meritbadge.herokuapp.com/bincode)](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.18+-lightgray.svg)](https://blog.rust-lang.org/2017/06/08/Rust-1.18.html) + +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. + +In addition to exposing two simple functions +(one that encodes to `Vec`, 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/alexcrichton/flate2-rs) compression +library. + +## [API Documentation](https://docs.rs/bincode/) + +## Bincode in the wild + +* [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. + +## Example + +```rust +use serde::{Serialize, Deserialize}; + +#[derive(Serialize, Deserialize, PartialEq, Debug)] +struct Entity { + x: f32, + y: f32, +} + +#[derive(Serialize, Deserialize, PartialEq, Debug)] +struct World(Vec); + +fn main() { + let world = World(vec![Entity { x: 0.0, y: 4.0 }, Entity { x: 10.0, y: 20.5 }]); + + let encoded: Vec = bincode::serialize(&world).unwrap(); + + // 8 bytes for the length of the vector, 4 bytes per float. + assert_eq!(encoded.len(), 8 + 4 * 4); + + let decoded: World = bincode::deserialize(&encoded[..]).unwrap(); + + assert_eq!(world, decoded); +} +``` + +## Details + +The encoding (and thus decoding) proceeds unsurprisingly -- primitive +types are encoded according to the underlying `Writer`, tuples and +structs are encoded by encoding their fields one-by-one, and enums are +encoded by first writing out the tag representing the variant and +then the contents. + +However, there are some implementation details to be aware of: + +* `isize`/`usize` are encoded as `i64`/`u64`, for portability. +* enums variants are encoded as a `u32` instead of a `usize`. + `u32` is enough for all practical uses. +* `str` is encoded as `(u64, &[u8])`, where the `u64` is the number of + bytes contained in the encoded string. + +## Specification + +Bincode's format will eventually be codified into a specification, along with +its configuration options and default configuration. In the meantime, here are +some frequently asked questions regarding use of the crate: + +### Is Bincode suitable for storage? + +The encoding format is stable across minor revisions, 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 occured. + +Bincode is invariant over byte-order in the default configuration +(`bincode::options::DefaultOptions`), 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 (`bincode::config::Bounded`), 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 1.0 maintains support for rust 1.18.0. Any changes to this are considered a breaking change for semver purposes. \ No newline at end of file diff --git a/src/byteorder.rs b/src/byteorder.rs new file mode 100644 index 0000000..298503d --- /dev/null +++ b/src/byteorder.rs @@ -0,0 +1,385 @@ +// Copyright (c) 2015 Andrew Gallant + +use std::io; +use std::io::Result; +use std::ptr::copy_nonoverlapping; + +#[derive(Copy, Clone)] +pub struct LittleEndian; + +#[derive(Copy, Clone)] +pub struct BigEndian; + +#[cfg(target_endian = "little")] +pub type NativeEndian = LittleEndian; + +#[cfg(target_endian = "big")] +pub type NativeEndian = BigEndian; + +macro_rules! read_num_bytes { + ($ty:ty, $size:expr, $src:expr, $which:ident) => {{ + assert!($size == ::std::mem::size_of::<$ty>()); + assert!($size <= $src.len()); + let mut data: $ty = 0; + unsafe { + copy_nonoverlapping($src.as_ptr(), &mut data as *mut $ty as *mut u8, $size); + } + data.$which() + }}; +} + +macro_rules! write_num_bytes { + ($ty:ty, $size:expr, $n:expr, $dst:expr, $which:ident) => {{ + assert!($size <= $dst.len()); + unsafe { + // N.B. https://github.com/rust-lang/rust/issues/22776 + let bytes = *(&$n.$which() as *const _ as *const [u8; $size]); + copy_nonoverlapping((&bytes).as_ptr(), $dst.as_mut_ptr(), $size); + } + }}; +} + +impl ByteOrder for LittleEndian { + #[inline] + fn read_u16(buf: &[u8]) -> u16 { + read_num_bytes!(u16, 2, buf, to_le) + } + + #[inline] + fn read_u32(buf: &[u8]) -> u32 { + read_num_bytes!(u32, 4, buf, to_le) + } + + #[inline] + fn read_u64(buf: &[u8]) -> u64 { + read_num_bytes!(u64, 8, buf, to_le) + } + + #[inline] + fn write_u16(buf: &mut [u8], n: u16) { + write_num_bytes!(u16, 2, n, buf, to_le); + } + + #[inline] + fn write_u32(buf: &mut [u8], n: u32) { + write_num_bytes!(u32, 4, n, buf, to_le); + } + + #[inline] + fn write_u64(buf: &mut [u8], n: u64) { + write_num_bytes!(u64, 8, n, buf, to_le); + } + + serde_if_integer128! { + #[inline] + fn write_u128(buf: &mut [u8], n: u128) { + write_num_bytes!(u128, 16, n, buf, to_le); + } + + #[inline] + fn read_u128(buf: &[u8]) -> u128 { + read_num_bytes!(u128, 16, buf, to_le) + } + } +} + +impl ByteOrder for BigEndian { + #[inline] + fn read_u16(buf: &[u8]) -> u16 { + read_num_bytes!(u16, 2, buf, to_be) + } + + #[inline] + fn read_u32(buf: &[u8]) -> u32 { + read_num_bytes!(u32, 4, buf, to_be) + } + + #[inline] + fn read_u64(buf: &[u8]) -> u64 { + read_num_bytes!(u64, 8, buf, to_be) + } + + #[inline] + fn write_u16(buf: &mut [u8], n: u16) { + write_num_bytes!(u16, 2, n, buf, to_be); + } + + #[inline] + fn write_u32(buf: &mut [u8], n: u32) { + write_num_bytes!(u32, 4, n, buf, to_be); + } + + #[inline] + fn write_u64(buf: &mut [u8], n: u64) { + write_num_bytes!(u64, 8, n, buf, to_be); + } + + serde_if_integer128! { + #[inline] + fn write_u128(buf: &mut [u8], n: u128) { + write_num_bytes!(u128, 16, n, buf, to_be); + } + + #[inline] + fn read_u128(buf: &[u8]) -> u128 { + read_num_bytes!(u128, 16, buf, to_be) + } + } +} + +pub trait ByteOrder: Clone + Copy { + fn read_u16(buf: &[u8]) -> u16; + + fn read_u32(buf: &[u8]) -> u32; + + fn read_u64(buf: &[u8]) -> u64; + + fn write_u16(buf: &mut [u8], n: u16); + + fn write_u32(buf: &mut [u8], n: u32); + + fn write_u64(buf: &mut [u8], n: u64); + + #[inline] + fn read_i16(buf: &[u8]) -> i16 { + Self::read_u16(buf) as i16 + } + + #[inline] + fn read_i32(buf: &[u8]) -> i32 { + Self::read_u32(buf) as i32 + } + + #[inline] + fn read_i64(buf: &[u8]) -> i64 { + Self::read_u64(buf) as i64 + } + + #[inline] + fn read_f32(buf: &[u8]) -> f32 { + unsafe { *(&Self::read_u32(buf) as *const u32 as *const f32) } + } + + #[inline] + fn read_f64(buf: &[u8]) -> f64 { + unsafe { *(&Self::read_u64(buf) as *const u64 as *const f64) } + } + + #[inline] + fn write_i16(buf: &mut [u8], n: i16) { + Self::write_u16(buf, n as u16) + } + + #[inline] + fn write_i32(buf: &mut [u8], n: i32) { + Self::write_u32(buf, n as u32) + } + + #[inline] + fn write_i64(buf: &mut [u8], n: i64) { + Self::write_u64(buf, n as u64) + } + + #[inline] + fn write_f32(buf: &mut [u8], n: f32) { + let n = unsafe { *(&n as *const f32 as *const u32) }; + Self::write_u32(buf, n) + } + + #[inline] + fn write_f64(buf: &mut [u8], n: f64) { + let n = unsafe { *(&n as *const f64 as *const u64) }; + Self::write_u64(buf, n) + } + + serde_if_integer128! { + fn read_u128(buf: &[u8]) -> u128; + fn write_u128(buf: &mut [u8], n: u128); + + #[inline] + fn read_i128(buf: &[u8]) -> i128 { + Self::read_u128(buf) as i128 + } + + #[inline] + fn write_i128(buf: &mut [u8], n: i128) { + Self::write_u128(buf, n as u128) + } + } +} + +pub trait ReadBytesExt: io::Read { + #[inline] + fn read_u8(&mut self) -> Result { + let mut buf = [0; 1]; + try!(self.read_exact(&mut buf)); + Ok(buf[0]) + } + + #[inline] + fn read_i8(&mut self) -> Result { + let mut buf = [0; 1]; + try!(self.read_exact(&mut buf)); + Ok(buf[0] as i8) + } + + #[inline] + fn read_u16(&mut self) -> Result { + let mut buf = [0; 2]; + try!(self.read_exact(&mut buf)); + Ok(T::read_u16(&buf)) + } + + #[inline] + fn read_i16(&mut self) -> Result { + let mut buf = [0; 2]; + try!(self.read_exact(&mut buf)); + Ok(T::read_i16(&buf)) + } + + #[inline] + fn read_u32(&mut self) -> Result { + let mut buf = [0; 4]; + try!(self.read_exact(&mut buf)); + Ok(T::read_u32(&buf)) + } + + #[inline] + fn read_i32(&mut self) -> Result { + let mut buf = [0; 4]; + try!(self.read_exact(&mut buf)); + Ok(T::read_i32(&buf)) + } + + #[inline] + fn read_u64(&mut self) -> Result { + let mut buf = [0; 8]; + try!(self.read_exact(&mut buf)); + Ok(T::read_u64(&buf)) + } + + #[inline] + fn read_i64(&mut self) -> Result { + let mut buf = [0; 8]; + try!(self.read_exact(&mut buf)); + Ok(T::read_i64(&buf)) + } + + #[inline] + fn read_f32(&mut self) -> Result { + let mut buf = [0; 4]; + try!(self.read_exact(&mut buf)); + Ok(T::read_f32(&buf)) + } + + #[inline] + fn read_f64(&mut self) -> Result { + let mut buf = [0; 8]; + try!(self.read_exact(&mut buf)); + Ok(T::read_f64(&buf)) + } + + serde_if_integer128! { + #[inline] + fn read_u128(&mut self) -> Result { + let mut buf = [0; 16]; + try!(self.read_exact(&mut buf)); + Ok(T::read_u128(&buf)) + } + + #[inline] + fn read_i128(&mut self) -> Result { + let mut buf = [0; 16]; + try!(self.read_exact(&mut buf)); + Ok(T::read_i128(&buf)) + } + } +} + +impl ReadBytesExt for R {} + +pub trait WriteBytesExt: io::Write { + #[inline] + fn write_u8(&mut self, n: u8) -> Result<()> { + self.write_all(&[n]) + } + + #[inline] + fn write_i8(&mut self, n: i8) -> Result<()> { + self.write_all(&[n as u8]) + } + + #[inline] + fn write_u16(&mut self, n: u16) -> Result<()> { + let mut buf = [0; 2]; + T::write_u16(&mut buf, n); + self.write_all(&buf) + } + + #[inline] + fn write_i16(&mut self, n: i16) -> Result<()> { + let mut buf = [0; 2]; + T::write_i16(&mut buf, n); + self.write_all(&buf) + } + + #[inline] + fn write_u32(&mut self, n: u32) -> Result<()> { + let mut buf = [0; 4]; + T::write_u32(&mut buf, n); + self.write_all(&buf) + } + + #[inline] + fn write_i32(&mut self, n: i32) -> Result<()> { + let mut buf = [0; 4]; + T::write_i32(&mut buf, n); + self.write_all(&buf) + } + + #[inline] + fn write_u64(&mut self, n: u64) -> Result<()> { + let mut buf = [0; 8]; + T::write_u64(&mut buf, n); + self.write_all(&buf) + } + + #[inline] + fn write_i64(&mut self, n: i64) -> Result<()> { + let mut buf = [0; 8]; + T::write_i64(&mut buf, n); + self.write_all(&buf) + } + + #[inline] + fn write_f32(&mut self, n: f32) -> Result<()> { + let mut buf = [0; 4]; + T::write_f32(&mut buf, n); + self.write_all(&buf) + } + + #[inline] + fn write_f64(&mut self, n: f64) -> Result<()> { + let mut buf = [0; 8]; + T::write_f64(&mut buf, n); + self.write_all(&buf) + } + + serde_if_integer128! { + #[inline] + fn write_u128(&mut self, n: u128) -> Result<()> { + let mut buf = [0; 16]; + T::write_u128(&mut buf, n); + self.write_all(&buf) + } + + #[inline] + fn write_i128(&mut self, n: i128) -> Result<()> { + let mut buf = [0; 16]; + T::write_i128(&mut buf, n); + self.write_all(&buf) + } + } +} + +impl WriteBytesExt for W {} diff --git a/src/config/endian.rs b/src/config/endian.rs new file mode 100644 index 0000000..2561620 --- /dev/null +++ b/src/config/endian.rs @@ -0,0 +1,27 @@ +pub trait BincodeByteOrder { + type Endian: ::byteorder::ByteOrder + 'static; +} + +/// Little-endian byte ordering. +#[derive(Copy, Clone)] +pub struct LittleEndian; + +/// Big-endian byte ordering. +#[derive(Copy, Clone)] +pub struct BigEndian; + +/// The native byte ordering of the current system. +#[derive(Copy, Clone)] +pub struct NativeEndian; + +impl BincodeByteOrder for LittleEndian { + type Endian = ::byteorder::LittleEndian; +} + +impl BincodeByteOrder for BigEndian { + type Endian = ::byteorder::BigEndian; +} + +impl BincodeByteOrder for NativeEndian { + type Endian = ::byteorder::NativeEndian; +} diff --git a/src/config/int.rs b/src/config/int.rs new file mode 100644 index 0000000..f716d1a --- /dev/null +++ b/src/config/int.rs @@ -0,0 +1,682 @@ +use std::io::Write; +use std::mem::size_of; + +use super::Options; +use de::read::BincodeRead; +use error::{ErrorKind, Result}; + +pub trait IntEncoding { + /// Gets the size (in bytes) that a value would be serialized to. + fn u16_size(n: u16) -> u64; + /// Gets the size (in bytes) that a value would be serialized to. + fn u32_size(n: u32) -> u64; + /// Gets the size (in bytes) that a value would be serialized to. + fn u64_size(n: u64) -> u64; + + /// Gets the size (in bytes) that a value would be serialized to. + fn i16_size(n: i16) -> u64; + /// Gets the size (in bytes) that a value would be serialized to. + fn i32_size(n: i32) -> u64; + /// Gets the size (in bytes) that a value would be serialized to. + fn i64_size(n: i64) -> u64; + + #[inline(always)] + fn len_size(len: usize) -> u64 { + Self::u64_size(len as u64) + } + + /// Serializes a sequence length. + #[inline(always)] + fn serialize_len( + ser: &mut ::ser::Serializer, + len: usize, + ) -> Result<()> { + Self::serialize_u64(ser, len as u64) + } + + fn serialize_u16( + ser: &mut ::ser::Serializer, + val: u16, + ) -> Result<()>; + + fn serialize_u32( + ser: &mut ::ser::Serializer, + val: u32, + ) -> Result<()>; + + fn serialize_u64( + ser: &mut ::ser::Serializer, + val: u64, + ) -> Result<()>; + + fn serialize_i16( + ser: &mut ::ser::Serializer, + val: i16, + ) -> Result<()>; + + fn serialize_i32( + ser: &mut ::ser::Serializer, + val: i32, + ) -> Result<()>; + + fn serialize_i64( + ser: &mut ::ser::Serializer, + val: i64, + ) -> Result<()>; + + /// Deserializes a sequence length. + #[inline(always)] + fn deserialize_len<'de, R: BincodeRead<'de>, O: Options>( + de: &mut ::de::Deserializer, + ) -> Result { + Self::deserialize_u64(de).and_then(cast_u64_to_usize) + } + + fn deserialize_u16<'de, R: BincodeRead<'de>, O: Options>( + de: &mut ::de::Deserializer, + ) -> Result; + + fn deserialize_u32<'de, R: BincodeRead<'de>, O: Options>( + de: &mut ::de::Deserializer, + ) -> Result; + + fn deserialize_u64<'de, R: BincodeRead<'de>, O: Options>( + de: &mut ::de::Deserializer, + ) -> Result; + + fn deserialize_i16<'de, R: BincodeRead<'de>, O: Options>( + de: &mut ::de::Deserializer, + ) -> Result; + + fn deserialize_i32<'de, R: BincodeRead<'de>, O: Options>( + de: &mut ::de::Deserializer, + ) -> Result; + + fn deserialize_i64<'de, R: BincodeRead<'de>, O: Options>( + de: &mut ::de::Deserializer, + ) -> Result; + + serde_if_integer128! { + fn u128_size(v: u128) -> u64; + fn i128_size(v: i128) -> u64; + fn serialize_u128( + ser: &mut ::Serializer, + val: u128, + ) -> Result<()>; + fn deserialize_u128<'de, R: BincodeRead<'de>, O: Options>( + de: &mut ::Deserializer, + ) -> Result; + fn serialize_i128( + ser: &mut ::Serializer, + val: i128, + ) -> Result<()>; + fn deserialize_i128<'de, R: BincodeRead<'de>, O: Options>( + de: &mut ::Deserializer, + ) -> Result; + } +} + +/// Fixed-size integer encoding. +/// +/// * Fixed size integers are encoded directly +/// * Enum discriminants are encoded as u32 +/// * Lengths and usize are encoded as u64 +#[derive(Copy, Clone)] +pub struct FixintEncoding; + +/// Variable-size integer encoding (excepting [ui]8). +/// +/// 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: +/// +/// ```ignore +/// fn zigzag(v: Signed) -> Unsigned { +/// match v { +/// 0 => 0, +/// v if v < 0 => |v| * 2 - 1 +/// v if v > 0 => v * 2 +/// } +/// } +/// ``` +/// +/// And works such that: +/// +/// ```ignore +/// 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); +/// 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. +#[derive(Copy, Clone)] +pub struct VarintEncoding; + +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; +const DESERIALIZE_EXTENSION_POINT_ERR: &str = r#" +Byte 255 is treated as an extension point; it should not be encoding anything. +Do you have a mismatched bincode version or configuration? +"#; + +impl VarintEncoding { + fn varint_size(n: u64) -> u64 { + if n <= SINGLE_BYTE_MAX as u64 { + 1 + } else if n <= u16::max_value() as u64 { + (1 + size_of::()) as u64 + } else if n <= u32::max_value() as u64 { + (1 + size_of::()) as u64 + } else { + (1 + size_of::()) as u64 + } + } + + #[inline(always)] + fn zigzag_encode(n: i64) -> u64 { + if n < 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 + !(n as u64) * 2 + 1 + } else { + (n as u64) * 2 + } + } + + #[inline(always)] + fn zigzag_decode(n: u64) -> i64 { + if n % 2 == 0 { + // positive number + (n / 2) as i64 + } 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 i64 + } + } + + fn serialize_varint( + ser: &mut ::ser::Serializer, + n: u64, + ) -> Result<()> { + if n <= SINGLE_BYTE_MAX as u64 { + ser.serialize_byte(n as u8) + } else if n <= u16::max_value() as u64 { + ser.serialize_byte(U16_BYTE)?; + ser.serialize_literal_u16(n as u16) + } else if n <= u32::max_value() as u64 { + ser.serialize_byte(U32_BYTE)?; + ser.serialize_literal_u32(n as u32) + } else { + ser.serialize_byte(U64_BYTE)?; + ser.serialize_literal_u64(n as u64) + } + } + + fn deserialize_varint<'de, R: BincodeRead<'de>, O: Options>( + de: &mut ::de::Deserializer, + ) -> Result { + #[allow(ellipsis_inclusive_range_patterns)] + match de.deserialize_byte()? { + byte @ 0...SINGLE_BYTE_MAX => Ok(byte as u64), + U16_BYTE => Ok(de.deserialize_literal_u16()? as u64), + U32_BYTE => Ok(de.deserialize_literal_u32()? as u64), + U64_BYTE => de.deserialize_literal_u64(), + U128_BYTE => Err(Box::new(ErrorKind::Custom( + "Invalid value (u128 range): you may have a version or configuration disagreement?" + .to_string(), + ))), + _ => Err(Box::new(ErrorKind::Custom( + DESERIALIZE_EXTENSION_POINT_ERR.to_string(), + ))), + } + } + + serde_if_integer128! { + // see zigzag_encode and zigzag_decode for implementation comments + #[inline(always)] + fn zigzag128_encode(n: i128) -> u128 { + if n < 0 { + !(n as u128) * 2 + 1 + } else { + (n as u128) * 2 + } + } + #[inline(always)] + fn zigzag128_decode(n: u128) -> i128 { + if n % 2 == 0 { + (n / 2) as i128 + } else { + !(n / 2) as i128 + } + } + + fn varint128_size(n: u128) -> u64 { + if n <= SINGLE_BYTE_MAX as u128 { + 1 + } else if n <= u16::max_value() as u128 { + (1 + size_of::()) as u64 + } else if n <= u32::max_value() as u128 { + (1 + size_of::()) as u64 + } else if n <= u64::max_value() as u128 { + (1 + size_of::()) as u64 + } else { + (1 + size_of::()) as u64 + } + } + + fn serialize_varint128( + ser: &mut ::ser::Serializer, + n: u128, + ) -> Result<()> { + if n <= SINGLE_BYTE_MAX as u128 { + ser.serialize_byte(n as u8) + } else if n <= u16::max_value() as u128 { + ser.serialize_byte(U16_BYTE)?; + ser.serialize_literal_u16(n as u16) + } else if n <= u32::max_value() as u128 { + ser.serialize_byte(U32_BYTE)?; + ser.serialize_literal_u32(n as u32) + } else if n <= u64::max_value() as u128 { + ser.serialize_byte(U64_BYTE)?; + ser.serialize_literal_u64(n as u64) + } else { + ser.serialize_byte(U128_BYTE)?; + ser.serialize_literal_u128(n) + } + } + + fn deserialize_varint128<'de, R: BincodeRead<'de>, O: Options>( + de: &mut ::de::Deserializer, + ) -> Result { + #[allow(ellipsis_inclusive_range_patterns)] + match de.deserialize_byte()? { + byte @ 0...SINGLE_BYTE_MAX => Ok(byte as u128), + U16_BYTE => Ok(de.deserialize_literal_u16()? as u128), + U32_BYTE => Ok(de.deserialize_literal_u32()? as u128), + U64_BYTE => Ok(de.deserialize_literal_u64()? as u128), + U128_BYTE => de.deserialize_literal_u128(), + _ => Err(Box::new(ErrorKind::Custom(DESERIALIZE_EXTENSION_POINT_ERR.to_string()))), + } + } + } +} + +impl IntEncoding for FixintEncoding { + #[inline(always)] + fn u16_size(_: u16) -> u64 { + size_of::() as u64 + } + #[inline(always)] + fn u32_size(_: u32) -> u64 { + size_of::() as u64 + } + #[inline(always)] + fn u64_size(_: u64) -> u64 { + size_of::() as u64 + } + + #[inline(always)] + fn i16_size(_: i16) -> u64 { + size_of::() as u64 + } + #[inline(always)] + fn i32_size(_: i32) -> u64 { + size_of::() as u64 + } + #[inline(always)] + fn i64_size(_: i64) -> u64 { + size_of::() as u64 + } + + #[inline(always)] + fn serialize_u16(ser: &mut ::Serializer, val: u16) -> Result<()> { + ser.serialize_literal_u16(val) + } + #[inline(always)] + fn serialize_u32(ser: &mut ::Serializer, val: u32) -> Result<()> { + ser.serialize_literal_u32(val) + } + #[inline(always)] + fn serialize_u64(ser: &mut ::Serializer, val: u64) -> Result<()> { + ser.serialize_literal_u64(val) + } + + #[inline(always)] + fn serialize_i16(ser: &mut ::Serializer, val: i16) -> Result<()> { + ser.serialize_literal_u16(val as u16) + } + #[inline(always)] + fn serialize_i32(ser: &mut ::Serializer, val: i32) -> Result<()> { + ser.serialize_literal_u32(val as u32) + } + #[inline(always)] + fn serialize_i64(ser: &mut ::Serializer, val: i64) -> Result<()> { + ser.serialize_literal_u64(val as u64) + } + + #[inline(always)] + fn deserialize_u16<'de, R: BincodeRead<'de>, O: Options>( + de: &mut ::Deserializer, + ) -> Result { + de.deserialize_literal_u16() + } + #[inline(always)] + fn deserialize_u32<'de, R: BincodeRead<'de>, O: Options>( + de: &mut ::Deserializer, + ) -> Result { + de.deserialize_literal_u32() + } + #[inline(always)] + fn deserialize_u64<'de, R: BincodeRead<'de>, O: Options>( + de: &mut ::Deserializer, + ) -> Result { + de.deserialize_literal_u64() + } + + #[inline(always)] + fn deserialize_i16<'de, R: BincodeRead<'de>, O: Options>( + de: &mut ::Deserializer, + ) -> Result { + Ok(de.deserialize_literal_u16()? as i16) + } + #[inline(always)] + fn deserialize_i32<'de, R: BincodeRead<'de>, O: Options>( + de: &mut ::Deserializer, + ) -> Result { + Ok(de.deserialize_literal_u32()? as i32) + } + #[inline(always)] + fn deserialize_i64<'de, R: BincodeRead<'de>, O: Options>( + de: &mut ::Deserializer, + ) -> Result { + Ok(de.deserialize_literal_u64()? as i64) + } + + serde_if_integer128! { + #[inline(always)] + fn u128_size(_: u128) -> u64{ + size_of::() as u64 + } + #[inline(always)] + fn i128_size(_: i128) -> u64{ + size_of::() as u64 + } + + #[inline(always)] + fn serialize_u128( + ser: &mut ::Serializer, + val: u128, + ) -> Result<()> { + ser.serialize_literal_u128(val) + } + #[inline(always)] + fn serialize_i128( + ser: &mut ::Serializer, + val: i128, + ) -> Result<()> { + ser.serialize_literal_u128(val as u128) + } + #[inline(always)] + fn deserialize_u128<'de, R: BincodeRead<'de>, O: Options>( + de: &mut ::Deserializer, + ) -> Result { + de.deserialize_literal_u128() + } + #[inline(always)] + fn deserialize_i128<'de, R: BincodeRead<'de>, O: Options>( + de: &mut ::Deserializer, + ) -> Result { + Ok(de.deserialize_literal_u128()? as i128) + } + } +} + +impl IntEncoding for VarintEncoding { + #[inline(always)] + fn u16_size(n: u16) -> u64 { + Self::varint_size(n as u64) + } + #[inline(always)] + fn u32_size(n: u32) -> u64 { + Self::varint_size(n as u64) + } + #[inline(always)] + fn u64_size(n: u64) -> u64 { + Self::varint_size(n) + } + + #[inline(always)] + fn i16_size(n: i16) -> u64 { + Self::varint_size(Self::zigzag_encode(n as i64)) + } + #[inline(always)] + fn i32_size(n: i32) -> u64 { + Self::varint_size(Self::zigzag_encode(n as i64)) + } + #[inline(always)] + fn i64_size(n: i64) -> u64 { + Self::varint_size(Self::zigzag_encode(n)) + } + + #[inline(always)] + fn serialize_u16(ser: &mut ::Serializer, val: u16) -> Result<()> { + Self::serialize_varint(ser, val as u64) + } + #[inline(always)] + fn serialize_u32(ser: &mut ::Serializer, val: u32) -> Result<()> { + Self::serialize_varint(ser, val as u64) + } + #[inline(always)] + fn serialize_u64(ser: &mut ::Serializer, val: u64) -> Result<()> { + Self::serialize_varint(ser, val) + } + + #[inline(always)] + fn serialize_i16(ser: &mut ::Serializer, val: i16) -> Result<()> { + Self::serialize_varint(ser, Self::zigzag_encode(val as i64)) + } + #[inline(always)] + fn serialize_i32(ser: &mut ::Serializer, val: i32) -> Result<()> { + Self::serialize_varint(ser, Self::zigzag_encode(val as i64)) + } + #[inline(always)] + fn serialize_i64(ser: &mut ::Serializer, val: i64) -> Result<()> { + Self::serialize_varint(ser, Self::zigzag_encode(val)) + } + + #[inline(always)] + fn deserialize_u16<'de, R: BincodeRead<'de>, O: Options>( + de: &mut ::Deserializer, + ) -> Result { + Self::deserialize_varint(de).and_then(cast_u64_to_u16) + } + #[inline(always)] + fn deserialize_u32<'de, R: BincodeRead<'de>, O: Options>( + de: &mut ::Deserializer, + ) -> Result { + Self::deserialize_varint(de).and_then(cast_u64_to_u32) + } + #[inline(always)] + fn deserialize_u64<'de, R: BincodeRead<'de>, O: Options>( + de: &mut ::Deserializer, + ) -> Result { + Self::deserialize_varint(de) + } + + #[inline(always)] + fn deserialize_i16<'de, R: BincodeRead<'de>, O: Options>( + de: &mut ::Deserializer, + ) -> Result { + Self::deserialize_varint(de) + .map(Self::zigzag_decode) + .and_then(cast_i64_to_i16) + } + #[inline(always)] + fn deserialize_i32<'de, R: BincodeRead<'de>, O: Options>( + de: &mut ::Deserializer, + ) -> Result { + Self::deserialize_varint(de) + .map(Self::zigzag_decode) + .and_then(cast_i64_to_i32) + } + #[inline(always)] + fn deserialize_i64<'de, R: BincodeRead<'de>, O: Options>( + de: &mut ::Deserializer, + ) -> Result { + Self::deserialize_varint(de).map(Self::zigzag_decode) + } + + serde_if_integer128! { + #[inline(always)] + fn u128_size(n: u128) -> u64 { + Self::varint128_size(n) + } + #[inline(always)] + fn i128_size(n: i128) -> u64 { + Self::varint128_size(Self::zigzag128_encode(n)) + } + #[inline(always)] + fn serialize_u128( + ser: &mut ::Serializer, + val: u128, + ) -> Result<()> { + Self::serialize_varint128(ser, val) + } + #[inline(always)] + fn serialize_i128( + ser: &mut ::Serializer, + val: i128, + ) -> Result<()> { + Self::serialize_varint128(ser, Self::zigzag128_encode(val)) + } + #[inline(always)] + fn deserialize_u128<'de, R: BincodeRead<'de>, O: Options>( + de: &mut ::Deserializer, + ) -> Result { + Self::deserialize_varint128(de) + } + #[inline(always)] + fn deserialize_i128<'de, R: BincodeRead<'de>, O: Options>( + de: &mut ::Deserializer, + ) -> Result { + Self::deserialize_varint128(de).map(Self::zigzag128_decode) + } + } +} + +fn cast_u64_to_usize(n: u64) -> Result { + if n <= usize::max_value() as u64 { + Ok(n as usize) + } else { + Err(Box::new(ErrorKind::Custom(format!( + "Invalid size {}: sizes must fit in a usize (0 to {})", + n, + usize::max_value() + )))) + } +} +fn cast_u64_to_u32(n: u64) -> Result { + if n <= u32::max_value() as u64 { + Ok(n as u32) + } else { + Err(Box::new(ErrorKind::Custom(format!( + "Invalid u32 {}: you may have a version disagreement?", + n, + )))) + } +} +fn cast_u64_to_u16(n: u64) -> Result { + if n <= u16::max_value() as u64 { + Ok(n as u16) + } else { + Err(Box::new(ErrorKind::Custom(format!( + "Invalid u16 {}: you may have a version disagreement?", + n, + )))) + } +} + +fn cast_i64_to_i32(n: i64) -> Result { + if n <= i32::max_value() as i64 && n >= i32::min_value() as i64 { + Ok(n as i32) + } else { + Err(Box::new(ErrorKind::Custom(format!( + "Invalid i32 {}: you may have a version disagreement?", + n, + )))) + } +} + +fn cast_i64_to_i16(n: i64) -> Result { + if n <= i16::max_value() as i64 && n >= i16::min_value() as i64 { + Ok(n as i16) + } else { + Err(Box::new(ErrorKind::Custom(format!( + "Invalid i16 {}: you may have a version disagreement?", + n, + )))) + } +} + +#[cfg(test)] +mod test { + use super::VarintEncoding; + + #[test] + fn test_zigzag_encode() { + let zigzag = VarintEncoding::zigzag_encode; + + assert_eq!(zigzag(0), 0); + for x in 1..512 { + assert_eq!(zigzag(x), (x as u64) * 2); + assert_eq!(zigzag(-x), (x as u64) * 2 - 1); + } + } + + #[test] + fn test_zigzag_decode() { + // zigzag' + let zigzagp = VarintEncoding::zigzag_decode; + for x in (0..512).map(|x| x * 2) { + assert_eq!(zigzagp(x), x as i64 / 2); + assert_eq!(zigzagp(x + 1), -(x as i64) / 2 - 1); + } + } + + #[test] + fn test_zigzag_edge_cases() { + let (zigzag, zigzagp) = (VarintEncoding::zigzag_encode, VarintEncoding::zigzag_decode); + + assert_eq!(zigzag(i64::max_value()), u64::max_value() - 1); + assert_eq!(zigzag(i64::min_value()), u64::max_value()); + + assert_eq!(zigzagp(u64::max_value() - 1), i64::max_value()); + assert_eq!(zigzagp(u64::max_value()), i64::min_value()); + } +} diff --git a/src/config/legacy.rs b/src/config/legacy.rs new file mode 100644 index 0000000..ec5c7f0 --- /dev/null +++ b/src/config/legacy.rs @@ -0,0 +1,253 @@ +use std::io::{Read, Write}; + +use self::EndianOption::*; +use self::LimitOption::*; +use super::{DefaultOptions, Options}; +use de::read::BincodeRead; +use error::Result; +use serde; + +/// A configuration builder whose options Bincode will use +/// while serializing and deserializing. +/// +/// ### Options +/// Endianness: The endianness with which multi-byte integers will be read/written. *default: little endian* +/// Limit: The maximum number of bytes that will be read/written in a bincode serialize/deserialize. *default: unlimited* +/// +/// ### Byte Limit Details +/// The purpose of byte-limiting is to prevent Denial-Of-Service attacks whereby malicious attackers get bincode +/// deserialization to crash your process by allocating too much memory or keeping a connection open for too long. +/// +/// When a byte limit is set, bincode will return `Err` on any deserialization that goes over the limit, or any +/// serialization that goes over the limit. +#[derive(Clone, Debug)] +#[deprecated( + since = "1.3.0", + note = "please use the `DefaultOptions`/`Options` system instead" +)] +pub struct Config { + limit: LimitOption, + endian: EndianOption, +} + +#[derive(Clone, Copy, Debug)] +enum LimitOption { + Unlimited, + Limited(u64), +} + +#[derive(Clone, Copy, Debug)] +enum EndianOption { + Big, + Little, + Native, +} + +macro_rules! config_map { + ($self:expr, $opts:ident => $call:expr) => { + match ($self.limit, $self.endian) { + (Unlimited, Little) => { + let $opts = DefaultOptions::new() + .with_fixint_encoding() + .allow_trailing_bytes() + .with_no_limit() + .with_little_endian(); + $call + } + (Unlimited, Big) => { + let $opts = DefaultOptions::new() + .with_fixint_encoding() + .allow_trailing_bytes() + .with_no_limit() + .with_big_endian(); + $call + } + (Unlimited, Native) => { + let $opts = DefaultOptions::new() + .with_fixint_encoding() + .allow_trailing_bytes() + .with_no_limit() + .with_native_endian(); + $call + } + + (Limited(l), Little) => { + let $opts = DefaultOptions::new() + .with_fixint_encoding() + .allow_trailing_bytes() + .with_limit(l) + .with_little_endian(); + $call + } + (Limited(l), Big) => { + let $opts = DefaultOptions::new() + .with_fixint_encoding() + .allow_trailing_bytes() + .with_limit(l) + .with_big_endian(); + $call + } + (Limited(l), Native) => { + let $opts = DefaultOptions::new() + .with_fixint_encoding() + .allow_trailing_bytes() + .with_limit(l) + .with_native_endian(); + $call + } + } + }; +} + +impl Config { + #[inline(always)] + pub(crate) fn new() -> Config { + Config { + limit: LimitOption::Unlimited, + endian: EndianOption::Little, + } + } + + /// Sets the byte limit to be unlimited. + /// This is the default. + #[inline(always)] + pub fn no_limit(&mut self) -> &mut Self { + self.limit = LimitOption::Unlimited; + self + } + + /// Sets the byte limit to `limit`. + #[inline(always)] + pub fn limit(&mut self, limit: u64) -> &mut Self { + self.limit = LimitOption::Limited(limit); + self + } + + /// Sets the endianness to little-endian + /// This is the default. + #[inline(always)] + pub fn little_endian(&mut self) -> &mut Self { + self.endian = EndianOption::Little; + self + } + + /// Sets the endianness to big-endian + #[inline(always)] + pub fn big_endian(&mut self) -> &mut Self { + self.endian = EndianOption::Big; + self + } + + /// Sets the endianness to the the machine-native endianness + #[inline(always)] + pub fn native_endian(&mut self) -> &mut Self { + self.endian = EndianOption::Native; + self + } + + /// Serializes a serializable object into a `Vec` of bytes using this configuration + #[inline(always)] + pub fn serialize(&self, t: &T) -> Result> { + config_map!(self, opts => ::internal::serialize(t, opts)) + } + + /// Returns the size that an object would be if serialized using Bincode with this configuration + #[inline(always)] + pub fn serialized_size(&self, t: &T) -> Result { + config_map!(self, opts => ::internal::serialized_size(t, opts)) + } + + /// Serializes an object directly into a `Writer` using this configuration + /// + /// If the serialization would take more bytes than allowed by the size limit, an error + /// is returned and *no bytes* will be written into the `Writer` + #[inline(always)] + pub fn serialize_into( + &self, + w: W, + t: &T, + ) -> Result<()> { + config_map!(self, opts => ::internal::serialize_into(w, t, opts)) + } + + /// Deserializes a slice of bytes into an instance of `T` using this configuration + #[inline(always)] + pub fn deserialize<'a, T: serde::Deserialize<'a>>(&self, bytes: &'a [u8]) -> Result { + config_map!(self, opts => ::internal::deserialize(bytes, opts)) + } + + /// TODO: document + #[doc(hidden)] + #[inline(always)] + pub fn deserialize_in_place<'a, R, T>(&self, reader: R, place: &mut T) -> Result<()> + where + R: BincodeRead<'a>, + T: serde::de::Deserialize<'a>, + { + config_map!(self, opts => ::internal::deserialize_in_place(reader, opts, place)) + } + + /// Deserializes a slice of bytes with state `seed` using this configuration. + #[inline(always)] + pub fn deserialize_seed<'a, T: serde::de::DeserializeSeed<'a>>( + &self, + seed: T, + bytes: &'a [u8], + ) -> Result { + config_map!(self, opts => ::internal::deserialize_seed(seed, bytes, opts)) + } + + /// Deserializes an object directly from a `Read`er using this configuration + /// + /// If this returns an `Error`, `reader` may be in an invalid state. + #[inline(always)] + pub fn deserialize_from( + &self, + reader: R, + ) -> Result { + config_map!(self, opts => ::internal::deserialize_from(reader, opts)) + } + + /// Deserializes an object directly from a `Read`er with state `seed` using this configuration + /// + /// If this returns an `Error`, `reader` may be in an invalid state. + #[inline(always)] + pub fn deserialize_from_seed<'a, R: Read, T: serde::de::DeserializeSeed<'a>>( + &self, + seed: T, + reader: R, + ) -> Result { + config_map!(self, opts => ::internal::deserialize_from_seed(seed, reader, opts)) + } + + /// Deserializes an object from a custom `BincodeRead`er using the default configuration. + /// It is highly recommended to use `deserialize_from` unless you need to implement + /// `BincodeRead` for performance reasons. + /// + /// If this returns an `Error`, `reader` may be in an invalid state. + #[inline(always)] + pub fn deserialize_from_custom<'a, R: BincodeRead<'a>, T: serde::de::DeserializeOwned>( + &self, + reader: R, + ) -> Result { + config_map!(self, opts => ::internal::deserialize_from_custom(reader, opts)) + } + + /// Deserializes an object from a custom `BincodeRead`er with state `seed` using the default + /// configuration. It is highly recommended to use `deserialize_from` unless you need to + /// implement `BincodeRead` for performance reasons. + /// + /// If this returns an `Error`, `reader` may be in an invalid state. + #[inline(always)] + pub fn deserialize_from_custom_seed< + 'a, + R: BincodeRead<'a>, + T: serde::de::DeserializeSeed<'a>, + >( + &self, + seed: T, + reader: R, + ) -> Result { + config_map!(self, opts => ::internal::deserialize_from_custom_seed(seed, reader, opts)) + } +} diff --git a/src/config/limit.rs b/src/config/limit.rs new file mode 100644 index 0000000..4772298 --- /dev/null +++ b/src/config/limit.rs @@ -0,0 +1,49 @@ +use error::{ErrorKind, Result}; + +/// A trait for stopping serialization and deserialization when a certain limit has been reached. +pub trait SizeLimit { + /// Tells the SizeLimit that a certain number of bytes has been + /// read or written. Returns Err if the limit has been exceeded. + fn add(&mut self, n: u64) -> Result<()>; + /// Returns the hard limit (if one exists) + fn limit(&self) -> Option; +} + +/// A SizeLimit that restricts serialized or deserialized messages from +/// exceeding a certain byte length. +#[derive(Copy, Clone)] +pub struct Bounded(pub u64); + +/// A SizeLimit without a limit! +/// Use this if you don't care about the size of encoded or decoded messages. +#[derive(Copy, Clone)] +pub struct Infinite; + +impl SizeLimit for Bounded { + #[inline(always)] + fn add(&mut self, n: u64) -> Result<()> { + if self.0 >= n { + self.0 -= n; + Ok(()) + } else { + Err(Box::new(ErrorKind::SizeLimit)) + } + } + + #[inline(always)] + fn limit(&self) -> Option { + Some(self.0) + } +} + +impl SizeLimit for Infinite { + #[inline(always)] + fn add(&mut self, _: u64) -> Result<()> { + Ok(()) + } + + #[inline(always)] + fn limit(&self) -> Option { + None + } +} diff --git a/src/config/mod.rs b/src/config/mod.rs new file mode 100644 index 0000000..33fa920 --- /dev/null +++ b/src/config/mod.rs @@ -0,0 +1,408 @@ +//! `bincode` uses a Builder-pattern to configure the Serializers and Deserializers in this +//! crate. This means that if you need to customize the behavior of `bincode`, you should create an +//! instance of the `DefaultOptions` struct: +//! +//! ```rust +//! use bincode::Options; +//! let my_options = bincode::DefaultOptions::new(); +//! ``` +//! +//! # Options Struct vs bincode functions +//! +//! Due to historical reasons, the default options used by the `serialize()` and `deserialize()` +//! family of functions are different than the default options created by the `DefaultOptions` struct: +//! +//! | | Byte limit | Endianness | Int Encoding | Trailing Behavior | +//! |----------|------------|------------|--------------|-------------------| +//! | struct | Unlimited | Little | Varint | Reject | +//! | function | Unlimited | Little | Fixint | Allow | +//! +//! This means that if you want to use the `Serialize` / `Deserialize` structs with the same +//! settings as the functions, you should adjust the `DefaultOptions` struct like so: +//! +//! ```rust +//! use bincode::Options; +//! let my_options = bincode::DefaultOptions::new() +//! .with_fixint_encoding() +//! .allow_trailing_bytes(); +//! ``` + +use de::read::BincodeRead; +use error::Result; +use serde; +use std::io::{Read, Write}; +use std::marker::PhantomData; + +pub(crate) use self::endian::BincodeByteOrder; +pub(crate) use self::int::IntEncoding; +pub(crate) use self::internal::*; +pub(crate) use self::limit::SizeLimit; +pub(crate) use self::trailing::TrailingBytes; + +pub use self::endian::{BigEndian, LittleEndian, NativeEndian}; +pub use self::int::{FixintEncoding, VarintEncoding}; +pub use self::legacy::*; +pub use self::limit::{Bounded, Infinite}; +pub use self::trailing::{AllowTrailing, RejectTrailing}; + +mod endian; +mod int; +mod legacy; +mod limit; +mod trailing; + +/// The default options for bincode serialization/deserialization. +/// +/// ### Defaults +/// By default bincode will use little-endian encoding for multi-byte integers, and will not +/// limit the number of serialized/deserialized bytes. +/// +/// ### Configuring `DefaultOptions` +/// +/// `DefaultOptions` implements the [Options] trait, which means it exposes functions to change the behavior of bincode. +/// +/// For example, if you wanted to limit the bincode deserializer to 1 kilobyte of user input: +/// +/// ```rust +/// use bincode::Options; +/// let my_options = bincode::DefaultOptions::new().with_limit(1024); +/// ``` +/// +/// ### DefaultOptions struct vs. functions +/// +/// The default configuration used by this struct is not the same as that used by the bincode +/// helper functions in the root of this crate. See the +/// [config](index.html#options-struct-vs-bincode-functions) module for more details +#[derive(Copy, Clone)] +pub struct DefaultOptions(Infinite); + +impl DefaultOptions { + /// Get a default configuration object. + /// + /// ### Default Configuration: + /// + /// | Byte limit | Endianness | Int Encoding | Trailing Behavior | + /// |------------|------------|--------------|-------------------| + /// | Unlimited | Little | Varint | Reject | + pub fn new() -> DefaultOptions { + DefaultOptions(Infinite) + } +} + +impl Default for DefaultOptions { + fn default() -> Self { + Self::new() + } +} + +impl InternalOptions for DefaultOptions { + type Limit = Infinite; + type Endian = LittleEndian; + type IntEncoding = VarintEncoding; + type Trailing = RejectTrailing; + + #[inline(always)] + fn limit(&mut self) -> &mut Infinite { + &mut self.0 + } +} + +/// A configuration builder trait whose options Bincode will use +/// while serializing and deserializing. +/// +/// ### Options +/// Endianness: The endianness with which multi-byte integers will be read/written. *default: little endian* +/// +/// Limit: The maximum number of bytes that will be read/written in a bincode serialize/deserialize. *default: unlimited* +/// +/// Int Encoding: The encoding used for numbers, enum discriminants, and lengths. *default: varint* +/// +/// Trailing Behavior: The behavior when there are trailing bytes left over in a slice after deserialization. *default: reject* +/// +/// ### Byte Limit Details +/// The purpose of byte-limiting is to prevent Denial-Of-Service attacks whereby malicious attackers get bincode +/// deserialization to crash your process by allocating too much memory or keeping a connection open for too long. +/// +/// When a byte limit is set, bincode will return `Err` on any deserialization that goes over the limit, or any +/// serialization that goes over the limit. +pub trait Options: InternalOptions + Sized { + /// Sets the byte limit to be unlimited. + /// This is the default. + fn with_no_limit(self) -> WithOtherLimit { + WithOtherLimit::new(self, Infinite) + } + + /// Sets the byte limit to `limit`. + fn with_limit(self, limit: u64) -> WithOtherLimit { + WithOtherLimit::new(self, Bounded(limit)) + } + + /// Sets the endianness to little-endian + /// This is the default. + fn with_little_endian(self) -> WithOtherEndian { + WithOtherEndian::new(self) + } + + /// Sets the endianness to big-endian + fn with_big_endian(self) -> WithOtherEndian { + WithOtherEndian::new(self) + } + + /// Sets the endianness to the the machine-native endianness + fn with_native_endian(self) -> WithOtherEndian { + WithOtherEndian::new(self) + } + + /// Sets the length encoding to varint + fn with_varint_encoding(self) -> WithOtherIntEncoding { + WithOtherIntEncoding::new(self) + } + + /// Sets the length encoding to be fixed + fn with_fixint_encoding(self) -> WithOtherIntEncoding { + WithOtherIntEncoding::new(self) + } + + /// Sets the deserializer to reject trailing bytes + fn reject_trailing_bytes(self) -> WithOtherTrailing { + WithOtherTrailing::new(self) + } + + /// Sets the deserializer to allow trailing bytes + fn allow_trailing_bytes(self) -> WithOtherTrailing { + WithOtherTrailing::new(self) + } + + /// Serializes a serializable object into a `Vec` of bytes using this configuration + #[inline(always)] + fn serialize(self, t: &S) -> Result> { + ::internal::serialize(t, self) + } + + /// Returns the size that an object would be if serialized using Bincode with this configuration + #[inline(always)] + fn serialized_size(self, t: &T) -> Result { + ::internal::serialized_size(t, self) + } + + /// Serializes an object directly into a `Writer` using this configuration + /// + /// If the serialization would take more bytes than allowed by the size limit, an error + /// is returned and *no bytes* will be written into the `Writer` + #[inline(always)] + fn serialize_into(self, w: W, t: &T) -> Result<()> { + ::internal::serialize_into(w, t, self) + } + + /// Deserializes a slice of bytes into an instance of `T` using this configuration + #[inline(always)] + fn deserialize<'a, T: serde::Deserialize<'a>>(self, bytes: &'a [u8]) -> Result { + ::internal::deserialize(bytes, self) + } + + /// TODO: document + #[doc(hidden)] + #[inline(always)] + fn deserialize_in_place<'a, R, T>(self, reader: R, place: &mut T) -> Result<()> + where + R: BincodeRead<'a>, + T: serde::de::Deserialize<'a>, + { + ::internal::deserialize_in_place(reader, self, place) + } + + /// Deserializes a slice of bytes with state `seed` using this configuration. + #[inline(always)] + fn deserialize_seed<'a, T: serde::de::DeserializeSeed<'a>>( + self, + seed: T, + bytes: &'a [u8], + ) -> Result { + ::internal::deserialize_seed(seed, bytes, self) + } + + /// Deserializes an object directly from a `Read`er using this configuration + /// + /// If this returns an `Error`, `reader` may be in an invalid state. + #[inline(always)] + fn deserialize_from(self, reader: R) -> Result { + ::internal::deserialize_from(reader, self) + } + + /// Deserializes an object directly from a `Read`er with state `seed` using this configuration + /// + /// If this returns an `Error`, `reader` may be in an invalid state. + #[inline(always)] + fn deserialize_from_seed<'a, R: Read, T: serde::de::DeserializeSeed<'a>>( + self, + seed: T, + reader: R, + ) -> Result { + ::internal::deserialize_from_seed(seed, reader, self) + } + + /// Deserializes an object from a custom `BincodeRead`er using the default configuration. + /// It is highly recommended to use `deserialize_from` unless you need to implement + /// `BincodeRead` for performance reasons. + /// + /// If this returns an `Error`, `reader` may be in an invalid state. + #[inline(always)] + fn deserialize_from_custom<'a, R: BincodeRead<'a>, T: serde::de::DeserializeOwned>( + self, + reader: R, + ) -> Result { + ::internal::deserialize_from_custom(reader, self) + } + + /// Deserializes an object from a custom `BincodeRead`er with state `seed` using the default + /// configuration. It is highly recommended to use `deserialize_from` unless you need to + /// implement `BincodeRead` for performance reasons. + /// + /// If this returns an `Error`, `reader` may be in an invalid state. + #[inline(always)] + fn deserialize_from_custom_seed<'a, R: BincodeRead<'a>, T: serde::de::DeserializeSeed<'a>>( + self, + seed: T, + reader: R, + ) -> Result { + ::internal::deserialize_from_custom_seed(seed, reader, self) + } +} + +impl Options for T {} + +/// A configuration struct with a user-specified byte limit +#[derive(Clone, Copy)] +pub struct WithOtherLimit { + _options: O, + pub(crate) new_limit: L, +} + +/// A configuration struct with a user-specified endian order +#[derive(Clone, Copy)] +pub struct WithOtherEndian { + options: O, + _endian: PhantomData, +} + +/// A configuration struct with a user-specified length encoding +#[derive(Clone, Copy)] +pub struct WithOtherIntEncoding { + options: O, + _length: PhantomData, +} + +/// A configuration struct with a user-specified trailing bytes behavior. +#[derive(Clone, Copy)] +pub struct WithOtherTrailing { + options: O, + _trailing: PhantomData, +} + +impl WithOtherLimit { + #[inline(always)] + pub(crate) fn new(options: O, limit: L) -> WithOtherLimit { + WithOtherLimit { + _options: options, + new_limit: limit, + } + } +} + +impl WithOtherEndian { + #[inline(always)] + pub(crate) fn new(options: O) -> WithOtherEndian { + WithOtherEndian { + options, + _endian: PhantomData, + } + } +} + +impl WithOtherIntEncoding { + #[inline(always)] + pub(crate) fn new(options: O) -> WithOtherIntEncoding { + WithOtherIntEncoding { + options, + _length: PhantomData, + } + } +} + +impl WithOtherTrailing { + #[inline(always)] + pub(crate) fn new(options: O) -> WithOtherTrailing { + WithOtherTrailing { + options, + _trailing: PhantomData, + } + } +} + +impl InternalOptions for WithOtherEndian { + type Limit = O::Limit; + type Endian = E; + type IntEncoding = O::IntEncoding; + type Trailing = O::Trailing; + #[inline(always)] + fn limit(&mut self) -> &mut O::Limit { + self.options.limit() + } +} + +impl InternalOptions for WithOtherLimit { + type Limit = L; + type Endian = O::Endian; + type IntEncoding = O::IntEncoding; + type Trailing = O::Trailing; + fn limit(&mut self) -> &mut L { + &mut self.new_limit + } +} + +impl InternalOptions for WithOtherIntEncoding { + type Limit = O::Limit; + type Endian = O::Endian; + type IntEncoding = I; + type Trailing = O::Trailing; + + fn limit(&mut self) -> &mut O::Limit { + self.options.limit() + } +} + +impl InternalOptions for WithOtherTrailing { + type Limit = O::Limit; + type Endian = O::Endian; + type IntEncoding = O::IntEncoding; + type Trailing = T; + + fn limit(&mut self) -> &mut O::Limit { + self.options.limit() + } +} + +mod internal { + use super::*; + + pub trait InternalOptions { + type Limit: SizeLimit + 'static; + type Endian: BincodeByteOrder + 'static; + type IntEncoding: IntEncoding + 'static; + type Trailing: TrailingBytes + 'static; + + fn limit(&mut self) -> &mut Self::Limit; + } + + impl<'a, O: InternalOptions> InternalOptions for &'a mut O { + type Limit = O::Limit; + type Endian = O::Endian; + type IntEncoding = O::IntEncoding; + type Trailing = O::Trailing; + + #[inline(always)] + fn limit(&mut self) -> &mut Self::Limit { + (*self).limit() + } + } +} diff --git a/src/config/trailing.rs b/src/config/trailing.rs new file mode 100644 index 0000000..6052fc7 --- /dev/null +++ b/src/config/trailing.rs @@ -0,0 +1,37 @@ +use de::read::SliceReader; +use {ErrorKind, Result}; + +/// A trait for erroring deserialization if not all bytes were read. +pub trait TrailingBytes { + /// Checks a given slice reader to determine if deserialization used all bytes in the slice. + fn check_end(reader: &SliceReader) -> Result<()>; +} + +/// A TrailingBytes config that will allow trailing bytes in slices after deserialization. +#[derive(Copy, Clone)] +pub struct AllowTrailing; + +/// A TrailingBytes config that will cause bincode to produce an error if bytes are left over in the slice when deserialization is complete. + +#[derive(Copy, Clone)] +pub struct RejectTrailing; + +impl TrailingBytes for AllowTrailing { + #[inline(always)] + fn check_end(_reader: &SliceReader) -> Result<()> { + Ok(()) + } +} + +impl TrailingBytes for RejectTrailing { + #[inline(always)] + fn check_end(reader: &SliceReader) -> Result<()> { + if reader.is_finished() { + Ok(()) + } else { + Err(Box::new(ErrorKind::Custom( + "Slice had bytes remaining after deserialization".to_string(), + ))) + } + } +} diff --git a/src/de/mod.rs b/src/de/mod.rs new file mode 100644 index 0000000..7b2bdf5 --- /dev/null +++ b/src/de/mod.rs @@ -0,0 +1,515 @@ +use config::{BincodeByteOrder, Options}; +use std::io::Read; + +use self::read::{BincodeRead, IoReader, SliceReader}; +use byteorder::ReadBytesExt; +use config::{IntEncoding, SizeLimit}; +use serde; +use serde::de::Error as DeError; +use serde::de::IntoDeserializer; +use {Error, ErrorKind, Result}; + +/// Specialized ways to read data into bincode. +pub mod read; + +/// A Deserializer that reads bytes from a buffer. +/// +/// This struct should rarely be used. +/// In most cases, prefer the `deserialize_from` function. +/// +/// The ByteOrder that is chosen will impact the endianness that +/// is used to read integers out of the reader. +/// +/// ```ignore +/// let d = Deserializer::new(&mut some_reader, SizeLimit::new()); +/// serde::Deserialize::deserialize(&mut deserializer); +/// let bytes_read = d.bytes_read(); +/// ``` +pub struct Deserializer { + pub(crate) reader: R, + options: O, +} + +macro_rules! impl_deserialize_literal { + ($name:ident : $ty:ty = $read:ident()) => { + #[inline] + pub(crate) fn $name(&mut self) -> Result<$ty> { + self.read_literal_type::<$ty>()?; + self.reader + .$read::<::Endian>() + .map_err(Into::into) + } + }; +} + +impl<'de, IR: Read, O: Options> Deserializer, O> { + /// Creates a new Deserializer with a given `Read`er and options. + pub fn with_reader(r: IR, options: O) -> Self { + Deserializer { + reader: IoReader::new(r), + options, + } + } +} + +impl<'de, O: Options> Deserializer, O> { + /// Creates a new Deserializer that will read from the given slice. + pub fn from_slice(slice: &'de [u8], options: O) -> Self { + Deserializer { + reader: SliceReader::new(slice), + options, + } + } +} + +impl<'de, R: BincodeRead<'de>, O: Options> Deserializer { + /// Creates a new Deserializer with the given `BincodeRead`er + pub fn with_bincode_read(r: R, options: O) -> Deserializer { + Deserializer { reader: r, options } + } + + pub(crate) fn deserialize_byte(&mut self) -> Result { + self.read_literal_type::()?; + self.reader.read_u8().map_err(Into::into) + } + + impl_deserialize_literal! { deserialize_literal_u16 : u16 = read_u16() } + impl_deserialize_literal! { deserialize_literal_u32 : u32 = read_u32() } + impl_deserialize_literal! { deserialize_literal_u64 : u64 = read_u64() } + + serde_if_integer128! { + impl_deserialize_literal! { deserialize_literal_u128 : u128 = read_u128() } + } + + fn read_bytes(&mut self, count: u64) -> Result<()> { + self.options.limit().add(count) + } + + fn read_literal_type(&mut self) -> Result<()> { + use std::mem::size_of; + self.read_bytes(size_of::() as u64) + } + + fn read_vec(&mut self) -> Result> { + let len = O::IntEncoding::deserialize_len(self)?; + self.read_bytes(len as u64)?; + self.reader.get_byte_buffer(len) + } + + fn read_string(&mut self) -> Result { + let vec = self.read_vec()?; + String::from_utf8(vec).map_err(|e| ErrorKind::InvalidUtf8Encoding(e.utf8_error()).into()) + } +} + +macro_rules! impl_deserialize_int { + ($name:ident = $visitor_method:ident ($dser_method:ident)) => { + #[inline] + fn $name(self, visitor: V) -> Result + where + V: serde::de::Visitor<'de>, + { + visitor.$visitor_method(O::IntEncoding::$dser_method(self)?) + } + }; +} + +impl<'de, 'a, R, O> serde::Deserializer<'de> for &'a mut Deserializer +where + R: BincodeRead<'de>, + O: Options, +{ + type Error = Error; + + #[inline] + fn deserialize_any(self, _visitor: V) -> Result + where + V: serde::de::Visitor<'de>, + { + Err(Box::new(ErrorKind::DeserializeAnyNotSupported)) + } + + fn deserialize_bool(self, visitor: V) -> Result + where + V: serde::de::Visitor<'de>, + { + match self.deserialize_byte()? { + 1 => visitor.visit_bool(true), + 0 => visitor.visit_bool(false), + value => Err(ErrorKind::InvalidBoolEncoding(value).into()), + } + } + + impl_deserialize_int!(deserialize_u16 = visit_u16(deserialize_u16)); + impl_deserialize_int!(deserialize_u32 = visit_u32(deserialize_u32)); + impl_deserialize_int!(deserialize_u64 = visit_u64(deserialize_u64)); + impl_deserialize_int!(deserialize_i16 = visit_i16(deserialize_i16)); + impl_deserialize_int!(deserialize_i32 = visit_i32(deserialize_i32)); + impl_deserialize_int!(deserialize_i64 = visit_i64(deserialize_i64)); + + fn deserialize_f32(self, visitor: V) -> Result + where + V: serde::de::Visitor<'de>, + { + self.read_literal_type::()?; + let value = self + .reader + .read_f32::<::Endian>()?; + visitor.visit_f32(value) + } + + fn deserialize_f64(self, visitor: V) -> Result + where + V: serde::de::Visitor<'de>, + { + self.read_literal_type::()?; + let value = self + .reader + .read_f64::<::Endian>()?; + visitor.visit_f64(value) + } + + serde_if_integer128! { + impl_deserialize_int!(deserialize_u128 = visit_u128(deserialize_u128)); + impl_deserialize_int!(deserialize_i128 = visit_i128(deserialize_i128)); + } + + #[inline] + fn deserialize_u8(self, visitor: V) -> Result + where + V: serde::de::Visitor<'de>, + { + visitor.visit_u8(self.deserialize_byte()? as u8) + } + + #[inline] + fn deserialize_i8(self, visitor: V) -> Result + where + V: serde::de::Visitor<'de>, + { + visitor.visit_i8(self.deserialize_byte()? as i8) + } + + fn deserialize_unit(self, visitor: V) -> Result + where + V: serde::de::Visitor<'de>, + { + visitor.visit_unit() + } + + fn deserialize_char(self, visitor: V) -> Result + where + V: serde::de::Visitor<'de>, + { + use std::str; + + let error = || ErrorKind::InvalidCharEncoding.into(); + + let mut buf = [0u8; 4]; + + // Look at the first byte to see how many bytes must be read + self.reader.read_exact(&mut buf[..1])?; + let width = utf8_char_width(buf[0]); + if width == 1 { + return visitor.visit_char(buf[0] as char); + } + if width == 0 { + return Err(error()); + } + + if self.reader.read_exact(&mut buf[1..width]).is_err() { + return Err(error()); + } + + let res = str::from_utf8(&buf[..width]) + .ok() + .and_then(|s| s.chars().next()) + .ok_or_else(error)?; + visitor.visit_char(res) + } + + fn deserialize_str(self, visitor: V) -> Result + where + V: serde::de::Visitor<'de>, + { + let len = O::IntEncoding::deserialize_len(self)?; + self.read_bytes(len as u64)?; + self.reader.forward_read_str(len, visitor) + } + + fn deserialize_string(self, visitor: V) -> Result + where + V: serde::de::Visitor<'de>, + { + visitor.visit_string(self.read_string()?) + } + + fn deserialize_bytes(self, visitor: V) -> Result + where + V: serde::de::Visitor<'de>, + { + let len = O::IntEncoding::deserialize_len(self)?; + self.read_bytes(len as u64)?; + self.reader.forward_read_bytes(len, visitor) + } + + fn deserialize_byte_buf(self, visitor: V) -> Result + where + V: serde::de::Visitor<'de>, + { + visitor.visit_byte_buf(self.read_vec()?) + } + + fn deserialize_enum( + self, + _enum: &'static str, + _variants: &'static [&'static str], + visitor: V, + ) -> Result + where + V: serde::de::Visitor<'de>, + { + impl<'de, 'a, R: 'a, O> serde::de::EnumAccess<'de> for &'a mut Deserializer + where + R: BincodeRead<'de>, + O: Options, + { + type Error = Error; + type Variant = Self; + + fn variant_seed(self, seed: V) -> Result<(V::Value, Self::Variant)> + where + V: serde::de::DeserializeSeed<'de>, + { + let idx: u32 = O::IntEncoding::deserialize_u32(self)?; + let val: Result<_> = seed.deserialize(idx.into_deserializer()); + Ok((val?, self)) + } + } + + visitor.visit_enum(self) + } + + fn deserialize_tuple(self, len: usize, visitor: V) -> Result + where + V: serde::de::Visitor<'de>, + { + struct Access<'a, R: Read + 'a, O: Options + 'a> { + deserializer: &'a mut Deserializer, + len: usize, + } + + impl<'de, 'a, 'b: 'a, R: BincodeRead<'de> + 'b, O: Options> serde::de::SeqAccess<'de> + for Access<'a, R, O> + { + type Error = Error; + + fn next_element_seed(&mut self, seed: T) -> Result> + where + T: serde::de::DeserializeSeed<'de>, + { + if self.len > 0 { + self.len -= 1; + let value = + serde::de::DeserializeSeed::deserialize(seed, &mut *self.deserializer)?; + Ok(Some(value)) + } else { + Ok(None) + } + } + + fn size_hint(&self) -> Option { + Some(self.len) + } + } + + visitor.visit_seq(Access { + deserializer: self, + len, + }) + } + + fn deserialize_option(self, visitor: V) -> Result + where + V: serde::de::Visitor<'de>, + { + let value: u8 = serde::de::Deserialize::deserialize(&mut *self)?; + match value { + 0 => visitor.visit_none(), + 1 => visitor.visit_some(&mut *self), + v => Err(ErrorKind::InvalidTagEncoding(v as usize).into()), + } + } + + fn deserialize_seq(self, visitor: V) -> Result + where + V: serde::de::Visitor<'de>, + { + let len = O::IntEncoding::deserialize_len(self)?; + + self.deserialize_tuple(len, visitor) + } + + fn deserialize_map(self, visitor: V) -> Result + where + V: serde::de::Visitor<'de>, + { + struct Access<'a, R: Read + 'a, O: Options + 'a> { + deserializer: &'a mut Deserializer, + len: usize, + } + + impl<'de, 'a, 'b: 'a, R: BincodeRead<'de> + 'b, O: Options> serde::de::MapAccess<'de> + for Access<'a, R, O> + { + type Error = Error; + + fn next_key_seed(&mut self, seed: K) -> Result> + where + K: serde::de::DeserializeSeed<'de>, + { + if self.len > 0 { + self.len -= 1; + let key = + serde::de::DeserializeSeed::deserialize(seed, &mut *self.deserializer)?; + Ok(Some(key)) + } else { + Ok(None) + } + } + + fn next_value_seed(&mut self, seed: V) -> Result + where + V: serde::de::DeserializeSeed<'de>, + { + let value = serde::de::DeserializeSeed::deserialize(seed, &mut *self.deserializer)?; + Ok(value) + } + + fn size_hint(&self) -> Option { + Some(self.len) + } + } + + let len = O::IntEncoding::deserialize_len(self)?; + + visitor.visit_map(Access { + deserializer: self, + len, + }) + } + + fn deserialize_struct( + self, + _name: &str, + fields: &'static [&'static str], + visitor: V, + ) -> Result + where + V: serde::de::Visitor<'de>, + { + self.deserialize_tuple(fields.len(), visitor) + } + + fn deserialize_identifier(self, _visitor: V) -> Result + where + V: serde::de::Visitor<'de>, + { + let message = "Bincode does not support Deserializer::deserialize_identifier"; + Err(Error::custom(message)) + } + + fn deserialize_newtype_struct(self, _name: &str, visitor: V) -> Result + where + V: serde::de::Visitor<'de>, + { + visitor.visit_newtype_struct(self) + } + + fn deserialize_unit_struct(self, _name: &'static str, visitor: V) -> Result + where + V: serde::de::Visitor<'de>, + { + visitor.visit_unit() + } + + fn deserialize_tuple_struct( + self, + _name: &'static str, + len: usize, + visitor: V, + ) -> Result + where + V: serde::de::Visitor<'de>, + { + self.deserialize_tuple(len, visitor) + } + + fn deserialize_ignored_any(self, _visitor: V) -> Result + where + V: serde::de::Visitor<'de>, + { + let message = "Bincode does not support Deserializer::deserialize_ignored_any"; + Err(Error::custom(message)) + } + + fn is_human_readable(&self) -> bool { + false + } +} + +impl<'de, 'a, R, O> serde::de::VariantAccess<'de> for &'a mut Deserializer +where + R: BincodeRead<'de>, + O: Options, +{ + type Error = Error; + + fn unit_variant(self) -> Result<()> { + Ok(()) + } + + fn newtype_variant_seed(self, seed: T) -> Result + where + T: serde::de::DeserializeSeed<'de>, + { + serde::de::DeserializeSeed::deserialize(seed, self) + } + + fn tuple_variant(self, len: usize, visitor: V) -> Result + where + V: serde::de::Visitor<'de>, + { + serde::de::Deserializer::deserialize_tuple(self, len, visitor) + } + + fn struct_variant(self, fields: &'static [&'static str], visitor: V) -> Result + where + V: serde::de::Visitor<'de>, + { + serde::de::Deserializer::deserialize_tuple(self, fields.len(), visitor) + } +} +static 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 +fn utf8_char_width(b: u8) -> usize { + UTF8_CHAR_WIDTH[b as usize] as usize +} diff --git a/src/de/read.rs b/src/de/read.rs new file mode 100644 index 0000000..08b76ad --- /dev/null +++ b/src/de/read.rs @@ -0,0 +1,202 @@ +use error::Result; +use serde; +use std::io; + +/// An optional Read trait for advanced Bincode usage. +/// +/// It is highly recommended to use bincode with `io::Read` or `&[u8]` before +/// implementing a custom `BincodeRead`. +/// +/// The forward_read_* methods are necessary because some byte sources want +/// to pass a long-lived borrow to the visitor and others want to pass a +/// transient slice. +pub trait BincodeRead<'storage>: io::Read { + /// Check that the next `length` bytes are a valid string and pass + /// it on to the serde reader. + fn forward_read_str(&mut self, length: usize, visitor: V) -> Result + where + V: serde::de::Visitor<'storage>; + + /// Transfer ownership of the next `length` bytes to the caller. + fn get_byte_buffer(&mut self, length: usize) -> Result>; + + /// Pass a slice of the next `length` bytes on to the serde reader. + fn forward_read_bytes(&mut self, length: usize, visitor: V) -> Result + where + V: serde::de::Visitor<'storage>; +} + +/// A BincodeRead implementation for byte slices +pub struct SliceReader<'storage> { + slice: &'storage [u8], +} + +/// A BincodeRead implementation for `io::Read`ers +pub struct IoReader { + reader: R, + temp_buffer: Vec, +} + +impl<'storage> SliceReader<'storage> { + /// Constructs a slice reader + pub(crate) fn new(bytes: &'storage [u8]) -> SliceReader<'storage> { + SliceReader { slice: bytes } + } + + #[inline(always)] + fn get_byte_slice(&mut self, length: usize) -> Result<&'storage [u8]> { + if length > self.slice.len() { + return Err(SliceReader::unexpected_eof()); + } + let (read_slice, remaining) = self.slice.split_at(length); + self.slice = remaining; + Ok(read_slice) + } + + pub(crate) fn is_finished(&self) -> bool { + self.slice.is_empty() + } +} + +impl IoReader { + /// Constructs an IoReadReader + pub(crate) fn new(r: R) -> IoReader { + IoReader { + reader: r, + temp_buffer: vec![], + } + } +} + +impl<'storage> io::Read for SliceReader<'storage> { + #[inline(always)] + fn read(&mut self, out: &mut [u8]) -> io::Result { + if out.len() > self.slice.len() { + return Err(io::ErrorKind::UnexpectedEof.into()); + } + let (read_slice, remaining) = self.slice.split_at(out.len()); + out.copy_from_slice(read_slice); + self.slice = remaining; + + Ok(out.len()) + } + + #[inline(always)] + fn read_exact(&mut self, out: &mut [u8]) -> io::Result<()> { + self.read(out).map(|_| ()) + } +} + +impl io::Read for IoReader { + #[inline(always)] + fn read(&mut self, out: &mut [u8]) -> io::Result { + self.reader.read(out) + } + #[inline(always)] + fn read_exact(&mut self, out: &mut [u8]) -> io::Result<()> { + self.reader.read_exact(out) + } +} + +impl<'storage> SliceReader<'storage> { + #[inline(always)] + fn unexpected_eof() -> Box<::ErrorKind> { + Box::new(::ErrorKind::Io(io::Error::new( + io::ErrorKind::UnexpectedEof, + "", + ))) + } +} + +impl<'storage> BincodeRead<'storage> for SliceReader<'storage> { + #[inline(always)] + fn forward_read_str(&mut self, length: usize, visitor: V) -> Result + where + V: serde::de::Visitor<'storage>, + { + use ErrorKind; + let string = match ::std::str::from_utf8(self.get_byte_slice(length)?) { + Ok(s) => s, + Err(e) => return Err(ErrorKind::InvalidUtf8Encoding(e).into()), + }; + visitor.visit_borrowed_str(string) + } + + #[inline(always)] + fn get_byte_buffer(&mut self, length: usize) -> Result> { + self.get_byte_slice(length).map(|x| x.to_vec()) + } + + #[inline(always)] + fn forward_read_bytes(&mut self, length: usize, visitor: V) -> Result + where + V: serde::de::Visitor<'storage>, + { + visitor.visit_borrowed_bytes(self.get_byte_slice(length)?) + } +} + +impl IoReader +where + R: io::Read, +{ + fn fill_buffer(&mut self, length: usize) -> Result<()> { + self.temp_buffer.resize(length, 0); + + self.reader.read_exact(&mut self.temp_buffer)?; + + Ok(()) + } +} + +impl<'a, R> BincodeRead<'a> for IoReader +where + R: io::Read, +{ + fn forward_read_str(&mut self, length: usize, visitor: V) -> Result + where + V: serde::de::Visitor<'a>, + { + self.fill_buffer(length)?; + + let string = match ::std::str::from_utf8(&self.temp_buffer[..]) { + Ok(s) => s, + Err(e) => return Err(::ErrorKind::InvalidUtf8Encoding(e).into()), + }; + + visitor.visit_str(string) + } + + fn get_byte_buffer(&mut self, length: usize) -> Result> { + self.fill_buffer(length)?; + Ok(::std::mem::replace(&mut self.temp_buffer, Vec::new())) + } + + fn forward_read_bytes(&mut self, length: usize, visitor: V) -> Result + where + V: serde::de::Visitor<'a>, + { + self.fill_buffer(length)?; + visitor.visit_bytes(&self.temp_buffer[..]) + } +} + +#[cfg(test)] +mod test { + use super::IoReader; + + #[test] + fn test_fill_buffer() { + let buffer = vec![0u8; 64]; + let mut reader = IoReader::new(buffer.as_slice()); + + reader.fill_buffer(20).unwrap(); + assert_eq!(20, reader.temp_buffer.len()); + + reader.fill_buffer(30).unwrap(); + assert_eq!(30, reader.temp_buffer.len()); + + reader.fill_buffer(5).unwrap(); + assert_eq!(5, reader.temp_buffer.len()); + } +} diff --git a/src/error.rs b/src/error.rs new file mode 100644 index 0000000..420fa7a --- /dev/null +++ b/src/error.rs @@ -0,0 +1,115 @@ +use std::error::Error as StdError; +use std::io; +use std::str::Utf8Error; +use std::{error, fmt}; + +use serde; + +/// The result of a serialization or deserialization operation. +pub type Result = ::std::result::Result; + +/// An error that can be produced during (de)serializing. +pub type Error = Box; + +/// The kind of error that can be produced during a serialization or deserialization. +#[derive(Debug)] +pub enum ErrorKind { + /// If the error stems from the reader/writer that is being used + /// during (de)serialization, that error will be stored and returned here. + Io(io::Error), + /// Returned if the deserializer attempts to deserialize a string that is not valid utf8 + InvalidUtf8Encoding(Utf8Error), + /// Returned if the deserializer attempts to deserialize a bool that was + /// not encoded as either a 1 or a 0 + InvalidBoolEncoding(u8), + /// Returned if the deserializer attempts to deserialize a char that is not in the correct format. + InvalidCharEncoding, + /// Returned if the deserializer attempts to deserialize the tag of an enum that is + /// not in the expected ranges + InvalidTagEncoding(usize), + /// Serde has a deserialize_any method that lets the format hint to the + /// object which route to take in deserializing. + DeserializeAnyNotSupported, + /// If (de)serializing a message takes more than the provided size limit, this + /// error is returned. + SizeLimit, + /// Bincode can not encode sequences of unknown length (like iterators). + SequenceMustHaveLength, + /// A custom error message from Serde. + Custom(String), +} + +impl StdError for ErrorKind { + fn description(&self) -> &str { + match *self { + ErrorKind::Io(ref err) => error::Error::description(err), + ErrorKind::InvalidUtf8Encoding(_) => "string is not valid utf8", + ErrorKind::InvalidBoolEncoding(_) => "invalid u8 while decoding bool", + ErrorKind::InvalidCharEncoding => "char is not valid", + ErrorKind::InvalidTagEncoding(_) => "tag for enum is not valid", + ErrorKind::SequenceMustHaveLength => { + "Bincode can only encode sequences and maps that have a knowable size ahead of time" + } + ErrorKind::DeserializeAnyNotSupported => { + "Bincode doesn't support serde::Deserializer::deserialize_any" + } + ErrorKind::SizeLimit => "the size limit has been reached", + ErrorKind::Custom(ref msg) => msg, + } + } + + fn cause(&self) -> Option<&error::Error> { + match *self { + ErrorKind::Io(ref err) => Some(err), + ErrorKind::InvalidUtf8Encoding(_) => None, + ErrorKind::InvalidBoolEncoding(_) => None, + ErrorKind::InvalidCharEncoding => None, + ErrorKind::InvalidTagEncoding(_) => None, + ErrorKind::SequenceMustHaveLength => None, + ErrorKind::DeserializeAnyNotSupported => None, + ErrorKind::SizeLimit => None, + ErrorKind::Custom(_) => None, + } + } +} + +impl From for Error { + fn from(err: io::Error) -> Error { + ErrorKind::Io(err).into() + } +} + +impl fmt::Display for ErrorKind { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + match *self { + ErrorKind::Io(ref ioerr) => write!(fmt, "io error: {}", ioerr), + ErrorKind::InvalidUtf8Encoding(ref e) => write!(fmt, "{}: {}", self.description(), e), + ErrorKind::InvalidBoolEncoding(b) => { + write!(fmt, "{}, expected 0 or 1, found {}", self.description(), b) + } + ErrorKind::InvalidCharEncoding => write!(fmt, "{}", self.description()), + ErrorKind::InvalidTagEncoding(tag) => { + write!(fmt, "{}, found {}", self.description(), tag) + } + ErrorKind::SequenceMustHaveLength => write!(fmt, "{}", self.description()), + ErrorKind::SizeLimit => write!(fmt, "{}", self.description()), + ErrorKind::DeserializeAnyNotSupported => write!( + fmt, + "Bincode does not support the serde::Deserializer::deserialize_any method" + ), + ErrorKind::Custom(ref s) => s.fmt(fmt), + } + } +} + +impl serde::de::Error for Error { + fn custom(desc: T) -> Error { + ErrorKind::Custom(desc.to_string()).into() + } +} + +impl serde::ser::Error for Error { + fn custom(msg: T) -> Self { + ErrorKind::Custom(msg.to_string()).into() + } +} diff --git a/src/internal.rs b/src/internal.rs new file mode 100644 index 0000000..1d2a9a1 --- /dev/null +++ b/src/internal.rs @@ -0,0 +1,124 @@ +use serde; +use std::io::{Read, Write}; +use std::marker::PhantomData; + +use config::{Infinite, InternalOptions, Options, SizeLimit, TrailingBytes}; +use de::read::BincodeRead; +use Result; + +pub(crate) fn serialize_into(writer: W, value: &T, mut options: O) -> Result<()> +where + W: Write, + T: serde::Serialize, + O: InternalOptions, +{ + if options.limit().limit().is_some() { + // "compute" the size for the side-effect + // of returning Err if the bound was reached. + serialized_size(value, &mut options)?; + } + + let mut serializer = ::ser::Serializer::<_, O>::new(writer, options); + serde::Serialize::serialize(value, &mut serializer) +} + +pub(crate) fn serialize(value: &T, mut options: O) -> Result> +where + T: serde::Serialize, + O: InternalOptions, +{ + let mut writer = { + let actual_size = serialized_size(value, &mut options)?; + Vec::with_capacity(actual_size as usize) + }; + + serialize_into(&mut writer, value, options.with_no_limit())?; + Ok(writer) +} + +pub(crate) fn serialized_size(value: &T, options: O) -> Result +where + T: serde::Serialize, +{ + let mut size_counter = ::ser::SizeChecker { options, total: 0 }; + + let result = value.serialize(&mut size_counter); + result.map(|_| size_counter.total) +} + +pub(crate) fn deserialize_from(reader: R, options: O) -> Result +where + R: Read, + T: serde::de::DeserializeOwned, + O: InternalOptions, +{ + deserialize_from_seed(PhantomData, reader, options) +} + +pub(crate) fn deserialize_from_seed<'a, R, T, O>(seed: T, reader: R, options: O) -> Result +where + R: Read, + T: serde::de::DeserializeSeed<'a>, + O: InternalOptions, +{ + let reader = ::de::read::IoReader::new(reader); + deserialize_from_custom_seed(seed, reader, options) +} + +pub(crate) fn deserialize_from_custom<'a, R, T, O>(reader: R, options: O) -> Result +where + R: BincodeRead<'a>, + T: serde::de::DeserializeOwned, + O: InternalOptions, +{ + deserialize_from_custom_seed(PhantomData, reader, options) +} + +pub(crate) fn deserialize_from_custom_seed<'a, R, T, O>( + seed: T, + reader: R, + options: O, +) -> Result +where + R: BincodeRead<'a>, + T: serde::de::DeserializeSeed<'a>, + O: InternalOptions, +{ + let mut deserializer = ::de::Deserializer::<_, O>::with_bincode_read(reader, options); + seed.deserialize(&mut deserializer) +} + +pub(crate) fn deserialize_in_place<'a, R, T, O>(reader: R, options: O, place: &mut T) -> Result<()> +where + R: BincodeRead<'a>, + T: serde::de::Deserialize<'a>, + O: InternalOptions, +{ + let mut deserializer = ::de::Deserializer::<_, _>::with_bincode_read(reader, options); + serde::Deserialize::deserialize_in_place(&mut deserializer, place) +} + +pub(crate) fn deserialize<'a, T, O>(bytes: &'a [u8], options: O) -> Result +where + T: serde::de::Deserialize<'a>, + O: InternalOptions, +{ + deserialize_seed(PhantomData, bytes, options) +} + +pub(crate) fn deserialize_seed<'a, T, O>(seed: T, bytes: &'a [u8], options: O) -> Result +where + T: serde::de::DeserializeSeed<'a>, + O: InternalOptions, +{ + let options = ::config::WithOtherLimit::new(options, Infinite); + + let reader = ::de::read::SliceReader::new(bytes); + let mut deserializer = ::de::Deserializer::with_bincode_read(reader, options); + let val = seed.deserialize(&mut deserializer)?; + + match O::Trailing::check_end(&deserializer.reader) { + Ok(_) => Ok(val), + Err(err) => Err(err), + } +} diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..3969ab7 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,201 @@ +#![deny(missing_docs)] +#![allow(unknown_lints, bare_trait_objects, deprecated)] + +//! 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! +//! +//! ### Using Basic Functions +//! +//! ```edition2018 +//! fn main() { +//! // The object that we will serialize. +//! let target: Option = Some("hello world".to_string()); +//! +//! let encoded: Vec = bincode::serialize(&target).unwrap(); +//! let decoded: Option = bincode::deserialize(&encoded[..]).unwrap(); +//! assert_eq!(target, decoded); +//! } +//! ``` +//! +//! ### 128bit numbers +//! +//! Support for `i128` and `u128` is automatically enabled on Rust toolchains +//! greater than or equal to `1.26.0` and disabled for targets which do not support it + +#![doc(html_root_url = "https://docs.rs/bincode/1.3.3")] +#![crate_name = "bincode"] +#![crate_type = "rlib"] +#![crate_type = "dylib"] + +#[macro_use] +extern crate serde; + +pub mod config; +/// Deserialize bincode data to a Rust data structure. +pub mod de; + +mod byteorder; +mod error; +mod internal; +mod ser; + +pub use config::{Config, DefaultOptions, Options}; +pub use de::read::BincodeRead; +pub use de::Deserializer; +pub use error::{Error, ErrorKind, Result}; +pub use ser::Serializer; + +/// Get a default configuration object. +/// +/// ### Default Configuration: +/// +/// | Byte limit | Endianness | +/// |------------|------------| +/// | Unlimited | Little | +#[inline(always)] +#[deprecated(since = "1.3.0", note = "please use `options()` instead")] +pub fn config() -> Config { + Config::new() +} + +/// Get a default configuration object. +/// +/// **Warning:** the default configuration returned by this function +/// is not the same as that used by the other functions in this +/// module. See the +/// [config](config/index.html#options-struct-vs-bincode-functions) +/// module for more details +/// +/// ### Default Configuration: +/// +/// | Byte limit | Endianness | Int Encoding | Trailing Behavior | +/// |------------|------------|--------------|-------------------| +/// | Unlimited | Little | Varint | Reject | +#[inline(always)] +pub fn options() -> DefaultOptions { + DefaultOptions::new() +} + +/// Serializes an object directly into a `Writer` using the default configuration. +/// +/// If the serialization would take more bytes than allowed by the size limit, an error +/// is returned and *no bytes* will be written into the `Writer`. +/// +/// **Warning:** the default configuration used by this function is not +/// the same as that used by the `DefaultOptions` struct. See the +/// [config](config/index.html#options-struct-vs-bincode-functions) +/// module for more details +pub fn serialize_into(writer: W, value: &T) -> Result<()> +where + W: std::io::Write, + T: serde::Serialize, +{ + DefaultOptions::new() + .with_fixint_encoding() + .serialize_into(writer, value) +} + +/// Serializes a serializable object into a `Vec` of bytes using the default configuration. +/// +/// **Warning:** the default configuration used by this function is not +/// the same as that used by the `DefaultOptions` struct. See the +/// [config](config/index.html#options-struct-vs-bincode-functions) +/// module for more details +pub fn serialize(value: &T) -> Result> +where + T: serde::Serialize, +{ + DefaultOptions::new() + .with_fixint_encoding() + .allow_trailing_bytes() + .serialize(value) +} + +/// Deserializes an object directly from a `Read`er using the default configuration. +/// +/// If this returns an `Error`, `reader` may be in an invalid state. +/// +/// **Warning:** the default configuration used by this function is not +/// the same as that used by the `DefaultOptions` struct. See the +/// [config](config/index.html#options-struct-vs-bincode-functions) +/// module for more details +pub fn deserialize_from(reader: R) -> Result +where + R: std::io::Read, + T: serde::de::DeserializeOwned, +{ + DefaultOptions::new() + .with_fixint_encoding() + .allow_trailing_bytes() + .deserialize_from(reader) +} + +/// Deserializes an object from a custom `BincodeRead`er using the default configuration. +/// It is highly recommended to use `deserialize_from` unless you need to implement +/// `BincodeRead` for performance reasons. +/// +/// If this returns an `Error`, `reader` may be in an invalid state. +/// +/// **Warning:** the default configuration used by this function is not +/// the same as that used by the `DefaultOptions` struct. See the +/// [config](config/index.html#options-struct-vs-bincode-functions) +/// module for more details +pub fn deserialize_from_custom<'a, R, T>(reader: R) -> Result +where + R: de::read::BincodeRead<'a>, + T: serde::de::DeserializeOwned, +{ + DefaultOptions::new() + .with_fixint_encoding() + .allow_trailing_bytes() + .deserialize_from_custom(reader) +} + +/// Only use this if you know what you're doing. +/// +/// This is part of the public API. +#[doc(hidden)] +pub fn deserialize_in_place<'a, R, T>(reader: R, place: &mut T) -> Result<()> +where + T: serde::de::Deserialize<'a>, + R: BincodeRead<'a>, +{ + DefaultOptions::new() + .with_fixint_encoding() + .allow_trailing_bytes() + .deserialize_in_place(reader, place) +} + +/// Deserializes a slice of bytes into an instance of `T` using the default configuration. +/// +/// **Warning:** the default configuration used by this function is not +/// the same as that used by the `DefaultOptions` struct. See the +/// [config](config/index.html#options-struct-vs-bincode-functions) +/// module for more details +pub fn deserialize<'a, T>(bytes: &'a [u8]) -> Result +where + T: serde::de::Deserialize<'a>, +{ + DefaultOptions::new() + .with_fixint_encoding() + .allow_trailing_bytes() + .deserialize(bytes) +} + +/// Returns the size that an object would be if serialized using Bincode with the default configuration. +/// +/// **Warning:** the default configuration used by this function is not +/// the same as that used by the `DefaultOptions` struct. See the +/// [config](config/index.html#options-struct-vs-bincode-functions) +/// module for more details +pub fn serialized_size(value: &T) -> Result +where + T: serde::Serialize, +{ + DefaultOptions::new() + .with_fixint_encoding() + .allow_trailing_bytes() + .serialized_size(value) +} diff --git a/src/ser/mod.rs b/src/ser/mod.rs new file mode 100644 index 0000000..be4f3f2 --- /dev/null +++ b/src/ser/mod.rs @@ -0,0 +1,772 @@ +use std::io::Write; +use std::u32; + +use serde; + +use byteorder::WriteBytesExt; + +use super::config::{IntEncoding, SizeLimit}; +use super::{Error, ErrorKind, Result}; +use config::{BincodeByteOrder, Options}; +use std::mem::size_of; + +/// An Serializer that encodes values directly into a Writer. +/// +/// The specified byte-order will impact the endianness that is +/// used during the encoding. +/// +/// This struct should not be used often. +/// For most cases, prefer the `encode_into` function. +pub struct Serializer { + writer: W, + _options: O, +} + +macro_rules! impl_serialize_literal { + ($ser_method:ident($ty:ty) = $write:ident()) => { + pub(crate) fn $ser_method(&mut self, v: $ty) -> Result<()> { + self.writer + .$write::<::Endian>(v) + .map_err(Into::into) + } + }; +} + +impl Serializer { + /// Creates a new Serializer with the given `Write`r. + pub fn new(w: W, options: O) -> Serializer { + Serializer { + writer: w, + _options: options, + } + } + + pub(crate) fn serialize_byte(&mut self, v: u8) -> Result<()> { + self.writer.write_u8(v).map_err(Into::into) + } + + impl_serialize_literal! {serialize_literal_u16(u16) = write_u16()} + impl_serialize_literal! {serialize_literal_u32(u32) = write_u32()} + impl_serialize_literal! {serialize_literal_u64(u64) = write_u64()} + + serde_if_integer128! { + impl_serialize_literal!{serialize_literal_u128(u128) = write_u128()} + } +} + +macro_rules! impl_serialize_int { + ($ser_method:ident($ty:ty) = $ser_int:ident()) => { + fn $ser_method(self, v: $ty) -> Result<()> { + O::IntEncoding::$ser_int(self, v) + } + }; +} + +impl<'a, W: Write, O: Options> serde::Serializer for &'a mut Serializer { + type Ok = (); + type Error = Error; + type SerializeSeq = Compound<'a, W, O>; + type SerializeTuple = Compound<'a, W, O>; + type SerializeTupleStruct = Compound<'a, W, O>; + type SerializeTupleVariant = Compound<'a, W, O>; + type SerializeMap = Compound<'a, W, O>; + type SerializeStruct = Compound<'a, W, O>; + type SerializeStructVariant = Compound<'a, W, O>; + + fn serialize_unit(self) -> Result<()> { + Ok(()) + } + + fn serialize_unit_struct(self, _: &'static str) -> Result<()> { + Ok(()) + } + + fn serialize_bool(self, v: bool) -> Result<()> { + self.serialize_byte(v as u8) + } + + fn serialize_u8(self, v: u8) -> Result<()> { + self.serialize_byte(v) + } + + impl_serialize_int! {serialize_u16(u16) = serialize_u16()} + impl_serialize_int! {serialize_u32(u32) = serialize_u32()} + impl_serialize_int! {serialize_u64(u64) = serialize_u64()} + + fn serialize_i8(self, v: i8) -> Result<()> { + self.serialize_byte(v as u8) + } + + impl_serialize_int! {serialize_i16(i16) = serialize_i16()} + impl_serialize_int! {serialize_i32(i32) = serialize_i32()} + impl_serialize_int! {serialize_i64(i64) = serialize_i64()} + + serde_if_integer128! { + impl_serialize_int!{serialize_u128(u128) = serialize_u128()} + impl_serialize_int!{serialize_i128(i128) = serialize_i128()} + } + + fn serialize_f32(self, v: f32) -> Result<()> { + self.writer + .write_f32::<::Endian>(v) + .map_err(Into::into) + } + + fn serialize_f64(self, v: f64) -> Result<()> { + self.writer + .write_f64::<::Endian>(v) + .map_err(Into::into) + } + + fn serialize_str(self, v: &str) -> Result<()> { + O::IntEncoding::serialize_len(self, v.len())?; + self.writer.write_all(v.as_bytes()).map_err(Into::into) + } + + fn serialize_char(self, c: char) -> Result<()> { + self.writer + .write_all(encode_utf8(c).as_slice()) + .map_err(Into::into) + } + + fn serialize_bytes(self, v: &[u8]) -> Result<()> { + O::IntEncoding::serialize_len(self, v.len())?; + self.writer.write_all(v).map_err(Into::into) + } + + fn serialize_none(self) -> Result<()> { + self.writer.write_u8(0).map_err(Into::into) + } + + fn serialize_some(self, v: &T) -> Result<()> + where + T: serde::Serialize, + { + self.writer.write_u8(1)?; + v.serialize(self) + } + + fn serialize_seq(self, len: Option) -> Result { + let len = len.ok_or(ErrorKind::SequenceMustHaveLength)?; + O::IntEncoding::serialize_len(self, len)?; + Ok(Compound { ser: self }) + } + + fn serialize_tuple(self, _len: usize) -> Result { + Ok(Compound { ser: self }) + } + + fn serialize_tuple_struct( + self, + _name: &'static str, + _len: usize, + ) -> Result { + Ok(Compound { ser: self }) + } + + fn serialize_tuple_variant( + self, + _name: &'static str, + variant_index: u32, + _variant: &'static str, + _len: usize, + ) -> Result { + O::IntEncoding::serialize_u32(self, variant_index)?; + Ok(Compound { ser: self }) + } + + fn serialize_map(self, len: Option) -> Result { + let len = len.ok_or(ErrorKind::SequenceMustHaveLength)?; + O::IntEncoding::serialize_len(self, len)?; + Ok(Compound { ser: self }) + } + + fn serialize_struct(self, _name: &'static str, _len: usize) -> Result { + Ok(Compound { ser: self }) + } + + fn serialize_struct_variant( + self, + _name: &'static str, + variant_index: u32, + _variant: &'static str, + _len: usize, + ) -> Result { + O::IntEncoding::serialize_u32(self, variant_index)?; + Ok(Compound { ser: self }) + } + + fn serialize_newtype_struct(self, _name: &'static str, value: &T) -> Result<()> + where + T: serde::ser::Serialize, + { + value.serialize(self) + } + + fn serialize_newtype_variant( + self, + _name: &'static str, + variant_index: u32, + _variant: &'static str, + value: &T, + ) -> Result<()> + where + T: serde::ser::Serialize, + { + O::IntEncoding::serialize_u32(self, variant_index)?; + value.serialize(self) + } + + fn serialize_unit_variant( + self, + _name: &'static str, + variant_index: u32, + _variant: &'static str, + ) -> Result<()> { + O::IntEncoding::serialize_u32(self, variant_index) + } + + fn is_human_readable(&self) -> bool { + false + } +} + +pub(crate) struct SizeChecker { + pub options: O, + pub total: u64, +} + +impl SizeChecker { + fn add_raw(&mut self, size: u64) -> Result<()> { + self.options.limit().add(size)?; + self.total += size; + + Ok(()) + } + + fn add_discriminant(&mut self, idx: u32) -> Result<()> { + let bytes = O::IntEncoding::u32_size(idx); + self.add_raw(bytes) + } + + fn add_len(&mut self, len: usize) -> Result<()> { + let bytes = O::IntEncoding::len_size(len); + self.add_raw(bytes) + } +} + +macro_rules! impl_size_int { + ($ser_method:ident($ty:ty) = $size_method:ident()) => { + fn $ser_method(self, v: $ty) -> Result<()> { + self.add_raw(O::IntEncoding::$size_method(v)) + } + }; +} + +impl<'a, O: Options> serde::Serializer for &'a mut SizeChecker { + type Ok = (); + type Error = Error; + type SerializeSeq = SizeCompound<'a, O>; + type SerializeTuple = SizeCompound<'a, O>; + type SerializeTupleStruct = SizeCompound<'a, O>; + type SerializeTupleVariant = SizeCompound<'a, O>; + type SerializeMap = SizeCompound<'a, O>; + type SerializeStruct = SizeCompound<'a, O>; + type SerializeStructVariant = SizeCompound<'a, O>; + + fn serialize_unit(self) -> Result<()> { + Ok(()) + } + + fn serialize_unit_struct(self, _: &'static str) -> Result<()> { + Ok(()) + } + + fn serialize_bool(self, _: bool) -> Result<()> { + self.add_raw(1) + } + + fn serialize_u8(self, _: u8) -> Result<()> { + self.add_raw(1) + } + fn serialize_i8(self, _: i8) -> Result<()> { + self.add_raw(1) + } + + impl_size_int! {serialize_u16(u16) = u16_size()} + impl_size_int! {serialize_u32(u32) = u32_size()} + impl_size_int! {serialize_u64(u64) = u64_size()} + impl_size_int! {serialize_i16(i16) = i16_size()} + impl_size_int! {serialize_i32(i32) = i32_size()} + impl_size_int! {serialize_i64(i64) = i64_size()} + + serde_if_integer128! { + impl_size_int!{serialize_u128(u128) = u128_size()} + impl_size_int!{serialize_i128(i128) = i128_size()} + } + + fn serialize_f32(self, _: f32) -> Result<()> { + self.add_raw(size_of::() as u64) + } + + fn serialize_f64(self, _: f64) -> Result<()> { + self.add_raw(size_of::() as u64) + } + + fn serialize_str(self, v: &str) -> Result<()> { + self.add_len(v.len())?; + self.add_raw(v.len() as u64) + } + + fn serialize_char(self, c: char) -> Result<()> { + self.add_raw(encode_utf8(c).as_slice().len() as u64) + } + + fn serialize_bytes(self, v: &[u8]) -> Result<()> { + self.add_len(v.len())?; + self.add_raw(v.len() as u64) + } + + fn serialize_none(self) -> Result<()> { + self.add_raw(1) + } + + fn serialize_some(self, v: &T) -> Result<()> + where + T: serde::Serialize, + { + self.add_raw(1)?; + v.serialize(self) + } + + fn serialize_seq(self, len: Option) -> Result { + let len = len.ok_or(ErrorKind::SequenceMustHaveLength)?; + + self.add_len(len)?; + Ok(SizeCompound { ser: self }) + } + + fn serialize_tuple(self, _len: usize) -> Result { + Ok(SizeCompound { ser: self }) + } + + fn serialize_tuple_struct( + self, + _name: &'static str, + _len: usize, + ) -> Result { + Ok(SizeCompound { ser: self }) + } + + fn serialize_tuple_variant( + self, + _name: &'static str, + variant_index: u32, + _variant: &'static str, + _len: usize, + ) -> Result { + self.add_raw(O::IntEncoding::u32_size(variant_index))?; + Ok(SizeCompound { ser: self }) + } + + fn serialize_map(self, len: Option) -> Result { + let len = len.ok_or(ErrorKind::SequenceMustHaveLength)?; + + self.add_len(len)?; + Ok(SizeCompound { ser: self }) + } + + fn serialize_struct(self, _name: &'static str, _len: usize) -> Result { + Ok(SizeCompound { ser: self }) + } + + fn serialize_struct_variant( + self, + _name: &'static str, + variant_index: u32, + _variant: &'static str, + _len: usize, + ) -> Result { + self.add_discriminant(variant_index)?; + Ok(SizeCompound { ser: self }) + } + + fn serialize_newtype_struct( + self, + _name: &'static str, + v: &V, + ) -> Result<()> { + v.serialize(self) + } + + fn serialize_unit_variant( + self, + _name: &'static str, + variant_index: u32, + _variant: &'static str, + ) -> Result<()> { + self.add_discriminant(variant_index) + } + + fn serialize_newtype_variant( + self, + _name: &'static str, + variant_index: u32, + _variant: &'static str, + value: &V, + ) -> Result<()> { + self.add_discriminant(variant_index)?; + value.serialize(self) + } + + fn is_human_readable(&self) -> bool { + false + } +} + +pub struct Compound<'a, W: 'a, O: Options + 'a> { + ser: &'a mut Serializer, +} + +impl<'a, W, O> serde::ser::SerializeSeq for Compound<'a, W, O> +where + W: Write, + O: Options, +{ + type Ok = (); + type Error = Error; + + #[inline] + fn serialize_element(&mut self, value: &T) -> Result<()> + where + T: serde::ser::Serialize, + { + value.serialize(&mut *self.ser) + } + + #[inline] + fn end(self) -> Result<()> { + Ok(()) + } +} + +impl<'a, W, O> serde::ser::SerializeTuple for Compound<'a, W, O> +where + W: Write, + O: Options, +{ + type Ok = (); + type Error = Error; + + #[inline] + fn serialize_element(&mut self, value: &T) -> Result<()> + where + T: serde::ser::Serialize, + { + value.serialize(&mut *self.ser) + } + + #[inline] + fn end(self) -> Result<()> { + Ok(()) + } +} + +impl<'a, W, O> serde::ser::SerializeTupleStruct for Compound<'a, W, O> +where + W: Write, + O: Options, +{ + type Ok = (); + type Error = Error; + + #[inline] + fn serialize_field(&mut self, value: &T) -> Result<()> + where + T: serde::ser::Serialize, + { + value.serialize(&mut *self.ser) + } + + #[inline] + fn end(self) -> Result<()> { + Ok(()) + } +} + +impl<'a, W, O> serde::ser::SerializeTupleVariant for Compound<'a, W, O> +where + W: Write, + O: Options, +{ + type Ok = (); + type Error = Error; + + #[inline] + fn serialize_field(&mut self, value: &T) -> Result<()> + where + T: serde::ser::Serialize, + { + value.serialize(&mut *self.ser) + } + + #[inline] + fn end(self) -> Result<()> { + Ok(()) + } +} + +impl<'a, W, O> serde::ser::SerializeMap for Compound<'a, W, O> +where + W: Write, + O: Options, +{ + type Ok = (); + type Error = Error; + + #[inline] + fn serialize_key(&mut self, value: &K) -> Result<()> + where + K: serde::ser::Serialize, + { + value.serialize(&mut *self.ser) + } + + #[inline] + fn serialize_value(&mut self, value: &V) -> Result<()> + where + V: serde::ser::Serialize, + { + value.serialize(&mut *self.ser) + } + + #[inline] + fn end(self) -> Result<()> { + Ok(()) + } +} + +impl<'a, W, O> serde::ser::SerializeStruct for Compound<'a, W, O> +where + W: Write, + O: Options, +{ + type Ok = (); + type Error = Error; + + #[inline] + fn serialize_field(&mut self, _key: &'static str, value: &T) -> Result<()> + where + T: serde::ser::Serialize, + { + value.serialize(&mut *self.ser) + } + + #[inline] + fn end(self) -> Result<()> { + Ok(()) + } +} + +impl<'a, W, O> serde::ser::SerializeStructVariant for Compound<'a, W, O> +where + W: Write, + O: Options, +{ + type Ok = (); + type Error = Error; + + #[inline] + fn serialize_field(&mut self, _key: &'static str, value: &T) -> Result<()> + where + T: serde::ser::Serialize, + { + value.serialize(&mut *self.ser) + } + + #[inline] + fn end(self) -> Result<()> { + Ok(()) + } +} + +pub(crate) struct SizeCompound<'a, S: Options + 'a> { + ser: &'a mut SizeChecker, +} + +impl<'a, O: Options> serde::ser::SerializeSeq for SizeCompound<'a, O> { + type Ok = (); + type Error = Error; + + #[inline] + fn serialize_element(&mut self, value: &T) -> Result<()> + where + T: serde::ser::Serialize, + { + value.serialize(&mut *self.ser) + } + + #[inline] + fn end(self) -> Result<()> { + Ok(()) + } +} + +impl<'a, O: Options> serde::ser::SerializeTuple for SizeCompound<'a, O> { + type Ok = (); + type Error = Error; + + #[inline] + fn serialize_element(&mut self, value: &T) -> Result<()> + where + T: serde::ser::Serialize, + { + value.serialize(&mut *self.ser) + } + + #[inline] + fn end(self) -> Result<()> { + Ok(()) + } +} + +impl<'a, O: Options> serde::ser::SerializeTupleStruct for SizeCompound<'a, O> { + type Ok = (); + type Error = Error; + + #[inline] + fn serialize_field(&mut self, value: &T) -> Result<()> + where + T: serde::ser::Serialize, + { + value.serialize(&mut *self.ser) + } + + #[inline] + fn end(self) -> Result<()> { + Ok(()) + } +} + +impl<'a, O: Options> serde::ser::SerializeTupleVariant for SizeCompound<'a, O> { + type Ok = (); + type Error = Error; + + #[inline] + fn serialize_field(&mut self, value: &T) -> Result<()> + where + T: serde::ser::Serialize, + { + value.serialize(&mut *self.ser) + } + + #[inline] + fn end(self) -> Result<()> { + Ok(()) + } +} + +impl<'a, O: Options + 'a> serde::ser::SerializeMap for SizeCompound<'a, O> { + type Ok = (); + type Error = Error; + + #[inline] + fn serialize_key(&mut self, value: &K) -> Result<()> + where + K: serde::ser::Serialize, + { + value.serialize(&mut *self.ser) + } + + #[inline] + fn serialize_value(&mut self, value: &V) -> Result<()> + where + V: serde::ser::Serialize, + { + value.serialize(&mut *self.ser) + } + + #[inline] + fn end(self) -> Result<()> { + Ok(()) + } +} + +impl<'a, O: Options> serde::ser::SerializeStruct for SizeCompound<'a, O> { + type Ok = (); + type Error = Error; + + #[inline] + fn serialize_field(&mut self, _key: &'static str, value: &T) -> Result<()> + where + T: serde::ser::Serialize, + { + value.serialize(&mut *self.ser) + } + + #[inline] + fn end(self) -> Result<()> { + Ok(()) + } +} + +impl<'a, O: Options> serde::ser::SerializeStructVariant for SizeCompound<'a, O> { + type Ok = (); + type Error = Error; + + #[inline] + fn serialize_field(&mut self, _key: &'static str, value: &T) -> Result<()> + where + T: serde::ser::Serialize, + { + value.serialize(&mut *self.ser) + } + + #[inline] + fn end(self) -> Result<()> { + 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(c: char) -> EncodeUtf8 { + let code = c as u32; + let mut buf = [0; 4]; + let pos = if code < MAX_ONE_B { + buf[3] = code as u8; + 3 + } else if code < MAX_TWO_B { + buf[2] = (code >> 6 & 0x1F) as u8 | TAG_TWO_B; + buf[3] = (code & 0x3F) as u8 | TAG_CONT; + 2 + } else if code < MAX_THREE_B { + buf[1] = (code >> 12 & 0x0F) as u8 | TAG_THREE_B; + buf[2] = (code >> 6 & 0x3F) as u8 | TAG_CONT; + buf[3] = (code & 0x3F) as u8 | TAG_CONT; + 1 + } else { + 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; + 0 + }; + EncodeUtf8 { buf, pos } +} + +struct EncodeUtf8 { + buf: [u8; 4], + pos: usize, +} + +impl EncodeUtf8 { + fn as_slice(&self) -> &[u8] { + &self.buf[self.pos..] + } +} diff --git a/tests/test.rs b/tests/test.rs new file mode 100644 index 0000000..23d65f4 --- /dev/null +++ b/tests/test.rs @@ -0,0 +1,899 @@ +#[macro_use] +extern crate serde_derive; + +extern crate bincode; +#[macro_use] +extern crate serde; +extern crate serde_bytes; + +use std::borrow::Cow; +use std::collections::HashMap; +use std::fmt::{self, Debug}; +use std::result::Result as StdResult; + +use bincode::{ + deserialize, deserialize_from, deserialize_in_place, serialize, serialized_size, + DefaultOptions, ErrorKind, Options, Result, +}; +use serde::de::{Deserialize, DeserializeSeed, Deserializer, SeqAccess, Visitor}; + +const LEN_SIZE: u64 = 8; + +fn the_same_impl(element: V, options: &mut O) +where + V: serde::Serialize + serde::de::DeserializeOwned + PartialEq + Debug + 'static, + O: Options, +{ + let size = options.serialized_size(&element).unwrap(); + + { + let encoded = options.serialize(&element).unwrap(); + let decoded: V = options.deserialize(&encoded[..]).unwrap(); + let decoded_reader = options.deserialize_from(&mut &encoded[..]).unwrap(); + + assert_eq!(element, decoded); + assert_eq!(element, decoded_reader); + assert_eq!(size, encoded.len() as u64); + } +} + +fn the_same(element: V) +where + V: serde::Serialize + serde::de::DeserializeOwned + PartialEq + Debug + Clone + 'static, +{ + // add a new macro which calls the previous when you add a new option set + macro_rules! all_endians { + ($element:expr, $options:expr) => { + the_same_impl($element.clone(), &mut $options.with_native_endian()); + the_same_impl($element.clone(), &mut $options.with_big_endian()); + the_same_impl($element.clone(), &mut $options.with_little_endian()); + }; + } + + macro_rules! all_integer_encodings { + ($element:expr, $options:expr) => { + all_endians!($element, $options.with_fixint_encoding()); + all_endians!($element, $options.with_varint_encoding()); + }; + } + + all_integer_encodings!(element, DefaultOptions::new()); +} + +#[test] +fn test_numbers() { + // unsigned positive + the_same(5u8); + the_same(5u16); + the_same(5u32); + the_same(5u64); + the_same(5usize); + // signed positive + the_same(5i8); + the_same(5i16); + the_same(5i32); + the_same(5i64); + the_same(5isize); + // signed negative + the_same(-5i8); + the_same(-5i16); + the_same(-5i32); + the_same(-5i64); + the_same(-5isize); + // floating + the_same(-100f32); + the_same(0f32); + the_same(5f32); + the_same(-100f64); + the_same(5f64); +} + +serde_if_integer128! { + #[test] + fn test_numbers_128bit() { + // unsigned positive + the_same(5u128); + the_same(u128::max_value()); + // signed positive + the_same(5i128); + the_same(i128::max_value()); + // signed negative + the_same(-5i128); + the_same(i128::min_value()); + } +} + +#[test] +fn test_string() { + the_same("".to_string()); + the_same("a".to_string()); +} + +#[test] +fn test_tuple() { + the_same((1isize,)); + the_same((1isize, 2isize, 3isize)); + the_same((1isize, "foo".to_string(), ())); +} + +#[test] +fn test_basic_struct() { + #[derive(Serialize, Deserialize, PartialEq, Debug, Clone)] + struct Easy { + x: isize, + s: String, + y: usize, + } + the_same(Easy { + x: -4, + s: "foo".to_string(), + y: 10, + }); +} + +#[test] +fn test_nested_struct() { + #[derive(Serialize, Deserialize, PartialEq, Debug, Clone)] + struct Easy { + x: isize, + s: String, + y: usize, + } + #[derive(Serialize, Deserialize, PartialEq, Debug, Clone)] + struct Nest { + f: Easy, + b: usize, + s: Easy, + } + + the_same(Nest { + f: Easy { + x: -1, + s: "foo".to_string(), + y: 20, + }, + b: 100, + s: Easy { + x: -100, + s: "bar".to_string(), + y: 20, + }, + }); +} + +#[test] +fn test_struct_newtype() { + #[derive(Serialize, Deserialize, PartialEq, Debug, Clone)] + struct NewtypeStr(usize); + + the_same(NewtypeStr(5)); +} + +#[test] +fn test_struct_tuple() { + #[derive(Serialize, Deserialize, PartialEq, Debug, Clone)] + struct TubStr(usize, String, f32); + + the_same(TubStr(5, "hello".to_string(), 3.2)); +} + +#[test] +fn test_option() { + the_same(Some(5usize)); + the_same(Some("foo bar".to_string())); + the_same(None::); +} + +#[test] +fn test_enum() { + #[derive(Serialize, Deserialize, PartialEq, Debug, Clone)] + enum TestEnum { + NoArg, + OneArg(usize), + Args(usize, usize), + AnotherNoArg, + StructLike { x: usize, y: f32 }, + } + the_same(TestEnum::NoArg); + the_same(TestEnum::OneArg(4)); + //the_same(TestEnum::Args(4, 5)); + the_same(TestEnum::AnotherNoArg); + the_same(TestEnum::StructLike { x: 4, y: 3.14159 }); + the_same(vec![ + TestEnum::NoArg, + TestEnum::OneArg(5), + TestEnum::AnotherNoArg, + TestEnum::StructLike { x: 4, y: 1.4 }, + ]); +} + +#[test] +fn test_vec() { + let v: Vec = vec![]; + the_same(v); + the_same(vec![1u64]); + the_same(vec![1u64, 2, 3, 4, 5, 6]); +} + +#[test] +fn test_map() { + let mut m = HashMap::new(); + m.insert(4u64, "foo".to_string()); + m.insert(0u64, "bar".to_string()); + the_same(m); +} + +#[test] +fn test_bool() { + the_same(true); + the_same(false); +} + +#[test] +fn test_unicode() { + the_same("å".to_string()); + the_same("aåååååååa".to_string()); +} + +#[test] +fn test_fixed_size_array() { + the_same([24u32; 32]); + the_same([1u64, 2, 3, 4, 5, 6, 7, 8]); + the_same([0u8; 19]); +} + +#[test] +fn deserializing_errors() { + match *deserialize::(&vec![0xA][..]).unwrap_err() { + ErrorKind::InvalidBoolEncoding(0xA) => {} + _ => panic!(), + } + + let invalid_str = vec![1, 0, 0, 0, 0, 0, 0, 0, 0xFF]; + + match *deserialize::(&invalid_str[..]).unwrap_err() { + ErrorKind::InvalidUtf8Encoding(_) => {} + _ => panic!(), + } + + // Out-of-bounds variant + #[derive(Serialize, Deserialize, Debug)] + enum Test { + One, + Two, + }; + + let invalid_enum = vec![0, 0, 0, 5]; + + match *deserialize::(&invalid_enum[..]).unwrap_err() { + // Error message comes from serde + ErrorKind::Custom(_) => {} + _ => panic!(), + } + match *deserialize::>(&vec![5, 0][..]).unwrap_err() { + ErrorKind::InvalidTagEncoding(_) => {} + _ => panic!(), + } +} + +#[test] +fn trailing_bytes() { + match DefaultOptions::new() + .deserialize::(b"1x") + .map_err(|e| *e) + { + Err(ErrorKind::Custom(_)) => {} + other => panic!("Expecting TrailingBytes, got {:?}", other), + } +} + +#[test] +fn too_big_deserialize() { + let serialized = vec![0, 0, 0, 3]; + let deserialized: Result = DefaultOptions::new() + .with_fixint_encoding() + .with_limit(3) + .deserialize_from(&mut &serialized[..]); + assert!(deserialized.is_err()); + + let serialized = vec![0, 0, 0, 3]; + let deserialized: Result = DefaultOptions::new() + .with_fixint_encoding() + .with_limit(4) + .deserialize_from(&mut &serialized[..]); + assert!(deserialized.is_ok()); +} + +#[test] +fn char_serialization() { + let chars = "Aa\0☺♪"; + for c in chars.chars() { + let encoded = DefaultOptions::new() + .with_limit(4) + .serialize(&c) + .expect("serializing char failed"); + let decoded: char = deserialize(&encoded).expect("deserializing failed"); + assert_eq!(decoded, c); + } +} + +#[test] +fn too_big_char_deserialize() { + let serialized = vec![0x41]; + let deserialized: Result = DefaultOptions::new() + .with_limit(1) + .deserialize_from(&mut &serialized[..]); + assert!(deserialized.is_ok()); + assert_eq!(deserialized.unwrap(), 'A'); +} + +#[test] +fn too_big_serialize() { + assert!(DefaultOptions::new() + .with_fixint_encoding() + .with_limit(3) + .serialize(&0u32) + .is_err()); + assert!(DefaultOptions::new() + .with_fixint_encoding() + .with_limit(4) + .serialize(&0u32) + .is_ok()); + + assert!(DefaultOptions::new() + .with_fixint_encoding() + .with_limit(LEN_SIZE + 4) + .serialize(&"abcde") + .is_err()); + assert!(DefaultOptions::new() + .with_fixint_encoding() + .with_limit(LEN_SIZE + 5) + .serialize(&"abcde") + .is_ok()); +} + +#[test] +fn test_serialized_size() { + assert!(serialized_size(&0u8).unwrap() == 1); + assert!(serialized_size(&0u16).unwrap() == 2); + assert!(serialized_size(&0u32).unwrap() == 4); + assert!(serialized_size(&0u64).unwrap() == 8); + + // length isize stored as u64 + assert!(serialized_size(&"").unwrap() == LEN_SIZE); + assert!(serialized_size(&"a").unwrap() == LEN_SIZE + 1); + + assert!(serialized_size(&vec![0u32, 1u32, 2u32]).unwrap() == LEN_SIZE + 3 * (4)); +} + +#[test] +fn test_serialized_size_bounded() { + // JUST RIGHT + assert!( + DefaultOptions::new() + .with_fixint_encoding() + .with_limit(1) + .serialized_size(&0u8) + .unwrap() + == 1 + ); + assert!( + DefaultOptions::new() + .with_fixint_encoding() + .with_limit(2) + .serialized_size(&0u16) + .unwrap() + == 2 + ); + assert!( + DefaultOptions::new() + .with_fixint_encoding() + .with_limit(4) + .serialized_size(&0u32) + .unwrap() + == 4 + ); + assert!( + DefaultOptions::new() + .with_fixint_encoding() + .with_limit(8) + .serialized_size(&0u64) + .unwrap() + == 8 + ); + assert!( + DefaultOptions::new() + .with_fixint_encoding() + .with_limit(8) + .serialized_size(&"") + .unwrap() + == LEN_SIZE + ); + assert!( + DefaultOptions::new() + .with_fixint_encoding() + .with_limit(8 + 1) + .serialized_size(&"a") + .unwrap() + == LEN_SIZE + 1 + ); + assert!( + DefaultOptions::new() + .with_fixint_encoding() + .with_limit(LEN_SIZE + 3 * 4) + .serialized_size(&vec![0u32, 1u32, 2u32]) + .unwrap() + == LEN_SIZE + 3 * 4 + ); + // Below + assert!(DefaultOptions::new() + .with_fixint_encoding() + .with_limit(0) + .serialized_size(&0u8) + .is_err()); + assert!(DefaultOptions::new() + .with_fixint_encoding() + .with_limit(1) + .serialized_size(&0u16) + .is_err()); + assert!(DefaultOptions::new() + .with_fixint_encoding() + .with_limit(3) + .serialized_size(&0u32) + .is_err()); + assert!(DefaultOptions::new() + .with_fixint_encoding() + .with_limit(7) + .serialized_size(&0u64) + .is_err()); + assert!(DefaultOptions::new() + .with_fixint_encoding() + .with_limit(7) + .serialized_size(&"") + .is_err()); + assert!(DefaultOptions::new() + .with_fixint_encoding() + .with_limit(8 + 0) + .serialized_size(&"a") + .is_err()); + assert!(DefaultOptions::new() + .with_fixint_encoding() + .with_limit(8 + 3 * 4 - 1) + .serialized_size(&vec![0u32, 1u32, 2u32]) + .is_err()); +} + +#[test] +fn encode_box() { + the_same(Box::new(5)); +} + +#[test] +fn test_cow_serialize() { + let large_object = vec![1u32, 2, 3, 4, 5, 6]; + let mut large_map = HashMap::new(); + large_map.insert(1, 2); + + #[derive(Serialize, Deserialize, Debug)] + enum Message<'a> { + M1(Cow<'a, Vec>), + M2(Cow<'a, HashMap>), + } + + // Test 1 + { + let serialized = serialize(&Message::M1(Cow::Borrowed(&large_object))).unwrap(); + let deserialized: Message<'static> = deserialize_from(&mut &serialized[..]).unwrap(); + + match deserialized { + Message::M1(b) => assert!(&b.into_owned() == &large_object), + _ => assert!(false), + } + } + + // Test 2 + { + let serialized = serialize(&Message::M2(Cow::Borrowed(&large_map))).unwrap(); + let deserialized: Message<'static> = deserialize_from(&mut &serialized[..]).unwrap(); + + match deserialized { + Message::M2(b) => assert!(&b.into_owned() == &large_map), + _ => assert!(false), + } + } +} + +#[test] +fn test_strbox_serialize() { + let strx: &'static str = "hello world"; + let serialized = serialize(&Cow::Borrowed(strx)).unwrap(); + let deserialized: Cow<'static, String> = deserialize_from(&mut &serialized[..]).unwrap(); + let stringx: String = deserialized.into_owned(); + assert!(strx == &stringx[..]); +} + +#[test] +fn test_slicebox_serialize() { + let slice = [1u32, 2, 3, 4, 5]; + let serialized = serialize(&Cow::Borrowed(&slice[..])).unwrap(); + println!("{:?}", serialized); + let deserialized: Cow<'static, Vec> = deserialize_from(&mut &serialized[..]).unwrap(); + { + let sb: &[u32] = &deserialized; + assert!(slice == sb); + } + let vecx: Vec = deserialized.into_owned(); + assert!(slice == &vecx[..]); +} + +#[test] +fn test_multi_strings_serialize() { + assert!(serialize(&("foo", "bar", "baz")).is_ok()); +} + +#[test] +fn test_oom_protection() { + use std::io::Cursor; + #[derive(Serialize, Deserialize, PartialEq, Debug)] + struct FakeVec { + len: u64, + byte: u8, + } + let x = DefaultOptions::new() + .with_limit(10) + .serialize(&FakeVec { + len: 0xffffffffffffffffu64, + byte: 1, + }) + .unwrap(); + let y: Result> = DefaultOptions::new() + .with_limit(10) + .deserialize_from(&mut Cursor::new(&x[..])); + assert!(y.is_err()); +} + +#[test] +fn path_buf() { + use std::path::{Path, PathBuf}; + let path = Path::new("foo").to_path_buf(); + let serde_encoded = serialize(&path).unwrap(); + let decoded: PathBuf = deserialize(&serde_encoded).unwrap(); + assert!(path.to_str() == decoded.to_str()); +} + +#[test] +fn bytes() { + use serde_bytes::Bytes; + + let data = b"abc\0123"; + let s = serialize(&data[..]).unwrap(); + let s2 = serialize(&Bytes::new(data)).unwrap(); + assert_eq!(s[..], s2[..]); +} + +#[test] +fn serde_bytes() { + use serde_bytes::ByteBuf; + the_same(ByteBuf::from(vec![1, 2, 3, 4, 5])); +} + +#[test] +fn endian_difference() { + let x = 10u64; + let little = serialize(&x).unwrap(); + let big = DefaultOptions::new() + .with_big_endian() + .serialize(&x) + .unwrap(); + assert_ne!(little, big); +} + +#[test] +fn test_zero_copy_parse() { + #[derive(Serialize, Deserialize, Eq, PartialEq, Debug)] + struct Foo<'a> { + borrowed_str: &'a str, + borrowed_bytes: &'a [u8], + } + + let f = Foo { + borrowed_str: "hi", + borrowed_bytes: &[0, 1, 2, 3], + }; + { + let encoded = serialize(&f).unwrap(); + let out: Foo = deserialize(&encoded[..]).unwrap(); + assert_eq!(out, f); + } +} + +#[test] +fn test_zero_copy_parse_deserialize_into() { + use bincode::BincodeRead; + use std::io; + + /// A BincodeRead implementation for byte slices + pub struct SliceReader<'storage> { + slice: &'storage [u8], + } + + impl<'storage> SliceReader<'storage> { + #[inline(always)] + fn unexpected_eof() -> Box<::ErrorKind> { + return Box::new(::ErrorKind::Io(io::Error::new( + io::ErrorKind::UnexpectedEof, + "", + ))); + } + } + + impl<'storage> io::Read for SliceReader<'storage> { + #[inline(always)] + fn read(&mut self, out: &mut [u8]) -> io::Result { + (&mut self.slice).read(out) + } + #[inline(always)] + fn read_exact(&mut self, out: &mut [u8]) -> io::Result<()> { + (&mut self.slice).read_exact(out) + } + } + + impl<'storage> BincodeRead<'storage> for SliceReader<'storage> { + #[inline(always)] + fn forward_read_str(&mut self, length: usize, visitor: V) -> Result + where + V: serde::de::Visitor<'storage>, + { + use ErrorKind; + if length > self.slice.len() { + return Err(SliceReader::unexpected_eof()); + } + + let string = match ::std::str::from_utf8(&self.slice[..length]) { + Ok(s) => s, + Err(e) => return Err(ErrorKind::InvalidUtf8Encoding(e).into()), + }; + let r = visitor.visit_borrowed_str(string); + self.slice = &self.slice[length..]; + r + } + + #[inline(always)] + fn get_byte_buffer(&mut self, length: usize) -> Result> { + if length > self.slice.len() { + return Err(SliceReader::unexpected_eof()); + } + + let r = &self.slice[..length]; + self.slice = &self.slice[length..]; + Ok(r.to_vec()) + } + + #[inline(always)] + fn forward_read_bytes(&mut self, length: usize, visitor: V) -> Result + where + V: serde::de::Visitor<'storage>, + { + if length > self.slice.len() { + return Err(SliceReader::unexpected_eof()); + } + + let r = visitor.visit_borrowed_bytes(&self.slice[..length]); + self.slice = &self.slice[length..]; + r + } + } + + #[derive(Serialize, Deserialize, Eq, PartialEq, Debug)] + struct Foo<'a> { + borrowed_str: &'a str, + borrowed_bytes: &'a [u8], + } + + let f = Foo { + borrowed_str: "hi", + borrowed_bytes: &[0, 1, 2, 3], + }; + + { + let encoded = serialize(&f).unwrap(); + let mut target = Foo { + borrowed_str: "hello", + borrowed_bytes: &[10, 11, 12, 13], + }; + deserialize_in_place( + SliceReader { + slice: &encoded[..], + }, + &mut target, + ) + .unwrap(); + assert_eq!(target, f); + } +} + +#[test] +fn not_human_readable() { + use std::net::Ipv4Addr; + let ip = Ipv4Addr::new(1, 2, 3, 4); + the_same(ip); + assert_eq!(&ip.octets()[..], &serialize(&ip).unwrap()[..]); + assert_eq!( + ::std::mem::size_of::() as u64, + serialized_size(&ip).unwrap() + ); +} + +// The example is taken from serde::de::DeserializeSeed. +struct ExtendVec<'a, T: 'a>(&'a mut Vec); + +impl<'de, 'a, T> DeserializeSeed<'de> for ExtendVec<'a, T> +where + T: Deserialize<'de>, +{ + // The return type of the `deserialize` method. This implementation + // appends onto an existing vector but does not create any new data + // structure, so the return type is (). + type Value = (); + + fn deserialize(self, deserializer: D) -> StdResult + where + D: Deserializer<'de>, + { + // Visitor implementation that will walk an inner array of the JSON + // input. + struct ExtendVecVisitor<'a, T: 'a>(&'a mut Vec); + + impl<'de, 'a, T> Visitor<'de> for ExtendVecVisitor<'a, T> + where + T: Deserialize<'de>, + { + type Value = (); + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + write!(formatter, "an array of integers") + } + + fn visit_seq(self, mut seq: A) -> StdResult<(), A::Error> + where + A: SeqAccess<'de>, + { + // Visit each element in the inner array and push it onto + // the existing vector. + while let Some(elem) = seq.next_element()? { + self.0.push(elem); + } + Ok(()) + } + } + + deserializer.deserialize_seq(ExtendVecVisitor(self.0)) + } +} + +#[test] +fn test_default_deserialize_seed() { + let config = DefaultOptions::new(); + + let data: Vec<_> = (10..100).collect(); + let bytes = config.serialize(&data).expect("Config::serialize failed"); + + let mut seed_data: Vec<_> = (0..10).collect(); + { + let seed = ExtendVec(&mut seed_data); + config + .deserialize_seed(seed, &bytes) + .expect("Config::deserialize_seed failed"); + } + + assert_eq!(seed_data, (0..100).collect::>()); +} + +#[test] +fn test_big_endian_deserialize_seed() { + let config = DefaultOptions::new().with_big_endian(); + + let data: Vec<_> = (10..100).collect(); + let bytes = config.serialize(&data).expect("Config::serialize failed"); + + let mut seed_data: Vec<_> = (0..10).collect(); + { + let seed = ExtendVec(&mut seed_data); + config + .deserialize_seed(seed, &bytes) + .expect("Config::deserialize_seed failed"); + } + + assert_eq!(seed_data, (0..100).collect::>()); +} + +#[test] +fn test_default_deserialize_from_seed() { + let config = DefaultOptions::new(); + + let data: Vec<_> = (10..100).collect(); + let bytes = config.serialize(&data).expect("Config::serialize failed"); + + let mut seed_data: Vec<_> = (0..10).collect(); + { + let seed = ExtendVec(&mut seed_data); + config + .deserialize_from_seed(seed, &mut &*bytes) + .expect("Config::deserialize_from_seed failed"); + } + + assert_eq!(seed_data, (0..100).collect::>()); +} + +#[test] +fn test_big_endian_deserialize_from_seed() { + let config = DefaultOptions::new().with_big_endian(); + + let data: Vec<_> = (10..100).collect(); + let bytes = config.serialize(&data).expect("Config::serialize failed"); + + let mut seed_data: Vec<_> = (0..10).collect(); + { + let seed = ExtendVec(&mut seed_data); + config + .deserialize_from_seed(seed, &mut &*bytes) + .expect("Config::deserialize_from_seed failed"); + } + + assert_eq!(seed_data, (0..100).collect::>()); +} + +#[test] +fn test_varint_length_prefixes() { + let a = vec![(); 127]; // should be a single byte + let b = vec![(); 250]; // also should be a single byte + let c = vec![(); 251]; + let d = vec![(); u16::max_value() as usize + 1]; + + assert_eq!( + DefaultOptions::new() + .with_varint_encoding() + .serialized_size(&a[..]) + .unwrap(), + 1 + ); // 2 ** 7 - 1 + assert_eq!( + DefaultOptions::new() + .with_varint_encoding() + .serialized_size(&b[..]) + .unwrap(), + 1 + ); // 250 + assert_eq!( + DefaultOptions::new() + .with_varint_encoding() + .serialized_size(&c[..]) + .unwrap(), + (1 + std::mem::size_of::()) as u64 + ); // 251 + assert_eq!( + DefaultOptions::new() + .with_varint_encoding() + .serialized_size(&d[..]) + .unwrap(), + (1 + std::mem::size_of::()) as u64 + ); // 2 ** 16 + 1 +} + +#[test] +fn test_byte_vec_struct() { + #[derive(PartialEq, Eq, Clone, Serialize, Deserialize, Debug)] + struct ByteVecs { + a: Vec, + b: Vec, + c: Vec, + }; + + let byte_struct = ByteVecs { + a: vec![2; 20], + b: vec![3; 30], + c: vec![1; 10], + }; + + the_same(byte_struct); +} -- cgit v1.2.3