mirror of
https://github.com/tokio-rs/bytes.git
synced 2026-08-08 00:00:26 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c45697ce42 | ||
|
|
0ac54ca706 | ||
|
|
d7c1d658d9 | ||
|
|
ac46ebdd46 | ||
|
|
79fb85323c | ||
|
|
291df5acc9 | ||
|
|
ed7d5ff39e | ||
|
|
dc4fb3e8f4 | ||
|
|
f488be48d0 | ||
|
|
03fdde9dcf | ||
|
|
f8c7b574c0 | ||
|
|
fd13c7dcdb | ||
|
|
6b4b0eda29 | ||
|
|
9965a04b56 | ||
|
|
3443ca5a0b | ||
|
|
8cc940779f | ||
|
|
7a5154ba8b | ||
|
|
fa1daac3ae | ||
|
|
caf520ac7f | ||
|
|
4950c50376 | ||
|
|
86694b0564 | ||
|
|
0c17e99283 | ||
|
|
cb7f8449b5 | ||
|
|
a8806c2457 | ||
|
|
baa5053572 | ||
|
|
ce09d7d358 | ||
|
|
9d3ec1cffb | ||
|
|
4e2c9c065a | ||
|
|
327615e5d4 | ||
|
|
b5fbfc3edb | ||
|
|
4eb62b912a | ||
|
|
e4af48633c | ||
|
|
0d4cc7ffed | ||
|
|
ce8d8a0a02 | ||
|
|
536db06f16 | ||
|
|
ca004117f8 | ||
|
|
7968f6f83d | ||
|
|
c5fae00c76 | ||
|
|
99584cc10d | ||
|
|
46289278f5 | ||
|
|
1bcd2129d1 | ||
|
|
f586ffc525 | ||
|
|
c6972d6132 | ||
|
|
47e83056f2 | ||
|
|
8bcac21cb4 | ||
|
|
d2e7abdb29 | ||
|
|
e24587dd61 | ||
|
|
9257a6ea08 | ||
|
|
0ba3b4c4cd | ||
|
|
0864aea970 | ||
|
|
abb4a2e66c | ||
|
|
09214ba51b | ||
|
|
fbc64bcc67 | ||
|
|
3bf6583b5c | ||
|
|
dbbdb63d76 | ||
|
|
f73c6c8e85 | ||
|
|
72cbb92e0e | ||
|
|
bde8c50703 | ||
|
|
fd9243f9e2 | ||
|
|
a4e16a552b | ||
|
|
a14ef4617c | ||
|
|
bd9c164cb6 | ||
|
|
74e6e200fd | ||
|
|
64c4fa2867 | ||
|
|
c7756c3e59 | ||
|
|
b29112ce44 | ||
|
|
99a27542a0 | ||
|
|
74b04c7aae | ||
|
|
21ed332836 | ||
|
|
05e9d5cab9 | ||
|
|
f15bba3375 | ||
|
|
c93a94b974 | ||
|
|
050d65b2ce | ||
|
|
9b227220df | ||
|
|
8a8c41f5c2 | ||
|
|
5c7b4317e0 | ||
|
|
6e4b1f244b | ||
|
|
a36f661354 | ||
|
|
d1b5d4ceb1 | ||
|
|
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 | ||
|
|
406b048ae6 | ||
|
|
8c041142a0 | ||
|
|
3557bafa5c | ||
|
|
c87739bb55 | ||
|
|
e9a7098658 | ||
|
|
32ea8281b3 | ||
|
|
dfce95b89d | ||
|
|
2d95683bd5 | ||
|
|
b68fa46e3d | ||
|
|
ef09e98fbc | ||
|
|
d656d37180 | ||
|
|
51e435b7e0 | ||
|
|
15050b1da5 | ||
|
|
e444722098 | ||
|
|
d561006290 | ||
|
|
2c27ddaf7e | ||
|
|
ae1b45495b | ||
|
|
ebe522731f | ||
|
|
bd4630a321 | ||
|
|
025d53342e | ||
|
|
ce79f0a268 | ||
|
|
ff7c0a1d90 | ||
|
|
4b68ef407f | ||
|
|
86c83959dc | ||
|
|
355a662976 | ||
|
|
3d169f1f34 | ||
|
|
c316c2433d | ||
|
|
e5c4c6028d | ||
|
|
ba9a975358 | ||
|
|
6a3d20bb8d | ||
|
|
2ca61d881d | ||
|
|
8d6c2b61cc | ||
|
|
02891144be | ||
|
|
149922d7cf | ||
|
|
03d501b18d | ||
|
|
34540be54c | ||
|
|
cfca1c04fa | ||
|
|
c8c46d8513 | ||
|
|
7839100389 | ||
|
|
6750a26fd0 | ||
|
|
b9ccd2a866 | ||
|
|
544997958f | ||
|
|
d315d00a3b | ||
|
|
fb2d8cf1c0 | ||
|
|
7ed78cef47 | ||
|
|
aab71ef82c | ||
|
|
7e8373da8d | ||
|
|
3240fb9cd9 | ||
|
|
9ae51c9f0c | ||
|
|
2b0602e756 | ||
|
|
3f5890be70 | ||
|
|
70ee87ea29 | ||
|
|
edf1af958a | ||
|
|
7110d57b2f | ||
|
|
07db74b009 | ||
|
|
6af66c4f21 | ||
|
|
fa44c7e355 | ||
|
|
2c0cb1b6b8 | ||
|
|
b196559818 | ||
|
|
37f6cabd96 | ||
|
|
e5c7ef3b86 | ||
|
|
30bd7c1f21 | ||
|
|
923d927bd1 | ||
|
|
0b4185c716 | ||
|
|
e158160418 | ||
|
|
4645f6ec4b | ||
|
|
1a6901cdcd | ||
|
|
9aa24ebea1 | ||
|
|
627864187c | ||
|
|
b78bb3baaa | ||
|
|
6c6c55d8e1 | ||
|
|
613d4bd5d5 | ||
|
|
dc9c8e304e | ||
|
|
bed128b2c0 | ||
|
|
5a265cc8eb | ||
|
|
4fe4e9429a | ||
|
|
9a4018e757 | ||
|
|
99fba239db | ||
|
|
dcd6c184e4 | ||
|
|
9e6d65a1d6 | ||
|
|
02b6144644 | ||
|
|
2e319b51be | ||
|
|
06b94c55b0 | ||
|
|
d70f575afd | ||
|
|
933b8b26f6 | ||
|
|
b44fc31463 | ||
|
|
d0142aa6da | ||
|
|
94396162b2 | ||
|
|
bb9bf7ee3e | ||
|
|
4462056e26 | ||
|
|
30c0e4e9c8 | ||
|
|
d19c929018 | ||
|
|
8fec8a92ad | ||
|
|
4f8c565111 | ||
|
|
fd8f716e68 | ||
|
|
22a5fb8d9b | ||
|
|
e842296c4d | ||
|
|
f7f8d6c9ef | ||
|
|
87160b6232 | ||
|
|
4466b75ae4 | ||
|
|
9eb5bd50b8 | ||
|
|
b46d3fd32e | ||
|
|
8c11456185 | ||
|
|
128c56ddc4 | ||
|
|
5c6eadfcb0 | ||
|
|
c6fe5a1e4f | ||
|
|
99aafb0a22 | ||
|
|
cf5a1bc4f1 | ||
|
|
0360f191f8 | ||
|
|
aa06b6dd6a | ||
|
|
5048eec143 | ||
|
|
268226051d | ||
|
|
646624c130 | ||
|
|
bababa8797 | ||
|
|
0e0066e8a0 | ||
|
|
53d1c788e0 | ||
|
|
4c6ebeba87 | ||
|
|
8da9e81469 | ||
|
|
36c9a8c287 | ||
|
|
44d40d34d7 | ||
|
|
70fed562eb | ||
|
|
accc8a460d | ||
|
|
8b01298806 | ||
|
|
a8320da0f8 | ||
|
|
93c08064bb | ||
|
|
2b796d40e9 | ||
|
|
12d0804f17 | ||
|
|
4886b44516 | ||
|
|
a367a723d8 | ||
|
|
11fe277c0d | ||
|
|
57e84f267b | ||
|
|
d717fde5ca | ||
|
|
b42d94c33b | ||
|
|
8d2508bfeb | ||
|
|
ec7d7f27fe | ||
|
|
d7306d949b | ||
|
|
a4bfc63de7 | ||
|
|
6f97d04077 | ||
|
|
e00c08c6c7 | ||
|
|
e1c7f183ca | ||
|
|
4ca7e0fabf | ||
|
|
b10992a5e8 | ||
|
|
b1dc10e907 | ||
|
|
c16ad2bc9d | ||
|
|
a7d38e29e5 | ||
|
|
98e0d954b5 | ||
|
|
d05bfb6346 | ||
|
|
3c58b0c75c | ||
|
|
4105901244 | ||
|
|
1f188b5628 | ||
|
|
f693e038d9 | ||
|
|
d0d27bd540 | ||
|
|
046c864543 | ||
|
|
38abb8074b | ||
|
|
be23af6bb7 | ||
|
|
fbebb19a02 | ||
|
|
04e0ac75e2 | ||
|
|
b2efe63c70 | ||
|
|
16b4266c3c | ||
|
|
b6a424d892 | ||
|
|
6529f6392a | ||
|
|
3f68c4bd27 | ||
|
|
eec203c118 | ||
|
|
41b722dee8 | ||
|
|
d650404bb8 | ||
|
|
1c2234f7fe | ||
|
|
dc25c7564e | ||
|
|
b10b1cd2e2 | ||
|
|
3ca009577b | ||
|
|
270d2e2844 | ||
|
|
12dfc417ce | ||
|
|
6b624b849a | ||
|
|
01c1e05a91 | ||
|
|
a76dd8ed0e | ||
|
|
4ce8b1c2c8 | ||
|
|
3d0a4adc30 | ||
|
|
ef82792adf | ||
|
|
3fae2b0bbf | ||
|
|
846aec9d2b | ||
|
|
7edb577d0a | ||
|
|
531c77654c | ||
|
|
ed087be853 | ||
|
|
b4abd1431a | ||
|
|
296cac263c | ||
|
|
23ad12f842 | ||
|
|
d20661676f | ||
|
|
c17f16fdf2 | ||
|
|
7b63fa034f | ||
|
|
d2b4cc3870 | ||
|
|
2d3b4b9002 | ||
|
|
0d7d120733 | ||
|
|
5584fa84dc | ||
|
|
64f8a0c6f6 | ||
|
|
d25958970e | ||
|
|
c5452b8cce | ||
|
|
a91ee81bda | ||
|
|
e39f2ba917 | ||
|
|
e62bd07b77 | ||
|
|
4d645c7f53 | ||
|
|
40f1d1aa77 | ||
|
|
c4546493ea | ||
|
|
e22415b416 | ||
|
|
c9d3427fd5 | ||
|
|
ac42766535 | ||
|
|
c4f2e20eb1 | ||
|
|
dfe4cec871 | ||
|
|
1ead637f69 | ||
|
|
c8f0bbd513 | ||
|
|
8af74ae40e | ||
|
|
29e5dc72bb | ||
|
|
635274752b | ||
|
|
fb67281e72 | ||
|
|
f0ce42d9c3 | ||
|
|
7a12abb6e6 | ||
|
|
e4fd392458 | ||
|
|
74a59c66b4 | ||
|
|
805b15e517 | ||
|
|
54f98821f3 | ||
|
|
8f526231d8 | ||
|
|
53624038ad | ||
|
|
83680dda27 | ||
|
|
bb1227116b | ||
|
|
68a0abf687 | ||
|
|
bd2c643e17 | ||
|
|
a87dea0bd4 | ||
|
|
3f9b7f6d46 | ||
|
|
e806a59b4a | ||
|
|
6f00c6117b | ||
|
|
113bff22c6 | ||
|
|
b7c7ff5ab6 | ||
|
|
7e02c29e85 | ||
|
|
7444721d98 | ||
|
|
e39ba25a95 | ||
|
|
1f1aa36547 | ||
|
|
a3fea6b1e2 | ||
|
|
d7a9e9ffc9 | ||
|
|
1442ad219c | ||
|
|
4ebffd0103 | ||
|
|
66c00aaf72 | ||
|
|
974043bd13 |
@@ -0,0 +1,183 @@
|
||||
name: CI
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
schedule:
|
||||
- cron: '0 2 * * 0'
|
||||
|
||||
env:
|
||||
RUSTFLAGS: -Dwarnings
|
||||
RUST_BACKTRACE: 1
|
||||
nightly: nightly-2024-09-15
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
|
||||
jobs:
|
||||
# Check formatting
|
||||
rustfmt:
|
||||
name: rustfmt
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Install Rust
|
||||
run: rustup update stable
|
||||
- name: Check formatting
|
||||
run: cargo fmt --all --check
|
||||
|
||||
# TODO
|
||||
# # Apply clippy lints
|
||||
# clippy:
|
||||
# name: clippy
|
||||
# runs-on: ubuntu-latest
|
||||
# steps:
|
||||
# - uses: actions/checkout@v4
|
||||
# - 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@v4
|
||||
- name: Install cargo-hack
|
||||
uses: taiki-e/install-action@cargo-hack
|
||||
- name: Check
|
||||
run: cargo hack check --feature-powerset --optional-deps --rust-version
|
||||
|
||||
# Stable
|
||||
stable:
|
||||
name: stable
|
||||
strategy:
|
||||
matrix:
|
||||
os:
|
||||
- ubuntu-latest
|
||||
- macos-latest
|
||||
- windows-latest
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Install Rust
|
||||
# --no-self-update is necessary because the windows environment cannot self-update rustup.exe.
|
||||
run: rustup update stable --no-self-update
|
||||
- name: Install cargo-hack
|
||||
uses: taiki-e/install-action@cargo-hack
|
||||
- name: Test
|
||||
run: ci/test-stable.sh test
|
||||
|
||||
# Nightly
|
||||
nightly:
|
||||
name: nightly
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Install Rust
|
||||
run: rustup update $nightly && rustup default $nightly
|
||||
- name: Install cargo-hack
|
||||
uses: taiki-e/install-action@cargo-hack
|
||||
- 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@v4
|
||||
- name: Install Rust
|
||||
run: rustup update stable
|
||||
- name: Install cross
|
||||
uses: taiki-e/install-action@cross
|
||||
if: matrix.target != 'wasm32-unknown-unknown'
|
||||
- name: cross build --target ${{ matrix.target }}
|
||||
run: 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@v4
|
||||
- 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@v4
|
||||
- name: Install Rust
|
||||
run: rustup update $nightly && rustup default $nightly
|
||||
- name: Miri
|
||||
run: ci/miri.sh
|
||||
|
||||
# Loom
|
||||
loom:
|
||||
name: loom
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- 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
|
||||
- miri
|
||||
- loom
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Install Rust
|
||||
run: rustup update $nightly && rustup default $nightly
|
||||
- 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'
|
||||
-14
@@ -1,14 +0,0 @@
|
||||
---
|
||||
language: rust
|
||||
sudo: false
|
||||
|
||||
script:
|
||||
- cargo test
|
||||
- cargo doc --no-deps
|
||||
|
||||
after_success:
|
||||
- test $TRAVIS_PULL_REQUEST == "false" && test $TRAVIS_BRANCH == "master" && bash deploy.sh
|
||||
|
||||
env:
|
||||
global:
|
||||
secure: "mBLJANLvtmyWCXw4zMquptqHQnws0pF+C/u4zL1Jfwz8T4UnUjmBUMxSOgSEIzrOM3qb+CTCjY2/j6BM21+/Zfdl8k8CvFWtkqQUPwIfrtwddCgI+P8Hlrk8G43drz/8XAbZ7dOl+Ovwhr0xnSD9ImfyXJec1kDWhubmgyt47Fs="
|
||||
+391
@@ -0,0 +1,391 @@
|
||||
# 1.8.0 (October 21, 2024)
|
||||
|
||||
- Guarantee address in `split_off`/`split_to` for empty slices (#740)
|
||||
|
||||
# 1.7.2 (September 17, 2024)
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix default impl of `Buf::{get_int, get_int_le}` (#732)
|
||||
|
||||
### Documented
|
||||
|
||||
- Fix double spaces in comments and doc comments (#731)
|
||||
|
||||
### Internal changes
|
||||
|
||||
- Ensure BytesMut::advance reduces capacity (#728)
|
||||
|
||||
# 1.7.1 (August 1, 2024)
|
||||
|
||||
This release reverts the following change due to a regression:
|
||||
|
||||
- Reuse capacity when possible in `<BytesMut as Buf>::advance` impl (#698)
|
||||
|
||||
The revert can be found at #726.
|
||||
|
||||
# 1.7.0 (July 31, 2024)
|
||||
|
||||
### Added
|
||||
|
||||
- Add conversion from `Bytes` to `BytesMut` (#695, #710)
|
||||
- Add reclaim method without additional allocation (#686)
|
||||
|
||||
### Documented
|
||||
|
||||
- Clarify how `BytesMut::zeroed` works (#714)
|
||||
- Clarify the behavior of `Buf::chunk` (#717)
|
||||
|
||||
### Changed
|
||||
|
||||
- Change length condition of `BytesMut::truncate`
|
||||
- Reuse capacity when possible in `<BytesMut as Buf>::advance` impl (#698)
|
||||
- Improve `must_use` suggestion of `BytesMut::split` (#699)
|
||||
|
||||
### Internal changes
|
||||
|
||||
- Use `ManuallyDrop` instead of `mem::forget` (#678)
|
||||
- Don't set `len` in `BytesMut::reserve` (#682)
|
||||
- Optimize `Bytes::copy_to_bytes` (#688)
|
||||
- Refactor `BytesMut::truncate` (#694)
|
||||
- Refactor `BytesMut::resize` (#696)
|
||||
- Reorder assertion in `Bytes::split_to`, `Bytes::split_off` (#689, #693)
|
||||
- Use `offset_from` in more places (#705)
|
||||
- Correct the wrong usage of `IntoIter` (#707)
|
||||
|
||||
# 1.6.1 (July 13, 2024)
|
||||
|
||||
This release fixes a bug where `Bytes::is_unique` returns incorrect values when
|
||||
the `Bytes` originates from a shared `BytesMut`. (#718)
|
||||
|
||||
# 1.6.0 (March 22, 2024)
|
||||
|
||||
### Added
|
||||
|
||||
- Add `Bytes::is_unique` (#643)
|
||||
|
||||
### Documented
|
||||
|
||||
- Fix changelog typo (#628)
|
||||
- Fix some spelling mistakes (#633)
|
||||
- Typo fix (#637)
|
||||
- Fix broken links (#639)
|
||||
- Add security policy (#649)
|
||||
|
||||
### Internal changes
|
||||
|
||||
- Move comment to correct constant (#629)
|
||||
- Various cleanup (#635)
|
||||
- Simplify `UninitSlice::as_uninit_slice_mut()` logic (#644)
|
||||
- Use `self.` instead of `Self::` (#642)
|
||||
- `BytesMut`: Assert alignment of `Shared` (#652)
|
||||
- Remove unnecessary namespace qualifier (#660)
|
||||
- Remove an unnecessary else branch (#662)
|
||||
- Remove unreachable else branch (#661)
|
||||
- make parameter mut in `From<Vec>` (#667)
|
||||
- Restore commented tests (#665)
|
||||
- Use `sub` instead of `offset` (#668)
|
||||
- Calculate original capacity only if necessary (#666)
|
||||
- `set_vec_pos` does not need a second parameter (#672)
|
||||
- `get_vec_pos`: use `&self` instead of `&mut self` (#670)
|
||||
- Refactor `split_at`/`split_to` (#663)
|
||||
- Use `Iterator` from the prelude (#673)
|
||||
- `copy_to_bytes`: Add panic section to docs (#676)
|
||||
- Remove redundant reserve call (#674)
|
||||
- Use `ManuallyDrop` instead of `mem::forget` (#675)
|
||||
|
||||
|
||||
# 1.5.0 (September 7, 2023)
|
||||
|
||||
### Added
|
||||
|
||||
- Add `UninitSlice::{new,uninit}` (#598, #599)
|
||||
- Implement `BufMut` for `&mut [MaybeUninit<u8>]` (#597)
|
||||
|
||||
### Changed
|
||||
|
||||
- Mark `BytesMut::extend_from_slice` as inline (#595)
|
||||
|
||||
# 1.4.0 (January 31, 2023)
|
||||
|
||||
### Added
|
||||
|
||||
- Make `IntoIter` constructor public (#581)
|
||||
|
||||
### Fixed
|
||||
|
||||
- Avoid large reallocations when freezing `BytesMut` (#592)
|
||||
|
||||
### Documented
|
||||
|
||||
- Document which functions require `std` (#591)
|
||||
- Fix duplicate "the the" typos (#585)
|
||||
|
||||
# 1.3.0 (November 20, 2022)
|
||||
|
||||
### Added
|
||||
|
||||
- Rename and expose `BytesMut::spare_capacity_mut` (#572)
|
||||
- Implement native-endian get and put functions for `Buf` and `BufMut` (#576)
|
||||
|
||||
### Fixed
|
||||
|
||||
- Don't have important data in unused capacity when calling reserve (#563)
|
||||
|
||||
### Documented
|
||||
|
||||
- `Bytes::new` etc should return `Self` not `Bytes` (#568)
|
||||
|
||||
# 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.
|
||||
* Bytes: Recycle space when reserving space in vec mode (#197).
|
||||
* Bytes: Add resize fn (#203).
|
||||
|
||||
# 0.4.7 (April 27, 2018)
|
||||
|
||||
* Make `Buf` and `BufMut` usable as trait objects (#186).
|
||||
* impl BorrowMut for BytesMut (#185).
|
||||
* Improve accessor performance (#195).
|
||||
|
||||
# 0.4.6 (Janary 8, 2018)
|
||||
|
||||
* Implement FromIterator for Bytes/BytesMut (#148).
|
||||
* Add `advance` fn to Bytes/BytesMut (#166).
|
||||
* Add `unsplit` fn to `BytesMut` (#162, #173).
|
||||
* Improvements to Bytes split fns (#92).
|
||||
|
||||
# 0.4.5 (August 12, 2017)
|
||||
|
||||
* Fix range bug in `Take::bytes`
|
||||
* Misc performance improvements
|
||||
* Add extra `PartialEq` implementations.
|
||||
* Add `Bytes::with_capacity`
|
||||
* Implement `AsMut[u8]` for `BytesMut`
|
||||
|
||||
# 0.4.4 (May 26, 2017)
|
||||
|
||||
* Add serde support behind feature flag
|
||||
* Add `extend_from_slice` on `Bytes` and `BytesMut`
|
||||
* Add `truncate` and `clear` on `Bytes`
|
||||
* Misc additional std trait implementations
|
||||
* Misc performance improvements
|
||||
|
||||
# 0.4.3 (April 30, 2017)
|
||||
|
||||
* Fix Vec::advance_mut bug
|
||||
* Bump minimum Rust version to 1.15
|
||||
* Misc performance tweaks
|
||||
|
||||
# 0.4.2 (April 5, 2017)
|
||||
|
||||
* Misc performance tweaks
|
||||
* Improved `Debug` implementation for `Bytes`
|
||||
* Avoid some incorrect assert panics
|
||||
|
||||
# 0.4.1 (March 15, 2017)
|
||||
|
||||
* Expose `buf` module and have most types available from there vs. root.
|
||||
* Implement `IntoBuf` for `T: Buf`.
|
||||
* Add `FromBuf` and `Buf::collect`.
|
||||
* Add iterator adapter for `Buf`.
|
||||
* Add scatter/gather support to `Buf` and `BufMut`.
|
||||
* Add `Buf::chain`.
|
||||
* Reduce allocations on repeated calls to `BytesMut::reserve`.
|
||||
* Implement `Debug` for more types.
|
||||
* Remove `Source` in favor of `IntoBuf`.
|
||||
* Implement `Extend` for `BytesMut`.
|
||||
|
||||
|
||||
# 0.4.0 (February 24, 2017)
|
||||
|
||||
* Initial release
|
||||
+28
-28
@@ -1,35 +1,35 @@
|
||||
[package]
|
||||
|
||||
name = "bytes"
|
||||
version = "0.1.0"
|
||||
license = "MIT"
|
||||
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", "rope", "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.8.0"
|
||||
edition = "2018"
|
||||
rust-version = "1.39"
|
||||
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"]
|
||||
|
||||
[features]
|
||||
default = ["std"]
|
||||
std = []
|
||||
|
||||
[dependencies]
|
||||
serde = { version = "1.0.60", optional = true, default-features = false, features = ["alloc"] }
|
||||
|
||||
[dev-dependencies]
|
||||
serde_test = "1.0"
|
||||
|
||||
rand = "0.1.2"
|
||||
iobuf = "*"
|
||||
[target.'cfg(loom)'.dev-dependencies]
|
||||
loom = "0.7"
|
||||
|
||||
|
||||
[[bench]]
|
||||
|
||||
name = "bench"
|
||||
path = "bench/bench.rs"
|
||||
|
||||
[[test]]
|
||||
|
||||
name = "test"
|
||||
path = "test/test.rs"
|
||||
[package.metadata.docs.rs]
|
||||
rustdoc-args = ["--cfg", "docsrs"]
|
||||
|
||||
@@ -1,52 +1,25 @@
|
||||
Copyright (c) 2015 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 documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
Permission is hereby granted, free of charge, to any
|
||||
person obtaining a copy of this software and associated
|
||||
documentation files (the "Software"), to deal in the
|
||||
Software without restriction, including without
|
||||
limitation the rights to use, copy, modify, merge,
|
||||
publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software
|
||||
is furnished to do so, subject to the following
|
||||
conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
The above copyright notice and this permission notice
|
||||
shall be included in all copies or substantial portions
|
||||
of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
---
|
||||
|
||||
Additionally, the Rope implementation is heavily inspired by ByteString found
|
||||
in the Google protobuf library. The following applies to this code:
|
||||
|
||||
Copyright 2014, Google Inc. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the name of Google Inc. nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
|
||||
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
|
||||
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
|
||||
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
|
||||
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
|
||||
@@ -2,15 +2,55 @@
|
||||
|
||||
A utility library for working with bytes.
|
||||
|
||||
[](https://travis-ci.org/carllerche/bytes)
|
||||
[![Crates.io][crates-badge]][crates-url]
|
||||
[![Build Status][ci-badge]][ci-url]
|
||||
|
||||
- [API documentation](http://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
|
||||
|
||||
To use `bytes`, first add this to your `Cargo.toml`:
|
||||
|
||||
```toml
|
||||
[dependencies.bytes]
|
||||
git = "https://github.com/carllerche/bytes"
|
||||
[dependencies]
|
||||
bytes = "1"
|
||||
```
|
||||
|
||||
Next, add this to your crate:
|
||||
|
||||
```rust
|
||||
use bytes::{Bytes, BytesMut, Buf, BufMut};
|
||||
```
|
||||
|
||||
## Serde support
|
||||
|
||||
Serde support is optional and disabled by default. To enable use the feature `serde`.
|
||||
|
||||
```toml
|
||||
[dependencies]
|
||||
bytes = { version = "1", features = ["serde"] }
|
||||
```
|
||||
|
||||
## Building documentation
|
||||
|
||||
When building the `bytes` documentation the `docsrs` option should be used, otherwise
|
||||
feature gates will not be shown. This requires a nightly toolchain:
|
||||
|
||||
```
|
||||
RUSTDOCFLAGS="--cfg docsrs" cargo +nightly doc
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
This project is licensed under the [MIT license](LICENSE).
|
||||
|
||||
### 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.
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
# Security Policy
|
||||
|
||||
Bytes is part of the Tokio project and uses the same security policy as [Tokio][tokio-security].
|
||||
|
||||
## Report a security issue
|
||||
|
||||
The process for reporting an issue is the same as for [Tokio][tokio-security]. This includes private reporting via security@tokio.rs.
|
||||
|
||||
[tokio-security]: https://github.com/tokio-rs/tokio/security/policy
|
||||
@@ -1,34 +0,0 @@
|
||||
#![feature(test, core)]
|
||||
|
||||
use bytes::ByteBuf;
|
||||
use bytes::traits::*;
|
||||
use iobuf::{RWIobuf};
|
||||
use test::Bencher;
|
||||
|
||||
extern crate bytes;
|
||||
extern crate iobuf;
|
||||
extern crate test;
|
||||
|
||||
const SIZE:usize = 4_096;
|
||||
|
||||
#[bench]
|
||||
pub fn bench_byte_buf_fill_4kb(b: &mut Bencher) {
|
||||
b.iter(|| {
|
||||
let mut buf = ByteBuf::mut_with_capacity(SIZE);
|
||||
|
||||
for _ in 0..SIZE {
|
||||
buf.write_slice(&[0]);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
pub fn bench_rw_iobuf_fill_4kb(b: &mut Bencher) {
|
||||
b.iter(|| {
|
||||
let mut buf = RWIobuf::new(SIZE);
|
||||
|
||||
for _ in 0..SIZE {
|
||||
let _ = buf.fill(&[0]);
|
||||
}
|
||||
});
|
||||
}
|
||||
+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);
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
#![feature(test)]
|
||||
#![warn(rust_2018_idioms)]
|
||||
|
||||
extern crate test;
|
||||
|
||||
use bytes::Bytes;
|
||||
use test::Bencher;
|
||||
|
||||
#[bench]
|
||||
fn deref_unique(b: &mut Bencher) {
|
||||
let buf = Bytes::from(vec![0; 1024]);
|
||||
|
||||
b.iter(|| {
|
||||
for _ in 0..1024 {
|
||||
test::black_box(&buf[..]);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn deref_shared(b: &mut Bencher) {
|
||||
let buf = Bytes::from(vec![0; 1024]);
|
||||
let _b2 = buf.clone();
|
||||
|
||||
b.iter(|| {
|
||||
for _ in 0..1024 {
|
||||
test::black_box(&buf[..]);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn deref_static(b: &mut Bencher) {
|
||||
let buf = Bytes::from_static(b"hello world");
|
||||
|
||||
b.iter(|| {
|
||||
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(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(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(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));
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn split_off_and_drop(b: &mut Bencher) {
|
||||
b.iter(|| {
|
||||
for _ in 0..1024 {
|
||||
let v = vec![10; 200];
|
||||
let mut b = Bytes::from(v);
|
||||
test::black_box(b.split_off(100));
|
||||
test::black_box(b);
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
});
|
||||
}
|
||||
Executable
+10
@@ -0,0 +1,10 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
rustup component add miri
|
||||
cargo miri setup
|
||||
|
||||
export MIRIFLAGS="-Zmiri-strict-provenance"
|
||||
|
||||
cargo miri test
|
||||
cargo miri test --target mips64-unknown-linux-gnuabi64
|
||||
Executable
+22
@@ -0,0 +1,22 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -ex
|
||||
|
||||
cmd="${1:-test}"
|
||||
|
||||
# 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
|
||||
|
||||
if [[ "${RUST_VERSION}" == "nightly"* ]]; then
|
||||
# Check benchmarks
|
||||
cargo check --benches
|
||||
|
||||
# Check minimal versions
|
||||
cargo clean
|
||||
cargo update -Zminimal-versions
|
||||
cargo check --all-features
|
||||
fi
|
||||
Executable
+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"
|
||||
@@ -1,18 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
rev=$(git rev-parse --short HEAD)
|
||||
|
||||
cd target/doc
|
||||
|
||||
git init
|
||||
git config user.name "Carl Lerche"
|
||||
git config user.email "[email protected]"
|
||||
|
||||
git remote add upstream "https://$GH_TOKEN@github.com/carllerche/bytes"
|
||||
git fetch upstream && git reset upstream/gh-pages
|
||||
|
||||
touch .
|
||||
|
||||
git add -A .
|
||||
git commit -m "rebuild pages at ${rev}"
|
||||
git push -q upstream HEAD:gh-pages
|
||||
-180
@@ -1,180 +0,0 @@
|
||||
use std::{mem, ptr};
|
||||
use std::rt::heap;
|
||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||
|
||||
const MAX_ALLOC_SIZE: usize = (1 << 32) - 1;
|
||||
|
||||
/// Allocates memory to be used by Bufs or Bytes. Allows allocating memory
|
||||
/// using alternate stratgies than the default Rust heap allocator. Also does
|
||||
/// not require that allocations are continuous in memory.
|
||||
///
|
||||
/// For example, an alternate allocator could use a slab of 4kb chunks of
|
||||
/// memory and return as many chunks as needed to satisfy the length
|
||||
/// requirement.
|
||||
pub trait Allocator: Sync + Send {
|
||||
|
||||
/// Allocate memory. May or may not be contiguous.
|
||||
fn allocate(&self, len: usize) -> MemRef;
|
||||
|
||||
/// Deallocate a chunk of memory
|
||||
fn deallocate(&self, mem: *mut Mem);
|
||||
}
|
||||
|
||||
pub struct MemRef {
|
||||
ptr: *mut u8,
|
||||
}
|
||||
|
||||
impl MemRef {
|
||||
pub fn new(mem: *mut Mem) -> MemRef {
|
||||
let ptr = mem as *mut u8;
|
||||
|
||||
unsafe {
|
||||
MemRef {
|
||||
ptr: ptr.offset(mem::size_of::<Mem>() as isize),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn none() -> MemRef {
|
||||
MemRef { ptr: ptr::null_mut() }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_none(&self) -> bool {
|
||||
self.ptr.is_null()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn ptr(&self) -> *mut u8 {
|
||||
self.ptr
|
||||
}
|
||||
|
||||
pub fn bytes(&self) -> &[u8] {
|
||||
use std::raw::Slice;
|
||||
|
||||
unsafe {
|
||||
mem::transmute(Slice {
|
||||
data: self.ptr(),
|
||||
len: self.mem().len,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn bytes_mut(&mut self) -> &mut [u8] {
|
||||
unsafe { mem::transmute(self.bytes()) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn mem_ptr(&self) -> *mut Mem {
|
||||
unsafe {
|
||||
self.ptr.offset(-(mem::size_of::<Mem>() as isize)) as *mut Mem
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn mem(&self) -> &Mem {
|
||||
unsafe {
|
||||
mem::transmute(self.mem_ptr())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for MemRef {
|
||||
#[inline]
|
||||
fn clone(&self) -> MemRef {
|
||||
self.mem().refs.fetch_add(1, Ordering::Relaxed);
|
||||
MemRef { ptr: self.ptr }
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for MemRef {
|
||||
fn drop(&mut self) {
|
||||
// Guard against the ref having already been dropped
|
||||
if self.ptr.is_null() { return; }
|
||||
|
||||
// Decrement the ref count
|
||||
if 1 == self.mem().refs.fetch_sub(1, Ordering::Relaxed) {
|
||||
// Last ref dropped, free the memory
|
||||
unsafe {
|
||||
let alloc: &Allocator = mem::transmute(self.mem().allocator);
|
||||
alloc.deallocate(self.mem_ptr());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl Send for MemRef { }
|
||||
unsafe impl Sync for MemRef { }
|
||||
|
||||
/// Memory allocated by an Allocator must be prefixed with Mem
|
||||
pub struct Mem {
|
||||
// TODO: It should be possible to reduce the size of this struct
|
||||
allocator: *const Allocator,
|
||||
refs: AtomicUsize,
|
||||
len: usize,
|
||||
}
|
||||
|
||||
impl Mem {
|
||||
fn new(len: usize, allocator: *const Allocator) -> Mem {
|
||||
Mem {
|
||||
allocator: allocator,
|
||||
refs: AtomicUsize::new(1),
|
||||
len: len,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub static HEAP: Heap = Heap;
|
||||
|
||||
#[allow(missing_copy_implementations)]
|
||||
pub struct Heap;
|
||||
|
||||
impl Heap {
|
||||
pub fn allocate(&self, len: usize) -> MemRef {
|
||||
// Make sure that the allocation is within the permitted range
|
||||
if len > MAX_ALLOC_SIZE {
|
||||
return MemRef::none();
|
||||
}
|
||||
|
||||
let alloc_len = len + mem::size_of::<Mem>();
|
||||
|
||||
unsafe {
|
||||
// Attempt to allocate the memory
|
||||
let ptr: *mut Mem = mem::transmute(
|
||||
heap::allocate(alloc_len, mem::min_align_of::<u8>()));
|
||||
|
||||
// If failed, return None
|
||||
if ptr.is_null() {
|
||||
return MemRef::none();
|
||||
}
|
||||
|
||||
// Write the mem header
|
||||
ptr::write(ptr, Mem::new(len, mem::transmute(self as &Allocator)));
|
||||
|
||||
// Return the info
|
||||
MemRef::new(ptr)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn deallocate(&self, mem: *mut Mem) {
|
||||
unsafe {
|
||||
let m: &Mem = mem::transmute(mem);
|
||||
|
||||
heap::deallocate(
|
||||
mem as *mut u8, m.len + mem::size_of::<Mem>(),
|
||||
mem::min_align_of::<u8>())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Allocator for Heap {
|
||||
fn allocate(&self, len: usize) -> MemRef {
|
||||
Heap::allocate(self, len)
|
||||
}
|
||||
|
||||
fn deallocate(&self, mem: *mut Mem) {
|
||||
Heap::deallocate(self, mem)
|
||||
}
|
||||
}
|
||||
+1472
File diff suppressed because it is too large
Load Diff
+1641
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,240 @@
|
||||
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
|
||||
/// 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
|
||||
/// function's documentation for more detail.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use bytes::{Bytes, Buf};
|
||||
///
|
||||
/// let mut buf = (&b"hello "[..])
|
||||
/// .chain(&b"world"[..]);
|
||||
///
|
||||
/// let full: Bytes = buf.copy_to_bytes(11);
|
||||
/// assert_eq!(full[..], b"hello world"[..]);
|
||||
/// ```
|
||||
///
|
||||
/// [`Buf::chain`]: Buf::chain
|
||||
#[derive(Debug)]
|
||||
pub struct Chain<T, U> {
|
||||
a: T,
|
||||
b: U,
|
||||
}
|
||||
|
||||
impl<T, U> Chain<T, U> {
|
||||
/// Creates a new `Chain` sequencing the provided values.
|
||||
pub(crate) fn new(a: T, b: U) -> Chain<T, U> {
|
||||
Chain { a, b }
|
||||
}
|
||||
|
||||
/// Gets a reference to the first underlying `Buf`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use bytes::Buf;
|
||||
///
|
||||
/// let buf = (&b"hello"[..])
|
||||
/// .chain(&b"world"[..]);
|
||||
///
|
||||
/// assert_eq!(buf.first_ref()[..], b"hello"[..]);
|
||||
/// ```
|
||||
pub fn first_ref(&self) -> &T {
|
||||
&self.a
|
||||
}
|
||||
|
||||
/// Gets a mutable reference to the first underlying `Buf`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use bytes::Buf;
|
||||
///
|
||||
/// let mut buf = (&b"hello"[..])
|
||||
/// .chain(&b"world"[..]);
|
||||
///
|
||||
/// buf.first_mut().advance(1);
|
||||
///
|
||||
/// let full = buf.copy_to_bytes(9);
|
||||
/// assert_eq!(full, b"elloworld"[..]);
|
||||
/// ```
|
||||
pub fn first_mut(&mut self) -> &mut T {
|
||||
&mut self.a
|
||||
}
|
||||
|
||||
/// Gets a reference to the last underlying `Buf`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use bytes::Buf;
|
||||
///
|
||||
/// let buf = (&b"hello"[..])
|
||||
/// .chain(&b"world"[..]);
|
||||
///
|
||||
/// assert_eq!(buf.last_ref()[..], b"world"[..]);
|
||||
/// ```
|
||||
pub fn last_ref(&self) -> &U {
|
||||
&self.b
|
||||
}
|
||||
|
||||
/// Gets a mutable reference to the last underlying `Buf`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use bytes::Buf;
|
||||
///
|
||||
/// let mut buf = (&b"hello "[..])
|
||||
/// .chain(&b"world"[..]);
|
||||
///
|
||||
/// buf.last_mut().advance(1);
|
||||
///
|
||||
/// let full = buf.copy_to_bytes(10);
|
||||
/// assert_eq!(full, b"hello orld"[..]);
|
||||
/// ```
|
||||
pub fn last_mut(&mut self) -> &mut U {
|
||||
&mut self.b
|
||||
}
|
||||
|
||||
/// Consumes this `Chain`, returning the underlying values.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use bytes::Buf;
|
||||
///
|
||||
/// let chain = (&b"hello"[..])
|
||||
/// .chain(&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)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, U> Buf for Chain<T, U>
|
||||
where
|
||||
T: Buf,
|
||||
U: Buf,
|
||||
{
|
||||
fn remaining(&self) -> usize {
|
||||
self.a.remaining().saturating_add(self.b.remaining())
|
||||
}
|
||||
|
||||
fn chunk(&self) -> &[u8] {
|
||||
if self.a.has_remaining() {
|
||||
self.a.chunk()
|
||||
} else {
|
||||
self.b.chunk()
|
||||
}
|
||||
}
|
||||
|
||||
fn advance(&mut self, mut cnt: usize) {
|
||||
let a_rem = self.a.remaining();
|
||||
|
||||
if a_rem != 0 {
|
||||
if a_rem >= cnt {
|
||||
self.a.advance(cnt);
|
||||
return;
|
||||
}
|
||||
|
||||
// Consume what is left of a
|
||||
self.a.advance(a_rem);
|
||||
|
||||
cnt -= a_rem;
|
||||
}
|
||||
|
||||
self.b.advance(cnt);
|
||||
}
|
||||
|
||||
#[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()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<T, U> BufMut for Chain<T, U>
|
||||
where
|
||||
T: BufMut,
|
||||
U: BufMut,
|
||||
{
|
||||
fn remaining_mut(&self) -> usize {
|
||||
self.a
|
||||
.remaining_mut()
|
||||
.saturating_add(self.b.remaining_mut())
|
||||
}
|
||||
|
||||
fn chunk_mut(&mut self) -> &mut UninitSlice {
|
||||
if self.a.has_remaining_mut() {
|
||||
self.a.chunk_mut()
|
||||
} else {
|
||||
self.b.chunk_mut()
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn advance_mut(&mut self, mut cnt: usize) {
|
||||
let a_rem = self.a.remaining_mut();
|
||||
|
||||
if a_rem != 0 {
|
||||
if a_rem >= cnt {
|
||||
self.a.advance_mut(cnt);
|
||||
return;
|
||||
}
|
||||
|
||||
// Consume what is left of a
|
||||
self.a.advance_mut(a_rem);
|
||||
|
||||
cnt -= a_rem;
|
||||
}
|
||||
|
||||
self.b.advance_mut(cnt);
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
+127
@@ -0,0 +1,127 @@
|
||||
use crate::Buf;
|
||||
|
||||
/// Iterator over the bytes contained by the buffer.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Basic usage:
|
||||
///
|
||||
/// ```
|
||||
/// use bytes::Bytes;
|
||||
///
|
||||
/// 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'));
|
||||
/// assert_eq!(iter.next(), Some(b'c'));
|
||||
/// assert_eq!(iter.next(), None);
|
||||
/// ```
|
||||
#[derive(Debug)]
|
||||
pub struct IntoIter<T> {
|
||||
inner: T,
|
||||
}
|
||||
|
||||
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 fn new(inner: T) -> IntoIter<T> {
|
||||
IntoIter { inner }
|
||||
}
|
||||
|
||||
/// Consumes this `IntoIter`, returning the underlying value.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// use bytes::{Buf, Bytes};
|
||||
///
|
||||
/// let buf = Bytes::from(&b"abc"[..]);
|
||||
/// let mut iter = buf.into_iter();
|
||||
///
|
||||
/// assert_eq!(iter.next(), Some(b'a'));
|
||||
///
|
||||
/// let buf = iter.into_inner();
|
||||
/// assert_eq!(2, buf.remaining());
|
||||
/// ```
|
||||
pub fn into_inner(self) -> T {
|
||||
self.inner
|
||||
}
|
||||
|
||||
/// Gets a reference to the underlying `Buf`.
|
||||
///
|
||||
/// It is inadvisable to directly read from the underlying `Buf`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// use bytes::{Buf, Bytes};
|
||||
///
|
||||
/// let buf = Bytes::from(&b"abc"[..]);
|
||||
/// let mut iter = buf.into_iter();
|
||||
///
|
||||
/// assert_eq!(iter.next(), Some(b'a'));
|
||||
///
|
||||
/// assert_eq!(2, iter.get_ref().remaining());
|
||||
/// ```
|
||||
pub fn get_ref(&self) -> &T {
|
||||
&self.inner
|
||||
}
|
||||
|
||||
/// Gets a mutable reference to the underlying `Buf`.
|
||||
///
|
||||
/// It is inadvisable to directly read from the underlying `Buf`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// use bytes::{Buf, BytesMut};
|
||||
///
|
||||
/// let buf = BytesMut::from(&b"abc"[..]);
|
||||
/// let mut iter = buf.into_iter();
|
||||
///
|
||||
/// assert_eq!(iter.next(), Some(b'a'));
|
||||
///
|
||||
/// iter.get_mut().advance(1);
|
||||
///
|
||||
/// assert_eq!(iter.next(), Some(b'c'));
|
||||
/// ```
|
||||
pub fn get_mut(&mut self) -> &mut T {
|
||||
&mut self.inner
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Buf> Iterator for IntoIter<T> {
|
||||
type Item = u8;
|
||||
|
||||
fn next(&mut self) -> Option<u8> {
|
||||
if !self.inner.has_remaining() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let b = self.inner.chunk()[0];
|
||||
self.inner.advance(1);
|
||||
|
||||
Some(b)
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
let rem = self.inner.remaining();
|
||||
(rem, Some(rem))
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
//! Utilities for working with buffers.
|
||||
//!
|
||||
//! A buffer is any structure that contains a sequence of bytes. The bytes may
|
||||
//! or may not be stored in contiguous memory. This module contains traits used
|
||||
//! to abstract over buffers as well as utilities for working with buffer types.
|
||||
//!
|
||||
//! # `Buf`, `BufMut`
|
||||
//!
|
||||
//! These are the two foundational traits for abstractly working with buffers.
|
||||
//! They can be thought as iterators for byte structures. They offer additional
|
||||
//! performance over `Iterator` by providing an API optimized for byte slices.
|
||||
//!
|
||||
//! See [`Buf`] and [`BufMut`] for more details.
|
||||
//!
|
||||
//! [rope]: https://en.wikipedia.org/wiki/Rope_(data_structure)
|
||||
|
||||
mod buf_impl;
|
||||
mod buf_mut;
|
||||
mod chain;
|
||||
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_impl::Buf;
|
||||
pub use self::buf_mut::BufMut;
|
||||
pub use self::chain::Chain;
|
||||
pub use self::iter::IntoIter;
|
||||
pub use self::limit::Limit;
|
||||
pub use self::take::Take;
|
||||
pub use self::uninit_slice::UninitSlice;
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
pub use self::{reader::Reader, writer::Writer};
|
||||
@@ -0,0 +1,81 @@
|
||||
use crate::Buf;
|
||||
|
||||
use std::{cmp, io};
|
||||
|
||||
/// A `Buf` adapter which implements `io::Read` for the inner value.
|
||||
///
|
||||
/// This struct is generally created by calling `reader()` on `Buf`. See
|
||||
/// documentation of [`reader()`](Buf::reader) for more
|
||||
/// details.
|
||||
#[derive(Debug)]
|
||||
pub struct Reader<B> {
|
||||
buf: B,
|
||||
}
|
||||
|
||||
pub fn new<B>(buf: B) -> Reader<B> {
|
||||
Reader { buf }
|
||||
}
|
||||
|
||||
impl<B: Buf> Reader<B> {
|
||||
/// Gets a reference to the underlying `Buf`.
|
||||
///
|
||||
/// It is inadvisable to directly read from the underlying `Buf`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// use bytes::Buf;
|
||||
///
|
||||
/// let buf = b"hello world".reader();
|
||||
///
|
||||
/// assert_eq!(b"hello world", buf.get_ref());
|
||||
/// ```
|
||||
pub fn get_ref(&self) -> &B {
|
||||
&self.buf
|
||||
}
|
||||
|
||||
/// Gets a mutable reference to the underlying `Buf`.
|
||||
///
|
||||
/// It is inadvisable to directly read from the underlying `Buf`.
|
||||
pub fn get_mut(&mut self) -> &mut B {
|
||||
&mut self.buf
|
||||
}
|
||||
|
||||
/// Consumes this `Reader`, returning the underlying value.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// use bytes::Buf;
|
||||
/// use std::io;
|
||||
///
|
||||
/// let mut buf = b"hello world".reader();
|
||||
/// let mut dst = vec![];
|
||||
///
|
||||
/// io::copy(&mut buf, &mut dst).unwrap();
|
||||
///
|
||||
/// let buf = buf.into_inner();
|
||||
/// assert_eq!(0, buf.remaining());
|
||||
/// ```
|
||||
pub fn into_inner(self) -> B {
|
||||
self.buf
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: Buf + Sized> io::Read for Reader<B> {
|
||||
fn read(&mut self, dst: &mut [u8]) -> io::Result<usize> {
|
||||
let len = cmp::min(self.buf.remaining(), dst.len());
|
||||
|
||||
Buf::copy_to_slice(&mut self.buf, &mut dst[0..len]);
|
||||
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)
|
||||
}
|
||||
}
|
||||
+155
@@ -0,0 +1,155 @@
|
||||
use crate::{Buf, Bytes};
|
||||
|
||||
use core::cmp;
|
||||
|
||||
/// A `Buf` adapter which limits the bytes read from an underlying buffer.
|
||||
///
|
||||
/// This struct is generally created by calling `take()` on `Buf`. See
|
||||
/// documentation of [`take()`](Buf::take) for more details.
|
||||
#[derive(Debug)]
|
||||
pub struct Take<T> {
|
||||
inner: T,
|
||||
limit: usize,
|
||||
}
|
||||
|
||||
pub fn new<T>(inner: T, limit: usize) -> Take<T> {
|
||||
Take { inner, limit }
|
||||
}
|
||||
|
||||
impl<T> Take<T> {
|
||||
/// Consumes this `Take`, returning the underlying value.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// use bytes::{Buf, BufMut};
|
||||
///
|
||||
/// let mut buf = b"hello world".take(2);
|
||||
/// let mut dst = vec![];
|
||||
///
|
||||
/// dst.put(&mut buf);
|
||||
/// assert_eq!(*dst, b"he"[..]);
|
||||
///
|
||||
/// let mut buf = buf.into_inner();
|
||||
///
|
||||
/// dst.clear();
|
||||
/// dst.put(&mut buf);
|
||||
/// assert_eq!(*dst, b"llo world"[..]);
|
||||
/// ```
|
||||
pub fn into_inner(self) -> T {
|
||||
self.inner
|
||||
}
|
||||
|
||||
/// Gets a reference to the underlying `Buf`.
|
||||
///
|
||||
/// It is inadvisable to directly read from the underlying `Buf`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// use bytes::Buf;
|
||||
///
|
||||
/// let buf = b"hello world".take(2);
|
||||
///
|
||||
/// assert_eq!(11, buf.get_ref().remaining());
|
||||
/// ```
|
||||
pub fn get_ref(&self) -> &T {
|
||||
&self.inner
|
||||
}
|
||||
|
||||
/// Gets a mutable reference to the underlying `Buf`.
|
||||
///
|
||||
/// It is inadvisable to directly read from the underlying `Buf`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// use bytes::{Buf, BufMut};
|
||||
///
|
||||
/// let mut buf = b"hello world".take(2);
|
||||
/// let mut dst = vec![];
|
||||
///
|
||||
/// buf.get_mut().advance(2);
|
||||
///
|
||||
/// dst.put(&mut buf);
|
||||
/// assert_eq!(*dst, b"ll"[..]);
|
||||
/// ```
|
||||
pub fn get_mut(&mut self) -> &mut T {
|
||||
&mut self.inner
|
||||
}
|
||||
|
||||
/// Returns the maximum number of bytes that can be read.
|
||||
///
|
||||
/// # Note
|
||||
///
|
||||
/// If the inner `Buf` has fewer bytes than indicated by this method then
|
||||
/// that is the actual number of available bytes.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// use bytes::Buf;
|
||||
///
|
||||
/// let mut buf = b"hello world".take(2);
|
||||
///
|
||||
/// assert_eq!(2, buf.limit());
|
||||
/// assert_eq!(b'h', buf.get_u8());
|
||||
/// assert_eq!(1, buf.limit());
|
||||
/// ```
|
||||
pub fn limit(&self) -> usize {
|
||||
self.limit
|
||||
}
|
||||
|
||||
/// Sets the maximum number of bytes that can be read.
|
||||
///
|
||||
/// # Note
|
||||
///
|
||||
/// If the inner `Buf` has fewer bytes than `lim` then that is the actual
|
||||
/// number of available bytes.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// use bytes::{Buf, BufMut};
|
||||
///
|
||||
/// let mut buf = b"hello world".take(2);
|
||||
/// let mut dst = vec![];
|
||||
///
|
||||
/// dst.put(&mut buf);
|
||||
/// assert_eq!(*dst, b"he"[..]);
|
||||
///
|
||||
/// dst.clear();
|
||||
///
|
||||
/// buf.set_limit(3);
|
||||
/// dst.put(&mut buf);
|
||||
/// assert_eq!(*dst, b"llo"[..]);
|
||||
/// ```
|
||||
pub fn set_limit(&mut self, lim: usize) {
|
||||
self.limit = lim
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Buf> Buf for Take<T> {
|
||||
fn remaining(&self) -> usize {
|
||||
cmp::min(self.inner.remaining(), self.limit)
|
||||
}
|
||||
|
||||
fn chunk(&self) -> &[u8] {
|
||||
let bytes = self.inner.chunk();
|
||||
&bytes[..cmp::min(bytes.len(), self.limit)]
|
||||
}
|
||||
|
||||
fn advance(&mut self, cnt: usize) {
|
||||
assert!(cnt <= self.limit);
|
||||
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,257 @@
|
||||
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 {
|
||||
/// Creates a `&mut UninitSlice` wrapping a slice of initialised memory.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use bytes::buf::UninitSlice;
|
||||
///
|
||||
/// let mut buffer = [0u8; 64];
|
||||
/// let slice = UninitSlice::new(&mut buffer[..]);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn new(slice: &mut [u8]) -> &mut UninitSlice {
|
||||
unsafe { &mut *(slice as *mut [u8] as *mut [MaybeUninit<u8>] as *mut UninitSlice) }
|
||||
}
|
||||
|
||||
/// Creates a `&mut UninitSlice` wrapping a slice of uninitialised memory.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use bytes::buf::UninitSlice;
|
||||
/// use core::mem::MaybeUninit;
|
||||
///
|
||||
/// let mut buffer = [MaybeUninit::uninit(); 64];
|
||||
/// let slice = UninitSlice::uninit(&mut buffer[..]);
|
||||
///
|
||||
/// let mut vec = Vec::with_capacity(1024);
|
||||
/// let spare: &mut UninitSlice = vec.spare_capacity_mut().into();
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn uninit(slice: &mut [MaybeUninit<u8>]) -> &mut UninitSlice {
|
||||
unsafe { &mut *(slice as *mut [MaybeUninit<u8>] as *mut UninitSlice) }
|
||||
}
|
||||
|
||||
fn uninit_ref(slice: &[MaybeUninit<u8>]) -> &UninitSlice {
|
||||
unsafe { &*(slice as *const [MaybeUninit<u8>] as *const 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);
|
||||
Self::uninit(maybe_init)
|
||||
}
|
||||
|
||||
/// 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 uninitialized
|
||||
/// 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(&mut self) -> &mut [MaybeUninit<u8>] {
|
||||
&mut self.0
|
||||
}
|
||||
|
||||
/// 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()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&'a mut [u8]> for &'a mut UninitSlice {
|
||||
fn from(slice: &'a mut [u8]) -> Self {
|
||||
UninitSlice::new(slice)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&'a mut [MaybeUninit<u8>]> for &'a mut UninitSlice {
|
||||
fn from(slice: &'a mut [MaybeUninit<u8>]) -> Self {
|
||||
UninitSlice::uninit(slice)
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! impl_index {
|
||||
($($t:ty),*) => {
|
||||
$(
|
||||
impl Index<$t> for UninitSlice {
|
||||
type Output = UninitSlice;
|
||||
|
||||
#[inline]
|
||||
fn index(&self, index: $t) -> &UninitSlice {
|
||||
UninitSlice::uninit_ref(&self.0[index])
|
||||
}
|
||||
}
|
||||
|
||||
impl IndexMut<$t> for UninitSlice {
|
||||
#[inline]
|
||||
fn index_mut(&mut self, index: $t) -> &mut UninitSlice {
|
||||
UninitSlice::uninit(&mut self.0[index])
|
||||
}
|
||||
}
|
||||
)*
|
||||
};
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
use crate::BufMut;
|
||||
|
||||
use std::{cmp, io};
|
||||
|
||||
/// A `BufMut` adapter which implements `io::Write` for the inner value.
|
||||
///
|
||||
/// This struct is generally created by calling `writer()` on `BufMut`. See
|
||||
/// documentation of [`writer()`](BufMut::writer) for more
|
||||
/// details.
|
||||
#[derive(Debug)]
|
||||
pub struct Writer<B> {
|
||||
buf: B,
|
||||
}
|
||||
|
||||
pub fn new<B>(buf: B) -> Writer<B> {
|
||||
Writer { buf }
|
||||
}
|
||||
|
||||
impl<B: BufMut> Writer<B> {
|
||||
/// Gets a reference to the underlying `BufMut`.
|
||||
///
|
||||
/// It is inadvisable to directly write to the underlying `BufMut`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// use bytes::BufMut;
|
||||
///
|
||||
/// let buf = Vec::with_capacity(1024).writer();
|
||||
///
|
||||
/// assert_eq!(1024, buf.get_ref().capacity());
|
||||
/// ```
|
||||
pub fn get_ref(&self) -> &B {
|
||||
&self.buf
|
||||
}
|
||||
|
||||
/// Gets a mutable reference to the underlying `BufMut`.
|
||||
///
|
||||
/// It is inadvisable to directly write to the underlying `BufMut`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// use bytes::BufMut;
|
||||
///
|
||||
/// let mut buf = vec![].writer();
|
||||
///
|
||||
/// buf.get_mut().reserve(1024);
|
||||
///
|
||||
/// assert_eq!(1024, buf.get_ref().capacity());
|
||||
/// ```
|
||||
pub fn get_mut(&mut self) -> &mut B {
|
||||
&mut self.buf
|
||||
}
|
||||
|
||||
/// Consumes this `Writer`, returning the underlying value.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// use bytes::BufMut;
|
||||
/// use std::io;
|
||||
///
|
||||
/// let mut buf = vec![].writer();
|
||||
/// let mut src = &b"hello world"[..];
|
||||
///
|
||||
/// io::copy(&mut src, &mut buf).unwrap();
|
||||
///
|
||||
/// let buf = buf.into_inner();
|
||||
/// assert_eq!(*buf, b"hello world"[..]);
|
||||
/// ```
|
||||
pub fn into_inner(self) -> B {
|
||||
self.buf
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: BufMut + Sized> io::Write for Writer<B> {
|
||||
fn write(&mut self, src: &[u8]) -> io::Result<usize> {
|
||||
let n = cmp::min(self.buf.remaining_mut(), src.len());
|
||||
|
||||
self.buf.put(&src[0..n]);
|
||||
Ok(n)
|
||||
}
|
||||
|
||||
fn flush(&mut self) -> io::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
-270
@@ -1,270 +0,0 @@
|
||||
use {alloc, Bytes, SeqByteStr, MAX_CAPACITY};
|
||||
use traits::{Buf, MutBuf, MutBufExt, ByteStr};
|
||||
use std::{cmp, ptr};
|
||||
use std::num::UnsignedInt;
|
||||
|
||||
/*
|
||||
*
|
||||
* ===== ByteBuf =====
|
||||
*
|
||||
*/
|
||||
|
||||
/// A `Buf` backed by a contiguous region of memory.
|
||||
pub struct ByteBuf {
|
||||
mem: alloc::MemRef,
|
||||
cap: u32,
|
||||
pos: u32,
|
||||
lim: u32
|
||||
}
|
||||
|
||||
impl ByteBuf {
|
||||
/// Create a new `ByteBuf` by copying the contents of the given slice.
|
||||
pub fn from_slice(bytes: &[u8]) -> ByteBuf {
|
||||
let mut buf = ByteBuf::mut_with_capacity(bytes.len());
|
||||
buf.write(bytes).ok().expect("unexpected failure");
|
||||
buf.flip()
|
||||
}
|
||||
|
||||
pub fn mut_with_capacity(capacity: usize) -> MutByteBuf {
|
||||
assert!(capacity <= MAX_CAPACITY);
|
||||
MutByteBuf { buf: ByteBuf::new(capacity as u32) }
|
||||
}
|
||||
|
||||
pub fn none() -> ByteBuf {
|
||||
ByteBuf {
|
||||
mem: alloc::MemRef::none(),
|
||||
cap: 0,
|
||||
pos: 0,
|
||||
lim: 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn from_mem_ref(mem: alloc::MemRef, cap: u32, pos: u32, lim: u32) -> ByteBuf {
|
||||
debug_assert!(pos <= lim && lim <= cap, "invalid arguments; cap={}; pos={}; lim={}", cap, pos, lim);
|
||||
|
||||
ByteBuf {
|
||||
mem: mem,
|
||||
cap: cap,
|
||||
pos: pos,
|
||||
lim: lim,
|
||||
}
|
||||
}
|
||||
|
||||
fn new(mut capacity: u32) -> ByteBuf {
|
||||
// Handle 0 capacity case
|
||||
if capacity == 0 {
|
||||
return ByteBuf::none();
|
||||
}
|
||||
|
||||
// Round the capacity to the closest power of 2
|
||||
capacity = UnsignedInt::next_power_of_two(capacity);
|
||||
|
||||
// Allocate the memory
|
||||
let mem = alloc::HEAP.allocate(capacity as usize);
|
||||
|
||||
// If the allocation failed, return a blank buf
|
||||
if mem.is_none() {
|
||||
return ByteBuf::none();
|
||||
}
|
||||
|
||||
ByteBuf {
|
||||
mem: mem,
|
||||
cap: capacity,
|
||||
pos: 0,
|
||||
lim: capacity
|
||||
}
|
||||
}
|
||||
|
||||
pub fn capacity(&self) -> usize {
|
||||
self.cap as usize
|
||||
}
|
||||
|
||||
pub fn flip(self) -> MutByteBuf {
|
||||
let mut buf = MutByteBuf { buf: self };
|
||||
buf.clear();
|
||||
buf
|
||||
}
|
||||
|
||||
pub fn read_slice(&mut self, dst: &mut [u8]) -> usize {
|
||||
let len = cmp::min(dst.len(), self.remaining());
|
||||
let cnt = len as u32;
|
||||
|
||||
unsafe {
|
||||
ptr::copy_nonoverlapping_memory(
|
||||
dst.as_mut_ptr(),
|
||||
self.mem.ptr().offset(self.pos as isize), len);
|
||||
}
|
||||
|
||||
self.pos += cnt;
|
||||
len
|
||||
}
|
||||
|
||||
pub fn to_seq_byte_str(self) -> SeqByteStr {
|
||||
unsafe {
|
||||
let ByteBuf { mem, pos, lim, .. } = self;
|
||||
SeqByteStr::from_mem_ref(
|
||||
mem, pos, lim - pos)
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn to_bytes(self) -> Bytes {
|
||||
Bytes::of(self.to_seq_byte_str())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn pos(&self) -> usize {
|
||||
self.pos as usize
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn lim(&self) -> usize {
|
||||
self.lim as usize
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn remaining_u32(&self) -> u32 {
|
||||
self.lim - self.pos
|
||||
}
|
||||
}
|
||||
|
||||
impl Buf for ByteBuf {
|
||||
|
||||
#[inline]
|
||||
fn remaining(&self) -> usize {
|
||||
self.remaining_u32() as usize
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn bytes<'a>(&'a self) -> &'a [u8] {
|
||||
&self.mem.bytes()[self.pos()..self.lim()]
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn advance(&mut self, mut cnt: usize) {
|
||||
cnt = cmp::min(cnt, self.remaining());
|
||||
self.pos += cnt as u32;
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn read_slice(&mut self, dst: &mut [u8]) -> usize {
|
||||
ByteBuf::read_slice(self, dst)
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl Send for ByteBuf { }
|
||||
|
||||
/*
|
||||
*
|
||||
* ===== ROByteBuf =====
|
||||
*
|
||||
*/
|
||||
|
||||
/// Same as `ByteBuf` but cannot be flipped to a `MutByteBuf`.
|
||||
pub struct ROByteBuf {
|
||||
buf: ByteBuf,
|
||||
}
|
||||
|
||||
impl ROByteBuf {
|
||||
pub unsafe fn from_mem_ref(mem: alloc::MemRef, cap: u32, pos: u32, lim: u32) -> ROByteBuf {
|
||||
ROByteBuf {
|
||||
buf: ByteBuf::from_mem_ref(mem, cap, pos, lim)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_seq_byte_str(self) -> SeqByteStr {
|
||||
self.buf.to_seq_byte_str()
|
||||
}
|
||||
|
||||
pub fn to_bytes(self) -> Bytes {
|
||||
self.buf.to_bytes()
|
||||
}
|
||||
}
|
||||
|
||||
impl Buf for ROByteBuf {
|
||||
|
||||
fn remaining(&self) -> usize {
|
||||
self.buf.remaining()
|
||||
}
|
||||
|
||||
fn bytes<'a>(&'a self) -> &'a [u8] {
|
||||
self.buf.bytes()
|
||||
}
|
||||
|
||||
fn advance(&mut self, cnt: usize) {
|
||||
self.buf.advance(cnt)
|
||||
}
|
||||
|
||||
fn read_slice(&mut self, dst: &mut [u8]) -> usize {
|
||||
self.buf.read_slice(dst)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
* ===== MutByteBuf =====
|
||||
*
|
||||
*/
|
||||
|
||||
pub struct MutByteBuf {
|
||||
buf: ByteBuf,
|
||||
}
|
||||
|
||||
impl MutByteBuf {
|
||||
pub fn capacity(&self) -> usize {
|
||||
self.buf.capacity() as usize
|
||||
}
|
||||
|
||||
pub fn flip(self) -> ByteBuf {
|
||||
let mut buf = self.buf;
|
||||
|
||||
buf.lim = buf.pos;
|
||||
buf.pos = 0;
|
||||
buf
|
||||
}
|
||||
|
||||
pub fn clear(&mut self) {
|
||||
self.buf.pos = 0;
|
||||
self.buf.lim = self.buf.cap;
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn write_slice(&mut self, src: &[u8]) -> usize {
|
||||
let cnt = src.len() as u32;
|
||||
let rem = self.buf.remaining_u32();
|
||||
|
||||
if rem < cnt {
|
||||
self.write_ptr(src.as_ptr(), rem)
|
||||
} else {
|
||||
self.write_ptr(src.as_ptr(), cnt)
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn write_ptr(&mut self, src: *const u8, len: u32) -> usize {
|
||||
unsafe {
|
||||
ptr::copy_nonoverlapping_memory(
|
||||
self.buf.mem.ptr().offset(self.buf.pos as isize),
|
||||
src, len as usize);
|
||||
|
||||
self.buf.pos += len;
|
||||
len as usize
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl MutBuf for MutByteBuf {
|
||||
fn remaining(&self) -> usize {
|
||||
self.buf.remaining()
|
||||
}
|
||||
|
||||
fn advance(&mut self, cnt: usize) {
|
||||
self.buf.advance(cnt)
|
||||
}
|
||||
|
||||
fn mut_bytes<'a>(&'a mut self) -> &'a mut [u8] {
|
||||
let pos = self.buf.pos();
|
||||
let lim = self.buf.lim();
|
||||
&mut self.buf.mem.bytes_mut()[pos..lim]
|
||||
}
|
||||
}
|
||||
-227
@@ -1,227 +0,0 @@
|
||||
use {alloc, Bytes, ByteBuf, ROByteBuf};
|
||||
use traits::{Buf, MutBuf, MutBufExt, ByteStr};
|
||||
use std::{cmp, ops};
|
||||
|
||||
/*
|
||||
*
|
||||
* ===== SeqByteStr =====
|
||||
*
|
||||
*/
|
||||
|
||||
pub struct SeqByteStr {
|
||||
mem: alloc::MemRef,
|
||||
pos: u32,
|
||||
len: u32,
|
||||
}
|
||||
|
||||
impl SeqByteStr {
|
||||
/// Create a new `SeqByteStr` from a byte slice.
|
||||
///
|
||||
/// The contents of the byte slice will be copied.
|
||||
pub fn from_slice(bytes: &[u8]) -> SeqByteStr {
|
||||
let mut buf = ByteBuf::mut_with_capacity(bytes.len());
|
||||
|
||||
if let Err(e) = buf.write(bytes) {
|
||||
panic!("failed to copy bytes from slice; err={:?}", e);
|
||||
}
|
||||
|
||||
buf.flip().to_seq_byte_str()
|
||||
}
|
||||
|
||||
/// Creates a new `SeqByteStr` from a `MemRef`, an offset, and a length.
|
||||
///
|
||||
/// This function is unsafe as there are no guarantees that the given
|
||||
/// arguments are valid.
|
||||
pub unsafe fn from_mem_ref(mem: alloc::MemRef, pos: u32, len: u32) -> SeqByteStr {
|
||||
SeqByteStr {
|
||||
mem: mem,
|
||||
pos: pos,
|
||||
len: len,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ByteStr for SeqByteStr {
|
||||
type Buf = ROByteBuf;
|
||||
|
||||
fn buf(&self) -> ROByteBuf {
|
||||
unsafe {
|
||||
let pos = self.pos;
|
||||
let lim = pos + self.len;
|
||||
|
||||
ROByteBuf::from_mem_ref(self.mem.clone(), lim, pos, lim)
|
||||
}
|
||||
}
|
||||
|
||||
fn concat<B: ByteStr>(&self, _other: B) -> Bytes {
|
||||
unimplemented!();
|
||||
}
|
||||
|
||||
fn len(&self) -> usize {
|
||||
self.len as usize
|
||||
}
|
||||
|
||||
fn slice(&self, begin: usize, end: usize) -> Bytes {
|
||||
if begin >= end || begin >= self.len() {
|
||||
return Bytes::empty()
|
||||
}
|
||||
|
||||
let bytes = unsafe {
|
||||
SeqByteStr::from_mem_ref(
|
||||
self.mem.clone(),
|
||||
self.pos + begin as u32,
|
||||
(end - begin) as u32)
|
||||
};
|
||||
|
||||
Bytes::of(bytes)
|
||||
}
|
||||
|
||||
fn to_bytes(self) -> Bytes {
|
||||
Bytes::of(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl ops::Index<usize> for SeqByteStr {
|
||||
type Output = u8;
|
||||
|
||||
fn index(&self, index: &usize) -> &u8 {
|
||||
assert!(*index < self.len());
|
||||
|
||||
unsafe {
|
||||
&*self.mem.ptr()
|
||||
.offset(*index as isize + self.pos as isize)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for SeqByteStr {
|
||||
fn clone(&self) -> SeqByteStr {
|
||||
SeqByteStr {
|
||||
mem: self.mem.clone(),
|
||||
pos: self.pos,
|
||||
len: self.len,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
* ===== SmallByteStr =====
|
||||
*
|
||||
*/
|
||||
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
const MAX_LEN: usize = 7;
|
||||
|
||||
#[cfg(target_pointer_width = "32")]
|
||||
const MAX_LEN: usize = 3;
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct SmallByteStr {
|
||||
len: u8,
|
||||
bytes: [u8; MAX_LEN],
|
||||
}
|
||||
|
||||
impl SmallByteStr {
|
||||
pub fn zero() -> SmallByteStr {
|
||||
use std::mem;
|
||||
|
||||
SmallByteStr {
|
||||
len: 0,
|
||||
bytes: unsafe { mem::zeroed() }
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_slice(bytes: &[u8]) -> Option<SmallByteStr> {
|
||||
use std::mem;
|
||||
use std::slice::bytes;
|
||||
|
||||
if bytes.len() > MAX_LEN {
|
||||
return None;
|
||||
}
|
||||
|
||||
let mut ret = SmallByteStr {
|
||||
len: bytes.len() as u8,
|
||||
bytes: unsafe { mem::zeroed() },
|
||||
};
|
||||
|
||||
// Copy the memory
|
||||
bytes::copy_memory(&mut ret.bytes, bytes);
|
||||
|
||||
Some(ret)
|
||||
}
|
||||
}
|
||||
|
||||
impl ByteStr for SmallByteStr {
|
||||
type Buf = SmallByteStrBuf;
|
||||
|
||||
fn buf(&self) -> SmallByteStrBuf {
|
||||
SmallByteStrBuf { small: self.clone() }
|
||||
}
|
||||
|
||||
fn concat<B: ByteStr>(&self, _other: B) -> Bytes {
|
||||
unimplemented!();
|
||||
}
|
||||
|
||||
fn len(&self) -> usize {
|
||||
self.len as usize
|
||||
}
|
||||
|
||||
fn slice(&self, _begin: usize, _end: usize) -> Bytes {
|
||||
unimplemented!();
|
||||
}
|
||||
|
||||
fn split_at(&self, _mid: usize) -> (Bytes, Bytes) {
|
||||
unimplemented!();
|
||||
}
|
||||
|
||||
fn to_bytes(self) -> Bytes {
|
||||
Bytes::of(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl ops::Index<usize> for SmallByteStr {
|
||||
type Output = u8;
|
||||
|
||||
fn index(&self, index: &usize) -> &u8 {
|
||||
assert!(*index < self.len());
|
||||
&self.bytes[*index]
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
#[allow(missing_copy_implementations)]
|
||||
pub struct SmallByteStrBuf {
|
||||
small: SmallByteStr,
|
||||
}
|
||||
|
||||
impl SmallByteStrBuf {
|
||||
fn len(&self) -> usize {
|
||||
(self.small.len & 0x0F) as usize
|
||||
}
|
||||
|
||||
fn pos(&self) -> usize {
|
||||
(self.small.len >> 4) as usize
|
||||
}
|
||||
}
|
||||
|
||||
impl Buf for SmallByteStrBuf {
|
||||
fn remaining(&self) -> usize {
|
||||
self.len() - self.pos()
|
||||
}
|
||||
|
||||
fn bytes(&self) -> &[u8] {
|
||||
&self.small.bytes[self.pos()..self.len()]
|
||||
}
|
||||
|
||||
fn advance(&mut self, mut cnt: usize) {
|
||||
cnt = cmp::min(cnt, self.remaining());
|
||||
self.small.len += (cnt as u8) << 4;
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_size_of() {
|
||||
use std::mem;
|
||||
assert_eq!(mem::size_of::<SmallByteStr>(), mem::size_of::<usize>());
|
||||
}
|
||||
+1439
-281
File diff suppressed because it is too large
Load Diff
+1918
File diff suppressed because it is too large
Load Diff
@@ -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]);
|
||||
+139
-354
@@ -1,380 +1,165 @@
|
||||
#![crate_name = "bytes"]
|
||||
#![unstable]
|
||||
#![allow(unknown_lints, unexpected_cfgs)]
|
||||
#![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]
|
||||
#![cfg_attr(docsrs, feature(doc_cfg))]
|
||||
|
||||
#![feature(core)]
|
||||
#![feature(alloc)]
|
||||
//! Provides abstractions for working with bytes.
|
||||
//!
|
||||
//! The `bytes` crate provides an efficient byte buffer structure
|
||||
//! ([`Bytes`]) and traits for working with buffer
|
||||
//! implementations ([`Buf`], [`BufMut`]).
|
||||
//!
|
||||
//! # `Bytes`
|
||||
//!
|
||||
//! `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.
|
||||
//!
|
||||
//! `Bytes` values facilitate zero-copy network programming by allowing multiple
|
||||
//! `Bytes` objects to point to the same underlying memory. This is managed by
|
||||
//! 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
|
||||
//! example:
|
||||
//!
|
||||
//! ```rust
|
||||
//! use bytes::{BytesMut, BufMut};
|
||||
//!
|
||||
//! let mut buf = BytesMut::with_capacity(1024);
|
||||
//! buf.put(&b"hello world"[..]);
|
||||
//! buf.put_u16(1234);
|
||||
//!
|
||||
//! let a = buf.split();
|
||||
//! assert_eq!(a, b"hello world\x04\xD2"[..]);
|
||||
//!
|
||||
//! buf.put(&b"goodbye world"[..]);
|
||||
//!
|
||||
//! let b = buf.split();
|
||||
//! assert_eq!(b, b"goodbye world"[..]);
|
||||
//!
|
||||
//! assert_eq!(buf.capacity(), 998);
|
||||
//! ```
|
||||
//!
|
||||
//! In the above example, only a single buffer of 1024 is allocated. The handles
|
||||
//! `a` and `b` will share the underlying buffer and maintain indices tracking
|
||||
//! the view into the buffer represented by the handle.
|
||||
//!
|
||||
//! See the [struct docs](`Bytes`) for more details.
|
||||
//!
|
||||
//! # `Buf`, `BufMut`
|
||||
//!
|
||||
//! These two traits provide read and write access to buffers. The underlying
|
||||
//! storage may or may not be in contiguous memory. For example, `Bytes` is a
|
||||
//! buffer that guarantees contiguous memory, but a [rope] stores the bytes in
|
||||
//! disjoint chunks. `Buf` and `BufMut` maintain cursors tracking the current
|
||||
//! position in the underlying byte storage. When bytes are read or written, the
|
||||
//! cursor is advanced.
|
||||
//!
|
||||
//! [rope]: https://en.wikipedia.org/wiki/Rope_(data_structure)
|
||||
//!
|
||||
//! ## Relation with `Read` and `Write`
|
||||
//!
|
||||
//! At first glance, it may seem that `Buf` and `BufMut` overlap in
|
||||
//! functionality with [`std::io::Read`] and [`std::io::Write`]. However, they
|
||||
//! serve different purposes. A buffer is the value that is provided as an
|
||||
//! argument to `Read::read` and `Write::write`. `Read` and `Write` may then
|
||||
//! perform a syscall, which has the potential of failing. Operations on `Buf`
|
||||
//! and `BufMut` are infallible.
|
||||
|
||||
pub use byte_buf::{ByteBuf, ROByteBuf, MutByteBuf};
|
||||
pub use byte_str::{SeqByteStr, SmallByteStr, SmallByteStrBuf};
|
||||
pub use bytes::Bytes;
|
||||
pub use ring::{RingBuf, RingBufReader, RingBufWriter};
|
||||
pub use rope::Rope;
|
||||
pub use slice::{SliceBuf, MutSliceBuf};
|
||||
extern crate alloc;
|
||||
|
||||
use std::{cmp, io, ops, ptr, u32};
|
||||
#[cfg(feature = "std")]
|
||||
extern crate std;
|
||||
|
||||
extern crate core;
|
||||
pub mod buf;
|
||||
pub use crate::buf::{Buf, BufMut};
|
||||
|
||||
mod alloc;
|
||||
mod byte_buf;
|
||||
mod byte_str;
|
||||
mod bytes;
|
||||
mod ring;
|
||||
mod rope;
|
||||
mod slice;
|
||||
mod bytes_mut;
|
||||
mod fmt;
|
||||
mod loom;
|
||||
pub use crate::bytes::Bytes;
|
||||
pub use crate::bytes_mut::BytesMut;
|
||||
|
||||
pub mod traits {
|
||||
pub use {Buf, BufExt, MutBuf, MutBufExt, ByteStr};
|
||||
}
|
||||
// Optional Serde support
|
||||
#[cfg(feature = "serde")]
|
||||
mod serde;
|
||||
|
||||
const MAX_CAPACITY: usize = u32::MAX as usize;
|
||||
|
||||
/// A trait for values that provide random and sequential access to bytes.
|
||||
pub trait Buf {
|
||||
|
||||
/// Returns the number of bytes that can be accessed from the Buf
|
||||
fn remaining(&self) -> usize;
|
||||
|
||||
/// Returns a slice starting at the current Buf position and of length
|
||||
/// between 0 and `Buf::remaining()`.
|
||||
fn bytes<'a>(&'a self) -> &'a [u8];
|
||||
|
||||
/// Advance the internal cursor of the Buf
|
||||
fn advance(&mut self, cnt: usize);
|
||||
|
||||
/// Returns true if there are any more bytes to consume
|
||||
fn has_remaining(&self) -> bool {
|
||||
self.remaining() > 0
|
||||
#[inline(never)]
|
||||
#[cold]
|
||||
fn abort() -> ! {
|
||||
#[cfg(feature = "std")]
|
||||
{
|
||||
std::process::abort();
|
||||
}
|
||||
|
||||
/// Read bytes from this Buf into the given slice and advance the cursor by
|
||||
/// the number of bytes read.
|
||||
///
|
||||
/// If there are fewer bytes remaining than is needed to satisfy the
|
||||
/// request (aka `dst.len()` > self.remaining()`), then
|
||||
/// `Err(BufError::Overflow)` is returned.
|
||||
///
|
||||
/// ```
|
||||
/// use bytes::{SliceBuf, Buf};
|
||||
///
|
||||
/// let mut buf = SliceBuf::wrap(b"hello world");
|
||||
/// let mut dst = [0; 5];
|
||||
///
|
||||
/// buf.read_slice(&mut dst);
|
||||
/// assert_eq!(b"hello", dst);
|
||||
/// assert_eq!(6, buf.remaining());
|
||||
/// ```
|
||||
fn read_slice(&mut self, dst: &mut [u8]) -> usize {
|
||||
let mut off = 0;
|
||||
let len = cmp::min(dst.len(), self.remaining());
|
||||
|
||||
while off < len {
|
||||
let mut cnt;
|
||||
|
||||
unsafe {
|
||||
let src = self.bytes();
|
||||
cnt = cmp::min(src.len(), len - off);
|
||||
|
||||
ptr::copy_nonoverlapping_memory(
|
||||
dst[off..].as_mut_ptr(), src.as_ptr(), cnt);
|
||||
|
||||
off += src.len();
|
||||
#[cfg(not(feature = "std"))]
|
||||
{
|
||||
struct Abort;
|
||||
impl Drop for Abort {
|
||||
fn drop(&mut self) {
|
||||
panic!();
|
||||
}
|
||||
|
||||
self.advance(cnt);
|
||||
}
|
||||
|
||||
len
|
||||
let _a = Abort;
|
||||
panic!("abort");
|
||||
}
|
||||
}
|
||||
|
||||
pub trait BufExt {
|
||||
|
||||
/// Read bytes from this Buf into the given sink and advance the cursor by
|
||||
/// the number of bytes read.
|
||||
fn read<S: Sink>(&mut self, dst: S) -> Result<usize, S::Error>;
|
||||
}
|
||||
|
||||
// TODO: Remove Sized
|
||||
pub trait MutBuf : Sized {
|
||||
|
||||
/// Returns the number of bytes that can be accessed from the Buf
|
||||
fn remaining(&self) -> usize;
|
||||
|
||||
/// Advance the internal cursor of the Buf
|
||||
fn advance(&mut self, cnt: usize);
|
||||
|
||||
/// Returns true if there are any more bytes to consume
|
||||
fn has_remaining(&self) -> bool {
|
||||
self.remaining() > 0
|
||||
}
|
||||
|
||||
/// Returns a mutable slice starting at the current Buf position and of
|
||||
/// length between 0 and `Buf::remaining()`.
|
||||
fn mut_bytes<'a>(&'a mut self) -> &'a mut [u8];
|
||||
|
||||
/// Read bytes from this Buf into the given slice and advance the cursor by
|
||||
/// the number of bytes read.
|
||||
///
|
||||
/// If there are fewer bytes remaining than is needed to satisfy the
|
||||
/// request (aka `dst.len()` > self.remaining()`), then
|
||||
/// `Err(BufError::Overflow)` is returned.
|
||||
///
|
||||
/// ```
|
||||
/// use bytes::{MutSliceBuf, Buf, MutBuf};
|
||||
///
|
||||
/// let mut dst = [0; 6];
|
||||
///
|
||||
/// {
|
||||
/// let mut buf = MutSliceBuf::wrap(&mut dst);
|
||||
/// buf.write_slice(b"hello");
|
||||
///
|
||||
/// assert_eq!(1, buf.remaining());
|
||||
/// }
|
||||
///
|
||||
/// assert_eq!(b"hello\0", dst);
|
||||
/// ```
|
||||
fn write_slice(&mut self, src: &[u8]) -> usize {
|
||||
let mut off = 0;
|
||||
let len = cmp::min(src.len(), self.remaining());
|
||||
|
||||
while off < len {
|
||||
let mut cnt;
|
||||
|
||||
unsafe {
|
||||
let dst = self.mut_bytes();
|
||||
cnt = cmp::min(dst.len(), len - off);
|
||||
|
||||
ptr::copy_nonoverlapping_memory(
|
||||
dst.as_mut_ptr(), src[off..].as_ptr(), cnt);
|
||||
|
||||
off += cnt;
|
||||
}
|
||||
|
||||
self.advance(cnt);
|
||||
}
|
||||
|
||||
len
|
||||
#[inline(always)]
|
||||
#[cfg(feature = "std")]
|
||||
fn saturating_sub_usize_u64(a: usize, b: u64) -> usize {
|
||||
use core::convert::TryFrom;
|
||||
match usize::try_from(b) {
|
||||
Ok(b) => a.saturating_sub(b),
|
||||
Err(_) => 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub trait MutBufExt {
|
||||
|
||||
/// Write bytes from the given source into the current `MutBuf` and advance
|
||||
/// the cursor by the number of bytes written.
|
||||
fn write<S: Source>(&mut self, src: S) -> Result<usize, S::Error>;
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
* ===== ByteStr =====
|
||||
*
|
||||
*/
|
||||
|
||||
pub trait ByteStr : Clone + Sized + Send + Sync + ops::Index<usize, Output=u8> {
|
||||
|
||||
// Until HKT lands, the buf must be bound by 'static
|
||||
type Buf: Buf+'static;
|
||||
|
||||
/// Returns a read-only `Buf` for accessing the byte contents of the
|
||||
/// `ByteStr`.
|
||||
fn buf(&self) -> Self::Buf;
|
||||
|
||||
/// Returns a new `Bytes` value representing the concatenation of `self`
|
||||
/// with the given `Bytes`.
|
||||
fn concat<B: ByteStr+'static>(&self, other: B) -> Bytes;
|
||||
|
||||
/// Returns the number of bytes in the ByteStr
|
||||
fn len(&self) -> usize;
|
||||
|
||||
/// Returns true if the length of the `ByteStr` is 0
|
||||
fn is_empty(&self) -> bool {
|
||||
self.len() == 0
|
||||
}
|
||||
|
||||
/// Returns a new ByteStr value containing the byte range between `begin`
|
||||
/// (inclusive) and `end` (exclusive)
|
||||
fn slice(&self, begin: usize, end: usize) -> Bytes;
|
||||
|
||||
/// Returns a new ByteStr value containing the byte range starting from
|
||||
/// `begin` (inclusive) to the end of the byte str.
|
||||
///
|
||||
/// Equivalent to `bytes.slice(begin, bytes.len())`
|
||||
fn slice_from(&self, begin: usize) -> Bytes {
|
||||
self.slice(begin, self.len())
|
||||
}
|
||||
|
||||
/// Returns a new ByteStr value containing the byte range from the start up
|
||||
/// to `end` (exclusive).
|
||||
///
|
||||
/// Equivalent to `bytes.slice(0, end)`
|
||||
fn slice_to(&self, end: usize) -> Bytes {
|
||||
self.slice(0, end)
|
||||
}
|
||||
|
||||
/// Divides the value into two `Bytes` at the given index.
|
||||
///
|
||||
/// The first will contain all bytes from `[0, mid]` (excluding the index
|
||||
/// `mid` itself) and the second will contain all indices from `[mid, len)`
|
||||
/// (excluding the index `len` itself).
|
||||
///
|
||||
/// Panics if `mid > len`.
|
||||
fn split_at(&self, mid: usize) -> (Bytes, Bytes) {
|
||||
(self.slice_to(mid), self.slice_from(mid))
|
||||
}
|
||||
|
||||
/// Consumes the value and returns a `Bytes` instance containing
|
||||
/// identical bytes
|
||||
fn to_bytes(self) -> Bytes;
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
* ===== *Ext impls =====
|
||||
*
|
||||
*/
|
||||
|
||||
impl<B: Buf> BufExt for B {
|
||||
fn read<S: Sink>(&mut self, dst: S) -> Result<usize, S::Error> {
|
||||
dst.sink(self)
|
||||
#[inline(always)]
|
||||
#[cfg(feature = "std")]
|
||||
fn min_u64_usize(a: u64, b: usize) -> usize {
|
||||
use core::convert::TryFrom;
|
||||
match usize::try_from(a) {
|
||||
Ok(a) => usize::min(a, b),
|
||||
Err(_) => b,
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: MutBuf> MutBufExt for B {
|
||||
fn write<S: Source>(&mut self, src: S) -> Result<usize, S::Error> {
|
||||
src.fill(self)
|
||||
}
|
||||
/// Panic with a nice error message.
|
||||
#[cold]
|
||||
fn panic_advance(idx: usize, len: usize) -> ! {
|
||||
panic!(
|
||||
"advance out of bounds: the len is {} but advancing by {}",
|
||||
len, idx
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
* ===== Sink / Source =====
|
||||
*
|
||||
*/
|
||||
|
||||
/// An value that reads bytes from a Buf into itself
|
||||
pub trait Sink {
|
||||
type Error;
|
||||
|
||||
fn sink<B: Buf>(self, buf: &mut B) -> Result<usize, Self::Error>;
|
||||
#[cold]
|
||||
fn panic_does_not_fit(size: usize, nbytes: usize) -> ! {
|
||||
panic!(
|
||||
"size too large: the integer type can fit {} bytes, but nbytes is {}",
|
||||
size, nbytes
|
||||
);
|
||||
}
|
||||
|
||||
pub trait Source {
|
||||
type Error;
|
||||
|
||||
fn fill<B: MutBuf>(self, buf: &mut B) -> Result<usize, Self::Error>;
|
||||
/// Precondition: dst >= original
|
||||
///
|
||||
/// The following line is equivalent to:
|
||||
///
|
||||
/// ```rust,ignore
|
||||
/// self.ptr.as_ptr().offset_from(ptr) as usize;
|
||||
/// ```
|
||||
///
|
||||
/// But due to min rust is 1.39 and it is only stabilized
|
||||
/// in 1.47, we cannot use it.
|
||||
#[inline]
|
||||
fn offset_from(dst: *const u8, original: *const u8) -> usize {
|
||||
dst as usize - original as usize
|
||||
}
|
||||
|
||||
impl<'a> Sink for &'a mut [u8] {
|
||||
type Error = BufError;
|
||||
|
||||
fn sink<B: Buf>(self, buf: &mut B) -> Result<usize, BufError> {
|
||||
Ok(buf.read_slice(self))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Sink for &'a mut Vec<u8> {
|
||||
type Error = BufError;
|
||||
|
||||
fn sink<B: Buf>(self, buf: &mut B) -> Result<usize, BufError> {
|
||||
use std::slice;
|
||||
|
||||
let rem = buf.remaining();
|
||||
let cap = self.capacity();
|
||||
let len = rem - cap;
|
||||
|
||||
// Ensure that the vec is big enough
|
||||
if cap < rem {
|
||||
self.reserve(len);
|
||||
}
|
||||
|
||||
unsafe {
|
||||
{
|
||||
let dst = self.as_mut_slice();
|
||||
buf.read_slice(slice::from_raw_parts_mut(dst.as_mut_ptr(), rem));
|
||||
}
|
||||
|
||||
self.set_len(rem);
|
||||
}
|
||||
|
||||
Ok(len)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Source for &'a [u8] {
|
||||
type Error = BufError;
|
||||
|
||||
fn fill<B: MutBuf>(self, buf: &mut B) -> Result<usize, BufError> {
|
||||
Ok(buf.write_slice(self))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Source for &'a Vec<u8> {
|
||||
type Error = BufError;
|
||||
|
||||
fn fill<B: MutBuf>(self, buf: &mut B) -> Result<usize, BufError> {
|
||||
Ok(buf.write_slice(self.as_slice()))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Source for &'a Bytes {
|
||||
type Error = BufError;
|
||||
|
||||
fn fill<B: MutBuf>(self, _buf: &mut B) -> Result<usize, BufError> {
|
||||
unimplemented!();
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Source for &'a mut (io::Read+'a) {
|
||||
type Error = io::Error;
|
||||
|
||||
fn fill<B: MutBuf>(self, _buf: &mut B) -> Result<usize, io::Error> {
|
||||
unimplemented!();
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Source for &'a mut (Iterator<Item=u8>+'a) {
|
||||
type Error = BufError;
|
||||
|
||||
fn fill<B: MutBuf>(self, _buf: &mut B) -> Result<usize, BufError> {
|
||||
unimplemented!();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
* ===== Buf impls =====
|
||||
*
|
||||
*/
|
||||
|
||||
impl Buf for Box<Buf+'static> {
|
||||
fn remaining(&self) -> usize {
|
||||
(**self).remaining()
|
||||
}
|
||||
|
||||
fn bytes(&self) -> &[u8] {
|
||||
(**self).bytes()
|
||||
}
|
||||
|
||||
fn advance(&mut self, cnt: usize) {
|
||||
(**self).advance(cnt);
|
||||
}
|
||||
|
||||
fn read_slice(&mut self, dst: &mut [u8]) -> usize {
|
||||
(**self).read_slice(dst)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
* ===== BufError / BufResult =====
|
||||
*
|
||||
*/
|
||||
|
||||
#[derive(Copy, Debug)]
|
||||
pub enum BufError {
|
||||
Underflow,
|
||||
Overflow,
|
||||
}
|
||||
|
||||
pub type BufResult<T> = Result<T, BufError>;
|
||||
|
||||
+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> {}
|
||||
}
|
||||
}
|
||||
-200
@@ -1,200 +0,0 @@
|
||||
use super::{Buf, MutBuf};
|
||||
use std::{cmp, fmt, mem, ptr, slice};
|
||||
use std::num::UnsignedInt;
|
||||
use std::rt::heap;
|
||||
|
||||
/// Buf backed by a continous chunk of memory. Maintains a read cursor and a
|
||||
/// write cursor. When reads and writes reach the end of the allocated buffer,
|
||||
/// wraps around to the start.
|
||||
pub struct RingBuf {
|
||||
ptr: *mut u8, // Pointer to the memory
|
||||
cap: usize, // Capacity of the buffer
|
||||
pos: usize, // Offset of read cursor
|
||||
len: usize // Number of bytes to read
|
||||
}
|
||||
|
||||
// TODO: There are most likely many optimizations that can be made
|
||||
impl RingBuf {
|
||||
pub fn new(mut capacity: usize) -> RingBuf {
|
||||
// Handle the 0 length buffer case
|
||||
if capacity == 0 {
|
||||
return RingBuf {
|
||||
ptr: ptr::null_mut(),
|
||||
cap: 0,
|
||||
pos: 0,
|
||||
len: 0
|
||||
}
|
||||
}
|
||||
|
||||
// Round to the next power of 2 for better alignment
|
||||
capacity = UnsignedInt::next_power_of_two(capacity);
|
||||
|
||||
// Allocate the memory
|
||||
let ptr = unsafe { heap::allocate(capacity, mem::min_align_of::<u8>()) };
|
||||
|
||||
RingBuf {
|
||||
ptr: ptr as *mut u8,
|
||||
cap: capacity,
|
||||
pos: 0,
|
||||
len: 0
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_full(&self) -> bool {
|
||||
self.cap == self.len
|
||||
}
|
||||
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.len == 0
|
||||
}
|
||||
|
||||
pub fn capacity(&self) -> usize {
|
||||
self.cap
|
||||
}
|
||||
|
||||
// Access readable bytes as a Buf
|
||||
pub fn reader<'a>(&'a mut self) -> RingBufReader<'a> {
|
||||
RingBufReader { ring: self }
|
||||
}
|
||||
|
||||
// Access writable bytes as a Buf
|
||||
pub fn writer<'a>(&'a mut self) -> RingBufWriter<'a> {
|
||||
RingBufWriter { ring: self }
|
||||
}
|
||||
|
||||
fn read_remaining(&self) -> usize {
|
||||
self.len
|
||||
}
|
||||
|
||||
fn write_remaining(&self) -> usize {
|
||||
self.cap - self.len
|
||||
}
|
||||
|
||||
fn advance_reader(&mut self, mut cnt: usize) {
|
||||
cnt = cmp::min(cnt, self.read_remaining());
|
||||
|
||||
self.pos += cnt;
|
||||
self.pos %= self.cap;
|
||||
self.len -= cnt;
|
||||
}
|
||||
|
||||
fn advance_writer(&mut self, mut cnt: usize) {
|
||||
cnt = cmp::min(cnt, self.write_remaining());
|
||||
self.len += cnt;
|
||||
}
|
||||
|
||||
fn as_slice(&self) -> &[u8] {
|
||||
unsafe {
|
||||
slice::from_raw_parts(self.ptr as *const u8, self.cap)
|
||||
}
|
||||
}
|
||||
|
||||
fn as_mut_slice(&mut self) -> &mut [u8] {
|
||||
unsafe {
|
||||
slice::from_raw_parts_mut(self.ptr, self.cap)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for RingBuf {
|
||||
fn clone(&self) -> RingBuf {
|
||||
use std::cmp;
|
||||
|
||||
let mut ret = RingBuf::new(self.cap);
|
||||
|
||||
ret.pos = self.pos;
|
||||
ret.len = self.len;
|
||||
|
||||
unsafe {
|
||||
let to = self.pos + self.len;
|
||||
|
||||
if to > self.cap {
|
||||
ptr::copy_memory(ret.ptr, self.ptr as *const u8, to % self.cap);
|
||||
}
|
||||
|
||||
ptr::copy_memory(
|
||||
ret.ptr.offset(self.pos as isize),
|
||||
self.ptr.offset(self.pos as isize) as *const u8,
|
||||
cmp::min(self.len, self.cap - self.pos));
|
||||
}
|
||||
|
||||
ret
|
||||
}
|
||||
|
||||
// TODO: an improved version of clone_from is possible that potentially
|
||||
// re-uses the buffer
|
||||
}
|
||||
|
||||
impl fmt::Debug for RingBuf {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(fmt, "RingBuf[.. {}]", self.len)
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for RingBuf {
|
||||
fn drop(&mut self) {
|
||||
if self.cap > 0 {
|
||||
unsafe {
|
||||
heap::deallocate(self.ptr, self.cap, mem::min_align_of::<u8>())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct RingBufReader<'a> {
|
||||
ring: &'a mut RingBuf
|
||||
}
|
||||
|
||||
impl<'a> Buf for RingBufReader<'a> {
|
||||
|
||||
fn remaining(&self) -> usize {
|
||||
self.ring.read_remaining()
|
||||
}
|
||||
|
||||
fn bytes<'b>(&'b self) -> &'b [u8] {
|
||||
let mut to = self.ring.pos + self.ring.len;
|
||||
|
||||
if to > self.ring.cap {
|
||||
to = self.ring.cap
|
||||
}
|
||||
|
||||
&self.ring.as_slice()[self.ring.pos .. to]
|
||||
}
|
||||
|
||||
fn advance(&mut self, cnt: usize) {
|
||||
self.ring.advance_reader(cnt)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct RingBufWriter<'a> {
|
||||
ring: &'a mut RingBuf
|
||||
}
|
||||
|
||||
impl<'a> MutBuf for RingBufWriter<'a> {
|
||||
|
||||
fn remaining(&self) -> usize {
|
||||
self.ring.write_remaining()
|
||||
}
|
||||
|
||||
fn advance(&mut self, cnt: usize) {
|
||||
self.ring.advance_writer(cnt)
|
||||
}
|
||||
|
||||
fn mut_bytes<'b>(&'b mut self) -> &'b mut [u8] {
|
||||
let mut from;
|
||||
let mut to;
|
||||
|
||||
from = self.ring.pos + self.ring.len;
|
||||
from %= self.ring.cap;
|
||||
|
||||
to = from + self.remaining();
|
||||
|
||||
if to >= self.ring.cap {
|
||||
to = self.ring.cap;
|
||||
}
|
||||
|
||||
&mut self.ring.as_mut_slice()[from..to]
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl Send for RingBuf { }
|
||||
-583
@@ -1,583 +0,0 @@
|
||||
use {Bytes, ByteBuf, Source, BufError};
|
||||
use traits::*;
|
||||
use std::{cmp, mem, ops};
|
||||
use std::sync::Arc;
|
||||
|
||||
// The implementation is mostly a port of the implementation found in the Java
|
||||
// protobuf lib.
|
||||
|
||||
const CONCAT_BY_COPY_LEN: usize = 128;
|
||||
const MAX_DEPTH: usize = 47;
|
||||
|
||||
// Used to decide when to rebalance the tree.
|
||||
static MIN_LENGTH_BY_DEPTH: [usize; MAX_DEPTH] = [
|
||||
1, 2, 3, 5, 8,
|
||||
13, 21, 34, 55, 89,
|
||||
144, 233, 377, 610, 987,
|
||||
1_597, 2_584, 4_181, 6_765, 10_946,
|
||||
17_711, 28_657, 46_368, 75_025, 121_393,
|
||||
196_418, 317_811, 514_229, 832_040, 1_346_269,
|
||||
2_178_309, 3_524_578, 5_702_887, 9_227_465, 14_930_352,
|
||||
24_157_817, 39_088_169, 63_245_986, 102_334_155, 165_580_141,
|
||||
267_914_296, 433_494_437, 701_408_733, 1_134_903_170, 1_836_311_903,
|
||||
2_971_215_073, 4_294_967_295];
|
||||
|
||||
/// An immutable sequence of bytes formed by concatenation of other `ByteStr`
|
||||
/// values, without copying the data in the pieces. The concatenation is
|
||||
/// represented as a tree whose leaf nodes are each a `Bytes` value.
|
||||
///
|
||||
/// Most of the operation here is inspired by the now-famous paper [Ropes: an
|
||||
/// Alternative to Strings. hans-j. boehm, russ atkinson and michael
|
||||
/// plass](http://www.cs.rit.edu/usr/local/pub/jeh/courses/QUARTERS/FP/Labs/CedarRope/rope-paper.pdf).
|
||||
///
|
||||
/// Fundamentally the Rope algorithm represents the collection of pieces as a
|
||||
/// binary tree. BAP95 uses a Fibonacci bound relating depth to a minimum
|
||||
/// sequence length, sequences that are too short relative to their depth cause
|
||||
/// a tree rebalance. More precisely, a tree of depth d is "balanced" in the
|
||||
/// terminology of BAP95 if its length is at least F(d+2), where F(n) is the
|
||||
/// n-the Fibonacci number. Thus for depths 0, 1, 2, 3, 4, 5,... we have
|
||||
/// minimum lengths 1, 2, 3, 5, 8, 13,...
|
||||
pub struct Rope {
|
||||
inner: Arc<RopeInner>,
|
||||
}
|
||||
|
||||
impl Rope {
|
||||
pub fn from_slice(bytes: &[u8]) -> Rope {
|
||||
Rope::new(Bytes::from_slice(bytes), Bytes::empty())
|
||||
}
|
||||
|
||||
/// Returns a Rope consisting of the supplied Bytes as a single segment.
|
||||
pub fn of<B: ByteStr + 'static>(bytes: B) -> Rope {
|
||||
let bytes = Bytes::of(bytes);
|
||||
|
||||
match bytes.try_unwrap() {
|
||||
Ok(rope) => rope,
|
||||
Err(bytes) => Rope::new(bytes, Bytes::empty()),
|
||||
}
|
||||
}
|
||||
|
||||
fn new(left: Bytes, right: Bytes) -> Rope {
|
||||
Rope { inner: Arc::new(RopeInner::new(left, right)) }
|
||||
}
|
||||
|
||||
pub fn len(&self) -> usize {
|
||||
self.inner.len as usize
|
||||
}
|
||||
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.len() == 0
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
* ===== Priv fns =====
|
||||
*
|
||||
*/
|
||||
|
||||
fn depth(&self) -> u16 {
|
||||
self.inner.depth
|
||||
}
|
||||
|
||||
fn left(&self) -> &Bytes {
|
||||
&self.inner.left
|
||||
}
|
||||
|
||||
fn right(&self) -> &Bytes {
|
||||
&self.inner.right
|
||||
}
|
||||
|
||||
fn pieces<'a>(&'a self) -> PieceIter<'a> {
|
||||
PieceIter::new(&self.inner)
|
||||
}
|
||||
}
|
||||
|
||||
impl ByteStr for Rope {
|
||||
type Buf = RopeBuf;
|
||||
|
||||
fn buf(&self) -> RopeBuf {
|
||||
RopeBuf::new(self.clone())
|
||||
}
|
||||
|
||||
fn concat<B: ByteStr+'static>(&self, other: B) -> Bytes {
|
||||
let left = Bytes::of(self.clone());
|
||||
let right = Bytes::of(other);
|
||||
Bytes::of(concat(left, right))
|
||||
}
|
||||
|
||||
fn len(&self) -> usize {
|
||||
Rope::len(self)
|
||||
}
|
||||
|
||||
fn slice(&self, begin: usize, end: usize) -> Bytes {
|
||||
if begin >= end || begin >= self.len() {
|
||||
return Bytes::empty()
|
||||
}
|
||||
|
||||
let end = cmp::min(end, self.len());
|
||||
let len = end - begin;
|
||||
|
||||
// Empty slice
|
||||
if len == 0 {
|
||||
return Bytes::empty();
|
||||
}
|
||||
|
||||
// Full rope
|
||||
if len == self.len() {
|
||||
return Bytes::of(self.clone());
|
||||
}
|
||||
|
||||
// == Proper substring ==
|
||||
|
||||
let left_len = self.inner.left.len();
|
||||
|
||||
if end <= left_len {
|
||||
// Slice on the left
|
||||
return self.inner.left.slice(begin, end);
|
||||
}
|
||||
|
||||
if begin >= left_len {
|
||||
// Slice on the right
|
||||
return self.inner.right.slice(begin - left_len, end - left_len);
|
||||
}
|
||||
|
||||
// Split slice
|
||||
let left_slice = self.inner.left.slice_from(begin);
|
||||
let right_slice = self.inner.right.slice_to(end - left_len);
|
||||
|
||||
Bytes::of(Rope::new(left_slice, right_slice))
|
||||
}
|
||||
|
||||
fn to_bytes(self) -> Bytes {
|
||||
Bytes::of(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl ops::Index<usize> for Rope {
|
||||
type Output = u8;
|
||||
|
||||
fn index(&self, index: &usize) -> &u8 {
|
||||
assert!(*index < self.len());
|
||||
|
||||
let left_len = self.inner.left.len();
|
||||
|
||||
if *index < left_len {
|
||||
self.inner.left.index(index)
|
||||
} else {
|
||||
self.inner.right.index(&(*index - left_len))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for Rope {
|
||||
fn clone(&self) -> Rope {
|
||||
Rope { inner: self.inner.clone() }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Source for &'a Rope {
|
||||
type Error = BufError;
|
||||
|
||||
fn fill<B: MutBuf>(self, _buf: &mut B) -> Result<usize, BufError> {
|
||||
unimplemented!();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
* ===== Helper Fns =====
|
||||
*
|
||||
*/
|
||||
|
||||
fn depth(bytes: &Bytes) -> u16 {
|
||||
match bytes.downcast_ref::<Rope>() {
|
||||
Some(rope) => rope.inner.depth,
|
||||
None => 0,
|
||||
}
|
||||
}
|
||||
|
||||
fn is_balanced(bytes: &Bytes) -> bool {
|
||||
if let Some(rope) = bytes.downcast_ref::<Rope>() {
|
||||
return rope.len() >= MIN_LENGTH_BY_DEPTH[rope.depth() as usize];
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
fn concat(left: Bytes, right: Bytes) -> Rope {
|
||||
if right.is_empty() {
|
||||
return Rope::of(left);
|
||||
}
|
||||
|
||||
if left.is_empty() {
|
||||
return Rope::of(right);
|
||||
}
|
||||
|
||||
let len = left.len() + right.len();
|
||||
|
||||
if len < CONCAT_BY_COPY_LEN {
|
||||
return concat_bytes(&left, &right, len);
|
||||
}
|
||||
|
||||
if let Some(left) = left.downcast_ref::<Rope>() {
|
||||
let len = left.inner.right.len() + right.len();
|
||||
|
||||
if len < CONCAT_BY_COPY_LEN {
|
||||
// Optimization from BAP95: As an optimization of the case
|
||||
// where the ByteString is constructed by repeated concatenate,
|
||||
// recognize the case where a short string is concatenated to a
|
||||
// left-hand node whose right-hand branch is short. In the
|
||||
// paper this applies to leaves, but we just look at the length
|
||||
// here. This has the advantage of shedding references to
|
||||
// unneeded data when substrings have been taken.
|
||||
//
|
||||
// When we recognize this case, we do a copy of the data and
|
||||
// create a new parent node so that the depth of the result is
|
||||
// the same as the given left tree.
|
||||
let new_right = concat_bytes(&left.inner.right, &right, len);
|
||||
return Rope::new(left.inner.left.clone(), Bytes::of(new_right));
|
||||
}
|
||||
|
||||
if depth(left.left()) > depth(left.right()) && left.depth() > depth(&right) {
|
||||
// Typically for concatenate-built strings the left-side is
|
||||
// deeper than the right. This is our final attempt to
|
||||
// concatenate without increasing the tree depth. We'll redo
|
||||
// the the node on the RHS. This is yet another optimization
|
||||
// for building the string by repeatedly concatenating on the
|
||||
// right.
|
||||
let new_right = Rope::new(left.right().clone(), right);
|
||||
return Rope::new(left.left().clone(), Bytes::of(new_right));
|
||||
}
|
||||
}
|
||||
|
||||
// Fine, we'll add a node and increase the tree depth -- unless we
|
||||
// rebalance ;^)
|
||||
let depth = cmp::max(depth(&left), depth(&right)) + 1;
|
||||
|
||||
if len >= MIN_LENGTH_BY_DEPTH[depth as usize] {
|
||||
// No need to rebalance
|
||||
return Rope::new(left, right);
|
||||
}
|
||||
|
||||
Balance::new().balance(left, right)
|
||||
}
|
||||
|
||||
fn concat_bytes(left: &Bytes, right: &Bytes, len: usize) -> Rope {
|
||||
let mut buf = ByteBuf::mut_with_capacity(len);
|
||||
|
||||
buf.write(left).ok().expect("unexpected error");
|
||||
buf.write(right).ok().expect("unexpected error");
|
||||
|
||||
return Rope::of(buf.flip().to_bytes());
|
||||
}
|
||||
|
||||
fn depth_for_len(len: usize) -> u16 {
|
||||
match MIN_LENGTH_BY_DEPTH.binary_search(&len) {
|
||||
Ok(idx) => idx as u16,
|
||||
Err(idx) => {
|
||||
// It wasn't an exact match, so convert to the index of the
|
||||
// containing fragment, which is one less even than the insertion
|
||||
// point.
|
||||
idx as u16 - 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
* ===== RopeBuf =====
|
||||
*
|
||||
*/
|
||||
|
||||
pub struct RopeBuf {
|
||||
rem: usize,
|
||||
|
||||
// Only here for the ref count
|
||||
#[allow(dead_code)]
|
||||
rope: Rope,
|
||||
|
||||
// This must be done with unsafe code to avoid having a lifetime bound on
|
||||
// RopeBuf but is safe due to Rope being held. As long as data doesn't
|
||||
// escape (which it shouldn't) it is safe. Doing this properly would
|
||||
// require HKT.
|
||||
pieces: PieceIter<'static>,
|
||||
leaf_buf: Option<Box<Buf+'static>>,
|
||||
}
|
||||
|
||||
impl RopeBuf {
|
||||
fn new(rope: Rope) -> RopeBuf {
|
||||
// In order to get the lifetimes to work out, transmute to a 'static
|
||||
// lifetime. Never allow the iter to escape the internals of RopeBuf.
|
||||
let mut pieces: PieceIter<'static> =
|
||||
unsafe { mem::transmute(rope.pieces()) };
|
||||
|
||||
// Get the next buf
|
||||
let leaf_buf = pieces.next()
|
||||
.map(|bytes| bytes.buf());
|
||||
|
||||
let len = rope.len();
|
||||
|
||||
RopeBuf {
|
||||
rope: rope,
|
||||
rem: len,
|
||||
pieces: pieces,
|
||||
leaf_buf: leaf_buf,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Buf for RopeBuf {
|
||||
fn remaining(&self) -> usize {
|
||||
self.rem
|
||||
}
|
||||
|
||||
fn bytes(&self) -> &[u8] {
|
||||
self.leaf_buf.as_ref()
|
||||
.map(|b| b.bytes())
|
||||
.unwrap_or(&[])
|
||||
}
|
||||
|
||||
fn advance(&mut self, mut cnt: usize) {
|
||||
cnt = cmp::min(cnt, self.rem);
|
||||
|
||||
// Advance the internal cursor
|
||||
self.rem -= cnt;
|
||||
|
||||
// Advance the leaf buffer
|
||||
while cnt > 0 {
|
||||
{
|
||||
let curr = self.leaf_buf.as_mut()
|
||||
.expect("expected a value");
|
||||
|
||||
if curr.remaining() > cnt {
|
||||
curr.advance(cnt);
|
||||
break;
|
||||
}
|
||||
|
||||
cnt -= curr.remaining();
|
||||
}
|
||||
|
||||
self.leaf_buf = self.pieces.next()
|
||||
.map(|bytes| bytes.buf());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
* ===== PieceIter =====
|
||||
*
|
||||
*/
|
||||
|
||||
// TODO: store stack inline if possible
|
||||
struct PieceIter<'a> {
|
||||
stack: Vec<&'a RopeInner>,
|
||||
next: Option<&'a Bytes>,
|
||||
}
|
||||
|
||||
impl<'a> PieceIter<'a> {
|
||||
fn new(root: &'a RopeInner) -> PieceIter<'a> {
|
||||
let mut iter = PieceIter {
|
||||
stack: vec![],
|
||||
next: None,
|
||||
};
|
||||
|
||||
iter.next = iter.get_leaf_by_left(root);
|
||||
iter
|
||||
}
|
||||
|
||||
fn get_leaf_by_left(&mut self, mut root: &'a RopeInner) -> Option<&'a Bytes> {
|
||||
loop {
|
||||
self.stack.push(root);
|
||||
let left = &root.left;
|
||||
|
||||
if left.is_empty() {
|
||||
return None;
|
||||
}
|
||||
|
||||
if let Some(rope) = left.downcast_ref::<Rope>() {
|
||||
root = &*rope.inner;
|
||||
continue;
|
||||
}
|
||||
|
||||
return Some(left);
|
||||
}
|
||||
}
|
||||
|
||||
fn next_non_empty_leaf(&mut self) -> Option<&'a Bytes>{
|
||||
loop {
|
||||
if let Some(node) = self.stack.pop() {
|
||||
if let Some(rope) = node.right.downcast_ref::<Rope>() {
|
||||
let res = self.get_leaf_by_left(&rope.inner);
|
||||
|
||||
if res.is_none() {
|
||||
continue;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
if node.right.is_empty() {
|
||||
continue;
|
||||
}
|
||||
|
||||
return Some(&node.right);
|
||||
}
|
||||
|
||||
return None;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Iterator for PieceIter<'a> {
|
||||
type Item = &'a Bytes;
|
||||
|
||||
fn next(&mut self) -> Option<&'a Bytes> {
|
||||
let ret = self.next.take();
|
||||
|
||||
if ret.is_some() {
|
||||
self.next = self.next_non_empty_leaf();
|
||||
}
|
||||
|
||||
ret
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
* ===== Balance =====
|
||||
*
|
||||
*/
|
||||
|
||||
struct Balance {
|
||||
stack: Vec<Bytes>,
|
||||
}
|
||||
|
||||
impl Balance {
|
||||
fn new() -> Balance {
|
||||
Balance { stack: vec![] }
|
||||
}
|
||||
|
||||
fn balance(&mut self, left: Bytes, right: Bytes) -> Rope {
|
||||
self.do_balance(left);
|
||||
self.do_balance(right);
|
||||
|
||||
let mut partial = self.stack.pop()
|
||||
.expect("expected a value");
|
||||
|
||||
while !partial.is_empty() {
|
||||
let new_left = self.stack.pop()
|
||||
.expect("expected a value");
|
||||
|
||||
partial = Bytes::of(Rope::new(new_left, partial));
|
||||
}
|
||||
|
||||
Rope::of(partial)
|
||||
}
|
||||
|
||||
fn do_balance(&mut self, root: Bytes) {
|
||||
// BAP95: Insert balanced subtrees whole. This means the result might not
|
||||
// be balanced, leading to repeated rebalancings on concatenate. However,
|
||||
// these rebalancings are shallow due to ignoring balanced subtrees, and
|
||||
// relatively few calls to insert() result.
|
||||
if is_balanced(&root) {
|
||||
self.insert(root);
|
||||
} else {
|
||||
let rope = root.try_unwrap::<Rope>()
|
||||
.ok().expect("expected a value");
|
||||
|
||||
self.do_balance(rope.left().clone());
|
||||
self.do_balance(rope.right().clone());
|
||||
}
|
||||
}
|
||||
|
||||
// Push a string on the balance stack (BAP95). BAP95 uses an array and
|
||||
// calls the elements in the array 'bins'. We instead use a stack, so the
|
||||
// 'bins' of lengths are represented by differences between the elements of
|
||||
// minLengthByDepth.
|
||||
//
|
||||
// If the length bin for our string, and all shorter length bins, are
|
||||
// empty, we just push it on the stack. Otherwise, we need to start
|
||||
// concatenating, putting the given string in the "middle" and continuing
|
||||
// until we land in an empty length bin that matches the length of our
|
||||
// concatenation.
|
||||
fn insert(&mut self, bytes: Bytes) {
|
||||
let depth_bin = depth_for_len(bytes.len());
|
||||
let bin_end = MIN_LENGTH_BY_DEPTH[depth_bin as usize + 1];
|
||||
|
||||
// BAP95: Concatenate all trees occupying bins representing the length
|
||||
// of our new piece or of shorter pieces, to the extent that is
|
||||
// possible. The goal is to clear the bin which our piece belongs in,
|
||||
// but that may not be entirely possible if there aren't enough longer
|
||||
// bins occupied.
|
||||
if let Some(len) = self.peek().map(|r| r.len()) {
|
||||
if len >= bin_end {
|
||||
self.stack.push(bytes);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
let bin_start = MIN_LENGTH_BY_DEPTH[depth_bin as usize];
|
||||
|
||||
// Concatenate the subtrees of shorter length
|
||||
let mut new_tree = self.stack.pop()
|
||||
.expect("expected a value");
|
||||
|
||||
while let Some(len) = self.peek().map(|r| r.len()) {
|
||||
// If the head is big enough, break the loop
|
||||
if len >= bin_start { break; }
|
||||
|
||||
let left = self.stack.pop()
|
||||
.expect("expected a value");
|
||||
|
||||
new_tree = Bytes::of(Rope::new(left, new_tree));
|
||||
}
|
||||
|
||||
// Concatenate the given string
|
||||
new_tree = Bytes::of(Rope::new(new_tree, bytes));
|
||||
|
||||
// Continue concatenating until we land in an empty bin
|
||||
while let Some(len) = self.peek().map(|r| r.len()) {
|
||||
let depth_bin = depth_for_len(new_tree.len());
|
||||
let bin_end = MIN_LENGTH_BY_DEPTH[depth_bin as usize + 1];
|
||||
|
||||
if len < bin_end {
|
||||
let left = self.stack.pop()
|
||||
.expect("expected a value");
|
||||
|
||||
new_tree = Bytes::of(Rope::new(left, new_tree));
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
self.stack.push(new_tree);
|
||||
}
|
||||
|
||||
fn peek(&self) -> Option<&Bytes> {
|
||||
self.stack.as_slice().last()
|
||||
}
|
||||
}
|
||||
|
||||
struct RopeInner {
|
||||
left: Bytes,
|
||||
right: Bytes,
|
||||
depth: u16,
|
||||
len: u32,
|
||||
}
|
||||
|
||||
impl RopeInner {
|
||||
fn new(left: Bytes, right: Bytes) -> RopeInner {
|
||||
// If left is 0 then right must be zero
|
||||
debug_assert!(!left.is_empty() || right.is_empty());
|
||||
|
||||
let len = left.len() + right.len();
|
||||
let depth = cmp::max(depth(&left), depth(&right)) + 1;
|
||||
|
||||
RopeInner {
|
||||
left: left,
|
||||
right: right,
|
||||
depth: depth,
|
||||
len: len as u32,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
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, $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,
|
||||
{
|
||||
serializer.serialize_bytes(&self)
|
||||
}
|
||||
}
|
||||
|
||||
struct $visitor_ty;
|
||||
|
||||
impl<'de> de::Visitor<'de> for $visitor_ty {
|
||||
type Value = $ty;
|
||||
|
||||
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>,
|
||||
{
|
||||
let len = cmp::min(seq.size_hint().unwrap_or(0), 4096);
|
||||
let mut values: Vec<u8> = Vec::with_capacity(len);
|
||||
|
||||
while let Some(value) = seq.next_element()? {
|
||||
values.push(value);
|
||||
}
|
||||
|
||||
Ok($ty::$from_vec(values))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E>
|
||||
where
|
||||
E: de::Error,
|
||||
{
|
||||
Ok($ty::$from_slice(v))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_byte_buf<E>(self, v: Vec<u8>) -> Result<Self::Value, E>
|
||||
where
|
||||
E: de::Error,
|
||||
{
|
||||
Ok($ty::$from_vec(v))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
|
||||
where
|
||||
E: de::Error,
|
||||
{
|
||||
Ok($ty::$from_slice(v.as_bytes()))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_string<E>(self, v: String) -> Result<Self::Value, E>
|
||||
where
|
||||
E: de::Error,
|
||||
{
|
||||
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>,
|
||||
{
|
||||
deserializer.deserialize_byte_buf($visitor_ty)
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
serde_impl!(Bytes, BytesVisitor, copy_from_slice, from);
|
||||
serde_impl!(BytesMut, BytesMutVisitor, from, from_vec);
|
||||
@@ -1,57 +0,0 @@
|
||||
use std::cmp;
|
||||
use {Buf, MutBuf};
|
||||
|
||||
pub struct SliceBuf<'a> {
|
||||
bytes: &'a [u8],
|
||||
pos: usize
|
||||
}
|
||||
|
||||
impl<'a> SliceBuf<'a> {
|
||||
pub fn wrap(bytes: &'a [u8]) -> SliceBuf<'a> {
|
||||
SliceBuf { bytes: bytes, pos: 0 }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Buf for SliceBuf<'a> {
|
||||
fn remaining(&self) -> usize {
|
||||
self.bytes.len() - self.pos
|
||||
}
|
||||
|
||||
fn bytes<'b>(&'b self) -> &'b [u8] {
|
||||
&self.bytes[self.pos..]
|
||||
}
|
||||
|
||||
fn advance(&mut self, mut cnt: usize) {
|
||||
cnt = cmp::min(cnt, self.remaining());
|
||||
self.pos += cnt;
|
||||
}
|
||||
}
|
||||
|
||||
pub struct MutSliceBuf<'a> {
|
||||
bytes: &'a mut [u8],
|
||||
pos: usize
|
||||
}
|
||||
|
||||
impl<'a> MutSliceBuf<'a> {
|
||||
pub fn wrap(bytes: &'a mut [u8]) -> MutSliceBuf<'a> {
|
||||
MutSliceBuf {
|
||||
bytes: bytes,
|
||||
pos: 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> MutBuf for MutSliceBuf<'a> {
|
||||
fn remaining(&self) -> usize {
|
||||
self.bytes.len() - self.pos
|
||||
}
|
||||
|
||||
fn advance(&mut self, mut cnt: usize) {
|
||||
cnt = cmp::min(cnt, self.remaining());
|
||||
self.pos += cnt;
|
||||
}
|
||||
|
||||
fn mut_bytes<'b>(&'b mut self) -> &'b mut [u8] {
|
||||
&mut self.bytes[self.pos..]
|
||||
}
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
#![feature(core)]
|
||||
|
||||
use rand::random;
|
||||
|
||||
extern crate bytes;
|
||||
extern crate rand;
|
||||
|
||||
mod test_byte_buf;
|
||||
mod test_rope;
|
||||
mod test_seq_byte_str;
|
||||
mod test_small_byte_str;
|
||||
|
||||
fn gen_bytes(n: usize) -> Vec<u8> {
|
||||
(0..n).map(|_| random()).collect()
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
use bytes::ByteBuf;
|
||||
use bytes::traits::*;
|
||||
|
||||
#[test]
|
||||
pub fn test_initial_buf_empty() {
|
||||
let buf = ByteBuf::mut_with_capacity(100);
|
||||
|
||||
assert!(buf.capacity() == 128);
|
||||
assert!(buf.remaining() == 128);
|
||||
|
||||
let buf = buf.flip();
|
||||
|
||||
assert!(buf.remaining() == 0);
|
||||
|
||||
let buf = buf.flip();
|
||||
|
||||
assert!(buf.remaining() == 128);
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_byte_buf_read_write() {
|
||||
let mut buf = ByteBuf::mut_with_capacity(32);
|
||||
|
||||
buf.write(b"hello world").unwrap();
|
||||
assert_eq!(21, buf.remaining());
|
||||
|
||||
buf.write(b" goodbye").unwrap();
|
||||
assert_eq!(13, buf.remaining());
|
||||
|
||||
let mut buf = buf.flip();
|
||||
let mut dst = [0; 5];
|
||||
|
||||
assert_eq!(5, buf.read(dst.as_mut_slice()).unwrap());
|
||||
assert_eq!(b"hello", dst);
|
||||
|
||||
assert_eq!(5, buf.read(dst.as_mut_slice()).unwrap());
|
||||
assert_eq!(b" worl", dst);
|
||||
|
||||
let mut dst = [0; 2];
|
||||
assert_eq!(2, buf.read(dst.as_mut_slice()).unwrap());
|
||||
assert_eq!(b"d ", dst);
|
||||
|
||||
let mut dst = [0; 7];
|
||||
assert_eq!(7, buf.read(dst.as_mut_slice()).unwrap());
|
||||
assert_eq!(b"goodbye", dst);
|
||||
}
|
||||
@@ -1,90 +0,0 @@
|
||||
use bytes::Rope;
|
||||
use bytes::traits::*;
|
||||
use super::gen_bytes;
|
||||
|
||||
const TEST_BYTES_1: &'static [u8] =
|
||||
&b"dblm4ng7jp4v9rdn1w6hhssmluoqrrrqj59rccl9
|
||||
nkv2tm1t2da4jyku51ge7f8hv581gkki8lekmf5f
|
||||
1l44whp4aiwbvhkziw02292on4noyvuwjzsloqyc
|
||||
5n0iyn4l6o6tgjhlek00mynfzb1wgcwj4mqp6zdr
|
||||
3625yy7rj7xuisal7b1a7xgq271abvt5ssxuj39v
|
||||
njtetokxxrgxzp7ik9adnypkmmcn4270yv9l46m7
|
||||
9mu2zmqmkxdmgia210vkdytb7ywfcyt2bvcsg9eq
|
||||
5yqizxl6888zrksvaxhzs2v355jxu8gr21m33t83
|
||||
qvoian1ra7c6pvxabshgngldxa408p18l1fdet2h";
|
||||
|
||||
const TEST_BYTES_2: &'static [u8] =
|
||||
&b"jmh14t79mllzj1ohxfj6fun7idwbks8oh35f83g6
|
||||
ryaowe86mmou5t1xa91uyg8e95wcu5mje1mswien
|
||||
tt4clgj029cw0pyuvfbvsgzdg1x7sr9qsjkf2b1t
|
||||
h43smgp1ea22lph17f78cel0cc2kjoht5281xuy8
|
||||
0ex9uaqwj4330jrp30stsk15j9bpqezu3w78ktit
|
||||
ev5g6xsngr35q7pemdm9hihf0ebrw5fbwhm530lo
|
||||
e0zyj1bm7yfyk7f2i45jhr3wu3bvb4hj8jve6db0
|
||||
iewmr9weecaon9vdnqo5hen9iaiox5vsaxuo461m
|
||||
8336ugp20u4sfky3kfawr0ome1tiqyx8chkerrjh
|
||||
a95s0gypcsgo9jqxasqkoj08t4uq5moxmay5plg5
|
||||
tlh6f9omhn0ezvi0w2n8hx7n6qk7rn1s3mjpnpl6
|
||||
hvilp8awaa4tvsis66q4e5b3xwy2z1h2klpa87h7";
|
||||
|
||||
#[test]
|
||||
pub fn test_rope_round_trip() {
|
||||
let rope = Rope::from_slice(b"zomg");
|
||||
|
||||
assert_eq!(4, rope.len());
|
||||
|
||||
let mut dst = vec![];
|
||||
rope.buf().read(&mut dst).unwrap();
|
||||
|
||||
assert_eq!(b"zomg", dst.as_slice());
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_rope_slice() {
|
||||
let mut dst = vec![];
|
||||
|
||||
let bytes = Rope::from_slice(TEST_BYTES_1);
|
||||
assert_eq!(TEST_BYTES_1.len(), bytes.len());
|
||||
|
||||
bytes.buf().read(&mut dst).unwrap();
|
||||
assert_eq!(dst.as_slice(), TEST_BYTES_1);
|
||||
|
||||
let left = bytes.slice_to(250);
|
||||
assert_eq!(250, left.len());
|
||||
|
||||
left.buf().read(&mut dst).unwrap();
|
||||
assert_eq!(dst.as_slice(), &TEST_BYTES_1[..250]);
|
||||
|
||||
let right = bytes.slice_from(250);
|
||||
assert_eq!(TEST_BYTES_1.len() - 250, right.len());
|
||||
|
||||
right.buf().read(&mut dst).unwrap();
|
||||
assert_eq!(dst.as_slice(), &TEST_BYTES_1[250..]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_rope_concat_two_byte_str() {
|
||||
let mut dst = vec![];
|
||||
|
||||
let left = Rope::from_slice(TEST_BYTES_1);
|
||||
let right = Rope::from_slice(TEST_BYTES_2);
|
||||
|
||||
let both = left.concat(right);
|
||||
|
||||
assert_eq!(both.len(), TEST_BYTES_1.len() + TEST_BYTES_2.len());
|
||||
|
||||
both.buf().read(&mut dst).unwrap();
|
||||
assert_eq!(dst.as_slice(), TEST_BYTES_1.to_vec() + TEST_BYTES_2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore]
|
||||
pub fn test_slice_parity() {
|
||||
let bytes = gen_bytes(2048 * 1024);
|
||||
let start = 512 * 1024 - 3333;
|
||||
let end = 512 * 1024 + 7777;
|
||||
|
||||
let _ = Rope::from_slice(bytes.as_slice()).slice(start, end);
|
||||
|
||||
// stuff
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
use bytes::SeqByteStr;
|
||||
use bytes::traits::*;
|
||||
use super::gen_bytes;
|
||||
|
||||
#[test]
|
||||
pub fn test_slice_round_trip() {
|
||||
let mut dst = vec![];
|
||||
let src = gen_bytes(2000);
|
||||
|
||||
let s = SeqByteStr::from_slice(src.as_slice());
|
||||
assert_eq!(2000, s.len());
|
||||
|
||||
s.buf().read(&mut dst).unwrap();
|
||||
assert_eq!(dst, src);
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_index() {
|
||||
let src = gen_bytes(2000);
|
||||
|
||||
let s = SeqByteStr::from_slice(src.as_slice());
|
||||
|
||||
for i in 0..2000 {
|
||||
assert_eq!(src[i], s[i]);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_fail]
|
||||
pub fn test_index_out_of_range() {
|
||||
let s = SeqByteStr::from_slice(gen_bytes(2000).as_slice());
|
||||
let _ = s[2001];
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
use bytes::SmallByteStr;
|
||||
use bytes::traits::*;
|
||||
use super::gen_bytes;
|
||||
|
||||
#[test]
|
||||
pub fn test_slice_round_trip() {
|
||||
let mut dst = vec![];
|
||||
let src = gen_bytes(3);
|
||||
|
||||
let s = SmallByteStr::from_slice(src.as_slice()).unwrap();
|
||||
assert_eq!(3, s.len());
|
||||
|
||||
s.buf().read(&mut dst).unwrap();
|
||||
assert_eq!(dst, src);
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_index() {
|
||||
let src = gen_bytes(3);
|
||||
|
||||
let s = SmallByteStr::from_slice(src.as_slice()).unwrap();
|
||||
|
||||
for i in 0..3 {
|
||||
assert_eq!(src[i], s[i]);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_fail]
|
||||
pub fn test_index_out_of_range() {
|
||||
let s = SmallByteStr::from_slice(gen_bytes(3).as_slice()).unwrap();
|
||||
let _ = s[2001];
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
#![warn(rust_2018_idioms)]
|
||||
|
||||
use bytes::Buf;
|
||||
#[cfg(feature = "std")]
|
||||
use std::io::IoSlice;
|
||||
|
||||
#[test]
|
||||
fn test_fresh_cursor_vec() {
|
||||
let mut buf = &b"hello"[..];
|
||||
|
||||
assert_eq!(buf.remaining(), 5);
|
||||
assert_eq!(buf.chunk(), b"hello");
|
||||
|
||||
buf.advance(2);
|
||||
|
||||
assert_eq!(buf.remaining(), 3);
|
||||
assert_eq!(buf.chunk(), b"llo");
|
||||
|
||||
buf.advance(3);
|
||||
|
||||
assert_eq!(buf.remaining(), 0);
|
||||
assert_eq!(buf.chunk(), b"");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_u8() {
|
||||
let mut buf = &b"\x21zomg"[..];
|
||||
assert_eq!(0x21, buf.get_u8());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_u16() {
|
||||
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]
|
||||
fn test_get_int() {
|
||||
let mut buf = &b"\xd6zomg"[..];
|
||||
assert_eq!(-42, buf.get_int(1));
|
||||
let mut buf = &b"\xd6zomg"[..];
|
||||
assert_eq!(-42, buf.get_int_le(1));
|
||||
|
||||
let mut buf = &b"\xfe\x1d\xc0zomg"[..];
|
||||
assert_eq!(0xffffffffffc01dfeu64 as i64, buf.get_int_le(3));
|
||||
let mut buf = &b"\xfe\x1d\xc0zomg"[..];
|
||||
assert_eq!(0xfffffffffffe1dc0u64 as i64, buf.get_int(3));
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn test_get_u16_buffer_underflow() {
|
||||
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_vec_deque() {
|
||||
use std::collections::VecDeque;
|
||||
|
||||
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[..]);
|
||||
}
|
||||
|
||||
#[allow(unused_allocation)] // This is intentional.
|
||||
#[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);
|
||||
}
|
||||
@@ -0,0 +1,276 @@
|
||||
#![warn(rust_2018_idioms)]
|
||||
|
||||
use bytes::buf::UninitSlice;
|
||||
use bytes::{BufMut, BytesMut};
|
||||
use core::fmt::Write;
|
||||
use core::mem::MaybeUninit;
|
||||
use core::usize;
|
||||
|
||||
#[test]
|
||||
fn test_vec_as_mut_buf() {
|
||||
let mut buf = Vec::with_capacity(64);
|
||||
|
||||
assert_eq!(buf.remaining_mut(), isize::MAX as usize);
|
||||
|
||||
assert!(buf.chunk_mut().len() >= 64);
|
||||
|
||||
buf.put(&b"zomg"[..]);
|
||||
|
||||
assert_eq!(&buf, b"zomg");
|
||||
|
||||
assert_eq!(buf.remaining_mut(), isize::MAX as usize - 4);
|
||||
assert_eq!(buf.capacity(), 64);
|
||||
|
||||
for _ in 0..16 {
|
||||
buf.put(&b"zomg"[..]);
|
||||
}
|
||||
|
||||
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);
|
||||
assert_eq!(b"\x21", &buf[..]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_put_u16() {
|
||||
let mut buf = Vec::with_capacity(8);
|
||||
buf.put_u16(8532);
|
||||
assert_eq!(b"\x21\x54", &buf[..]);
|
||||
|
||||
buf.clear();
|
||||
buf.put_u16_le(8532);
|
||||
assert_eq!(b"\x54\x21", &buf[..]);
|
||||
}
|
||||
|
||||
#[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 = "advance out of bounds: the len is 8 but advancing by 12")]
|
||||
fn test_vec_advance_mut() {
|
||||
// Verify fix for #354
|
||||
let mut buf = Vec::with_capacity(8);
|
||||
unsafe {
|
||||
buf.advance_mut(12);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_clone() {
|
||||
let mut buf = BytesMut::with_capacity(100);
|
||||
buf.write_str("this is a test").unwrap();
|
||||
let buf2 = buf.clone();
|
||||
|
||||
buf.write_str(" of our emergency broadcast system").unwrap();
|
||||
assert!(buf != buf2);
|
||||
}
|
||||
|
||||
fn do_test_slice_small<T: ?Sized>(make: impl Fn(&mut [u8]) -> &mut T)
|
||||
where
|
||||
for<'r> &'r mut T: BufMut,
|
||||
{
|
||||
let mut buf = [b'X'; 8];
|
||||
|
||||
let mut slice = make(&mut buf[..]);
|
||||
slice.put_bytes(b'A', 2);
|
||||
slice.put_u8(b'B');
|
||||
slice.put_slice(b"BCC");
|
||||
assert_eq!(2, slice.remaining_mut());
|
||||
assert_eq!(b"AABBCCXX", &buf[..]);
|
||||
|
||||
let mut slice = make(&mut buf[..]);
|
||||
slice.put_u32(0x61626364);
|
||||
assert_eq!(4, slice.remaining_mut());
|
||||
assert_eq!(b"abcdCCXX", &buf[..]);
|
||||
|
||||
let mut slice = make(&mut buf[..]);
|
||||
slice.put_u32_le(0x30313233);
|
||||
assert_eq!(4, slice.remaining_mut());
|
||||
assert_eq!(b"3210CCXX", &buf[..]);
|
||||
}
|
||||
|
||||
fn do_test_slice_large<T: ?Sized>(make: impl Fn(&mut [u8]) -> &mut T)
|
||||
where
|
||||
for<'r> &'r mut T: BufMut,
|
||||
{
|
||||
const LEN: usize = 100;
|
||||
const FILL: [u8; LEN] = [b'Y'; LEN];
|
||||
|
||||
let test = |fill: &dyn Fn(&mut &mut T, usize)| {
|
||||
for buf_len in 0..LEN {
|
||||
let mut buf = [b'X'; LEN];
|
||||
for fill_len in 0..=buf_len {
|
||||
let mut slice = make(&mut buf[..buf_len]);
|
||||
fill(&mut slice, fill_len);
|
||||
assert_eq!(buf_len - fill_len, slice.remaining_mut());
|
||||
let (head, tail) = buf.split_at(fill_len);
|
||||
assert_eq!(&FILL[..fill_len], head);
|
||||
assert!(tail.iter().all(|b| *b == b'X'));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
test(&|slice, fill_len| slice.put_slice(&FILL[..fill_len]));
|
||||
test(&|slice, fill_len| slice.put_bytes(FILL[0], fill_len));
|
||||
}
|
||||
|
||||
fn do_test_slice_put_slice_panics<T: ?Sized>(make: impl Fn(&mut [u8]) -> &mut T)
|
||||
where
|
||||
for<'r> &'r mut T: BufMut,
|
||||
{
|
||||
let mut buf = [b'X'; 4];
|
||||
let mut slice = make(&mut buf[..]);
|
||||
slice.put_slice(b"12345");
|
||||
}
|
||||
|
||||
fn do_test_slice_put_bytes_panics<T: ?Sized>(make: impl Fn(&mut [u8]) -> &mut T)
|
||||
where
|
||||
for<'r> &'r mut T: BufMut,
|
||||
{
|
||||
let mut buf = [b'X'; 4];
|
||||
let mut slice = make(&mut buf[..]);
|
||||
slice.put_bytes(b'1', 5);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_slice_buf_mut_small() {
|
||||
do_test_slice_small(|x| x);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_slice_buf_mut_large() {
|
||||
do_test_slice_large(|x| x);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn test_slice_buf_mut_put_slice_overflow() {
|
||||
do_test_slice_put_slice_panics(|x| x);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn test_slice_buf_mut_put_bytes_overflow() {
|
||||
do_test_slice_put_bytes_panics(|x| x);
|
||||
}
|
||||
|
||||
fn make_maybe_uninit_slice(slice: &mut [u8]) -> &mut [MaybeUninit<u8>] {
|
||||
// SAFETY: [u8] has the same layout as [MaybeUninit<u8>].
|
||||
unsafe { core::mem::transmute(slice) }
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_maybe_uninit_buf_mut_small() {
|
||||
do_test_slice_small(make_maybe_uninit_slice);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_maybe_uninit_buf_mut_large() {
|
||||
do_test_slice_large(make_maybe_uninit_slice);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn test_maybe_uninit_buf_mut_put_slice_overflow() {
|
||||
do_test_slice_put_slice_panics(make_maybe_uninit_slice);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn test_maybe_uninit_buf_mut_put_bytes_overflow() {
|
||||
do_test_slice_put_bytes_panics(make_maybe_uninit_slice);
|
||||
}
|
||||
|
||||
#[allow(unused_allocation)] // This is intentional.
|
||||
#[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");
|
||||
}
|
||||
+1481
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,147 @@
|
||||
//! 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, BytesMut};
|
||||
|
||||
#[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]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_bytesmut_from_bytes_vec() {
|
||||
let vec = vec![33u8; 1024];
|
||||
|
||||
// Test case where kind == KIND_VEC
|
||||
let b1 = Bytes::from(vec.clone());
|
||||
let b1m = BytesMut::from(b1);
|
||||
assert_eq!(b1m, vec);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_bytesmut_from_bytes_arc_1() {
|
||||
let vec = vec![33u8; 1024];
|
||||
|
||||
// Test case where kind == KIND_ARC, ref_cnt == 1
|
||||
let b1 = Bytes::from(vec.clone());
|
||||
drop(b1.clone());
|
||||
let b1m = BytesMut::from(b1);
|
||||
assert_eq!(b1m, vec);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_bytesmut_from_bytes_arc_2() {
|
||||
let vec = vec![33u8; 1024];
|
||||
|
||||
// Test case where kind == KIND_ARC, ref_cnt == 2
|
||||
let b1 = Bytes::from(vec.clone());
|
||||
let b2 = b1.clone();
|
||||
let b1m = BytesMut::from(b1);
|
||||
assert_eq!(b1m, vec);
|
||||
|
||||
// Test case where vtable = SHARED_VTABLE, kind == KIND_ARC, ref_cnt == 1
|
||||
let b2m = BytesMut::from(b2);
|
||||
assert_eq!(b2m, vec);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_bytesmut_from_bytes_arc_offset() {
|
||||
let vec = vec![33u8; 1024];
|
||||
|
||||
// Test case where offset != 0
|
||||
let mut b1 = Bytes::from(vec.clone());
|
||||
let b2 = b1.split_off(20);
|
||||
let b1m = BytesMut::from(b1);
|
||||
let b2m = BytesMut::from(b2);
|
||||
|
||||
assert_eq!(b2m, vec[20..]);
|
||||
assert_eq!(b1m, 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]);
|
||||
}
|
||||
@@ -0,0 +1,177 @@
|
||||
#![warn(rust_2018_idioms)]
|
||||
|
||||
use bytes::{Buf, BufMut, Bytes};
|
||||
#[cfg(feature = "std")]
|
||||
use std::io::IoSlice;
|
||||
|
||||
#[test]
|
||||
fn collect_two_bufs() {
|
||||
let a = Bytes::from(&b"hello"[..]);
|
||||
let b = Bytes::from(&b"world"[..]);
|
||||
|
||||
let res = a.chain(b).copy_to_bytes(10);
|
||||
assert_eq!(res, &b"helloworld"[..]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn writing_chained() {
|
||||
let mut a = [0u8; 64];
|
||||
let mut b = [0u8; 64];
|
||||
|
||||
{
|
||||
let mut buf = (&mut a[..]).chain_mut(&mut b[..]);
|
||||
|
||||
for i in 0u8..128 {
|
||||
buf.put_u8(i);
|
||||
}
|
||||
}
|
||||
|
||||
for i in 0..64 {
|
||||
let expect = i as u8;
|
||||
assert_eq!(expect, a[i]);
|
||||
assert_eq!(expect + 64, b[i]);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn iterating_two_bufs() {
|
||||
let a = Bytes::from(&b"hello"[..]);
|
||||
let b = Bytes::from(&b"world"[..]);
|
||||
|
||||
let res: Vec<u8> = a.chain(b).into_iter().collect();
|
||||
assert_eq!(res, &b"helloworld"[..]);
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
#[test]
|
||||
fn vectored_read() {
|
||||
let a = Bytes::from(&b"hello"[..]);
|
||||
let b = Bytes::from(&b"world"[..]);
|
||||
|
||||
let mut buf = a.chain(b);
|
||||
|
||||
{
|
||||
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.chunks_vectored(&mut iovecs));
|
||||
assert_eq!(iovecs[0][..], b"hello"[..]);
|
||||
assert_eq!(iovecs[1][..], b"world"[..]);
|
||||
assert_eq!(iovecs[2][..], b""[..]);
|
||||
assert_eq!(iovecs[3][..], b""[..]);
|
||||
}
|
||||
|
||||
buf.advance(2);
|
||||
|
||||
{
|
||||
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.chunks_vectored(&mut iovecs));
|
||||
assert_eq!(iovecs[0][..], b"llo"[..]);
|
||||
assert_eq!(iovecs[1][..], b"world"[..]);
|
||||
assert_eq!(iovecs[2][..], b""[..]);
|
||||
assert_eq!(iovecs[3][..], b""[..]);
|
||||
}
|
||||
|
||||
buf.advance(3);
|
||||
|
||||
{
|
||||
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.chunks_vectored(&mut iovecs));
|
||||
assert_eq!(iovecs[0][..], b"world"[..]);
|
||||
assert_eq!(iovecs[1][..], b""[..]);
|
||||
assert_eq!(iovecs[2][..], b""[..]);
|
||||
assert_eq!(iovecs[3][..], b""[..]);
|
||||
}
|
||||
|
||||
buf.advance(3);
|
||||
|
||||
{
|
||||
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.chunks_vectored(&mut iovecs));
|
||||
assert_eq!(iovecs[0][..], b"ld"[..]);
|
||||
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());
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
#![warn(rust_2018_idioms)]
|
||||
|
||||
use bytes::Bytes;
|
||||
|
||||
#[test]
|
||||
fn fmt() {
|
||||
let vec: Vec<_> = (0..0x100).map(|b| b as u8).collect();
|
||||
|
||||
let expected = "b\"\
|
||||
\\0\\x01\\x02\\x03\\x04\\x05\\x06\\x07\
|
||||
\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\
|
||||
\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\
|
||||
\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f\
|
||||
\x20!\\\"#$%&'()*+,-./0123456789:;<=>?\
|
||||
@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\\\]^_\
|
||||
`abcdefghijklmnopqrstuvwxyz{|}~\\x7f\
|
||||
\\x80\\x81\\x82\\x83\\x84\\x85\\x86\\x87\
|
||||
\\x88\\x89\\x8a\\x8b\\x8c\\x8d\\x8e\\x8f\
|
||||
\\x90\\x91\\x92\\x93\\x94\\x95\\x96\\x97\
|
||||
\\x98\\x99\\x9a\\x9b\\x9c\\x9d\\x9e\\x9f\
|
||||
\\xa0\\xa1\\xa2\\xa3\\xa4\\xa5\\xa6\\xa7\
|
||||
\\xa8\\xa9\\xaa\\xab\\xac\\xad\\xae\\xaf\
|
||||
\\xb0\\xb1\\xb2\\xb3\\xb4\\xb5\\xb6\\xb7\
|
||||
\\xb8\\xb9\\xba\\xbb\\xbc\\xbd\\xbe\\xbf\
|
||||
\\xc0\\xc1\\xc2\\xc3\\xc4\\xc5\\xc6\\xc7\
|
||||
\\xc8\\xc9\\xca\\xcb\\xcc\\xcd\\xce\\xcf\
|
||||
\\xd0\\xd1\\xd2\\xd3\\xd4\\xd5\\xd6\\xd7\
|
||||
\\xd8\\xd9\\xda\\xdb\\xdc\\xdd\\xde\\xdf\
|
||||
\\xe0\\xe1\\xe2\\xe3\\xe4\\xe5\\xe6\\xe7\
|
||||
\\xe8\\xe9\\xea\\xeb\\xec\\xed\\xee\\xef\
|
||||
\\xf0\\xf1\\xf2\\xf3\\xf4\\xf5\\xf6\\xf7\
|
||||
\\xf8\\xf9\\xfa\\xfb\\xfc\\xfd\\xfe\\xff\"";
|
||||
|
||||
assert_eq!(expected, format!("{:?}", Bytes::from(vec)));
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
#![warn(rust_2018_idioms)]
|
||||
|
||||
use bytes::{buf::IntoIter, Bytes};
|
||||
|
||||
#[test]
|
||||
fn iter_len() {
|
||||
let buf = Bytes::from_static(b"hello world");
|
||||
let iter = IntoIter::new(buf);
|
||||
|
||||
assert_eq!(iter.size_hint(), (11, Some(11)));
|
||||
assert_eq!(iter.len(), 11);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn empty_iter_len() {
|
||||
let buf = Bytes::new();
|
||||
let iter = IntoIter::new(buf);
|
||||
|
||||
assert_eq!(iter.size_hint(), (0, Some(0)));
|
||||
assert_eq!(iter.len(), 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);
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
#![cfg(feature = "serde")]
|
||||
#![warn(rust_2018_idioms)]
|
||||
|
||||
use serde_test::{assert_tokens, Token};
|
||||
|
||||
#[test]
|
||||
fn test_ser_de_empty() {
|
||||
let b = bytes::Bytes::new();
|
||||
assert_tokens(&b, &[Token::Bytes(b"")]);
|
||||
let b = bytes::BytesMut::with_capacity(0);
|
||||
assert_tokens(&b, &[Token::Bytes(b"")]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ser_de() {
|
||||
let b = bytes::Bytes::from(&b"bytes"[..]);
|
||||
assert_tokens(&b, &[Token::Bytes(b"bytes")]);
|
||||
let b = bytes::BytesMut::from(&b"bytes"[..]);
|
||||
assert_tokens(&b, &[Token::Bytes(b"bytes")]);
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
#![warn(rust_2018_idioms)]
|
||||
|
||||
use bytes::buf::Buf;
|
||||
use bytes::Bytes;
|
||||
|
||||
#[test]
|
||||
fn long_take() {
|
||||
// Tests that get a take with a size greater than the buffer length will not
|
||||
// overrun the buffer. Regression test for #138.
|
||||
let buf = b"hello world".take(100);
|
||||
assert_eq!(11, buf.remaining());
|
||||
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