mirror of
https://github.com/tokio-rs/bytes.git
synced 2026-08-08 00:00:26 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b7249149a9 | ||
|
|
d6e1999d97 | ||
|
|
38fd42acba | ||
|
|
7553a67be2 | ||
|
|
cd188cbd67 | ||
|
|
10d1f6ec5c | ||
|
|
068ed41bc0 | ||
|
|
f514bd38da | ||
|
|
28a1eab1e0 | ||
|
|
3536017ccf | ||
|
|
b8d27c016f | ||
|
|
0ce4fe3c91 | ||
|
|
716a0b189e | ||
|
|
b4b2c18c27 | ||
|
|
89061c3238 | ||
|
|
0a2c43af88 | ||
|
|
8198f9e28e | ||
|
|
547a32033e | ||
|
|
724476982b | ||
|
|
9e6edd18d2 | ||
|
|
e4c723697d | ||
|
|
d4f5023383 | ||
|
|
88f5e12350 | ||
|
|
131dae161f | ||
|
|
0e3b2466f1 | ||
|
|
68afb40df9 | ||
|
|
d946ef2e91 | ||
|
|
ba5c5c93af | ||
|
|
ebc61e5af1 | ||
|
|
55e296850d | ||
|
|
0e9fa0b602 | ||
|
|
ee24be7fa0 | ||
|
|
2697fa7a9d | ||
|
|
fa9cbf1258 | ||
|
|
ab8e3c01a8 | ||
|
|
f34dc5c3f9 | ||
|
|
baaf12d22a | ||
|
|
ed1d24e570 | ||
|
|
b89247c713 | ||
|
|
9c770188fd | ||
|
|
b9eade12a5 | ||
|
|
3d5624a452 | ||
|
|
2428c152a6 | ||
|
|
268f6f80b4 | ||
|
|
e4182808df | ||
|
|
8daf43e9bd | ||
|
|
7b18c1c076 | ||
|
|
df20a68356 | ||
|
|
8758a1aba5 | ||
|
|
27a0f9ca6e | ||
|
|
ed71a7beb3 | ||
|
|
064ad9a1a0 | ||
|
|
ed1d194660 | ||
|
|
e398b0a209 | ||
|
|
06907f3e7b | ||
|
|
54f5ced6c5 | ||
|
|
bd78f19393 | ||
|
|
39c6d7a512 | ||
|
|
b7f75829ab | ||
|
|
39de065a1e | ||
|
|
5866839e45 | ||
|
|
e0d8413d53 | ||
|
|
5a11c783ec | ||
|
|
4724c7e8a0 | ||
|
|
ced050730c | ||
|
|
94c543f74b | ||
|
|
447530b8a6 | ||
|
|
422048eb24 | ||
|
|
6fdb7391ce | ||
|
|
025bec2954 | ||
|
|
2d51809bd7 | ||
|
|
7daa7fe053 | ||
|
|
972f538b7e | ||
|
|
81550da474 | ||
|
|
90e7e650c9 | ||
|
|
bc4a6d56f4 | ||
|
|
3603cec7c2 | ||
|
|
5cde647c29 | ||
|
|
008d3e508e | ||
|
|
a3304e8b8b | ||
|
|
64fe7e10ab | ||
|
|
e9877e7a3d | ||
|
|
08ec01d1e7 | ||
|
|
1fbf83816b | ||
|
|
5e93fa4c6b | ||
|
|
9f40abc12a | ||
|
|
e8fa2511ff | ||
|
|
fa464ca483 | ||
|
|
b4ebe8432e | ||
|
|
8bbe9dd87b | ||
|
|
fe6e673864 | ||
|
|
f330ef6c4d | ||
|
|
87b75cce16 | ||
|
|
3853a1fac4 | ||
|
|
f9ebf74091 | ||
|
|
939a5edf3d | ||
|
|
788cb158ce | ||
|
|
ab028eb6a8 | ||
|
|
e0eebde993 | ||
|
|
729bc7c208 | ||
|
|
8695c08bcc | ||
|
|
39b6646e66 | ||
|
|
c7cf716180 | ||
|
|
8ae3bb2104 | ||
|
|
8733f74d59 | ||
|
|
17a8ac91e0 | ||
|
|
a7fc5274ad | ||
|
|
7e80f3b646 | ||
|
|
a4908213a6 | ||
|
|
af606aab9b | ||
|
|
98951ba26c | ||
|
|
171cffa505 | ||
|
|
a642e1c075 | ||
|
|
3cf91283f8 | ||
|
|
1db67b4a87 | ||
|
|
b7c1f2a135 | ||
|
|
cdd9fc09cd | ||
|
|
44fb206148 | ||
|
|
b3f86d8654 | ||
|
|
8135c1f606 | ||
|
|
59aea9e871 | ||
|
|
9a10addb44 | ||
|
|
b32f6298e2 | ||
|
|
856ed7c43d | ||
|
|
96268a80d4 | ||
|
|
2ac72333fa | ||
|
|
fe2183dc2f | ||
|
|
491ebbf79a | ||
|
|
43ac8e5494 | ||
|
|
ebe96021b0 | ||
|
|
97c1338833 | ||
|
|
c17e40115f | ||
|
|
73426dfaa3 | ||
|
|
425432ba6c | ||
|
|
4f5ed82b3c | ||
|
|
ae9991f3ba | ||
|
|
b6cb346adf | ||
|
|
79e4b2847f | ||
|
|
b1c17169d9 | ||
|
|
234d814122 | ||
|
|
b5d4f87e7e | ||
|
|
e07a949665 | ||
|
|
ae7d884582 | ||
|
|
ecdde1a996 | ||
|
|
e25b75a28e | ||
|
|
9b5e33d6f0 | ||
|
|
dea868a4b0 | ||
|
|
ac4e8f2fc5 | ||
|
|
ed7c7b5c58 | ||
|
|
09772c4e77 | ||
|
|
47fdf06e34 | ||
|
|
55aa530dc1 | ||
|
|
d8134903de | ||
|
|
654a11c84c | ||
|
|
5759211ff8 | ||
|
|
60aceba2bb | ||
|
|
d43e283e5e | ||
|
|
e0e30f00a1 | ||
|
|
4948b1053b | ||
|
|
0e8b440650 | ||
|
|
e13d2a783e | ||
|
|
55dfea8c18 | ||
|
|
f3b363a385 | ||
|
|
42b669690a | ||
|
|
9504447adc | ||
|
|
b3248c8807 | ||
|
|
c6c5b8fb54 | ||
|
|
7c3085aaec | ||
|
|
e64a123d00 | ||
|
|
e5304410a4 | ||
|
|
456221d165 | ||
|
|
f09c51c34e | ||
|
|
ad35fbef03 | ||
|
|
79f05591c9 | ||
|
|
ed244d3b54 | ||
|
|
dc961c3e78 | ||
|
|
890812af1b | ||
|
|
052648c3f5 | ||
|
|
042aa9023b | ||
|
|
f4100841f8 | ||
|
|
cdfd25f314 | ||
|
|
1ba5266bd9 | ||
|
|
83f68a013e | ||
|
|
63211d8c82 | ||
|
|
886dda0962 | ||
|
|
6414efe83b | ||
|
|
7785cde587 | ||
|
|
d98f49e67b | ||
|
|
a6b9844296 | ||
|
|
8d5b46cd10 | ||
|
|
3557bafa5c | ||
|
|
c87739bb55 | ||
|
|
2d95683bd5 | ||
|
|
d656d37180 | ||
|
|
e444722098 | ||
|
|
d561006290 | ||
|
|
2c27ddaf7e | ||
|
|
ae1b45495b | ||
|
|
ebe522731f | ||
|
|
bd4630a321 | ||
|
|
025d53342e | ||
|
|
ff7c0a1d90 | ||
|
|
4b68ef407f | ||
|
|
355a662976 | ||
|
|
3d169f1f34 | ||
|
|
c316c2433d |
@@ -0,0 +1,172 @@
|
||||
name: CI
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
|
||||
env:
|
||||
RUSTFLAGS: -Dwarnings
|
||||
RUST_BACKTRACE: 1
|
||||
nightly: nightly-2021-11-05
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
|
||||
jobs:
|
||||
# Check formatting
|
||||
rustfmt:
|
||||
name: rustfmt
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Install Rust
|
||||
run: rustup update stable && rustup default stable
|
||||
- name: Check formatting
|
||||
run: cargo fmt --all -- --check
|
||||
|
||||
# TODO
|
||||
# # Apply clippy lints
|
||||
# clippy:
|
||||
# name: clippy
|
||||
# runs-on: ubuntu-latest
|
||||
# steps:
|
||||
# - uses: actions/checkout@v3
|
||||
# - name: Apply clippy lints
|
||||
# run: cargo clippy --all-features
|
||||
|
||||
# This represents the minimum Rust version supported by
|
||||
# Bytes. Updating this should be done in a dedicated PR.
|
||||
#
|
||||
# Tests are not run as tests may require newer versions of
|
||||
# rust.
|
||||
minrust:
|
||||
name: minrust
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Install Rust
|
||||
run: rustup update 1.39.0 && rustup default 1.39.0
|
||||
- name: Check
|
||||
run: . ci/test-stable.sh check
|
||||
|
||||
# Stable
|
||||
stable:
|
||||
name: stable
|
||||
strategy:
|
||||
matrix:
|
||||
os:
|
||||
- ubuntu-latest
|
||||
- macos-latest
|
||||
- windows-latest
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Install Rust
|
||||
# --no-self-update is necessary because the windows environment cannot self-update rustup.exe.
|
||||
run: rustup update stable --no-self-update && rustup default stable
|
||||
- name: Test
|
||||
run: . ci/test-stable.sh test
|
||||
|
||||
# Nightly
|
||||
nightly:
|
||||
name: nightly
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Install Rust
|
||||
run: rustup update $nightly && rustup default $nightly
|
||||
- name: Test
|
||||
run: . ci/test-stable.sh test
|
||||
|
||||
# Run tests on some extra platforms
|
||||
cross:
|
||||
name: cross
|
||||
strategy:
|
||||
matrix:
|
||||
target:
|
||||
- i686-unknown-linux-gnu
|
||||
- armv7-unknown-linux-gnueabihf
|
||||
- powerpc-unknown-linux-gnu
|
||||
- powerpc64-unknown-linux-gnu
|
||||
- wasm32-unknown-unknown
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Install Rust
|
||||
run: rustup update stable && rustup default stable
|
||||
- name: cross build --target ${{ matrix.target }}
|
||||
run: |
|
||||
cargo install cross
|
||||
cross build --target ${{ matrix.target }}
|
||||
if: matrix.target != 'wasm32-unknown-unknown'
|
||||
# WASM support
|
||||
- name: cargo build --target ${{ matrix.target }}
|
||||
run: |
|
||||
rustup target add ${{ matrix.target }}
|
||||
cargo build --target ${{ matrix.target }}
|
||||
if: matrix.target == 'wasm32-unknown-unknown'
|
||||
|
||||
# Sanitizers
|
||||
tsan:
|
||||
name: tsan
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Install Rust
|
||||
run: rustup update $nightly && rustup default $nightly
|
||||
- name: Install rust-src
|
||||
run: rustup component add rust-src
|
||||
- name: ASAN / TSAN
|
||||
run: . ci/tsan.sh
|
||||
miri:
|
||||
name: miri
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Miri
|
||||
run: ci/miri.sh
|
||||
|
||||
# Loom
|
||||
loom:
|
||||
name: loom
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Install Rust
|
||||
run: rustup update $nightly && rustup default $nightly
|
||||
- name: Loom tests
|
||||
run: RUSTFLAGS="--cfg loom -Dwarnings" cargo test --lib
|
||||
|
||||
publish_docs:
|
||||
name: Publish Documentation
|
||||
needs:
|
||||
- rustfmt
|
||||
# - clippy
|
||||
- stable
|
||||
- nightly
|
||||
- minrust
|
||||
- cross
|
||||
- tsan
|
||||
- loom
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Install Rust
|
||||
run: rustup update stable && rustup default stable
|
||||
- name: Build documentation
|
||||
run: cargo doc --no-deps --all-features
|
||||
env:
|
||||
RUSTDOCFLAGS: --cfg docsrs
|
||||
- name: Publish documentation
|
||||
run: |
|
||||
cd target/doc
|
||||
git init
|
||||
git add .
|
||||
git -c user.name='ci' -c user.email='ci' commit -m 'Deploy Bytes API documentation'
|
||||
git push -f -q https://git:${{ secrets.github_token }}@github.com/${{ github.repository }} HEAD:gh-pages
|
||||
if: github.event_name == 'push' && github.event.ref == 'refs/heads/master' && github.repository == 'tokio-rs/bytes'
|
||||
-85
@@ -1,85 +0,0 @@
|
||||
---
|
||||
dist: trusty
|
||||
language: rust
|
||||
services: docker
|
||||
sudo: required
|
||||
rust: stable
|
||||
|
||||
env:
|
||||
global:
|
||||
- CRATE_NAME=bytes
|
||||
# Default job
|
||||
- TARGET=x86_64-unknown-linux-gnu
|
||||
- secure: "f17G5kb6uAQlAG9+GknFFYAmngGBqy9h+3FtNbp3mXTI0FOLltz00Ul5kGPysE4eagypm/dWOuvBkNjN01jhE6fCbekmInEsobIuanatrk6TvXT6caJqykxhPJC2cUoq8pKnMqEOuucEqPPUH6Qy6Hz4/2cRu5JV22Uv9dtS29Q="
|
||||
|
||||
matrix:
|
||||
include:
|
||||
# Run build on oldest supported rust version. Do not change the rust
|
||||
# version without a Github issue first.
|
||||
#
|
||||
# This job will also build and deploy the docs to gh-pages.
|
||||
- env: TARGET=x86_64-unknown-linux-gnu
|
||||
rust: 1.15.0
|
||||
after_success:
|
||||
- |
|
||||
pip install 'travis-cargo<0.2' --user &&
|
||||
export PATH=$HOME/.local/bin:$PATH
|
||||
- travis-cargo doc
|
||||
- travis-cargo doc-upload
|
||||
|
||||
# Run tests on some extra platforms
|
||||
- env: TARGET=i686-unknown-linux-gnu
|
||||
- env: TARGET=armv7-unknown-linux-gnueabihf
|
||||
- env: RUST_TEST_THREADS=1 TARGET=powerpc-unknown-linux-gnu
|
||||
- env: RUST_TEST_THREADS=1 TARGET=powerpc64-unknown-linux-gnu
|
||||
|
||||
# Serde implementation
|
||||
- env: EXTRA_ARGS="--features serde"
|
||||
|
||||
# WASM support
|
||||
- rust: beta
|
||||
script:
|
||||
- rustup target add wasm32-unknown-unknown
|
||||
- cargo build --target=wasm32-unknown-unknown
|
||||
|
||||
# Sanitizers
|
||||
- rust: nightly
|
||||
os: linux
|
||||
script:
|
||||
- |
|
||||
set -e
|
||||
|
||||
export RUST_TEST_THREADS=1
|
||||
export ASAN_OPTIONS="detect_odr_violation=0 detect_leaks=0"
|
||||
export TSAN_OPTIONS="suppressions=`pwd`/ci/tsan"
|
||||
|
||||
# Run address sanitizer
|
||||
RUSTFLAGS="-Z sanitizer=address" \
|
||||
cargo test --tests --target x86_64-unknown-linux-gnu
|
||||
|
||||
# Run thread sanitizer
|
||||
RUSTFLAGS="-Z sanitizer=thread" \
|
||||
cargo test --tests --target x86_64-unknown-linux-gnu
|
||||
|
||||
before_install: set -e
|
||||
|
||||
install:
|
||||
- sh ci/install.sh
|
||||
- source ~/.cargo/env || true
|
||||
|
||||
script:
|
||||
- bash ci/script.sh
|
||||
|
||||
after_script: set +e
|
||||
|
||||
before_deploy:
|
||||
- sh ci/before_deploy.sh
|
||||
|
||||
cache: cargo
|
||||
before_cache:
|
||||
# Travis can't cache files that are not readable by "others"
|
||||
- chmod -R a+r $HOME/.cargo
|
||||
|
||||
notifications:
|
||||
email:
|
||||
on_success: never
|
||||
+189
@@ -1,3 +1,192 @@
|
||||
# 1.2.1 (July 30, 2022)
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix unbounded memory growth when using `reserve` (#560)
|
||||
|
||||
# 1.2.0 (July 19, 2022)
|
||||
|
||||
### Added
|
||||
|
||||
- Add `BytesMut::zeroed` (#517)
|
||||
- Implement `Extend<Bytes>` for `BytesMut` (#527)
|
||||
- Add conversion from `BytesMut` to `Vec<u8>` (#543, #554)
|
||||
- Add conversion from `Bytes` to `Vec<u8>` (#547)
|
||||
- Add `UninitSlice::as_uninit_slice_mut()` (#548)
|
||||
- Add const to `Bytes::{len,is_empty}` (#514)
|
||||
|
||||
### Changed
|
||||
|
||||
- Reuse vector in `BytesMut::reserve` (#539, #544)
|
||||
|
||||
### Fixed
|
||||
|
||||
- Make miri happy (#515, #523, #542, #545, #553)
|
||||
- Make tsan happy (#541)
|
||||
- Fix `remaining_mut()` on chain (#488)
|
||||
- Fix amortized asymptotics of `BytesMut` (#555)
|
||||
|
||||
### Documented
|
||||
|
||||
- Redraw layout diagram with box drawing characters (#539)
|
||||
- Clarify `BytesMut::unsplit` docs (#535)
|
||||
|
||||
# 1.1.0 (August 25, 2021)
|
||||
|
||||
### Added
|
||||
|
||||
- `BufMut::put_bytes(self, val, cnt)` (#487)
|
||||
- Implement `From<Box<[u8]>>` for `Bytes` (#504)
|
||||
|
||||
### Changed
|
||||
|
||||
- Override `put_slice` for `&mut [u8]` (#483)
|
||||
- Panic on integer overflow in `Chain::remaining` (#482)
|
||||
- Add inline tags to `UninitSlice` methods (#443)
|
||||
- Override `copy_to_bytes` for Chain and Take (#481)
|
||||
- Keep capacity when unsplit on empty other buf (#502)
|
||||
|
||||
### Documented
|
||||
|
||||
- Clarify `BufMut` allocation guarantees (#501)
|
||||
- Clarify `BufMut::put_int` behavior (#486)
|
||||
- Clarify actions of `clear` and `truncate`. (#508)
|
||||
|
||||
# 1.0.1 (January 11, 2021)
|
||||
|
||||
### Changed
|
||||
- mark `Vec::put_slice` with `#[inline]` (#459)
|
||||
|
||||
### Fixed
|
||||
- Fix deprecation warning (#457)
|
||||
- use `Box::into_raw` instead of `mem::forget`-in-disguise (#458)
|
||||
|
||||
# 1.0.0 (December 22, 2020)
|
||||
|
||||
### Changed
|
||||
- Rename `Buf`/`BufMut` methods `bytes()` and `bytes_mut()` to `chunk()` and `chunk_mut()` (#450)
|
||||
|
||||
### Removed
|
||||
- remove unused Buf implementation. (#449)
|
||||
|
||||
# 0.6.0 (October 21, 2020)
|
||||
|
||||
API polish in preparation for a 1.0 release.
|
||||
|
||||
### Changed
|
||||
- `BufMut` is now an `unsafe` trait (#432).
|
||||
- `BufMut::bytes_mut()` returns `&mut UninitSlice`, a type owned by `bytes` to
|
||||
avoid undefined behavior (#433).
|
||||
- `Buf::copy_to_bytes(len)` replaces `Buf::into_bytes()` (#439).
|
||||
- `Buf`/`BufMut` utility methods are moved onto the trait and `*Ext` traits are
|
||||
removed (#431).
|
||||
|
||||
### Removed
|
||||
- `BufMut::bytes_vectored_mut()` (#430).
|
||||
- `new` methods on combinator types (#434).
|
||||
|
||||
# 0.5.6 (July 13, 2020)
|
||||
|
||||
- Improve `BytesMut` to reuse buffer when fully `advance`d.
|
||||
- Mark `BytesMut::{as_mut, set_len}` with `#[inline]`.
|
||||
- Relax synchronization when cloning in shared vtable of `Bytes`.
|
||||
- Move `loom` to `dev-dependencies`.
|
||||
|
||||
# 0.5.5 (June 18, 2020)
|
||||
|
||||
### Added
|
||||
- Allow using the `serde` feature in `no_std` environments (#385).
|
||||
|
||||
### Fix
|
||||
- Fix `BufMut::advance_mut` to panic if advanced passed the capacity (#354)..
|
||||
- Fix `BytesMut::freeze` ignoring amount previously `advance`d (#352).
|
||||
|
||||
# 0.5.4 (January 23, 2020)
|
||||
|
||||
### Added
|
||||
- Make `Bytes::new` a `const fn`.
|
||||
- Add `From<BytesMut>` for `Bytes`.
|
||||
|
||||
### Fix
|
||||
- Fix reversed arguments in `PartialOrd` for `Bytes`.
|
||||
- Fix `Bytes::truncate` losing original capacity when repr is an unshared `Vec`.
|
||||
- Fix `Bytes::from(Vec)` when allocator gave `Vec` a pointer with LSB set.
|
||||
- Fix panic in `Bytes::slice_ref` if argument is an empty slice.
|
||||
|
||||
# 0.5.3 (December 12, 2019)
|
||||
|
||||
### Added
|
||||
- `must_use` attributes to `split`, `split_off`, and `split_to` methods (#337).
|
||||
|
||||
### Fix
|
||||
- Potential freeing of a null pointer in `Bytes` when constructed with an empty `Vec<u8>` (#341, #342).
|
||||
- Calling `Bytes::truncate` with a size large than the length will no longer clear the `Bytes` (#333).
|
||||
|
||||
# 0.5.2 (November 27, 2019)
|
||||
|
||||
### Added
|
||||
- `Limit` methods `into_inner`, `get_ref`, `get_mut`, `limit`, and `set_limit` (#325).
|
||||
|
||||
# 0.5.1 (November 25, 2019)
|
||||
|
||||
### Fix
|
||||
- Growth documentation for `BytesMut` (#321)
|
||||
|
||||
# 0.5.0 (November 25, 2019)
|
||||
|
||||
### Fix
|
||||
- Potential overflow in `copy_to_slice`
|
||||
|
||||
### Changed
|
||||
- Increased minimum supported Rust version to 1.39.
|
||||
- `Bytes` is now a "trait object", allowing for custom allocation strategies (#298)
|
||||
- `BytesMut` implicitly grows internal storage. `remaining_mut()` returns
|
||||
`usize::MAX` (#316).
|
||||
- `BufMut::bytes_mut` returns `&mut [MaybeUninit<u8>]` to reflect the unknown
|
||||
initialization state (#305).
|
||||
- `Buf` / `BufMut` implementations for `&[u8]` and `&mut [u8]`
|
||||
respectively (#261).
|
||||
- Move `Buf` / `BufMut` "extra" functions to an extension trait (#306).
|
||||
- `BufMutExt::limit` (#309).
|
||||
- `Bytes::slice` takes a `RangeBounds` argument (#265).
|
||||
- `Bytes::from_static` is now a `const fn` (#311).
|
||||
- A multitude of smaller performance optimizations.
|
||||
|
||||
### Added
|
||||
- `no_std` support (#281).
|
||||
- `get_*`, `put_*`, `get_*_le`, and `put_*le` accessors for handling byte order.
|
||||
- `BorrowMut` implementation for `BytesMut` (#185).
|
||||
|
||||
### Removed
|
||||
- `IntoBuf` (#288).
|
||||
- `Buf` implementation for `&str` (#301).
|
||||
- `byteorder` dependency (#280).
|
||||
- `iovec` dependency, use `std::IoSlice` instead (#263).
|
||||
- optional `either` dependency (#315).
|
||||
- optional `i128` feature -- now available on stable. (#276).
|
||||
|
||||
# 0.4.12 (March 6, 2019)
|
||||
|
||||
### Added
|
||||
- Implement `FromIterator<&'a u8>` for `BytesMut`/`Bytes` (#244).
|
||||
- Implement `Buf` for `VecDeque` (#249).
|
||||
|
||||
# 0.4.11 (November 17, 2018)
|
||||
|
||||
* Use raw pointers for potentially racy loads (#233).
|
||||
* Implement `BufRead` for `buf::Reader` (#232).
|
||||
* Documentation tweaks (#234).
|
||||
|
||||
# 0.4.10 (September 4, 2018)
|
||||
|
||||
* impl `Buf` and `BufMut` for `Either` (#225).
|
||||
* Add `Bytes::slice_ref` (#208).
|
||||
|
||||
# 0.4.9 (July 12, 2018)
|
||||
|
||||
* Add 128 bit number support behind a feature flag (#209).
|
||||
* Implement `IntoBuf` for `&mut [u8]`
|
||||
|
||||
# 0.4.8 (May 25, 2018)
|
||||
|
||||
* Fix panic in `BytesMut` `FromIterator` implementation.
|
||||
|
||||
+25
-19
@@ -1,28 +1,34 @@
|
||||
[package]
|
||||
|
||||
name = "bytes"
|
||||
version = "0.4.8" # don't forget to update html_root_url
|
||||
license = "MIT/Apache-2.0"
|
||||
authors = ["Carl Lerche <[email protected]>"]
|
||||
description = "Types and traits for working with bytes"
|
||||
documentation = "https://carllerche.github.io/bytes/bytes"
|
||||
homepage = "https://github.com/carllerche/bytes"
|
||||
repository = "https://github.com/carllerche/bytes"
|
||||
readme = "README.md"
|
||||
keywords = ["buffers", "zero-copy", "io"]
|
||||
exclude = [
|
||||
".gitignore",
|
||||
".travis.yml",
|
||||
"deploy.sh",
|
||||
"bench/**/*",
|
||||
"test/**/*"
|
||||
name = "bytes"
|
||||
# When releasing to crates.io:
|
||||
# - Update CHANGELOG.md.
|
||||
# - Create "v1.x.y" git tag.
|
||||
version = "1.2.1"
|
||||
license = "MIT"
|
||||
authors = [
|
||||
"Carl Lerche <[email protected]>",
|
||||
"Sean McArthur <[email protected]>",
|
||||
]
|
||||
description = "Types and traits for working with bytes"
|
||||
repository = "https://github.com/tokio-rs/bytes"
|
||||
readme = "README.md"
|
||||
keywords = ["buffers", "zero-copy", "io"]
|
||||
categories = ["network-programming", "data-structures"]
|
||||
edition = "2018"
|
||||
|
||||
[features]
|
||||
default = ["std"]
|
||||
std = []
|
||||
|
||||
[dependencies]
|
||||
byteorder = "1.0.0"
|
||||
iovec = "0.1"
|
||||
serde = { version = "1.0", optional = true }
|
||||
serde = { version = "1.0.60", optional = true, default-features = false, features = ["alloc"] }
|
||||
|
||||
[dev-dependencies]
|
||||
serde_test = "1.0"
|
||||
|
||||
[target.'cfg(loom)'.dev-dependencies]
|
||||
loom = "0.5"
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
rustdoc-args = ["--cfg", "docsrs"]
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Copyright (c) 2017 Carl Lerche
|
||||
Copyright (c) 2018 Carl Lerche
|
||||
|
||||
Permission is hereby granted, free of charge, to any
|
||||
person obtaining a copy of this software and associated
|
||||
-201
@@ -1,201 +0,0 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright 2017 Carl Lerche
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
@@ -2,10 +2,15 @@
|
||||
|
||||
A utility library for working with bytes.
|
||||
|
||||
[](https://crates.io/crates/bytes)
|
||||
[](https://travis-ci.org/carllerche/bytes)
|
||||
[![Crates.io][crates-badge]][crates-url]
|
||||
[![Build Status][ci-badge]][ci-url]
|
||||
|
||||
[Documentation](https://carllerche.github.io/bytes/bytes/index.html)
|
||||
[crates-badge]: https://img.shields.io/crates/v/bytes.svg
|
||||
[crates-url]: https://crates.io/crates/bytes
|
||||
[ci-badge]: https://github.com/tokio-rs/bytes/workflows/CI/badge.svg
|
||||
[ci-url]: https://github.com/tokio-rs/bytes/actions
|
||||
|
||||
[Documentation](https://docs.rs/bytes)
|
||||
|
||||
## Usage
|
||||
|
||||
@@ -13,14 +18,12 @@ To use `bytes`, first add this to your `Cargo.toml`:
|
||||
|
||||
```toml
|
||||
[dependencies]
|
||||
bytes = "0.4"
|
||||
bytes = "1"
|
||||
```
|
||||
|
||||
Next, add this to your crate:
|
||||
|
||||
```rust
|
||||
extern crate bytes;
|
||||
|
||||
use bytes::{Bytes, BytesMut, Buf, BufMut};
|
||||
```
|
||||
|
||||
@@ -30,13 +33,15 @@ Serde support is optional and disabled by default. To enable use the feature `se
|
||||
|
||||
```toml
|
||||
[dependencies]
|
||||
bytes = { version = "0.4", features = ["serde"] }
|
||||
bytes = { version = "1", features = ["serde"] }
|
||||
```
|
||||
|
||||
# License
|
||||
## License
|
||||
|
||||
`bytes` is primarily distributed under the terms of both the MIT license and the
|
||||
Apache License (Version 2.0), with portions covered by various BSD-like
|
||||
licenses.
|
||||
This project is licensed under the [MIT license](LICENSE).
|
||||
|
||||
See LICENSE-APACHE, and LICENSE-MIT for details.
|
||||
### Contribution
|
||||
|
||||
Unless you explicitly state otherwise, any contribution intentionally submitted
|
||||
for inclusion in `bytes` by you, shall be licensed as MIT, without any additional
|
||||
terms or conditions.
|
||||
|
||||
+186
@@ -0,0 +1,186 @@
|
||||
#![feature(test)]
|
||||
#![warn(rust_2018_idioms)]
|
||||
|
||||
extern crate test;
|
||||
|
||||
use bytes::Buf;
|
||||
use test::Bencher;
|
||||
|
||||
/// Dummy Buf implementation
|
||||
struct TestBuf {
|
||||
buf: &'static [u8],
|
||||
readlens: &'static [usize],
|
||||
init_pos: usize,
|
||||
pos: usize,
|
||||
readlen_pos: usize,
|
||||
readlen: usize,
|
||||
}
|
||||
impl TestBuf {
|
||||
fn new(buf: &'static [u8], readlens: &'static [usize], init_pos: usize) -> TestBuf {
|
||||
let mut buf = TestBuf {
|
||||
buf,
|
||||
readlens,
|
||||
init_pos,
|
||||
pos: 0,
|
||||
readlen_pos: 0,
|
||||
readlen: 0,
|
||||
};
|
||||
buf.reset();
|
||||
buf
|
||||
}
|
||||
fn reset(&mut self) {
|
||||
self.pos = self.init_pos;
|
||||
self.readlen_pos = 0;
|
||||
self.next_readlen();
|
||||
}
|
||||
/// Compute the length of the next read :
|
||||
/// - use the next value specified in readlens (capped by remaining) if any
|
||||
/// - else the remaining
|
||||
fn next_readlen(&mut self) {
|
||||
self.readlen = self.buf.len() - self.pos;
|
||||
if let Some(readlen) = self.readlens.get(self.readlen_pos) {
|
||||
self.readlen = std::cmp::min(self.readlen, *readlen);
|
||||
self.readlen_pos += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
impl Buf for TestBuf {
|
||||
fn remaining(&self) -> usize {
|
||||
self.buf.len() - self.pos
|
||||
}
|
||||
fn advance(&mut self, cnt: usize) {
|
||||
self.pos += cnt;
|
||||
assert!(self.pos <= self.buf.len());
|
||||
self.next_readlen();
|
||||
}
|
||||
fn chunk(&self) -> &[u8] {
|
||||
if self.readlen == 0 {
|
||||
Default::default()
|
||||
} else {
|
||||
&self.buf[self.pos..self.pos + self.readlen]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Dummy Buf implementation
|
||||
/// version with methods forced to not be inlined (to simulate costly calls)
|
||||
struct TestBufC {
|
||||
inner: TestBuf,
|
||||
}
|
||||
impl TestBufC {
|
||||
fn new(buf: &'static [u8], readlens: &'static [usize], init_pos: usize) -> TestBufC {
|
||||
TestBufC {
|
||||
inner: TestBuf::new(buf, readlens, init_pos),
|
||||
}
|
||||
}
|
||||
fn reset(&mut self) {
|
||||
self.inner.reset()
|
||||
}
|
||||
}
|
||||
impl Buf for TestBufC {
|
||||
#[inline(never)]
|
||||
fn remaining(&self) -> usize {
|
||||
self.inner.remaining()
|
||||
}
|
||||
#[inline(never)]
|
||||
fn advance(&mut self, cnt: usize) {
|
||||
self.inner.advance(cnt)
|
||||
}
|
||||
#[inline(never)]
|
||||
fn chunk(&self) -> &[u8] {
|
||||
self.inner.chunk()
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! bench {
|
||||
($fname:ident, testbuf $testbuf:ident $readlens:expr, $method:ident $(,$arg:expr)*) => (
|
||||
#[bench]
|
||||
fn $fname(b: &mut Bencher) {
|
||||
let mut bufs = [
|
||||
$testbuf::new(&[1u8; 8+0], $readlens, 0),
|
||||
$testbuf::new(&[1u8; 8+1], $readlens, 1),
|
||||
$testbuf::new(&[1u8; 8+2], $readlens, 2),
|
||||
$testbuf::new(&[1u8; 8+3], $readlens, 3),
|
||||
$testbuf::new(&[1u8; 8+4], $readlens, 4),
|
||||
$testbuf::new(&[1u8; 8+5], $readlens, 5),
|
||||
$testbuf::new(&[1u8; 8+6], $readlens, 6),
|
||||
$testbuf::new(&[1u8; 8+7], $readlens, 7),
|
||||
];
|
||||
b.iter(|| {
|
||||
for i in 0..8 {
|
||||
bufs[i].reset();
|
||||
let buf: &mut dyn Buf = &mut bufs[i]; // type erasure
|
||||
test::black_box(buf.$method($($arg,)*));
|
||||
}
|
||||
})
|
||||
}
|
||||
);
|
||||
($fname:ident, slice, $method:ident $(,$arg:expr)*) => (
|
||||
#[bench]
|
||||
fn $fname(b: &mut Bencher) {
|
||||
// buf must be long enough for one read of 8 bytes starting at pos 7
|
||||
let arr = [1u8; 8+7];
|
||||
b.iter(|| {
|
||||
for i in 0..8 {
|
||||
let mut buf = &arr[i..];
|
||||
let buf = &mut buf as &mut dyn Buf; // type erasure
|
||||
test::black_box(buf.$method($($arg,)*));
|
||||
}
|
||||
})
|
||||
}
|
||||
);
|
||||
($fname:ident, option) => (
|
||||
#[bench]
|
||||
fn $fname(b: &mut Bencher) {
|
||||
let data = [1u8; 1];
|
||||
b.iter(|| {
|
||||
for _ in 0..8 {
|
||||
let mut buf = Some(data);
|
||||
let buf = &mut buf as &mut dyn Buf; // type erasure
|
||||
test::black_box(buf.get_u8());
|
||||
}
|
||||
})
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
macro_rules! bench_group {
|
||||
($method:ident $(,$arg:expr)*) => (
|
||||
bench!(slice, slice, $method $(,$arg)*);
|
||||
bench!(tbuf_1, testbuf TestBuf &[], $method $(,$arg)*);
|
||||
bench!(tbuf_1_costly, testbuf TestBufC &[], $method $(,$arg)*);
|
||||
bench!(tbuf_2, testbuf TestBuf &[1], $method $(,$arg)*);
|
||||
bench!(tbuf_2_costly, testbuf TestBufC &[1], $method $(,$arg)*);
|
||||
// bench!(tbuf_onebyone, testbuf TestBuf &[1,1,1,1,1,1,1,1], $method $(,$arg)*);
|
||||
// bench!(tbuf_onebyone_costly, testbuf TestBufC &[1,1,1,1,1,1,1,1], $method $(,$arg)*);
|
||||
);
|
||||
}
|
||||
|
||||
mod get_u8 {
|
||||
use super::*;
|
||||
bench_group!(get_u8);
|
||||
}
|
||||
mod get_u16 {
|
||||
use super::*;
|
||||
bench_group!(get_u16);
|
||||
}
|
||||
mod get_u32 {
|
||||
use super::*;
|
||||
bench_group!(get_u32);
|
||||
}
|
||||
mod get_u64 {
|
||||
use super::*;
|
||||
bench_group!(get_u64);
|
||||
}
|
||||
mod get_f32 {
|
||||
use super::*;
|
||||
bench_group!(get_f32);
|
||||
}
|
||||
mod get_f64 {
|
||||
use super::*;
|
||||
bench_group!(get_f64);
|
||||
}
|
||||
mod get_uint24 {
|
||||
use super::*;
|
||||
bench_group!(get_uint, 3);
|
||||
}
|
||||
+86
-183
@@ -1,31 +1,109 @@
|
||||
#![feature(test)]
|
||||
#![warn(rust_2018_idioms)]
|
||||
|
||||
extern crate bytes;
|
||||
extern crate test;
|
||||
|
||||
use bytes::Bytes;
|
||||
use test::Bencher;
|
||||
use bytes::{Bytes, BytesMut, BufMut};
|
||||
|
||||
#[bench]
|
||||
fn alloc_small(b: &mut Bencher) {
|
||||
fn deref_unique(b: &mut Bencher) {
|
||||
let buf = Bytes::from(vec![0; 1024]);
|
||||
|
||||
b.iter(|| {
|
||||
for _ in 0..1024 {
|
||||
test::black_box(BytesMut::with_capacity(12));
|
||||
test::black_box(&buf[..]);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn alloc_mid(b: &mut Bencher) {
|
||||
fn deref_shared(b: &mut Bencher) {
|
||||
let buf = Bytes::from(vec![0; 1024]);
|
||||
let _b2 = buf.clone();
|
||||
|
||||
b.iter(|| {
|
||||
test::black_box(BytesMut::with_capacity(128));
|
||||
for _ in 0..1024 {
|
||||
test::black_box(&buf[..]);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn alloc_big(b: &mut Bencher) {
|
||||
fn deref_static(b: &mut Bencher) {
|
||||
let buf = Bytes::from_static(b"hello world");
|
||||
|
||||
b.iter(|| {
|
||||
test::black_box(BytesMut::with_capacity(4096));
|
||||
for _ in 0..1024 {
|
||||
test::black_box(&buf[..]);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn clone_static(b: &mut Bencher) {
|
||||
let bytes =
|
||||
Bytes::from_static("hello world 1234567890 and have a good byte 0987654321".as_bytes());
|
||||
|
||||
b.iter(|| {
|
||||
for _ in 0..1024 {
|
||||
test::black_box(&bytes.clone());
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn clone_shared(b: &mut Bencher) {
|
||||
let bytes = Bytes::from(b"hello world 1234567890 and have a good byte 0987654321".to_vec());
|
||||
|
||||
b.iter(|| {
|
||||
for _ in 0..1024 {
|
||||
test::black_box(&bytes.clone());
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn clone_arc_vec(b: &mut Bencher) {
|
||||
use std::sync::Arc;
|
||||
let bytes = Arc::new(b"hello world 1234567890 and have a good byte 0987654321".to_vec());
|
||||
|
||||
b.iter(|| {
|
||||
for _ in 0..1024 {
|
||||
test::black_box(&bytes.clone());
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn from_long_slice(b: &mut Bencher) {
|
||||
let data = [0u8; 128];
|
||||
b.bytes = data.len() as u64;
|
||||
b.iter(|| {
|
||||
let buf = Bytes::copy_from_slice(&data[..]);
|
||||
test::black_box(buf);
|
||||
})
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn slice_empty(b: &mut Bencher) {
|
||||
b.iter(|| {
|
||||
// `clone` is to convert to ARC
|
||||
let b = Bytes::from(vec![17; 1024]).clone();
|
||||
for i in 0..1000 {
|
||||
test::black_box(b.slice(i % 100..i % 100));
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn slice_short_from_arc(b: &mut Bencher) {
|
||||
b.iter(|| {
|
||||
// `clone` is to convert to ARC
|
||||
let b = Bytes::from(vec![17; 1024]).clone();
|
||||
for i in 0..1000 {
|
||||
test::black_box(b.slice(1..2 + i % 10));
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -40,178 +118,3 @@ fn split_off_and_drop(b: &mut Bencher) {
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn deref_unique(b: &mut Bencher) {
|
||||
let mut buf = BytesMut::with_capacity(4096);
|
||||
buf.put(&[0u8; 1024][..]);
|
||||
|
||||
b.iter(|| {
|
||||
for _ in 0..1024 {
|
||||
test::black_box(&buf[..]);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn deref_unique_unroll(b: &mut Bencher) {
|
||||
let mut buf = BytesMut::with_capacity(4096);
|
||||
buf.put(&[0u8; 1024][..]);
|
||||
|
||||
b.iter(|| {
|
||||
for _ in 0..128 {
|
||||
test::black_box(&buf[..]);
|
||||
test::black_box(&buf[..]);
|
||||
test::black_box(&buf[..]);
|
||||
test::black_box(&buf[..]);
|
||||
test::black_box(&buf[..]);
|
||||
test::black_box(&buf[..]);
|
||||
test::black_box(&buf[..]);
|
||||
test::black_box(&buf[..]);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn deref_shared(b: &mut Bencher) {
|
||||
let mut buf = BytesMut::with_capacity(4096);
|
||||
buf.put(&[0u8; 1024][..]);
|
||||
let _b2 = buf.split_off(1024);
|
||||
|
||||
b.iter(|| {
|
||||
for _ in 0..1024 {
|
||||
test::black_box(&buf[..]);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn deref_inline(b: &mut Bencher) {
|
||||
let mut buf = BytesMut::with_capacity(8);
|
||||
buf.put(&[0u8; 8][..]);
|
||||
|
||||
b.iter(|| {
|
||||
for _ in 0..1024 {
|
||||
test::black_box(&buf[..]);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn deref_two(b: &mut Bencher) {
|
||||
let mut buf1 = BytesMut::with_capacity(8);
|
||||
buf1.put(&[0u8; 8][..]);
|
||||
|
||||
let mut buf2 = BytesMut::with_capacity(4096);
|
||||
buf2.put(&[0u8; 1024][..]);
|
||||
|
||||
b.iter(|| {
|
||||
for _ in 0..512 {
|
||||
test::black_box(&buf1[..]);
|
||||
test::black_box(&buf2[..]);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn alloc_write_split_to_mid(b: &mut Bencher) {
|
||||
b.iter(|| {
|
||||
let mut buf = BytesMut::with_capacity(128);
|
||||
buf.put_slice(&[0u8; 64]);
|
||||
test::black_box(buf.split_to(64));
|
||||
})
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn drain_write_drain(b: &mut Bencher) {
|
||||
let data = [0u8; 128];
|
||||
|
||||
b.iter(|| {
|
||||
let mut buf = BytesMut::with_capacity(1024);
|
||||
let mut parts = Vec::with_capacity(8);
|
||||
|
||||
for _ in 0..8 {
|
||||
buf.put(&data[..]);
|
||||
parts.push(buf.split_to(128));
|
||||
}
|
||||
|
||||
test::black_box(parts);
|
||||
})
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn fmt_write(b: &mut Bencher) {
|
||||
use std::fmt::Write;
|
||||
let mut buf = BytesMut::with_capacity(128);
|
||||
let s = "foo bar baz quux lorem ipsum dolor et";
|
||||
|
||||
b.bytes = s.len() as u64;
|
||||
b.iter(|| {
|
||||
let _ = write!(buf, "{}", s);
|
||||
test::black_box(&buf);
|
||||
unsafe { buf.set_len(0); }
|
||||
})
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn from_long_slice(b: &mut Bencher) {
|
||||
let data = [0u8; 128];
|
||||
b.bytes = data.len() as u64;
|
||||
b.iter(|| {
|
||||
let buf = BytesMut::from(&data[..]);
|
||||
test::black_box(buf);
|
||||
})
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn slice_empty(b: &mut Bencher) {
|
||||
b.iter(|| {
|
||||
let b = Bytes::from(vec![17; 1024]).clone();
|
||||
for i in 0..1000 {
|
||||
test::black_box(b.slice(i % 100, i % 100));
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn slice_short_from_arc(b: &mut Bencher) {
|
||||
b.iter(|| {
|
||||
// `clone` is to convert to ARC
|
||||
let b = Bytes::from(vec![17; 1024]).clone();
|
||||
for i in 0..1000 {
|
||||
test::black_box(b.slice(1, 2 + i % 10));
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// Keep in sync with bytes.rs
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
const INLINE_CAP: usize = 4 * 8 - 1;
|
||||
#[cfg(target_pointer_width = "32")]
|
||||
const INLINE_CAP: usize = 4 * 4 - 1;
|
||||
|
||||
#[bench]
|
||||
fn slice_avg_le_inline_from_arc(b: &mut Bencher) {
|
||||
b.iter(|| {
|
||||
// `clone` is to convert to ARC
|
||||
let b = Bytes::from(vec![17; 1024]).clone();
|
||||
for i in 0..1000 {
|
||||
// [1, INLINE_CAP]
|
||||
let len = 1 + i % (INLINE_CAP - 1);
|
||||
test::black_box(b.slice(i % 10, i % 10 + len));
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn slice_large_le_inline_from_arc(b: &mut Bencher) {
|
||||
b.iter(|| {
|
||||
// `clone` is to convert to ARC
|
||||
let b = Bytes::from(vec![17; 1024]).clone();
|
||||
for i in 0..1000 {
|
||||
// [INLINE_CAP - 10, INLINE_CAP]
|
||||
let len = INLINE_CAP - 9 + i % 10;
|
||||
test::black_box(b.slice(i % 10, i % 10 + len));
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -0,0 +1,266 @@
|
||||
#![feature(test)]
|
||||
#![warn(rust_2018_idioms)]
|
||||
|
||||
extern crate test;
|
||||
|
||||
use bytes::{BufMut, BytesMut};
|
||||
use test::Bencher;
|
||||
|
||||
#[bench]
|
||||
fn alloc_small(b: &mut Bencher) {
|
||||
b.iter(|| {
|
||||
for _ in 0..1024 {
|
||||
test::black_box(BytesMut::with_capacity(12));
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn alloc_mid(b: &mut Bencher) {
|
||||
b.iter(|| {
|
||||
test::black_box(BytesMut::with_capacity(128));
|
||||
})
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn alloc_big(b: &mut Bencher) {
|
||||
b.iter(|| {
|
||||
test::black_box(BytesMut::with_capacity(4096));
|
||||
})
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn deref_unique(b: &mut Bencher) {
|
||||
let mut buf = BytesMut::with_capacity(4096);
|
||||
buf.put(&[0u8; 1024][..]);
|
||||
|
||||
b.iter(|| {
|
||||
for _ in 0..1024 {
|
||||
test::black_box(&buf[..]);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn deref_unique_unroll(b: &mut Bencher) {
|
||||
let mut buf = BytesMut::with_capacity(4096);
|
||||
buf.put(&[0u8; 1024][..]);
|
||||
|
||||
b.iter(|| {
|
||||
for _ in 0..128 {
|
||||
test::black_box(&buf[..]);
|
||||
test::black_box(&buf[..]);
|
||||
test::black_box(&buf[..]);
|
||||
test::black_box(&buf[..]);
|
||||
test::black_box(&buf[..]);
|
||||
test::black_box(&buf[..]);
|
||||
test::black_box(&buf[..]);
|
||||
test::black_box(&buf[..]);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn deref_shared(b: &mut Bencher) {
|
||||
let mut buf = BytesMut::with_capacity(4096);
|
||||
buf.put(&[0u8; 1024][..]);
|
||||
let _b2 = buf.split_off(1024);
|
||||
|
||||
b.iter(|| {
|
||||
for _ in 0..1024 {
|
||||
test::black_box(&buf[..]);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn deref_two(b: &mut Bencher) {
|
||||
let mut buf1 = BytesMut::with_capacity(8);
|
||||
buf1.put(&[0u8; 8][..]);
|
||||
|
||||
let mut buf2 = BytesMut::with_capacity(4096);
|
||||
buf2.put(&[0u8; 1024][..]);
|
||||
|
||||
b.iter(|| {
|
||||
for _ in 0..512 {
|
||||
test::black_box(&buf1[..]);
|
||||
test::black_box(&buf2[..]);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn clone_frozen(b: &mut Bencher) {
|
||||
let bytes = BytesMut::from(&b"hello world 1234567890 and have a good byte 0987654321"[..])
|
||||
.split()
|
||||
.freeze();
|
||||
|
||||
b.iter(|| {
|
||||
for _ in 0..1024 {
|
||||
test::black_box(&bytes.clone());
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn alloc_write_split_to_mid(b: &mut Bencher) {
|
||||
b.iter(|| {
|
||||
let mut buf = BytesMut::with_capacity(128);
|
||||
buf.put_slice(&[0u8; 64]);
|
||||
test::black_box(buf.split_to(64));
|
||||
})
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn drain_write_drain(b: &mut Bencher) {
|
||||
let data = [0u8; 128];
|
||||
|
||||
b.iter(|| {
|
||||
let mut buf = BytesMut::with_capacity(1024);
|
||||
let mut parts = Vec::with_capacity(8);
|
||||
|
||||
for _ in 0..8 {
|
||||
buf.put(&data[..]);
|
||||
parts.push(buf.split_to(128));
|
||||
}
|
||||
|
||||
test::black_box(parts);
|
||||
})
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn fmt_write(b: &mut Bencher) {
|
||||
use std::fmt::Write;
|
||||
let mut buf = BytesMut::with_capacity(128);
|
||||
let s = "foo bar baz quux lorem ipsum dolor et";
|
||||
|
||||
b.bytes = s.len() as u64;
|
||||
b.iter(|| {
|
||||
let _ = write!(buf, "{}", s);
|
||||
test::black_box(&buf);
|
||||
unsafe {
|
||||
buf.set_len(0);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bytes_mut_extend(b: &mut Bencher) {
|
||||
let mut buf = BytesMut::with_capacity(256);
|
||||
let data = [33u8; 32];
|
||||
|
||||
b.bytes = data.len() as u64 * 4;
|
||||
b.iter(|| {
|
||||
for _ in 0..4 {
|
||||
buf.extend(&data);
|
||||
}
|
||||
test::black_box(&buf);
|
||||
unsafe {
|
||||
buf.set_len(0);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// BufMut for BytesMut vs Vec<u8>
|
||||
|
||||
#[bench]
|
||||
fn put_slice_bytes_mut(b: &mut Bencher) {
|
||||
let mut buf = BytesMut::with_capacity(256);
|
||||
let data = [33u8; 32];
|
||||
|
||||
b.bytes = data.len() as u64 * 4;
|
||||
b.iter(|| {
|
||||
for _ in 0..4 {
|
||||
buf.put_slice(&data);
|
||||
}
|
||||
test::black_box(&buf);
|
||||
unsafe {
|
||||
buf.set_len(0);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn put_u8_bytes_mut(b: &mut Bencher) {
|
||||
let mut buf = BytesMut::with_capacity(256);
|
||||
let cnt = 128;
|
||||
|
||||
b.bytes = cnt as u64;
|
||||
b.iter(|| {
|
||||
for _ in 0..cnt {
|
||||
buf.put_u8(b'x');
|
||||
}
|
||||
test::black_box(&buf);
|
||||
unsafe {
|
||||
buf.set_len(0);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn put_slice_vec(b: &mut Bencher) {
|
||||
let mut buf = Vec::<u8>::with_capacity(256);
|
||||
let data = [33u8; 32];
|
||||
|
||||
b.bytes = data.len() as u64 * 4;
|
||||
b.iter(|| {
|
||||
for _ in 0..4 {
|
||||
buf.put_slice(&data);
|
||||
}
|
||||
test::black_box(&buf);
|
||||
unsafe {
|
||||
buf.set_len(0);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn put_u8_vec(b: &mut Bencher) {
|
||||
let mut buf = Vec::<u8>::with_capacity(256);
|
||||
let cnt = 128;
|
||||
|
||||
b.bytes = cnt as u64;
|
||||
b.iter(|| {
|
||||
for _ in 0..cnt {
|
||||
buf.put_u8(b'x');
|
||||
}
|
||||
test::black_box(&buf);
|
||||
unsafe {
|
||||
buf.set_len(0);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn put_slice_vec_extend(b: &mut Bencher) {
|
||||
let mut buf = Vec::<u8>::with_capacity(256);
|
||||
let data = [33u8; 32];
|
||||
|
||||
b.bytes = data.len() as u64 * 4;
|
||||
b.iter(|| {
|
||||
for _ in 0..4 {
|
||||
buf.extend_from_slice(&data);
|
||||
}
|
||||
test::black_box(&buf);
|
||||
unsafe {
|
||||
buf.set_len(0);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn put_u8_vec_push(b: &mut Bencher) {
|
||||
let mut buf = Vec::<u8>::with_capacity(256);
|
||||
let cnt = 128;
|
||||
|
||||
b.bytes = cnt as u64;
|
||||
b.iter(|| {
|
||||
for _ in 0..cnt {
|
||||
buf.push(b'x');
|
||||
}
|
||||
test::black_box(&buf);
|
||||
unsafe {
|
||||
buf.set_len(0);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
# This script takes care of packaging the build artifacts that will go in the
|
||||
# release zipfile
|
||||
|
||||
$SRC_DIR = $PWD.Path
|
||||
$STAGE = [System.Guid]::NewGuid().ToString()
|
||||
|
||||
Set-Location $ENV:Temp
|
||||
New-Item -Type Directory -Name $STAGE
|
||||
Set-Location $STAGE
|
||||
|
||||
$ZIP = "$SRC_DIR\$($Env:CRATE_NAME)-$($Env:APPVEYOR_REPO_TAG_NAME)-$($Env:TARGET).zip"
|
||||
|
||||
# TODO Update this to package the right artifacts
|
||||
Copy-Item "$SRC_DIR\target\$($Env:TARGET)\release\hello.exe" '.\'
|
||||
|
||||
7z a "$ZIP" *
|
||||
|
||||
Push-AppveyorArtifact "$ZIP"
|
||||
|
||||
Remove-Item *.* -Force
|
||||
Set-Location ..
|
||||
Remove-Item $STAGE
|
||||
Set-Location $SRC_DIR
|
||||
@@ -1,33 +0,0 @@
|
||||
# This script takes care of building your crate and packaging it for release
|
||||
|
||||
set -ex
|
||||
|
||||
main() {
|
||||
local src=$(pwd) \
|
||||
stage=
|
||||
|
||||
case $TRAVIS_OS_NAME in
|
||||
linux)
|
||||
stage=$(mktemp -d)
|
||||
;;
|
||||
osx)
|
||||
stage=$(mktemp -d -t tmp)
|
||||
;;
|
||||
esac
|
||||
|
||||
test -f Cargo.lock || cargo generate-lockfile
|
||||
|
||||
# TODO Update this to build the artifacts that matter to you
|
||||
cross rustc --bin hello --target $TARGET --release -- -C lto
|
||||
|
||||
# TODO Update this to package the right artifacts
|
||||
cp target/$TARGET/release/hello $stage/
|
||||
|
||||
cd $stage
|
||||
tar czf $src/$CRATE_NAME-$TRAVIS_TAG-$TARGET.tar.gz *
|
||||
cd $src
|
||||
|
||||
rm -rf $stage
|
||||
}
|
||||
|
||||
main
|
||||
@@ -1,31 +0,0 @@
|
||||
set -ex
|
||||
|
||||
main() {
|
||||
curl https://sh.rustup.rs -sSf | \
|
||||
sh -s -- -y --default-toolchain $TRAVIS_RUST_VERSION
|
||||
|
||||
local target=
|
||||
if [ $TRAVIS_OS_NAME = linux ]; then
|
||||
target=x86_64-unknown-linux-gnu
|
||||
sort=sort
|
||||
else
|
||||
target=x86_64-apple-darwin
|
||||
sort=gsort # for `sort --sort-version`, from brew's coreutils.
|
||||
fi
|
||||
|
||||
# This fetches latest stable release
|
||||
local tag=$(git ls-remote --tags --refs --exit-code https://github.com/japaric/cross \
|
||||
| cut -d/ -f3 \
|
||||
| grep -E '^v[0-9.]+$' \
|
||||
| $sort --version-sort \
|
||||
| tail -n1)
|
||||
echo cross version: $tag
|
||||
curl -LSfs https://japaric.github.io/trust/install.sh | \
|
||||
sh -s -- \
|
||||
--force \
|
||||
--git japaric/cross \
|
||||
--tag $tag \
|
||||
--target $target
|
||||
}
|
||||
|
||||
main
|
||||
Executable
+11
@@ -0,0 +1,11 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
rustup toolchain install nightly --component miri
|
||||
rustup override set nightly
|
||||
cargo miri setup
|
||||
|
||||
export MIRIFLAGS="-Zmiri-strict-provenance"
|
||||
|
||||
cargo miri test
|
||||
cargo miri test --target mips64-unknown-linux-gnuabi64
|
||||
@@ -1,18 +0,0 @@
|
||||
# This script takes care of testing your crate
|
||||
|
||||
set -ex
|
||||
|
||||
main() {
|
||||
cross build --target $TARGET $EXTRA_ARGS
|
||||
|
||||
if [ ! -z $DISABLE_TESTS ]; then
|
||||
return
|
||||
fi
|
||||
|
||||
cross test --target $TARGET $EXTRA_ARGS
|
||||
}
|
||||
|
||||
# we don't run the "test phase" when doing deploys
|
||||
if [ -z $TRAVIS_TAG ]; then
|
||||
main
|
||||
fi
|
||||
@@ -0,0 +1,28 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -ex
|
||||
|
||||
cmd="${1:-test}"
|
||||
|
||||
# Install cargo-hack for feature flag test
|
||||
host=$(rustc -Vv | grep host | sed 's/host: //')
|
||||
curl -LsSf https://github.com/taiki-e/cargo-hack/releases/latest/download/cargo-hack-$host.tar.gz | tar xzf - -C ~/.cargo/bin
|
||||
|
||||
# Run with each feature
|
||||
# * --each-feature includes both default/no-default features
|
||||
# * --optional-deps is needed for serde feature
|
||||
cargo hack "${cmd}" --each-feature --optional-deps
|
||||
# Run with all features
|
||||
cargo "${cmd}" --all-features
|
||||
|
||||
cargo doc --no-deps --all-features
|
||||
|
||||
if [[ "${RUST_VERSION}" == "nightly"* ]]; then
|
||||
# Check benchmarks
|
||||
cargo check --benches
|
||||
|
||||
# Check minimal versions
|
||||
cargo clean
|
||||
cargo update -Zminimal-versions
|
||||
cargo check --all-features
|
||||
fi
|
||||
@@ -1,21 +0,0 @@
|
||||
# TSAN suppressions file for `bytes`
|
||||
|
||||
# TSAN does not understand fences and `Arc::drop` is implemented using a fence.
|
||||
# This causes many false positives.
|
||||
race:Arc*drop
|
||||
race:arc*Weak*drop
|
||||
|
||||
# `std` mpsc is not used in any Bytes code base. This race is triggered by some
|
||||
# rust runtime logic.
|
||||
race:std*mpsc_queue
|
||||
|
||||
# Not sure why this is warning, but it is in the test harness and not the library.
|
||||
race:TestEvent*clone
|
||||
race:test::run_tests_console::*closure
|
||||
|
||||
# Probably more fences in std.
|
||||
race:__call_tls_dtors
|
||||
|
||||
# `is_inline` is explicitly called concurrently without synchronization. The
|
||||
# safety explanation can be found in a comment.
|
||||
race:Inner::is_inline
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -ex
|
||||
|
||||
export ASAN_OPTIONS="detect_odr_violation=0 detect_leaks=0"
|
||||
|
||||
# Run address sanitizer
|
||||
RUSTFLAGS="-Z sanitizer=address" \
|
||||
cargo test --target x86_64-unknown-linux-gnu --test test_bytes --test test_buf --test test_buf_mut
|
||||
|
||||
# Run thread sanitizer
|
||||
RUSTFLAGS="-Z sanitizer=thread" \
|
||||
cargo -Zbuild-std test --target x86_64-unknown-linux-gnu --test test_bytes --test test_buf --test test_buf_mut
|
||||
@@ -0,0 +1 @@
|
||||
msrv = "1.39"
|
||||
File diff suppressed because it is too large
Load Diff
+438
-354
File diff suppressed because it is too large
Load Diff
+88
-72
@@ -1,10 +1,13 @@
|
||||
use {Buf, BufMut};
|
||||
use iovec::IoVec;
|
||||
use crate::buf::{IntoIter, UninitSlice};
|
||||
use crate::{Buf, BufMut, Bytes};
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
use std::io::IoSlice;
|
||||
|
||||
/// A `Chain` sequences two buffers.
|
||||
///
|
||||
/// `Chain` is an adapter that links two underlying buffers and provides a
|
||||
/// continous view across both buffers. It is able to sequence either immutable
|
||||
/// continuous view across both buffers. It is able to sequence either immutable
|
||||
/// buffers ([`Buf`] values) or mutable buffers ([`BufMut`] values).
|
||||
///
|
||||
/// This struct is generally created by calling [`Buf::chain`]. Please see that
|
||||
@@ -13,13 +16,12 @@ use iovec::IoVec;
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use bytes::{Bytes, Buf, IntoBuf};
|
||||
/// use bytes::buf::Chain;
|
||||
/// use bytes::{Bytes, Buf};
|
||||
///
|
||||
/// let buf = Bytes::from(&b"hello "[..]).into_buf()
|
||||
/// .chain(Bytes::from(&b"world"[..]));
|
||||
/// let mut buf = (&b"hello "[..])
|
||||
/// .chain(&b"world"[..]);
|
||||
///
|
||||
/// let full: Bytes = buf.collect();
|
||||
/// let full: Bytes = buf.copy_to_bytes(11);
|
||||
/// assert_eq!(full[..], b"hello world"[..]);
|
||||
/// ```
|
||||
///
|
||||
@@ -34,24 +36,8 @@ pub struct Chain<T, U> {
|
||||
|
||||
impl<T, U> Chain<T, U> {
|
||||
/// Creates a new `Chain` sequencing the provided values.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use bytes::BytesMut;
|
||||
/// use bytes::buf::Chain;
|
||||
///
|
||||
/// let buf = Chain::new(
|
||||
/// BytesMut::with_capacity(1024),
|
||||
/// BytesMut::with_capacity(1024));
|
||||
///
|
||||
/// // Use the chained buffer
|
||||
/// ```
|
||||
pub fn new(a: T, b: U) -> Chain<T, U> {
|
||||
Chain {
|
||||
a: a,
|
||||
b: b,
|
||||
}
|
||||
pub(crate) fn new(a: T, b: U) -> Chain<T, U> {
|
||||
Chain { a, b }
|
||||
}
|
||||
|
||||
/// Gets a reference to the first underlying `Buf`.
|
||||
@@ -59,12 +45,12 @@ impl<T, U> Chain<T, U> {
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use bytes::{Bytes, Buf, IntoBuf};
|
||||
/// use bytes::Buf;
|
||||
///
|
||||
/// let buf = Bytes::from(&b"hello"[..]).into_buf()
|
||||
/// .chain(Bytes::from(&b"world"[..]));
|
||||
/// let buf = (&b"hello"[..])
|
||||
/// .chain(&b"world"[..]);
|
||||
///
|
||||
/// assert_eq!(buf.first_ref().get_ref()[..], b"hello"[..]);
|
||||
/// assert_eq!(buf.first_ref()[..], b"hello"[..]);
|
||||
/// ```
|
||||
pub fn first_ref(&self) -> &T {
|
||||
&self.a
|
||||
@@ -75,15 +61,15 @@ impl<T, U> Chain<T, U> {
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use bytes::{Bytes, Buf, IntoBuf};
|
||||
/// use bytes::Buf;
|
||||
///
|
||||
/// let mut buf = Bytes::from(&b"hello "[..]).into_buf()
|
||||
/// .chain(Bytes::from(&b"world"[..]));
|
||||
/// let mut buf = (&b"hello"[..])
|
||||
/// .chain(&b"world"[..]);
|
||||
///
|
||||
/// buf.first_mut().set_position(1);
|
||||
/// buf.first_mut().advance(1);
|
||||
///
|
||||
/// let full: Bytes = buf.collect();
|
||||
/// assert_eq!(full[..], b"ello world"[..]);
|
||||
/// let full = buf.copy_to_bytes(9);
|
||||
/// assert_eq!(full, b"elloworld"[..]);
|
||||
/// ```
|
||||
pub fn first_mut(&mut self) -> &mut T {
|
||||
&mut self.a
|
||||
@@ -94,12 +80,12 @@ impl<T, U> Chain<T, U> {
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use bytes::{Bytes, Buf, IntoBuf};
|
||||
/// use bytes::Buf;
|
||||
///
|
||||
/// let buf = Bytes::from(&b"hello"[..]).into_buf()
|
||||
/// .chain(Bytes::from(&b"world"[..]));
|
||||
/// let buf = (&b"hello"[..])
|
||||
/// .chain(&b"world"[..]);
|
||||
///
|
||||
/// assert_eq!(buf.last_ref().get_ref()[..], b"world"[..]);
|
||||
/// assert_eq!(buf.last_ref()[..], b"world"[..]);
|
||||
/// ```
|
||||
pub fn last_ref(&self) -> &U {
|
||||
&self.b
|
||||
@@ -110,15 +96,15 @@ impl<T, U> Chain<T, U> {
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use bytes::{Bytes, Buf, IntoBuf};
|
||||
/// use bytes::Buf;
|
||||
///
|
||||
/// let mut buf = Bytes::from(&b"hello "[..]).into_buf()
|
||||
/// .chain(Bytes::from(&b"world"[..]));
|
||||
/// let mut buf = (&b"hello "[..])
|
||||
/// .chain(&b"world"[..]);
|
||||
///
|
||||
/// buf.last_mut().set_position(1);
|
||||
/// buf.last_mut().advance(1);
|
||||
///
|
||||
/// let full: Bytes = buf.collect();
|
||||
/// assert_eq!(full[..], b"hello orld"[..]);
|
||||
/// let full = buf.copy_to_bytes(10);
|
||||
/// assert_eq!(full, b"hello orld"[..]);
|
||||
/// ```
|
||||
pub fn last_mut(&mut self) -> &mut U {
|
||||
&mut self.b
|
||||
@@ -129,14 +115,14 @@ impl<T, U> Chain<T, U> {
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use bytes::{Bytes, Buf, IntoBuf};
|
||||
/// use bytes::Buf;
|
||||
///
|
||||
/// let buf = Bytes::from(&b"hello"[..]).into_buf()
|
||||
/// .chain(Bytes::from(&b"world"[..]));
|
||||
/// let chain = (&b"hello"[..])
|
||||
/// .chain(&b"world"[..]);
|
||||
///
|
||||
/// let (first, last) = buf.into_inner();
|
||||
/// assert_eq!(first.get_ref()[..], b"hello"[..]);
|
||||
/// assert_eq!(last.get_ref()[..], b"world"[..]);
|
||||
/// let (first, last) = chain.into_inner();
|
||||
/// assert_eq!(first[..], b"hello"[..]);
|
||||
/// assert_eq!(last[..], b"world"[..]);
|
||||
/// ```
|
||||
pub fn into_inner(self) -> (T, U) {
|
||||
(self.a, self.b)
|
||||
@@ -144,18 +130,19 @@ impl<T, U> Chain<T, U> {
|
||||
}
|
||||
|
||||
impl<T, U> Buf for Chain<T, U>
|
||||
where T: Buf,
|
||||
U: Buf,
|
||||
where
|
||||
T: Buf,
|
||||
U: Buf,
|
||||
{
|
||||
fn remaining(&self) -> usize {
|
||||
self.a.remaining() + self.b.remaining()
|
||||
self.a.remaining().checked_add(self.b.remaining()).unwrap()
|
||||
}
|
||||
|
||||
fn bytes(&self) -> &[u8] {
|
||||
fn chunk(&self) -> &[u8] {
|
||||
if self.a.has_remaining() {
|
||||
self.a.bytes()
|
||||
self.a.chunk()
|
||||
} else {
|
||||
self.b.bytes()
|
||||
self.b.chunk()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -177,26 +164,48 @@ impl<T, U> Buf for Chain<T, U>
|
||||
self.b.advance(cnt);
|
||||
}
|
||||
|
||||
fn bytes_vec<'a>(&'a self, dst: &mut [&'a IoVec]) -> usize {
|
||||
let mut n = self.a.bytes_vec(dst);
|
||||
n += self.b.bytes_vec(&mut dst[n..]);
|
||||
#[cfg(feature = "std")]
|
||||
fn chunks_vectored<'a>(&'a self, dst: &mut [IoSlice<'a>]) -> usize {
|
||||
let mut n = self.a.chunks_vectored(dst);
|
||||
n += self.b.chunks_vectored(&mut dst[n..]);
|
||||
n
|
||||
}
|
||||
|
||||
fn copy_to_bytes(&mut self, len: usize) -> Bytes {
|
||||
let a_rem = self.a.remaining();
|
||||
if a_rem >= len {
|
||||
self.a.copy_to_bytes(len)
|
||||
} else if a_rem == 0 {
|
||||
self.b.copy_to_bytes(len)
|
||||
} else {
|
||||
assert!(
|
||||
len - a_rem <= self.b.remaining(),
|
||||
"`len` greater than remaining"
|
||||
);
|
||||
let mut ret = crate::BytesMut::with_capacity(len);
|
||||
ret.put(&mut self.a);
|
||||
ret.put((&mut self.b).take(len - a_rem));
|
||||
ret.freeze()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, U> BufMut for Chain<T, U>
|
||||
where T: BufMut,
|
||||
U: BufMut,
|
||||
unsafe impl<T, U> BufMut for Chain<T, U>
|
||||
where
|
||||
T: BufMut,
|
||||
U: BufMut,
|
||||
{
|
||||
fn remaining_mut(&self) -> usize {
|
||||
self.a.remaining_mut() + self.b.remaining_mut()
|
||||
self.a
|
||||
.remaining_mut()
|
||||
.saturating_add(self.b.remaining_mut())
|
||||
}
|
||||
|
||||
unsafe fn bytes_mut(&mut self) -> &mut [u8] {
|
||||
fn chunk_mut(&mut self) -> &mut UninitSlice {
|
||||
if self.a.has_remaining_mut() {
|
||||
self.a.bytes_mut()
|
||||
self.a.chunk_mut()
|
||||
} else {
|
||||
self.b.bytes_mut()
|
||||
self.b.chunk_mut()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -217,10 +226,17 @@ impl<T, U> BufMut for Chain<T, U>
|
||||
|
||||
self.b.advance_mut(cnt);
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn bytes_vec_mut<'a>(&'a mut self, dst: &mut [&'a mut IoVec]) -> usize {
|
||||
let mut n = self.a.bytes_vec_mut(dst);
|
||||
n += self.b.bytes_vec_mut(&mut dst[n..]);
|
||||
n
|
||||
impl<T, U> IntoIterator for Chain<T, U>
|
||||
where
|
||||
T: Buf,
|
||||
U: Buf,
|
||||
{
|
||||
type Item = u8;
|
||||
type IntoIter = IntoIter<Chain<T, U>>;
|
||||
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
IntoIter::new(self)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,117 +0,0 @@
|
||||
use {Buf, BufMut, IntoBuf, Bytes, BytesMut};
|
||||
|
||||
/// Conversion from a [`Buf`]
|
||||
///
|
||||
/// Implementing `FromBuf` for a type defines how it is created from a buffer.
|
||||
/// This is common for types which represent byte storage of some kind.
|
||||
///
|
||||
/// [`FromBuf::from_buf`] is rarely called explicitly, and it is instead used
|
||||
/// through [`Buf::collect`]. See [`Buf::collect`] documentation for more examples.
|
||||
///
|
||||
/// See also [`IntoBuf`].
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Basic usage:
|
||||
///
|
||||
/// ```
|
||||
/// use bytes::{Bytes, IntoBuf};
|
||||
/// use bytes::buf::FromBuf;
|
||||
///
|
||||
/// let buf = Bytes::from(&b"hello world"[..]).into_buf();
|
||||
/// let vec = Vec::from_buf(buf);
|
||||
///
|
||||
/// assert_eq!(vec, &b"hello world"[..]);
|
||||
/// ```
|
||||
///
|
||||
/// Using [`Buf::collect`] to implicitly use `FromBuf`:
|
||||
///
|
||||
/// ```
|
||||
/// use bytes::{Buf, Bytes, IntoBuf};
|
||||
///
|
||||
/// let buf = Bytes::from(&b"hello world"[..]).into_buf();
|
||||
/// let vec: Vec<u8> = buf.collect();
|
||||
///
|
||||
/// assert_eq!(vec, &b"hello world"[..]);
|
||||
/// ```
|
||||
///
|
||||
/// Implementing `FromBuf` for your type:
|
||||
///
|
||||
/// ```
|
||||
/// use bytes::{BufMut, Bytes};
|
||||
/// use bytes::buf::{IntoBuf, FromBuf};
|
||||
///
|
||||
/// // A sample buffer, that's just a wrapper over Vec<u8>
|
||||
/// struct MyBuffer(Vec<u8>);
|
||||
///
|
||||
/// impl FromBuf for MyBuffer {
|
||||
/// fn from_buf<B>(buf: B) -> Self where B: IntoBuf {
|
||||
/// let mut v = Vec::new();
|
||||
/// v.put(buf.into_buf());
|
||||
/// MyBuffer(v)
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// // Now we can make a new buf
|
||||
/// let buf = Bytes::from(&b"hello world"[..]);
|
||||
///
|
||||
/// // And make a MyBuffer out of it
|
||||
/// let my_buf = MyBuffer::from_buf(buf);
|
||||
///
|
||||
/// assert_eq!(my_buf.0, &b"hello world"[..]);
|
||||
/// ```
|
||||
///
|
||||
/// [`Buf`]: trait.Buf.html
|
||||
/// [`FromBuf::from_buf`]: #method.from_buf
|
||||
/// [`Buf::collect`]: trait.Buf.html#method.collect
|
||||
/// [`IntoBuf`]: trait.IntoBuf.html
|
||||
pub trait FromBuf {
|
||||
/// Creates a value from a buffer.
|
||||
///
|
||||
/// See the [type-level documentation](#) for more details.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Basic usage:
|
||||
///
|
||||
/// ```
|
||||
/// use bytes::{Bytes, IntoBuf};
|
||||
/// use bytes::buf::FromBuf;
|
||||
///
|
||||
/// let buf = Bytes::from(&b"hello world"[..]).into_buf();
|
||||
/// let vec = Vec::from_buf(buf);
|
||||
///
|
||||
/// assert_eq!(vec, &b"hello world"[..]);
|
||||
/// ```
|
||||
fn from_buf<T>(buf: T) -> Self where T: IntoBuf;
|
||||
}
|
||||
|
||||
impl FromBuf for Vec<u8> {
|
||||
fn from_buf<T>(buf: T) -> Self
|
||||
where T: IntoBuf
|
||||
{
|
||||
let buf = buf.into_buf();
|
||||
let mut ret = Vec::with_capacity(buf.remaining());
|
||||
ret.put(buf);
|
||||
ret
|
||||
}
|
||||
}
|
||||
|
||||
impl FromBuf for Bytes {
|
||||
fn from_buf<T>(buf: T) -> Self
|
||||
where T: IntoBuf
|
||||
{
|
||||
BytesMut::from_buf(buf).freeze()
|
||||
}
|
||||
}
|
||||
|
||||
impl FromBuf for BytesMut {
|
||||
fn from_buf<T>(buf: T) -> Self
|
||||
where T: IntoBuf
|
||||
{
|
||||
let buf = buf.into_buf();
|
||||
let mut ret = BytesMut::with_capacity(buf.remaining());
|
||||
ret.put(buf);
|
||||
ret
|
||||
}
|
||||
}
|
||||
@@ -1,138 +0,0 @@
|
||||
use super::{Buf};
|
||||
|
||||
use std::io;
|
||||
|
||||
/// Conversion into a `Buf`
|
||||
///
|
||||
/// An `IntoBuf` implementation defines how to convert a value into a `Buf`.
|
||||
/// This is common for types that represent byte storage of some kind. `IntoBuf`
|
||||
/// may be implemented directly for types or on references for those types.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use bytes::{Buf, IntoBuf, BigEndian};
|
||||
///
|
||||
/// let bytes = b"\x00\x01hello world";
|
||||
/// let mut buf = bytes.into_buf();
|
||||
///
|
||||
/// assert_eq!(1, buf.get_u16::<BigEndian>());
|
||||
///
|
||||
/// let mut rest = [0; 11];
|
||||
/// buf.copy_to_slice(&mut rest);
|
||||
///
|
||||
/// assert_eq!(b"hello world", &rest);
|
||||
/// ```
|
||||
pub trait IntoBuf {
|
||||
/// The `Buf` type that `self` is being converted into
|
||||
type Buf: Buf;
|
||||
|
||||
/// Creates a `Buf` from a value.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use bytes::{Buf, IntoBuf, BigEndian};
|
||||
///
|
||||
/// let bytes = b"\x00\x01hello world";
|
||||
/// let mut buf = bytes.into_buf();
|
||||
///
|
||||
/// assert_eq!(1, buf.get_u16::<BigEndian>());
|
||||
///
|
||||
/// let mut rest = [0; 11];
|
||||
/// buf.copy_to_slice(&mut rest);
|
||||
///
|
||||
/// assert_eq!(b"hello world", &rest);
|
||||
/// ```
|
||||
fn into_buf(self) -> Self::Buf;
|
||||
}
|
||||
|
||||
impl<T: Buf> IntoBuf for T {
|
||||
type Buf = Self;
|
||||
|
||||
fn into_buf(self) -> Self {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> IntoBuf for &'a [u8] {
|
||||
type Buf = io::Cursor<&'a [u8]>;
|
||||
|
||||
fn into_buf(self) -> Self::Buf {
|
||||
io::Cursor::new(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> IntoBuf for &'a str {
|
||||
type Buf = io::Cursor<&'a [u8]>;
|
||||
|
||||
fn into_buf(self) -> Self::Buf {
|
||||
self.as_bytes().into_buf()
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoBuf for Vec<u8> {
|
||||
type Buf = io::Cursor<Vec<u8>>;
|
||||
|
||||
fn into_buf(self) -> Self::Buf {
|
||||
io::Cursor::new(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> IntoBuf for &'a Vec<u8> {
|
||||
type Buf = io::Cursor<&'a [u8]>;
|
||||
|
||||
fn into_buf(self) -> Self::Buf {
|
||||
io::Cursor::new(&self[..])
|
||||
}
|
||||
}
|
||||
|
||||
// Kind of annoying... but this impl is required to allow passing `&'static
|
||||
// [u8]` where for<'a> &'a T: IntoBuf is required.
|
||||
impl<'a> IntoBuf for &'a &'static [u8] {
|
||||
type Buf = io::Cursor<&'static [u8]>;
|
||||
|
||||
fn into_buf(self) -> Self::Buf {
|
||||
io::Cursor::new(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> IntoBuf for &'a &'static str {
|
||||
type Buf = io::Cursor<&'static [u8]>;
|
||||
|
||||
fn into_buf(self) -> Self::Buf {
|
||||
self.as_bytes().into_buf()
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoBuf for String {
|
||||
type Buf = io::Cursor<Vec<u8>>;
|
||||
|
||||
fn into_buf(self) -> Self::Buf {
|
||||
self.into_bytes().into_buf()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> IntoBuf for &'a String {
|
||||
type Buf = io::Cursor<&'a [u8]>;
|
||||
|
||||
fn into_buf(self) -> Self::Buf {
|
||||
self.as_bytes().into_buf()
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoBuf for u8 {
|
||||
type Buf = Option<[u8; 1]>;
|
||||
|
||||
fn into_buf(self) -> Self::Buf {
|
||||
Some([self])
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoBuf for i8 {
|
||||
type Buf = Option<[u8; 1]>;
|
||||
|
||||
fn into_buf(self) -> Self::Buf {
|
||||
Some([self as u8; 1])
|
||||
}
|
||||
}
|
||||
+41
-25
@@ -1,4 +1,4 @@
|
||||
use Buf;
|
||||
use crate::Buf;
|
||||
|
||||
/// Iterator over the bytes contained by the buffer.
|
||||
///
|
||||
@@ -9,10 +9,10 @@ use Buf;
|
||||
/// Basic usage:
|
||||
///
|
||||
/// ```
|
||||
/// use bytes::{Buf, IntoBuf, Bytes};
|
||||
/// use bytes::Bytes;
|
||||
///
|
||||
/// let buf = Bytes::from(&b"abc"[..]).into_buf();
|
||||
/// let mut iter = buf.iter();
|
||||
/// let buf = Bytes::from(&b"abc"[..]);
|
||||
/// let mut iter = buf.into_iter();
|
||||
///
|
||||
/// assert_eq!(iter.next(), Some(b'a'));
|
||||
/// assert_eq!(iter.next(), Some(b'b'));
|
||||
@@ -23,20 +23,39 @@ use Buf;
|
||||
/// [`iter`]: trait.Buf.html#method.iter
|
||||
/// [`Buf`]: trait.Buf.html
|
||||
#[derive(Debug)]
|
||||
pub struct Iter<T> {
|
||||
pub struct IntoIter<T> {
|
||||
inner: T,
|
||||
}
|
||||
|
||||
impl<T> Iter<T> {
|
||||
/// Consumes this `Iter`, returning the underlying value.
|
||||
impl<T> IntoIter<T> {
|
||||
/// Creates an iterator over the bytes contained by the buffer.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use bytes::Bytes;
|
||||
///
|
||||
/// let buf = Bytes::from_static(b"abc");
|
||||
/// let mut iter = buf.into_iter();
|
||||
///
|
||||
/// assert_eq!(iter.next(), Some(b'a'));
|
||||
/// assert_eq!(iter.next(), Some(b'b'));
|
||||
/// assert_eq!(iter.next(), Some(b'c'));
|
||||
/// assert_eq!(iter.next(), None);
|
||||
/// ```
|
||||
pub(crate) fn new(inner: T) -> IntoIter<T> {
|
||||
IntoIter { inner }
|
||||
}
|
||||
|
||||
/// Consumes this `IntoIter`, returning the underlying value.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// use bytes::{Buf, IntoBuf, Bytes};
|
||||
/// use bytes::{Buf, Bytes};
|
||||
///
|
||||
/// let buf = Bytes::from(&b"abc"[..]).into_buf();
|
||||
/// let mut iter = buf.iter();
|
||||
/// let buf = Bytes::from(&b"abc"[..]);
|
||||
/// let mut iter = buf.into_iter();
|
||||
///
|
||||
/// assert_eq!(iter.next(), Some(b'a'));
|
||||
///
|
||||
@@ -54,10 +73,10 @@ impl<T> Iter<T> {
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// use bytes::{Buf, IntoBuf, Bytes};
|
||||
/// use bytes::{Buf, Bytes};
|
||||
///
|
||||
/// let buf = Bytes::from(&b"abc"[..]).into_buf();
|
||||
/// let mut iter = buf.iter();
|
||||
/// let buf = Bytes::from(&b"abc"[..]);
|
||||
/// let mut iter = buf.into_iter();
|
||||
///
|
||||
/// assert_eq!(iter.next(), Some(b'a'));
|
||||
///
|
||||
@@ -74,27 +93,23 @@ impl<T> Iter<T> {
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// use bytes::{Buf, IntoBuf, BytesMut};
|
||||
/// use bytes::{Buf, BytesMut};
|
||||
///
|
||||
/// let buf = BytesMut::from(&b"abc"[..]).into_buf();
|
||||
/// let mut iter = buf.iter();
|
||||
/// let buf = BytesMut::from(&b"abc"[..]);
|
||||
/// let mut iter = buf.into_iter();
|
||||
///
|
||||
/// assert_eq!(iter.next(), Some(b'a'));
|
||||
///
|
||||
/// iter.get_mut().set_position(0);
|
||||
/// iter.get_mut().advance(1);
|
||||
///
|
||||
/// assert_eq!(iter.next(), Some(b'a'));
|
||||
/// assert_eq!(iter.next(), Some(b'c'));
|
||||
/// ```
|
||||
pub fn get_mut(&mut self) -> &mut T {
|
||||
&mut self.inner
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new<T>(inner: T) -> Iter<T> {
|
||||
Iter { inner: inner }
|
||||
}
|
||||
|
||||
impl<T: Buf> Iterator for Iter<T> {
|
||||
impl<T: Buf> Iterator for IntoIter<T> {
|
||||
type Item = u8;
|
||||
|
||||
fn next(&mut self) -> Option<u8> {
|
||||
@@ -102,8 +117,9 @@ impl<T: Buf> Iterator for Iter<T> {
|
||||
return None;
|
||||
}
|
||||
|
||||
let b = self.inner.bytes()[0];
|
||||
let b = self.inner.chunk()[0];
|
||||
self.inner.advance(1);
|
||||
|
||||
Some(b)
|
||||
}
|
||||
|
||||
@@ -113,4 +129,4 @@ impl<T: Buf> Iterator for Iter<T> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Buf> ExactSizeIterator for Iter<T> { }
|
||||
impl<T: Buf> ExactSizeIterator for IntoIter<T> {}
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
use crate::buf::UninitSlice;
|
||||
use crate::BufMut;
|
||||
|
||||
use core::cmp;
|
||||
|
||||
/// A `BufMut` adapter which limits the amount of bytes that can be written
|
||||
/// to an underlying buffer.
|
||||
#[derive(Debug)]
|
||||
pub struct Limit<T> {
|
||||
inner: T,
|
||||
limit: usize,
|
||||
}
|
||||
|
||||
pub(super) fn new<T>(inner: T, limit: usize) -> Limit<T> {
|
||||
Limit { inner, limit }
|
||||
}
|
||||
|
||||
impl<T> Limit<T> {
|
||||
/// Consumes this `Limit`, returning the underlying value.
|
||||
pub fn into_inner(self) -> T {
|
||||
self.inner
|
||||
}
|
||||
|
||||
/// Gets a reference to the underlying `BufMut`.
|
||||
///
|
||||
/// It is inadvisable to directly write to the underlying `BufMut`.
|
||||
pub fn get_ref(&self) -> &T {
|
||||
&self.inner
|
||||
}
|
||||
|
||||
/// Gets a mutable reference to the underlying `BufMut`.
|
||||
///
|
||||
/// It is inadvisable to directly write to the underlying `BufMut`.
|
||||
pub fn get_mut(&mut self) -> &mut T {
|
||||
&mut self.inner
|
||||
}
|
||||
|
||||
/// Returns the maximum number of bytes that can be written
|
||||
///
|
||||
/// # Note
|
||||
///
|
||||
/// If the inner `BufMut` has fewer bytes than indicated by this method then
|
||||
/// that is the actual number of available bytes.
|
||||
pub fn limit(&self) -> usize {
|
||||
self.limit
|
||||
}
|
||||
|
||||
/// Sets the maximum number of bytes that can be written.
|
||||
///
|
||||
/// # Note
|
||||
///
|
||||
/// If the inner `BufMut` has fewer bytes than `lim` then that is the actual
|
||||
/// number of available bytes.
|
||||
pub fn set_limit(&mut self, lim: usize) {
|
||||
self.limit = lim
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<T: BufMut> BufMut for Limit<T> {
|
||||
fn remaining_mut(&self) -> usize {
|
||||
cmp::min(self.inner.remaining_mut(), self.limit)
|
||||
}
|
||||
|
||||
fn chunk_mut(&mut self) -> &mut UninitSlice {
|
||||
let bytes = self.inner.chunk_mut();
|
||||
let end = cmp::min(bytes.len(), self.limit);
|
||||
&mut bytes[..end]
|
||||
}
|
||||
|
||||
unsafe fn advance_mut(&mut self, cnt: usize) {
|
||||
assert!(cnt <= self.limit);
|
||||
self.inner.advance_mut(cnt);
|
||||
self.limit -= cnt;
|
||||
}
|
||||
}
|
||||
+13
-9
@@ -16,22 +16,26 @@
|
||||
//! [`Buf`]: trait.Buf.html
|
||||
//! [`BufMut`]: trait.BufMut.html
|
||||
|
||||
mod buf;
|
||||
mod buf_impl;
|
||||
mod buf_mut;
|
||||
mod from_buf;
|
||||
mod chain;
|
||||
mod into_buf;
|
||||
mod iter;
|
||||
mod limit;
|
||||
#[cfg(feature = "std")]
|
||||
mod reader;
|
||||
mod take;
|
||||
mod uninit_slice;
|
||||
mod vec_deque;
|
||||
#[cfg(feature = "std")]
|
||||
mod writer;
|
||||
|
||||
pub use self::buf::Buf;
|
||||
pub use self::buf_impl::Buf;
|
||||
pub use self::buf_mut::BufMut;
|
||||
pub use self::from_buf::FromBuf;
|
||||
pub use self::chain::Chain;
|
||||
pub use self::into_buf::IntoBuf;
|
||||
pub use self::iter::Iter;
|
||||
pub use self::reader::Reader;
|
||||
pub use self::iter::IntoIter;
|
||||
pub use self::limit::Limit;
|
||||
pub use self::take::Take;
|
||||
pub use self::writer::Writer;
|
||||
pub use self::uninit_slice::UninitSlice;
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
pub use self::{reader::Reader, writer::Writer};
|
||||
|
||||
+15
-22
@@ -1,4 +1,4 @@
|
||||
use {Buf};
|
||||
use crate::Buf;
|
||||
|
||||
use std::{cmp, io};
|
||||
|
||||
@@ -13,7 +13,7 @@ pub struct Reader<B> {
|
||||
}
|
||||
|
||||
pub fn new<B>(buf: B) -> Reader<B> {
|
||||
Reader { buf: buf }
|
||||
Reader { buf }
|
||||
}
|
||||
|
||||
impl<B: Buf> Reader<B> {
|
||||
@@ -25,11 +25,10 @@ impl<B: Buf> Reader<B> {
|
||||
///
|
||||
/// ```rust
|
||||
/// use bytes::Buf;
|
||||
/// use std::io::{self, Cursor};
|
||||
///
|
||||
/// let mut buf = Cursor::new(b"hello world").reader();
|
||||
/// let buf = b"hello world".reader();
|
||||
///
|
||||
/// assert_eq!(0, buf.get_ref().position());
|
||||
/// assert_eq!(b"hello world", buf.get_ref());
|
||||
/// ```
|
||||
pub fn get_ref(&self) -> &B {
|
||||
&self.buf
|
||||
@@ -38,21 +37,6 @@ impl<B: Buf> Reader<B> {
|
||||
/// Gets a mutable reference to the underlying `Buf`.
|
||||
///
|
||||
/// It is inadvisable to directly read from the underlying `Buf`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// use bytes::Buf;
|
||||
/// use std::io::{self, Cursor};
|
||||
///
|
||||
/// let mut buf = Cursor::new(b"hello world").reader();
|
||||
/// let mut dst = vec![];
|
||||
///
|
||||
/// buf.get_mut().set_position(2);
|
||||
/// io::copy(&mut buf, &mut dst).unwrap();
|
||||
///
|
||||
/// assert_eq!(*dst, b"llo world"[..]);
|
||||
/// ```
|
||||
pub fn get_mut(&mut self) -> &mut B {
|
||||
&mut self.buf
|
||||
}
|
||||
@@ -63,9 +47,9 @@ impl<B: Buf> Reader<B> {
|
||||
///
|
||||
/// ```rust
|
||||
/// use bytes::Buf;
|
||||
/// use std::io::{self, Cursor};
|
||||
/// use std::io;
|
||||
///
|
||||
/// let mut buf = Cursor::new(b"hello world").reader();
|
||||
/// let mut buf = b"hello world".reader();
|
||||
/// let mut dst = vec![];
|
||||
///
|
||||
/// io::copy(&mut buf, &mut dst).unwrap();
|
||||
@@ -86,3 +70,12 @@ impl<B: Buf + Sized> io::Read for Reader<B> {
|
||||
Ok(len)
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: Buf + Sized> io::BufRead for Reader<B> {
|
||||
fn fill_buf(&mut self) -> io::Result<&[u8]> {
|
||||
Ok(self.buf.chunk())
|
||||
}
|
||||
fn consume(&mut self, amt: usize) {
|
||||
self.buf.advance(amt)
|
||||
}
|
||||
}
|
||||
|
||||
+21
-21
@@ -1,6 +1,6 @@
|
||||
use {Buf};
|
||||
use crate::{Buf, Bytes};
|
||||
|
||||
use std::cmp;
|
||||
use core::cmp;
|
||||
|
||||
/// A `Buf` adapter which limits the bytes read from an underlying buffer.
|
||||
///
|
||||
@@ -13,10 +13,7 @@ pub struct Take<T> {
|
||||
}
|
||||
|
||||
pub fn new<T>(inner: T, limit: usize) -> Take<T> {
|
||||
Take {
|
||||
inner: inner,
|
||||
limit: limit,
|
||||
}
|
||||
Take { inner, limit }
|
||||
}
|
||||
|
||||
impl<T> Take<T> {
|
||||
@@ -26,9 +23,8 @@ impl<T> Take<T> {
|
||||
///
|
||||
/// ```rust
|
||||
/// use bytes::{Buf, BufMut};
|
||||
/// use std::io::Cursor;
|
||||
///
|
||||
/// let mut buf = Cursor::new(b"hello world").take(2);
|
||||
/// let mut buf = b"hello world".take(2);
|
||||
/// let mut dst = vec![];
|
||||
///
|
||||
/// dst.put(&mut buf);
|
||||
@@ -51,12 +47,11 @@ impl<T> Take<T> {
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// use bytes::{Buf, BufMut};
|
||||
/// use std::io::Cursor;
|
||||
/// use bytes::Buf;
|
||||
///
|
||||
/// let mut buf = Cursor::new(b"hello world").take(2);
|
||||
/// let buf = b"hello world".take(2);
|
||||
///
|
||||
/// assert_eq!(0, buf.get_ref().position());
|
||||
/// assert_eq!(11, buf.get_ref().remaining());
|
||||
/// ```
|
||||
pub fn get_ref(&self) -> &T {
|
||||
&self.inner
|
||||
@@ -70,12 +65,11 @@ impl<T> Take<T> {
|
||||
///
|
||||
/// ```rust
|
||||
/// use bytes::{Buf, BufMut};
|
||||
/// use std::io::Cursor;
|
||||
///
|
||||
/// let mut buf = Cursor::new(b"hello world").take(2);
|
||||
/// let mut buf = b"hello world".take(2);
|
||||
/// let mut dst = vec![];
|
||||
///
|
||||
/// buf.get_mut().set_position(2);
|
||||
/// buf.get_mut().advance(2);
|
||||
///
|
||||
/// dst.put(&mut buf);
|
||||
/// assert_eq!(*dst, b"ll"[..]);
|
||||
@@ -95,9 +89,8 @@ impl<T> Take<T> {
|
||||
///
|
||||
/// ```rust
|
||||
/// use bytes::Buf;
|
||||
/// use std::io::Cursor;
|
||||
///
|
||||
/// let mut buf = Cursor::new(b"hello world").take(2);
|
||||
/// let mut buf = b"hello world".take(2);
|
||||
///
|
||||
/// assert_eq!(2, buf.limit());
|
||||
/// assert_eq!(b'h', buf.get_u8());
|
||||
@@ -118,9 +111,8 @@ impl<T> Take<T> {
|
||||
///
|
||||
/// ```rust
|
||||
/// use bytes::{Buf, BufMut};
|
||||
/// use std::io::Cursor;
|
||||
///
|
||||
/// let mut buf = Cursor::new(b"hello world").take(2);
|
||||
/// let mut buf = b"hello world".take(2);
|
||||
/// let mut dst = vec![];
|
||||
///
|
||||
/// dst.put(&mut buf);
|
||||
@@ -142,8 +134,8 @@ impl<T: Buf> Buf for Take<T> {
|
||||
cmp::min(self.inner.remaining(), self.limit)
|
||||
}
|
||||
|
||||
fn bytes(&self) -> &[u8] {
|
||||
let bytes = self.inner.bytes();
|
||||
fn chunk(&self) -> &[u8] {
|
||||
let bytes = self.inner.chunk();
|
||||
&bytes[..cmp::min(bytes.len(), self.limit)]
|
||||
}
|
||||
|
||||
@@ -152,4 +144,12 @@ impl<T: Buf> Buf for Take<T> {
|
||||
self.inner.advance(cnt);
|
||||
self.limit -= cnt;
|
||||
}
|
||||
|
||||
fn copy_to_bytes(&mut self, len: usize) -> Bytes {
|
||||
assert!(len <= self.remaining(), "`len` greater than remaining");
|
||||
|
||||
let r = self.inner.copy_to_bytes(len);
|
||||
self.limit -= len;
|
||||
r
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,209 @@
|
||||
use core::fmt;
|
||||
use core::mem::MaybeUninit;
|
||||
use core::ops::{
|
||||
Index, IndexMut, Range, RangeFrom, RangeFull, RangeInclusive, RangeTo, RangeToInclusive,
|
||||
};
|
||||
|
||||
/// Uninitialized byte slice.
|
||||
///
|
||||
/// Returned by `BufMut::chunk_mut()`, the referenced byte slice may be
|
||||
/// uninitialized. The wrapper provides safe access without introducing
|
||||
/// undefined behavior.
|
||||
///
|
||||
/// The safety invariants of this wrapper are:
|
||||
///
|
||||
/// 1. Reading from an `UninitSlice` is undefined behavior.
|
||||
/// 2. Writing uninitialized bytes to an `UninitSlice` is undefined behavior.
|
||||
///
|
||||
/// The difference between `&mut UninitSlice` and `&mut [MaybeUninit<u8>]` is
|
||||
/// that it is possible in safe code to write uninitialized bytes to an
|
||||
/// `&mut [MaybeUninit<u8>]`, which this type prohibits.
|
||||
#[repr(transparent)]
|
||||
pub struct UninitSlice([MaybeUninit<u8>]);
|
||||
|
||||
impl UninitSlice {
|
||||
/// Create a `&mut UninitSlice` from a pointer and a length.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The caller must ensure that `ptr` references a valid memory region owned
|
||||
/// by the caller representing a byte slice for the duration of `'a`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use bytes::buf::UninitSlice;
|
||||
///
|
||||
/// let bytes = b"hello world".to_vec();
|
||||
/// let ptr = bytes.as_ptr() as *mut _;
|
||||
/// let len = bytes.len();
|
||||
///
|
||||
/// let slice = unsafe { UninitSlice::from_raw_parts_mut(ptr, len) };
|
||||
/// ```
|
||||
#[inline]
|
||||
pub unsafe fn from_raw_parts_mut<'a>(ptr: *mut u8, len: usize) -> &'a mut UninitSlice {
|
||||
let maybe_init: &mut [MaybeUninit<u8>] =
|
||||
core::slice::from_raw_parts_mut(ptr as *mut _, len);
|
||||
&mut *(maybe_init as *mut [MaybeUninit<u8>] as *mut UninitSlice)
|
||||
}
|
||||
|
||||
/// Write a single byte at the specified offset.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// The function panics if `index` is out of bounds.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use bytes::buf::UninitSlice;
|
||||
///
|
||||
/// let mut data = [b'f', b'o', b'o'];
|
||||
/// let slice = unsafe { UninitSlice::from_raw_parts_mut(data.as_mut_ptr(), 3) };
|
||||
///
|
||||
/// slice.write_byte(0, b'b');
|
||||
///
|
||||
/// assert_eq!(b"boo", &data[..]);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn write_byte(&mut self, index: usize, byte: u8) {
|
||||
assert!(index < self.len());
|
||||
|
||||
unsafe { self[index..].as_mut_ptr().write(byte) }
|
||||
}
|
||||
|
||||
/// Copies bytes from `src` into `self`.
|
||||
///
|
||||
/// The length of `src` must be the same as `self`.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// The function panics if `src` has a different length than `self`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use bytes::buf::UninitSlice;
|
||||
///
|
||||
/// let mut data = [b'f', b'o', b'o'];
|
||||
/// let slice = unsafe { UninitSlice::from_raw_parts_mut(data.as_mut_ptr(), 3) };
|
||||
///
|
||||
/// slice.copy_from_slice(b"bar");
|
||||
///
|
||||
/// assert_eq!(b"bar", &data[..]);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn copy_from_slice(&mut self, src: &[u8]) {
|
||||
use core::ptr;
|
||||
|
||||
assert_eq!(self.len(), src.len());
|
||||
|
||||
unsafe {
|
||||
ptr::copy_nonoverlapping(src.as_ptr(), self.as_mut_ptr(), self.len());
|
||||
}
|
||||
}
|
||||
|
||||
/// Return a raw pointer to the slice's buffer.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The caller **must not** read from the referenced memory and **must not**
|
||||
/// write **uninitialized** bytes to the slice either.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use bytes::BufMut;
|
||||
///
|
||||
/// let mut data = [0, 1, 2];
|
||||
/// let mut slice = &mut data[..];
|
||||
/// let ptr = BufMut::chunk_mut(&mut slice).as_mut_ptr();
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn as_mut_ptr(&mut self) -> *mut u8 {
|
||||
self.0.as_mut_ptr() as *mut _
|
||||
}
|
||||
|
||||
/// Return a `&mut [MaybeUninit<u8>]` to this slice's buffer.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The caller **must not** read from the referenced memory and **must not** write
|
||||
/// **uninitialized** bytes to the slice either. This is because `BufMut` implementation
|
||||
/// that created the `UninitSlice` knows which parts are initialized. Writing uninitalized
|
||||
/// bytes to the slice may cause the `BufMut` to read those bytes and trigger undefined
|
||||
/// behavior.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use bytes::BufMut;
|
||||
///
|
||||
/// let mut data = [0, 1, 2];
|
||||
/// let mut slice = &mut data[..];
|
||||
/// unsafe {
|
||||
/// let uninit_slice = BufMut::chunk_mut(&mut slice).as_uninit_slice_mut();
|
||||
/// };
|
||||
/// ```
|
||||
#[inline]
|
||||
pub unsafe fn as_uninit_slice_mut<'a>(&'a mut self) -> &'a mut [MaybeUninit<u8>] {
|
||||
&mut *(self as *mut _ as *mut [MaybeUninit<u8>])
|
||||
}
|
||||
|
||||
/// Returns the number of bytes in the slice.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use bytes::BufMut;
|
||||
///
|
||||
/// let mut data = [0, 1, 2];
|
||||
/// let mut slice = &mut data[..];
|
||||
/// let len = BufMut::chunk_mut(&mut slice).len();
|
||||
///
|
||||
/// assert_eq!(len, 3);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn len(&self) -> usize {
|
||||
self.0.len()
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for UninitSlice {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
fmt.debug_struct("UninitSlice[...]").finish()
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! impl_index {
|
||||
($($t:ty),*) => {
|
||||
$(
|
||||
impl Index<$t> for UninitSlice {
|
||||
type Output = UninitSlice;
|
||||
|
||||
#[inline]
|
||||
fn index(&self, index: $t) -> &UninitSlice {
|
||||
let maybe_uninit: &[MaybeUninit<u8>] = &self.0[index];
|
||||
unsafe { &*(maybe_uninit as *const [MaybeUninit<u8>] as *const UninitSlice) }
|
||||
}
|
||||
}
|
||||
|
||||
impl IndexMut<$t> for UninitSlice {
|
||||
#[inline]
|
||||
fn index_mut(&mut self, index: $t) -> &mut UninitSlice {
|
||||
let maybe_uninit: &mut [MaybeUninit<u8>] = &mut self.0[index];
|
||||
unsafe { &mut *(maybe_uninit as *mut [MaybeUninit<u8>] as *mut UninitSlice) }
|
||||
}
|
||||
}
|
||||
)*
|
||||
};
|
||||
}
|
||||
|
||||
impl_index!(
|
||||
Range<usize>,
|
||||
RangeFrom<usize>,
|
||||
RangeFull,
|
||||
RangeInclusive<usize>,
|
||||
RangeTo<usize>,
|
||||
RangeToInclusive<usize>
|
||||
);
|
||||
@@ -0,0 +1,22 @@
|
||||
use alloc::collections::VecDeque;
|
||||
|
||||
use super::Buf;
|
||||
|
||||
impl Buf for VecDeque<u8> {
|
||||
fn remaining(&self) -> usize {
|
||||
self.len()
|
||||
}
|
||||
|
||||
fn chunk(&self) -> &[u8] {
|
||||
let (s1, s2) = self.as_slices();
|
||||
if s1.is_empty() {
|
||||
s2
|
||||
} else {
|
||||
s1
|
||||
}
|
||||
}
|
||||
|
||||
fn advance(&mut self, cnt: usize) {
|
||||
self.drain(..cnt);
|
||||
}
|
||||
}
|
||||
+5
-5
@@ -1,4 +1,4 @@
|
||||
use BufMut;
|
||||
use crate::BufMut;
|
||||
|
||||
use std::{cmp, io};
|
||||
|
||||
@@ -13,7 +13,7 @@ pub struct Writer<B> {
|
||||
}
|
||||
|
||||
pub fn new<B>(buf: B) -> Writer<B> {
|
||||
Writer { buf: buf }
|
||||
Writer { buf }
|
||||
}
|
||||
|
||||
impl<B: BufMut> Writer<B> {
|
||||
@@ -26,7 +26,7 @@ impl<B: BufMut> Writer<B> {
|
||||
/// ```rust
|
||||
/// use bytes::BufMut;
|
||||
///
|
||||
/// let mut buf = Vec::with_capacity(1024).writer();
|
||||
/// let buf = Vec::with_capacity(1024).writer();
|
||||
///
|
||||
/// assert_eq!(1024, buf.get_ref().capacity());
|
||||
/// ```
|
||||
@@ -59,10 +59,10 @@ impl<B: BufMut> Writer<B> {
|
||||
///
|
||||
/// ```rust
|
||||
/// use bytes::BufMut;
|
||||
/// use std::io::{self, Cursor};
|
||||
/// use std::io;
|
||||
///
|
||||
/// let mut buf = vec![].writer();
|
||||
/// let mut src = Cursor::new(b"hello world");
|
||||
/// let mut src = &b"hello world"[..];
|
||||
///
|
||||
/// io::copy(&mut src, &mut buf).unwrap();
|
||||
///
|
||||
|
||||
+842
-2395
File diff suppressed because it is too large
Load Diff
+1774
File diff suppressed because it is too large
Load Diff
@@ -1,40 +0,0 @@
|
||||
use std::fmt;
|
||||
|
||||
/// Alternative implementation of `fmt::Debug` for byte slice.
|
||||
///
|
||||
/// Standard `Debug` implementation for `[u8]` is comma separated
|
||||
/// list of numbers. Since large amount of byte strings are in fact
|
||||
/// ASCII strings or contain a lot of ASCII strings (e. g. HTTP),
|
||||
/// it is convenient to print strings as ASCII when possible.
|
||||
///
|
||||
/// This struct wraps `&[u8]` just to override `fmt::Debug`.
|
||||
///
|
||||
/// `BsDebug` is not a part of public API of bytes crate.
|
||||
pub struct BsDebug<'a>(pub &'a [u8]);
|
||||
|
||||
impl<'a> fmt::Debug for BsDebug<'a> {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
||||
try!(write!(fmt, "b\""));
|
||||
for &c in self.0 {
|
||||
// https://doc.rust-lang.org/reference.html#byte-escapes
|
||||
if c == b'\n' {
|
||||
try!(write!(fmt, "\\n"));
|
||||
} else if c == b'\r' {
|
||||
try!(write!(fmt, "\\r"));
|
||||
} else if c == b'\t' {
|
||||
try!(write!(fmt, "\\t"));
|
||||
} else if c == b'\\' || c == b'"' {
|
||||
try!(write!(fmt, "\\{}", c as char));
|
||||
} else if c == b'\0' {
|
||||
try!(write!(fmt, "\\0"));
|
||||
// ASCII printable
|
||||
} else if c >= 0x20 && c < 0x7f {
|
||||
try!(write!(fmt, "{}", c as char));
|
||||
} else {
|
||||
try!(write!(fmt, "\\x{:02x}", c));
|
||||
}
|
||||
}
|
||||
try!(write!(fmt, "\""));
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
use core::fmt::{Debug, Formatter, Result};
|
||||
|
||||
use super::BytesRef;
|
||||
use crate::{Bytes, BytesMut};
|
||||
|
||||
/// Alternative implementation of `std::fmt::Debug` for byte slice.
|
||||
///
|
||||
/// Standard `Debug` implementation for `[u8]` is comma separated
|
||||
/// list of numbers. Since large amount of byte strings are in fact
|
||||
/// ASCII strings or contain a lot of ASCII strings (e. g. HTTP),
|
||||
/// it is convenient to print strings as ASCII when possible.
|
||||
impl Debug for BytesRef<'_> {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
|
||||
write!(f, "b\"")?;
|
||||
for &b in self.0 {
|
||||
// https://doc.rust-lang.org/reference/tokens.html#byte-escapes
|
||||
if b == b'\n' {
|
||||
write!(f, "\\n")?;
|
||||
} else if b == b'\r' {
|
||||
write!(f, "\\r")?;
|
||||
} else if b == b'\t' {
|
||||
write!(f, "\\t")?;
|
||||
} else if b == b'\\' || b == b'"' {
|
||||
write!(f, "\\{}", b as char)?;
|
||||
} else if b == b'\0' {
|
||||
write!(f, "\\0")?;
|
||||
// ASCII printable
|
||||
} else if (0x20..0x7f).contains(&b) {
|
||||
write!(f, "{}", b as char)?;
|
||||
} else {
|
||||
write!(f, "\\x{:02x}", b)?;
|
||||
}
|
||||
}
|
||||
write!(f, "\"")?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for Bytes {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
|
||||
Debug::fmt(&BytesRef(self.as_ref()), f)
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for BytesMut {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
|
||||
Debug::fmt(&BytesRef(self.as_ref()), f)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
use core::fmt::{Formatter, LowerHex, Result, UpperHex};
|
||||
|
||||
use super::BytesRef;
|
||||
use crate::{Bytes, BytesMut};
|
||||
|
||||
impl LowerHex for BytesRef<'_> {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
|
||||
for &b in self.0 {
|
||||
write!(f, "{:02x}", b)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl UpperHex for BytesRef<'_> {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
|
||||
for &b in self.0 {
|
||||
write!(f, "{:02X}", b)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! hex_impl {
|
||||
($tr:ident, $ty:ty) => {
|
||||
impl $tr for $ty {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
|
||||
$tr::fmt(&BytesRef(self.as_ref()), f)
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
hex_impl!(LowerHex, Bytes);
|
||||
hex_impl!(LowerHex, BytesMut);
|
||||
hex_impl!(UpperHex, Bytes);
|
||||
hex_impl!(UpperHex, BytesMut);
|
||||
@@ -0,0 +1,5 @@
|
||||
mod debug;
|
||||
mod hex;
|
||||
|
||||
/// `BytesRef` is not a part of public API of bytes crate.
|
||||
struct BytesRef<'a>(&'a [u8]);
|
||||
+45
-30
@@ -1,3 +1,10 @@
|
||||
#![warn(missing_docs, missing_debug_implementations, rust_2018_idioms)]
|
||||
#![doc(test(
|
||||
no_crate_inject,
|
||||
attr(deny(warnings, rust_2018_idioms), allow(dead_code, unused_variables))
|
||||
))]
|
||||
#![no_std]
|
||||
|
||||
//! Provides abstractions for working with bytes.
|
||||
//!
|
||||
//! The `bytes` crate provides an efficient byte buffer structure
|
||||
@@ -9,7 +16,7 @@
|
||||
//!
|
||||
//! # `Bytes`
|
||||
//!
|
||||
//! `Bytes` is an efficient container for storing and operating on continguous
|
||||
//! `Bytes` is an efficient container for storing and operating on contiguous
|
||||
//! slices of memory. It is intended for use primarily in networking code, but
|
||||
//! could have applications elsewhere as well.
|
||||
//!
|
||||
@@ -18,23 +25,23 @@
|
||||
//! using a reference count to track when the memory is no longer needed and can
|
||||
//! be freed.
|
||||
//!
|
||||
//! A `Bytes` handle can be created directly from an existing byte store (such as &[u8]
|
||||
//! or Vec<u8>), but usually a `BytesMut` is used first and written to. For
|
||||
//! A `Bytes` handle can be created directly from an existing byte store (such as `&[u8]`
|
||||
//! or `Vec<u8>`), but usually a `BytesMut` is used first and written to. For
|
||||
//! example:
|
||||
//!
|
||||
//! ```rust
|
||||
//! use bytes::{BytesMut, BufMut, BigEndian};
|
||||
//! use bytes::{BytesMut, BufMut};
|
||||
//!
|
||||
//! let mut buf = BytesMut::with_capacity(1024);
|
||||
//! buf.put(&b"hello world"[..]);
|
||||
//! buf.put_u16::<BigEndian>(1234);
|
||||
//! buf.put_u16(1234);
|
||||
//!
|
||||
//! let a = buf.take();
|
||||
//! let a = buf.split();
|
||||
//! assert_eq!(a, b"hello world\x04\xD2"[..]);
|
||||
//!
|
||||
//! buf.put(&b"goodbye world"[..]);
|
||||
//!
|
||||
//! let b = buf.take();
|
||||
//! let b = buf.split();
|
||||
//! assert_eq!(b, b"goodbye world"[..]);
|
||||
//!
|
||||
//! assert_eq!(buf.capacity(), 998);
|
||||
@@ -68,34 +75,42 @@
|
||||
//! perform a syscall, which has the potential of failing. Operations on `Buf`
|
||||
//! and `BufMut` are infallible.
|
||||
|
||||
#![deny(warnings, missing_docs, missing_debug_implementations)]
|
||||
#![doc(html_root_url = "https://docs.rs/bytes/0.4.8")]
|
||||
extern crate alloc;
|
||||
|
||||
extern crate byteorder;
|
||||
extern crate iovec;
|
||||
#[cfg(feature = "std")]
|
||||
extern crate std;
|
||||
|
||||
pub mod buf;
|
||||
pub use buf::{
|
||||
Buf,
|
||||
BufMut,
|
||||
IntoBuf,
|
||||
};
|
||||
#[deprecated(since = "0.4.1", note = "moved to `buf` module")]
|
||||
#[doc(hidden)]
|
||||
pub use buf::{
|
||||
Reader,
|
||||
Writer,
|
||||
Take,
|
||||
};
|
||||
pub use crate::buf::{Buf, BufMut};
|
||||
|
||||
mod bytes;
|
||||
mod debug;
|
||||
pub use bytes::{Bytes, BytesMut};
|
||||
|
||||
#[deprecated]
|
||||
pub use byteorder::{ByteOrder, BigEndian, LittleEndian};
|
||||
mod bytes_mut;
|
||||
mod fmt;
|
||||
mod loom;
|
||||
pub use crate::bytes::Bytes;
|
||||
pub use crate::bytes_mut::BytesMut;
|
||||
|
||||
// Optional Serde support
|
||||
#[cfg(feature = "serde")]
|
||||
#[doc(hidden)]
|
||||
pub mod serde;
|
||||
mod serde;
|
||||
|
||||
#[inline(never)]
|
||||
#[cold]
|
||||
fn abort() -> ! {
|
||||
#[cfg(feature = "std")]
|
||||
{
|
||||
std::process::abort();
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "std"))]
|
||||
{
|
||||
struct Abort;
|
||||
impl Drop for Abort {
|
||||
fn drop(&mut self) {
|
||||
panic!();
|
||||
}
|
||||
}
|
||||
let _a = Abort;
|
||||
panic!("abort");
|
||||
}
|
||||
}
|
||||
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
#[cfg(not(all(test, loom)))]
|
||||
pub(crate) mod sync {
|
||||
pub(crate) mod atomic {
|
||||
pub(crate) use core::sync::atomic::{AtomicPtr, AtomicUsize, Ordering};
|
||||
|
||||
pub(crate) trait AtomicMut<T> {
|
||||
fn with_mut<F, R>(&mut self, f: F) -> R
|
||||
where
|
||||
F: FnOnce(&mut *mut T) -> R;
|
||||
}
|
||||
|
||||
impl<T> AtomicMut<T> for AtomicPtr<T> {
|
||||
fn with_mut<F, R>(&mut self, f: F) -> R
|
||||
where
|
||||
F: FnOnce(&mut *mut T) -> R,
|
||||
{
|
||||
f(self.get_mut())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(all(test, loom))]
|
||||
pub(crate) mod sync {
|
||||
pub(crate) mod atomic {
|
||||
pub(crate) use loom::sync::atomic::{AtomicPtr, AtomicUsize, Ordering};
|
||||
|
||||
pub(crate) trait AtomicMut<T> {}
|
||||
}
|
||||
}
|
||||
+30
-23
@@ -1,15 +1,16 @@
|
||||
extern crate serde;
|
||||
|
||||
use std::{cmp, fmt};
|
||||
use self::serde::{Serialize, Serializer, Deserialize, Deserializer, de};
|
||||
use super::{Bytes, BytesMut};
|
||||
use alloc::string::String;
|
||||
use alloc::vec::Vec;
|
||||
use core::{cmp, fmt};
|
||||
use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
|
||||
|
||||
macro_rules! serde_impl {
|
||||
($ty:ident, $visitor_ty:ident) => (
|
||||
($ty:ident, $visitor_ty:ident, $from_slice:ident, $from_vec:ident) => {
|
||||
impl Serialize for $ty {
|
||||
#[inline]
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where S: Serializer
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
serializer.serialize_bytes(&self)
|
||||
}
|
||||
@@ -20,63 +21,69 @@ macro_rules! serde_impl {
|
||||
impl<'de> de::Visitor<'de> for $visitor_ty {
|
||||
type Value = $ty;
|
||||
|
||||
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
formatter.write_str("byte array")
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_seq<V>(self, mut seq: V) -> Result<Self::Value, V::Error>
|
||||
where V: de::SeqAccess<'de>
|
||||
where
|
||||
V: de::SeqAccess<'de>,
|
||||
{
|
||||
let len = cmp::min(seq.size_hint().unwrap_or(0), 4096);
|
||||
let mut values = Vec::with_capacity(len);
|
||||
let mut values: Vec<u8> = Vec::with_capacity(len);
|
||||
|
||||
while let Some(value) = try!(seq.next_element()) {
|
||||
while let Some(value) = seq.next_element()? {
|
||||
values.push(value);
|
||||
}
|
||||
|
||||
Ok(values.into())
|
||||
Ok($ty::$from_vec(values))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E>
|
||||
where E: de::Error
|
||||
where
|
||||
E: de::Error,
|
||||
{
|
||||
Ok($ty::from(v))
|
||||
Ok($ty::$from_slice(v))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_byte_buf<E>(self, v: Vec<u8>) -> Result<Self::Value, E>
|
||||
where E: de::Error
|
||||
where
|
||||
E: de::Error,
|
||||
{
|
||||
Ok($ty::from(v))
|
||||
Ok($ty::$from_vec(v))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
|
||||
where E: de::Error
|
||||
where
|
||||
E: de::Error,
|
||||
{
|
||||
Ok($ty::from(v))
|
||||
Ok($ty::$from_slice(v.as_bytes()))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_string<E>(self, v: String) -> Result<Self::Value, E>
|
||||
where E: de::Error
|
||||
where
|
||||
E: de::Error,
|
||||
{
|
||||
Ok($ty::from(v))
|
||||
Ok($ty::$from_vec(v.into_bytes()))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for $ty {
|
||||
#[inline]
|
||||
fn deserialize<D>(deserializer: D) -> Result<$ty, D::Error>
|
||||
where D: Deserializer<'de>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
deserializer.deserialize_byte_buf($visitor_ty)
|
||||
}
|
||||
}
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
serde_impl!(Bytes, BytesVisitor);
|
||||
serde_impl!(BytesMut, BytesMutVisitor);
|
||||
serde_impl!(Bytes, BytesVisitor, copy_from_slice, from);
|
||||
serde_impl!(BytesMut, BytesMutVisitor, from, from_vec);
|
||||
|
||||
+86
-24
@@ -1,58 +1,120 @@
|
||||
extern crate bytes;
|
||||
extern crate byteorder;
|
||||
extern crate iovec;
|
||||
#![warn(rust_2018_idioms)]
|
||||
|
||||
use bytes::Buf;
|
||||
use iovec::IoVec;
|
||||
use std::io::Cursor;
|
||||
#[cfg(feature = "std")]
|
||||
use std::io::IoSlice;
|
||||
|
||||
#[test]
|
||||
fn test_fresh_cursor_vec() {
|
||||
let mut buf = Cursor::new(b"hello".to_vec());
|
||||
let mut buf = &b"hello"[..];
|
||||
|
||||
assert_eq!(buf.remaining(), 5);
|
||||
assert_eq!(buf.bytes(), b"hello");
|
||||
assert_eq!(buf.chunk(), b"hello");
|
||||
|
||||
buf.advance(2);
|
||||
|
||||
assert_eq!(buf.remaining(), 3);
|
||||
assert_eq!(buf.bytes(), b"llo");
|
||||
assert_eq!(buf.chunk(), b"llo");
|
||||
|
||||
buf.advance(3);
|
||||
|
||||
assert_eq!(buf.remaining(), 0);
|
||||
assert_eq!(buf.bytes(), b"");
|
||||
assert_eq!(buf.chunk(), b"");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_u8() {
|
||||
let mut buf = Cursor::new(b"\x21zomg");
|
||||
let mut buf = &b"\x21zomg"[..];
|
||||
assert_eq!(0x21, buf.get_u8());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_u16() {
|
||||
let buf = b"\x21\x54zomg";
|
||||
assert_eq!(0x2154, Cursor::new(buf).get_u16_be());
|
||||
assert_eq!(0x5421, Cursor::new(buf).get_u16_le());
|
||||
let mut buf = &b"\x21\x54zomg"[..];
|
||||
assert_eq!(0x2154, buf.get_u16());
|
||||
let mut buf = &b"\x21\x54zomg"[..];
|
||||
assert_eq!(0x5421, buf.get_u16_le());
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn test_get_u16_buffer_underflow() {
|
||||
let mut buf = Cursor::new(b"\x21");
|
||||
buf.get_u16_be();
|
||||
let mut buf = &b"\x21"[..];
|
||||
buf.get_u16();
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
#[test]
|
||||
fn test_bufs_vec() {
|
||||
let buf = &b"hello world"[..];
|
||||
|
||||
let b1: &[u8] = &mut [];
|
||||
let b2: &[u8] = &mut [];
|
||||
|
||||
let mut dst = [IoSlice::new(b1), IoSlice::new(b2)];
|
||||
|
||||
assert_eq!(1, buf.chunks_vectored(&mut dst[..]));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_bufs_vec() {
|
||||
let buf = Cursor::new(b"hello world");
|
||||
fn test_vec_deque() {
|
||||
use std::collections::VecDeque;
|
||||
|
||||
let b1: &[u8] = &mut [0];
|
||||
let b2: &[u8] = &mut [0];
|
||||
|
||||
let mut dst: [&IoVec; 2] =
|
||||
[b1.into(), b2.into()];
|
||||
|
||||
assert_eq!(1, buf.bytes_vec(&mut dst[..]));
|
||||
let mut buffer: VecDeque<u8> = VecDeque::new();
|
||||
buffer.extend(b"hello world");
|
||||
assert_eq!(11, buffer.remaining());
|
||||
assert_eq!(b"hello world", buffer.chunk());
|
||||
buffer.advance(6);
|
||||
assert_eq!(b"world", buffer.chunk());
|
||||
buffer.extend(b" piece");
|
||||
let mut out = [0; 11];
|
||||
buffer.copy_to_slice(&mut out);
|
||||
assert_eq!(b"world piece", &out[..]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_deref_buf_forwards() {
|
||||
struct Special;
|
||||
|
||||
impl Buf for Special {
|
||||
fn remaining(&self) -> usize {
|
||||
unreachable!("remaining");
|
||||
}
|
||||
|
||||
fn chunk(&self) -> &[u8] {
|
||||
unreachable!("chunk");
|
||||
}
|
||||
|
||||
fn advance(&mut self, _: usize) {
|
||||
unreachable!("advance");
|
||||
}
|
||||
|
||||
fn get_u8(&mut self) -> u8 {
|
||||
// specialized!
|
||||
b'x'
|
||||
}
|
||||
}
|
||||
|
||||
// these should all use the specialized method
|
||||
assert_eq!(Special.get_u8(), b'x');
|
||||
assert_eq!((&mut Special as &mut dyn Buf).get_u8(), b'x');
|
||||
assert_eq!((Box::new(Special) as Box<dyn Buf>).get_u8(), b'x');
|
||||
assert_eq!(Box::new(Special).get_u8(), b'x');
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn copy_to_bytes_less() {
|
||||
let mut buf = &b"hello world"[..];
|
||||
|
||||
let bytes = buf.copy_to_bytes(5);
|
||||
assert_eq!(bytes, &b"hello"[..]);
|
||||
assert_eq!(buf, &b" world"[..])
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn copy_to_bytes_overflow() {
|
||||
let mut buf = &b"hello world"[..];
|
||||
|
||||
let _bytes = buf.copy_to_bytes(12);
|
||||
}
|
||||
|
||||
+120
-25
@@ -1,27 +1,23 @@
|
||||
extern crate bytes;
|
||||
extern crate byteorder;
|
||||
extern crate iovec;
|
||||
#![warn(rust_2018_idioms)]
|
||||
|
||||
use bytes::buf::UninitSlice;
|
||||
use bytes::{BufMut, BytesMut};
|
||||
use iovec::IoVec;
|
||||
use std::usize;
|
||||
use std::fmt::Write;
|
||||
use core::fmt::Write;
|
||||
use core::usize;
|
||||
|
||||
#[test]
|
||||
fn test_vec_as_mut_buf() {
|
||||
let mut buf = Vec::with_capacity(64);
|
||||
|
||||
assert_eq!(buf.remaining_mut(), usize::MAX);
|
||||
assert_eq!(buf.remaining_mut(), isize::MAX as usize);
|
||||
|
||||
unsafe {
|
||||
assert!(buf.bytes_mut().len() >= 64);
|
||||
}
|
||||
assert!(buf.chunk_mut().len() >= 64);
|
||||
|
||||
buf.put(&b"zomg"[..]);
|
||||
|
||||
assert_eq!(&buf, b"zomg");
|
||||
|
||||
assert_eq!(buf.remaining_mut(), usize::MAX - 4);
|
||||
assert_eq!(buf.remaining_mut(), isize::MAX as usize - 4);
|
||||
assert_eq!(buf.capacity(), 64);
|
||||
|
||||
for _ in 0..16 {
|
||||
@@ -31,17 +27,25 @@ fn test_vec_as_mut_buf() {
|
||||
assert_eq!(buf.len(), 68);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_vec_put_bytes() {
|
||||
let mut buf = Vec::new();
|
||||
buf.push(17);
|
||||
buf.put_bytes(19, 2);
|
||||
assert_eq!([17, 19, 19], &buf[..]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_put_u8() {
|
||||
let mut buf = Vec::with_capacity(8);
|
||||
buf.put::<u8>(33);
|
||||
buf.put_u8(33);
|
||||
assert_eq!(b"\x21", &buf[..]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_put_u16() {
|
||||
let mut buf = Vec::with_capacity(8);
|
||||
buf.put_u16_be(8532);
|
||||
buf.put_u16(8532);
|
||||
assert_eq!(b"\x21\x54", &buf[..]);
|
||||
|
||||
buf.clear();
|
||||
@@ -50,13 +54,40 @@ fn test_put_u16() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_put_int() {
|
||||
let mut buf = Vec::with_capacity(8);
|
||||
buf.put_int(0x1020304050607080, 3);
|
||||
assert_eq!(b"\x60\x70\x80", &buf[..]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn test_put_int_nbytes_overflow() {
|
||||
let mut buf = Vec::with_capacity(8);
|
||||
buf.put_int(0x1020304050607080, 9);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_put_int_le() {
|
||||
let mut buf = Vec::with_capacity(8);
|
||||
buf.put_int_le(0x1020304050607080, 3);
|
||||
assert_eq!(b"\x80\x70\x60", &buf[..]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn test_put_int_le_nbytes_overflow() {
|
||||
let mut buf = Vec::with_capacity(8);
|
||||
buf.put_int_le(0x1020304050607080, 9);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic(expected = "cannot advance")]
|
||||
fn test_vec_advance_mut() {
|
||||
// Regression test for carllerche/bytes#108.
|
||||
// Verify fix for #354
|
||||
let mut buf = Vec::with_capacity(8);
|
||||
unsafe {
|
||||
buf.advance_mut(12);
|
||||
assert_eq!(buf.len(), 12);
|
||||
assert!(buf.capacity() >= 12, "capacity: {}", buf.capacity());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,18 +97,82 @@ fn test_clone() {
|
||||
buf.write_str("this is a test").unwrap();
|
||||
let buf2 = buf.clone();
|
||||
|
||||
buf.write_str(" of our emergecy broadcast system").unwrap();
|
||||
buf.write_str(" of our emergency broadcast system").unwrap();
|
||||
assert!(buf != buf2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_bufs_vec_mut() {
|
||||
use std::mem;
|
||||
fn test_mut_slice() {
|
||||
let mut v = vec![0, 0, 0, 0];
|
||||
let mut s = &mut v[..];
|
||||
s.put_u32(42);
|
||||
|
||||
let mut buf = BytesMut::from(&b"hello world"[..]);
|
||||
|
||||
unsafe {
|
||||
let mut dst: [&mut IoVec; 2] = mem::zeroed();
|
||||
assert_eq!(1, buf.bytes_vec_mut(&mut dst[..]));
|
||||
}
|
||||
assert_eq!(s.len(), 0);
|
||||
assert_eq!(&v, &[0, 0, 0, 42]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_slice_put_bytes() {
|
||||
let mut v = [0, 0, 0, 0];
|
||||
let mut s = &mut v[..];
|
||||
s.put_u8(17);
|
||||
s.put_bytes(19, 2);
|
||||
assert_eq!(1, s.remaining_mut());
|
||||
assert_eq!(&[17, 19, 19, 0], &v[..]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_deref_bufmut_forwards() {
|
||||
struct Special;
|
||||
|
||||
unsafe impl BufMut for Special {
|
||||
fn remaining_mut(&self) -> usize {
|
||||
unreachable!("remaining_mut");
|
||||
}
|
||||
|
||||
fn chunk_mut(&mut self) -> &mut UninitSlice {
|
||||
unreachable!("chunk_mut");
|
||||
}
|
||||
|
||||
unsafe fn advance_mut(&mut self, _: usize) {
|
||||
unreachable!("advance");
|
||||
}
|
||||
|
||||
fn put_u8(&mut self, _: u8) {
|
||||
// specialized!
|
||||
}
|
||||
}
|
||||
|
||||
// these should all use the specialized method
|
||||
Special.put_u8(b'x');
|
||||
(&mut Special as &mut dyn BufMut).put_u8(b'x');
|
||||
(Box::new(Special) as Box<dyn BufMut>).put_u8(b'x');
|
||||
Box::new(Special).put_u8(b'x');
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn write_byte_panics_if_out_of_bounds() {
|
||||
let mut data = [b'b', b'a', b'r'];
|
||||
|
||||
let slice = unsafe { UninitSlice::from_raw_parts_mut(data.as_mut_ptr(), 3) };
|
||||
slice.write_byte(4, b'f');
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn copy_from_slice_panics_if_different_length_1() {
|
||||
let mut data = [b'b', b'a', b'r'];
|
||||
|
||||
let slice = unsafe { UninitSlice::from_raw_parts_mut(data.as_mut_ptr(), 3) };
|
||||
slice.copy_from_slice(b"a");
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn copy_from_slice_panics_if_different_length_2() {
|
||||
let mut data = [b'b', b'a', b'r'];
|
||||
|
||||
let slice = unsafe { UninitSlice::from_raw_parts_mut(data.as_mut_ptr(), 3) };
|
||||
slice.copy_from_slice(b"abcd");
|
||||
}
|
||||
|
||||
+620
-167
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,97 @@
|
||||
//! Test using `Bytes` with an allocator that hands out "odd" pointers for
|
||||
//! vectors (pointers where the LSB is set).
|
||||
|
||||
#![cfg(not(miri))] // Miri does not support custom allocators (also, Miri is "odd" by default with 50% chance)
|
||||
|
||||
use std::alloc::{GlobalAlloc, Layout, System};
|
||||
use std::ptr;
|
||||
|
||||
use bytes::Bytes;
|
||||
|
||||
#[global_allocator]
|
||||
static ODD: Odd = Odd;
|
||||
|
||||
struct Odd;
|
||||
|
||||
unsafe impl GlobalAlloc for Odd {
|
||||
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
|
||||
if layout.align() == 1 && layout.size() > 0 {
|
||||
// Allocate slightly bigger so that we can offset the pointer by 1
|
||||
let size = layout.size() + 1;
|
||||
let new_layout = match Layout::from_size_align(size, 1) {
|
||||
Ok(layout) => layout,
|
||||
Err(_err) => return ptr::null_mut(),
|
||||
};
|
||||
let ptr = System.alloc(new_layout);
|
||||
if !ptr.is_null() {
|
||||
ptr.offset(1)
|
||||
} else {
|
||||
ptr
|
||||
}
|
||||
} else {
|
||||
System.alloc(layout)
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
|
||||
if layout.align() == 1 && layout.size() > 0 {
|
||||
let size = layout.size() + 1;
|
||||
let new_layout = match Layout::from_size_align(size, 1) {
|
||||
Ok(layout) => layout,
|
||||
Err(_err) => std::process::abort(),
|
||||
};
|
||||
System.dealloc(ptr.offset(-1), new_layout);
|
||||
} else {
|
||||
System.dealloc(ptr, layout);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sanity_check_odd_allocator() {
|
||||
let vec = vec![33u8; 1024];
|
||||
let p = vec.as_ptr() as usize;
|
||||
assert!(p & 0x1 == 0x1, "{:#b}", p);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_bytes_from_vec_drop() {
|
||||
let vec = vec![33u8; 1024];
|
||||
let _b = Bytes::from(vec);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_bytes_clone_drop() {
|
||||
let vec = vec![33u8; 1024];
|
||||
let b1 = Bytes::from(vec);
|
||||
let _b2 = b1.clone();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_bytes_into_vec() {
|
||||
let vec = vec![33u8; 1024];
|
||||
|
||||
// Test cases where kind == KIND_VEC
|
||||
let b1 = Bytes::from(vec.clone());
|
||||
assert_eq!(Vec::from(b1), vec);
|
||||
|
||||
// Test cases where kind == KIND_ARC, ref_cnt == 1
|
||||
let b1 = Bytes::from(vec.clone());
|
||||
drop(b1.clone());
|
||||
assert_eq!(Vec::from(b1), vec);
|
||||
|
||||
// Test cases where kind == KIND_ARC, ref_cnt == 2
|
||||
let b1 = Bytes::from(vec.clone());
|
||||
let b2 = b1.clone();
|
||||
assert_eq!(Vec::from(b1), vec);
|
||||
|
||||
// Test cases where vtable = SHARED_VTABLE, kind == KIND_ARC, ref_cnt == 1
|
||||
assert_eq!(Vec::from(b2), vec);
|
||||
|
||||
// Test cases where offset != 0
|
||||
let mut b1 = Bytes::from(vec.clone());
|
||||
let b2 = b1.split_off(20);
|
||||
|
||||
assert_eq!(Vec::from(b2), vec[20..]);
|
||||
assert_eq!(Vec::from(b1), vec[..20]);
|
||||
}
|
||||
@@ -0,0 +1,143 @@
|
||||
use std::alloc::{GlobalAlloc, Layout, System};
|
||||
use std::ptr::null_mut;
|
||||
use std::sync::atomic::{AtomicPtr, AtomicUsize, Ordering};
|
||||
|
||||
use bytes::{Buf, Bytes};
|
||||
|
||||
#[global_allocator]
|
||||
static LEDGER: Ledger = Ledger::new();
|
||||
|
||||
const LEDGER_LENGTH: usize = 2048;
|
||||
|
||||
struct Ledger {
|
||||
alloc_table: [(AtomicPtr<u8>, AtomicUsize); LEDGER_LENGTH],
|
||||
}
|
||||
|
||||
impl Ledger {
|
||||
const fn new() -> Self {
|
||||
const ELEM: (AtomicPtr<u8>, AtomicUsize) =
|
||||
(AtomicPtr::new(null_mut()), AtomicUsize::new(0));
|
||||
let alloc_table = [ELEM; LEDGER_LENGTH];
|
||||
|
||||
Self { alloc_table }
|
||||
}
|
||||
|
||||
/// Iterate over our table until we find an open entry, then insert into said entry
|
||||
fn insert(&self, ptr: *mut u8, size: usize) {
|
||||
for (entry_ptr, entry_size) in self.alloc_table.iter() {
|
||||
// SeqCst is good enough here, we don't care about perf, i just want to be correct!
|
||||
if entry_ptr
|
||||
.compare_exchange(null_mut(), ptr, Ordering::SeqCst, Ordering::SeqCst)
|
||||
.is_ok()
|
||||
{
|
||||
entry_size.store(size, Ordering::SeqCst);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn remove(&self, ptr: *mut u8) -> usize {
|
||||
for (entry_ptr, entry_size) in self.alloc_table.iter() {
|
||||
// set the value to be something that will never try and be deallocated, so that we
|
||||
// don't have any chance of a race condition
|
||||
//
|
||||
// dont worry, LEDGER_LENGTH is really long to compensate for us not reclaiming space
|
||||
if entry_ptr
|
||||
.compare_exchange(
|
||||
ptr,
|
||||
invalid_ptr(usize::MAX),
|
||||
Ordering::SeqCst,
|
||||
Ordering::SeqCst,
|
||||
)
|
||||
.is_ok()
|
||||
{
|
||||
return entry_size.load(Ordering::SeqCst);
|
||||
}
|
||||
}
|
||||
|
||||
panic!("Couldn't find a matching entry for {:x?}", ptr);
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl GlobalAlloc for Ledger {
|
||||
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
|
||||
let size = layout.size();
|
||||
let ptr = System.alloc(layout);
|
||||
self.insert(ptr, size);
|
||||
ptr
|
||||
}
|
||||
|
||||
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
|
||||
let orig_size = self.remove(ptr);
|
||||
|
||||
if orig_size != layout.size() {
|
||||
panic!(
|
||||
"bad dealloc: alloc size was {}, dealloc size is {}",
|
||||
orig_size,
|
||||
layout.size()
|
||||
);
|
||||
} else {
|
||||
System.dealloc(ptr, layout);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_bytes_advance() {
|
||||
let mut bytes = Bytes::from(vec![10, 20, 30]);
|
||||
bytes.advance(1);
|
||||
drop(bytes);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_bytes_truncate() {
|
||||
let mut bytes = Bytes::from(vec![10, 20, 30]);
|
||||
bytes.truncate(2);
|
||||
drop(bytes);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_bytes_truncate_and_advance() {
|
||||
let mut bytes = Bytes::from(vec![10, 20, 30]);
|
||||
bytes.truncate(2);
|
||||
bytes.advance(1);
|
||||
drop(bytes);
|
||||
}
|
||||
|
||||
/// Returns a dangling pointer with the given address. This is used to store
|
||||
/// integer data in pointer fields.
|
||||
#[inline]
|
||||
fn invalid_ptr<T>(addr: usize) -> *mut T {
|
||||
let ptr = std::ptr::null_mut::<u8>().wrapping_add(addr);
|
||||
debug_assert_eq!(ptr as usize, addr);
|
||||
ptr.cast::<T>()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_bytes_into_vec() {
|
||||
let vec = vec![33u8; 1024];
|
||||
|
||||
// Test cases where kind == KIND_VEC
|
||||
let b1 = Bytes::from(vec.clone());
|
||||
assert_eq!(Vec::from(b1), vec);
|
||||
|
||||
// Test cases where kind == KIND_ARC, ref_cnt == 1
|
||||
let b1 = Bytes::from(vec.clone());
|
||||
drop(b1.clone());
|
||||
assert_eq!(Vec::from(b1), vec);
|
||||
|
||||
// Test cases where kind == KIND_ARC, ref_cnt == 2
|
||||
let b1 = Bytes::from(vec.clone());
|
||||
let b2 = b1.clone();
|
||||
assert_eq!(Vec::from(b1), vec);
|
||||
|
||||
// Test cases where vtable = SHARED_VTABLE, kind == KIND_ARC, ref_cnt == 1
|
||||
assert_eq!(Vec::from(b2), vec);
|
||||
|
||||
// Test cases where offset != 0
|
||||
let mut b1 = Bytes::from(vec.clone());
|
||||
let b2 = b1.split_off(20);
|
||||
|
||||
assert_eq!(Vec::from(b2), vec[20..]);
|
||||
assert_eq!(Vec::from(b1), vec[..20]);
|
||||
}
|
||||
+115
-60
@@ -1,36 +1,31 @@
|
||||
extern crate bytes;
|
||||
extern crate iovec;
|
||||
#![warn(rust_2018_idioms)]
|
||||
|
||||
use bytes::{Buf, BufMut, Bytes, BytesMut};
|
||||
use bytes::buf::Chain;
|
||||
use iovec::IoVec;
|
||||
use std::io::Cursor;
|
||||
use bytes::{Buf, BufMut, Bytes};
|
||||
#[cfg(feature = "std")]
|
||||
use std::io::IoSlice;
|
||||
|
||||
#[test]
|
||||
fn collect_two_bufs() {
|
||||
let a = Cursor::new(Bytes::from(&b"hello"[..]));
|
||||
let b = Cursor::new(Bytes::from(&b"world"[..]));
|
||||
let a = Bytes::from(&b"hello"[..]);
|
||||
let b = Bytes::from(&b"world"[..]);
|
||||
|
||||
let res: Vec<u8> = a.chain(b).collect();
|
||||
let res = a.chain(b).copy_to_bytes(10);
|
||||
assert_eq!(res, &b"helloworld"[..]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn writing_chained() {
|
||||
let mut a = BytesMut::with_capacity(64);
|
||||
let mut b = BytesMut::with_capacity(64);
|
||||
let mut a = [0u8; 64];
|
||||
let mut b = [0u8; 64];
|
||||
|
||||
{
|
||||
let mut buf = Chain::new(&mut a, &mut b);
|
||||
let mut buf = (&mut a[..]).chain_mut(&mut b[..]);
|
||||
|
||||
for i in 0..128 {
|
||||
buf.put(i as u8);
|
||||
for i in 0u8..128 {
|
||||
buf.put_u8(i);
|
||||
}
|
||||
}
|
||||
|
||||
assert_eq!(64, a.len());
|
||||
assert_eq!(64, b.len());
|
||||
|
||||
for i in 0..64 {
|
||||
let expect = i as u8;
|
||||
assert_eq!(expect, a[i]);
|
||||
@@ -40,83 +35,143 @@ fn writing_chained() {
|
||||
|
||||
#[test]
|
||||
fn iterating_two_bufs() {
|
||||
let a = Cursor::new(Bytes::from(&b"hello"[..]));
|
||||
let b = Cursor::new(Bytes::from(&b"world"[..]));
|
||||
let a = Bytes::from(&b"hello"[..]);
|
||||
let b = Bytes::from(&b"world"[..]);
|
||||
|
||||
let res: Vec<u8> = a.chain(b).iter().collect();
|
||||
let res: Vec<u8> = a.chain(b).into_iter().collect();
|
||||
assert_eq!(res, &b"helloworld"[..]);
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
#[test]
|
||||
fn vectored_read() {
|
||||
let a = Cursor::new(Bytes::from(&b"hello"[..]));
|
||||
let b = Cursor::new(Bytes::from(&b"world"[..]));
|
||||
let a = Bytes::from(&b"hello"[..]);
|
||||
let b = Bytes::from(&b"world"[..]);
|
||||
|
||||
let mut buf = a.chain(b);
|
||||
|
||||
{
|
||||
let b1: &[u8] = &mut [0];
|
||||
let b2: &[u8] = &mut [0];
|
||||
let b3: &[u8] = &mut [0];
|
||||
let b4: &[u8] = &mut [0];
|
||||
let mut iovecs: [&IoVec; 4] =
|
||||
[b1.into(), b2.into(), b3.into(), b4.into()];
|
||||
let b1: &[u8] = &mut [];
|
||||
let b2: &[u8] = &mut [];
|
||||
let b3: &[u8] = &mut [];
|
||||
let b4: &[u8] = &mut [];
|
||||
let mut iovecs = [
|
||||
IoSlice::new(b1),
|
||||
IoSlice::new(b2),
|
||||
IoSlice::new(b3),
|
||||
IoSlice::new(b4),
|
||||
];
|
||||
|
||||
assert_eq!(2, buf.bytes_vec(&mut iovecs));
|
||||
assert_eq!(2, buf.chunks_vectored(&mut iovecs));
|
||||
assert_eq!(iovecs[0][..], b"hello"[..]);
|
||||
assert_eq!(iovecs[1][..], b"world"[..]);
|
||||
assert_eq!(iovecs[2][..], b"\0"[..]);
|
||||
assert_eq!(iovecs[3][..], b"\0"[..]);
|
||||
assert_eq!(iovecs[2][..], b""[..]);
|
||||
assert_eq!(iovecs[3][..], b""[..]);
|
||||
}
|
||||
|
||||
buf.advance(2);
|
||||
|
||||
{
|
||||
let b1: &[u8] = &mut [0];
|
||||
let b2: &[u8] = &mut [0];
|
||||
let b3: &[u8] = &mut [0];
|
||||
let b4: &[u8] = &mut [0];
|
||||
let mut iovecs: [&IoVec; 4] =
|
||||
[b1.into(), b2.into(), b3.into(), b4.into()];
|
||||
let b1: &[u8] = &mut [];
|
||||
let b2: &[u8] = &mut [];
|
||||
let b3: &[u8] = &mut [];
|
||||
let b4: &[u8] = &mut [];
|
||||
let mut iovecs = [
|
||||
IoSlice::new(b1),
|
||||
IoSlice::new(b2),
|
||||
IoSlice::new(b3),
|
||||
IoSlice::new(b4),
|
||||
];
|
||||
|
||||
assert_eq!(2, buf.bytes_vec(&mut iovecs));
|
||||
assert_eq!(2, buf.chunks_vectored(&mut iovecs));
|
||||
assert_eq!(iovecs[0][..], b"llo"[..]);
|
||||
assert_eq!(iovecs[1][..], b"world"[..]);
|
||||
assert_eq!(iovecs[2][..], b"\0"[..]);
|
||||
assert_eq!(iovecs[3][..], b"\0"[..]);
|
||||
assert_eq!(iovecs[2][..], b""[..]);
|
||||
assert_eq!(iovecs[3][..], b""[..]);
|
||||
}
|
||||
|
||||
buf.advance(3);
|
||||
|
||||
{
|
||||
let b1: &[u8] = &mut [0];
|
||||
let b2: &[u8] = &mut [0];
|
||||
let b3: &[u8] = &mut [0];
|
||||
let b4: &[u8] = &mut [0];
|
||||
let mut iovecs: [&IoVec; 4] =
|
||||
[b1.into(), b2.into(), b3.into(), b4.into()];
|
||||
let b1: &[u8] = &mut [];
|
||||
let b2: &[u8] = &mut [];
|
||||
let b3: &[u8] = &mut [];
|
||||
let b4: &[u8] = &mut [];
|
||||
let mut iovecs = [
|
||||
IoSlice::new(b1),
|
||||
IoSlice::new(b2),
|
||||
IoSlice::new(b3),
|
||||
IoSlice::new(b4),
|
||||
];
|
||||
|
||||
assert_eq!(1, buf.bytes_vec(&mut iovecs));
|
||||
assert_eq!(1, buf.chunks_vectored(&mut iovecs));
|
||||
assert_eq!(iovecs[0][..], b"world"[..]);
|
||||
assert_eq!(iovecs[1][..], b"\0"[..]);
|
||||
assert_eq!(iovecs[2][..], b"\0"[..]);
|
||||
assert_eq!(iovecs[3][..], b"\0"[..]);
|
||||
assert_eq!(iovecs[1][..], b""[..]);
|
||||
assert_eq!(iovecs[2][..], b""[..]);
|
||||
assert_eq!(iovecs[3][..], b""[..]);
|
||||
}
|
||||
|
||||
buf.advance(3);
|
||||
|
||||
{
|
||||
let b1: &[u8] = &mut [0];
|
||||
let b2: &[u8] = &mut [0];
|
||||
let b3: &[u8] = &mut [0];
|
||||
let b4: &[u8] = &mut [0];
|
||||
let mut iovecs: [&IoVec; 4] =
|
||||
[b1.into(), b2.into(), b3.into(), b4.into()];
|
||||
let b1: &[u8] = &mut [];
|
||||
let b2: &[u8] = &mut [];
|
||||
let b3: &[u8] = &mut [];
|
||||
let b4: &[u8] = &mut [];
|
||||
let mut iovecs = [
|
||||
IoSlice::new(b1),
|
||||
IoSlice::new(b2),
|
||||
IoSlice::new(b3),
|
||||
IoSlice::new(b4),
|
||||
];
|
||||
|
||||
assert_eq!(1, buf.bytes_vec(&mut iovecs));
|
||||
assert_eq!(1, buf.chunks_vectored(&mut iovecs));
|
||||
assert_eq!(iovecs[0][..], b"ld"[..]);
|
||||
assert_eq!(iovecs[1][..], b"\0"[..]);
|
||||
assert_eq!(iovecs[2][..], b"\0"[..]);
|
||||
assert_eq!(iovecs[3][..], b"\0"[..]);
|
||||
assert_eq!(iovecs[1][..], b""[..]);
|
||||
assert_eq!(iovecs[2][..], b""[..]);
|
||||
assert_eq!(iovecs[3][..], b""[..]);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn chain_growing_buffer() {
|
||||
let mut buff = [' ' as u8; 10];
|
||||
let mut vec = b"wassup".to_vec();
|
||||
|
||||
let mut chained = (&mut buff[..]).chain_mut(&mut vec).chain_mut(Vec::new()); // Required for potential overflow because remaining_mut for Vec is isize::MAX - vec.len(), but for chain_mut is usize::MAX
|
||||
|
||||
chained.put_slice(b"hey there123123");
|
||||
|
||||
assert_eq!(&buff, b"hey there1");
|
||||
assert_eq!(&vec, b"wassup23123");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn chain_overflow_remaining_mut() {
|
||||
let mut chained = Vec::<u8>::new().chain_mut(Vec::new()).chain_mut(Vec::new());
|
||||
|
||||
assert_eq!(chained.remaining_mut(), usize::MAX);
|
||||
chained.put_slice(&[0; 256]);
|
||||
assert_eq!(chained.remaining_mut(), usize::MAX);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn chain_get_bytes() {
|
||||
let mut ab = Bytes::copy_from_slice(b"ab");
|
||||
let mut cd = Bytes::copy_from_slice(b"cd");
|
||||
let ab_ptr = ab.as_ptr();
|
||||
let cd_ptr = cd.as_ptr();
|
||||
let mut chain = (&mut ab).chain(&mut cd);
|
||||
let a = chain.copy_to_bytes(1);
|
||||
let bc = chain.copy_to_bytes(2);
|
||||
let d = chain.copy_to_bytes(1);
|
||||
|
||||
assert_eq!(Bytes::copy_from_slice(b"a"), a);
|
||||
assert_eq!(Bytes::copy_from_slice(b"bc"), bc);
|
||||
assert_eq!(Bytes::copy_from_slice(b"d"), d);
|
||||
|
||||
// assert `get_bytes` did not allocate
|
||||
assert_eq!(ab_ptr, a.as_ptr());
|
||||
// assert `get_bytes` did not allocate
|
||||
assert_eq!(cd_ptr.wrapping_offset(1), d.as_ptr());
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
extern crate bytes;
|
||||
#![warn(rust_2018_idioms)]
|
||||
|
||||
use bytes::Bytes;
|
||||
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
extern crate bytes;
|
||||
|
||||
use bytes::{Buf, Bytes, BytesMut};
|
||||
use std::io::Cursor;
|
||||
|
||||
const LONG: &'static [u8] = b"mary had a little lamb, little lamb, little lamb";
|
||||
const SHORT: &'static [u8] = b"hello world";
|
||||
|
||||
#[test]
|
||||
fn collect_to_vec() {
|
||||
let buf: Vec<u8> = Cursor::new(SHORT).collect();
|
||||
assert_eq!(buf, SHORT);
|
||||
|
||||
let buf: Vec<u8> = Cursor::new(LONG).collect();
|
||||
assert_eq!(buf, LONG);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn collect_to_bytes() {
|
||||
let buf: Bytes = Cursor::new(SHORT).collect();
|
||||
assert_eq!(buf, SHORT);
|
||||
|
||||
let buf: Bytes = Cursor::new(LONG).collect();
|
||||
assert_eq!(buf, LONG);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn collect_to_bytes_mut() {
|
||||
let buf: BytesMut = Cursor::new(SHORT).collect();
|
||||
assert_eq!(buf, SHORT);
|
||||
|
||||
let buf: BytesMut = Cursor::new(LONG).collect();
|
||||
assert_eq!(buf, LONG);
|
||||
}
|
||||
+4
-5
@@ -1,20 +1,19 @@
|
||||
extern crate bytes;
|
||||
#![warn(rust_2018_idioms)]
|
||||
|
||||
use bytes::{Buf, IntoBuf, Bytes};
|
||||
use bytes::Bytes;
|
||||
|
||||
#[test]
|
||||
fn iter_len() {
|
||||
let buf = Bytes::from(&b"hello world"[..]).into_buf();
|
||||
let buf = Bytes::from_static(b"hello world");
|
||||
let iter = buf.iter();
|
||||
|
||||
assert_eq!(iter.size_hint(), (11, Some(11)));
|
||||
assert_eq!(iter.len(), 11);
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
fn empty_iter_len() {
|
||||
let buf = Bytes::from(&b""[..]).into_buf();
|
||||
let buf = Bytes::from_static(b"");
|
||||
let iter = buf.iter();
|
||||
|
||||
assert_eq!(iter.size_hint(), (0, Some(0)));
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
#![warn(rust_2018_idioms)]
|
||||
#![cfg(feature = "std")]
|
||||
|
||||
use std::io::{BufRead, Read};
|
||||
|
||||
use bytes::Buf;
|
||||
|
||||
#[test]
|
||||
fn read() {
|
||||
let buf1 = &b"hello "[..];
|
||||
let buf2 = &b"world"[..];
|
||||
let buf = Buf::chain(buf1, buf2); // Disambiguate with Read::chain
|
||||
let mut buffer = Vec::new();
|
||||
buf.reader().read_to_end(&mut buffer).unwrap();
|
||||
assert_eq!(b"hello world", &buffer[..]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn buf_read() {
|
||||
let buf1 = &b"hell"[..];
|
||||
let buf2 = &b"o\nworld"[..];
|
||||
let mut reader = Buf::chain(buf1, buf2).reader();
|
||||
let mut line = String::new();
|
||||
reader.read_line(&mut line).unwrap();
|
||||
assert_eq!("hello\n", &line);
|
||||
line.clear();
|
||||
reader.read_line(&mut line).unwrap();
|
||||
assert_eq!("world", &line);
|
||||
}
|
||||
+2
-3
@@ -1,8 +1,7 @@
|
||||
#![cfg(feature = "serde")]
|
||||
#![warn(rust_2018_idioms)]
|
||||
|
||||
extern crate bytes;
|
||||
extern crate serde_test;
|
||||
use serde_test::{Token, assert_tokens};
|
||||
use serde_test::{assert_tokens, Token};
|
||||
|
||||
#[test]
|
||||
fn test_ser_de_empty() {
|
||||
|
||||
+25
-6
@@ -1,13 +1,32 @@
|
||||
extern crate bytes;
|
||||
#![warn(rust_2018_idioms)]
|
||||
|
||||
use bytes::Buf;
|
||||
use std::io::Cursor;
|
||||
use bytes::buf::Buf;
|
||||
use bytes::Bytes;
|
||||
|
||||
#[test]
|
||||
fn long_take() {
|
||||
// Tests that take with a size greater than the buffer length will not
|
||||
// Tests that get a take with a size greater than the buffer length will not
|
||||
// overrun the buffer. Regression test for #138.
|
||||
let buf = Cursor::new(b"hello world").take(100);
|
||||
let buf = b"hello world".take(100);
|
||||
assert_eq!(11, buf.remaining());
|
||||
assert_eq!(b"hello world", buf.bytes());
|
||||
assert_eq!(b"hello world", buf.chunk());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn take_copy_to_bytes() {
|
||||
let mut abcd = Bytes::copy_from_slice(b"abcd");
|
||||
let abcd_ptr = abcd.as_ptr();
|
||||
let mut take = (&mut abcd).take(2);
|
||||
let a = take.copy_to_bytes(1);
|
||||
assert_eq!(Bytes::copy_from_slice(b"a"), a);
|
||||
// assert `to_bytes` did not allocate
|
||||
assert_eq!(abcd_ptr, a.as_ptr());
|
||||
assert_eq!(Bytes::copy_from_slice(b"bcd"), abcd);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn take_copy_to_bytes_panics() {
|
||||
let abcd = Bytes::copy_from_slice(b"abcd");
|
||||
abcd.take(2).copy_to_bytes(3);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user