Compare commits

...
Author SHA1 Message Date
Kyle BarronandGitHub d0a14deeb5 chore: prepare bytes v1.9.0 (#748) 2024-11-28 13:43:45 +01:00
Leonid LogvinovandGitHub 54f1c26f69 Rename hex_impl! to fmt_impl! and reuse it for fmt::Debug (#743) 2024-11-08 10:23:02 +01:00
Paolo BarboliniandGitHub 4cd8969e85 Replace BufMut::put with BufMut::put_slice in Writer impl (#745) 2024-11-01 18:22:07 +00:00
katelyn martinandGitHub 2d996a2b41 Fix typo in Buf::chunk() comment (#744) 2024-11-01 14:46:09 +00:00
Adam CimarostiandGitHub 30ee8e9cba Add Bytes::from_owner (#742) 2024-10-29 13:18:03 +01:00
Alice RyhlandGitHub c45697ce42 chore: prepare bytes v1.8.0 (#741) 2024-10-21 21:54:34 +02:00
Alice RyhlandGitHub 0ac54ca706 Guarantee address in split_off/split_to for empty slices (#740)
Signed-off-by: Alice Ryhl <[email protected]>
2024-10-18 19:46:49 +02:00
Paolo BarboliniandGitHub d7c1d658d9 chore: prepare bytes v1.7.2 (#736) 2024-09-18 07:39:32 +02:00
Taiki EndoandGitHub ac46ebdd46 ci: update nightly to nightly-2024-09-15 (#734) 2024-09-17 11:02:45 -04:00
Paolo BarboliniandGitHub 79fb85323c fix: apply sign extension when decoding int (#732)
Closes #730
2024-08-30 08:20:29 -04:00
Paolo BarboliniandGitHub 291df5acc9 Fix double spaces in comments and doc comments (#731) 2024-08-19 10:19:35 +02:00
Cameron BythewayandGitHub ed7d5ff39e test: ensure BytesMut::advance reduces capacity (#728) 2024-08-02 19:07:45 +00:00
Alice RyhlandGitHub dc4fb3e8f4 chore: prepare bytes v1.7.1 (#727) 2024-08-01 22:55:24 +02:00
Alice RyhlandGitHub f488be48d0 Revert "Reuse capacity when possible in <BytesMut as Buf>::advance impl" (#726)
This reverts commit baa5053572.
2024-08-01 22:38:17 +02:00
Motoyuki KimuraandGitHub 03fdde9dcf chore: prepare v1.7.0 (#724) 2024-07-31 13:33:47 +02:00
Alice Ryhl f8c7b574c0 Merge 'v1.6.1' into 'master' (#721) 2024-07-13 09:51:48 +02:00
Alice RyhlandGitHub fd13c7dcdb chore: prepare bytes v1.6.1 (#720) 2024-07-13 09:45:33 +02:00
Emily Crandall FleischmanandGitHub 6b4b0eda29 Fix Bytes::is_unique when created from shared BytesMut (#718)
The `is_unique` entry in the vtable for `Bytes` created from a shared
`BytesMut` just called the `shared_is_unique` function from the `bytes`
module. However, that function dereferences the `data` argument` as
`bytes::Shared`, but the actual underlying type is `bytes_mut::Shared`.
2024-07-13 01:09:46 +02:00
EXPLOSIONandGitHub 9965a04b56 Remove unnecessary file (#719) 2024-07-10 19:08:47 +09:00
vvvviivandGitHub 3443ca5a0b docs: clarify the behavior of Buf::chunk (#717) 2024-07-09 14:13:09 +02:00
Sebastian HahnandGitHub 8cc940779f Allow reclaiming the current allocation (#686) 2024-06-28 14:26:32 +02:00
Paolo BarboliniandGitHub 7a5154ba8b Clarify how BytesMut::zeroed works and advantages to manual impl (#714) 2024-06-21 14:07:25 +02:00
Anthony RamineandGitHub fa1daac3ae Change Bytes::make_mut to impl From<Bytes> for BytesMut (closes #709) (#710)
<Arc<T>>::make_mut returns a &mut T, such an API is doable for Bytes too
and thus we should reserve Bytes::make_mut for that.

Furthermore, it would be helpful to use From<Bytes> as a trait bound
in some cases with other traits such as Hyper's body trait, where Hyper
gives you Bytes values.

Finally, making it impl From<Bytes> for BytesMut means the API is more
easily discoverable as it appears on both Bytes and BytesMut.
2024-05-28 10:14:02 +02:00
Paolo BarboliniandGitHub caf520ac7f Fix iter tests to use the actual bytes IntoIter instead of std (#707) 2024-05-19 15:28:03 -04:00
Brad DunbarandGitHub 4950c50376 Offset from (#705) 2024-05-11 19:41:50 +02:00
Émile FugulinandGitHub 86694b0564 Add zero-copy make_mut (#695) 2024-05-05 17:58:00 +02:00
Alice RyhlandGitHub 0c17e99283 ci: silence unexpected-cfgs warnings due to #[cfg(loom)] (#703) 2024-05-05 14:19:18 +02:00
Alice RyhlandGitHub cb7f8449b5 Tweak clear and truncate length modifications (#700) 2024-04-26 09:24:05 +02:00
Paolo BarboliniandGitHub a8806c2457 Improve BytesMut::split suggestion (#699) 2024-04-25 10:43:15 +02:00
Paolo BarboliniandGitHub baa5053572 Reuse capacity when possible in <BytesMut as Buf>::advance impl (#698) 2024-04-25 09:08:16 +02:00
Brad DunbarandGitHub ce09d7d358 Bytes::split_off - check fast path first (#693)
Follow up to https://github.com/tokio-rs/bytes/pull/689

* If `at == self.len()`, we already know `at <= self.len()`.
* If `at == 0`, we already know `at <= self.len()`.
2024-04-24 08:23:39 -04:00
9d3ec1cffb Resize refactor (#696)
* use checked_sub

* return when additional == 0

* move safe operation out of unsafe block

* use spare_capacity_mut instead of chunk_mut

We don't need to check capacity because it's already been reserved
above.

* Add safety comments

* refactor to use guard clauses

This would be better written with let-else, but we won't get that until
`MSRV >= 1.65.x`.

* use if-let instead of unwrap

* reduce scope of unsafe blocks

Co-authored-by: Alice Ryhl <[email protected]>

---------

Co-authored-by: Alice Ryhl <[email protected]>
2024-04-24 05:49:53 -04:00
Brad DunbarandGitHub 4e2c9c065a Truncate tweaks (#694) 2024-04-17 11:27:00 +02:00
Joseph PerezandGitHub 327615e5d4 test(benches): encloses bytes into test::black_box for clone benches (#691)
Closes #690
Without it, it seems to me that compiler is able to inline the vtable,
resulting in similar results for `clone_shared` and `clone_arg_vec`.
2024-04-11 11:45:18 +02:00
tisonandGitHub b5fbfc3edb perf: improve Bytes::copy_to_bytes (#688)
Signed-off-by: tison <[email protected]>
2024-04-10 16:45:31 +02:00
Brad DunbarandGitHub 4eb62b912a Bytes::split_to - check fast path first (#689)
If `at == self.len()` then we already know `at <= self.len()`. If
`at == 0`, it can't be greater than `self.len()`.
2024-04-10 10:09:09 +02:00
Brad DunbarandGitHub e4af48633c Don't set len in BytesMut::reserve (#682)
A fundamental invariant of `reserve` is that it can extend capacity
while the stored data remains the same, even if it's moved to a new
allocation. As a result, `len` can never change during a call to
`reserve`.
2024-04-09 14:35:54 +02:00
Brad DunbarandGitHub 0d4cc7ffed Bytes: Use ManuallyDrop instead of mem::forget (#678) 2024-04-08 17:05:04 +02:00
Brad DunbarandGitHub ce8d8a0a02 chore: prepare bytes v1.6.0 (#681) 2024-03-22 20:55:20 +01:00
Brad DunbarandGitHub 536db06f16 Use ManuallyDrop instead of mem::forget (#675) 2024-03-14 14:40:03 +01:00
Brad DunbarandGitHub ca004117f8 Remove commented tests for Bytes::unsplit (#677)
Bytes doesn't have an unsplit method anymore. We can always retrieve
these from git history if necessary.
2024-03-04 09:05:00 +01:00
Brad DunbarandGitHub 7968f6f83d Remove redundant reserve call (#674) 2024-03-04 09:04:40 +01:00
Brad DunbarandGitHub c5fae00c76 copy_to_bytes: Add panic section to docs (#676)
Fixes #454.
2024-03-03 22:59:30 +09:00
Brad DunbarandGitHub 99584cc10d Use Iterator from the prelude (#673)
CI is [failing][failure] due to unused_imports because Iterator is
already in the prelude. Removing it fixes things up.

[failure]: https://github.com/tokio-rs/bytes/actions/runs/8034858583/job/21946873895
2024-03-03 00:40:17 +09:00
Brad DunbarandGitHub 46289278f5 Refactor split_at/split_to (#663)
* set len a little more concisely
* inline set_end
* remove kind assertions
* remove a duplicate assertion
* remove redundant assertion and min
* rename set_start to advance_unchecked
2024-02-23 14:22:58 -08:00
Brad DunbarandGitHub 1bcd2129d1 get_vec_pos: use &self instead of &mut self (#670)
I can't see any reason that get_vec_pos needs a &mut self.
2024-02-06 17:34:30 -05:00
Brad DunbarandGitHub f586ffc525 set_vec_pos does not need a second parameter (#672)
The second argument to `set_vec_pos` always contains the value of
`self.data`. Let's just use `self.data` and remove the second parameter
altogether.
2024-02-06 11:03:37 -08:00
Brad DunbarandGitHub c6972d6132 Calculate original capacity only if necessary (#666)
We don't need the original capacity if the shared data is unique, so
let's not calculate it until after that check.
2024-02-06 10:46:49 -08:00
Brad DunbarandGitHub 47e83056f2 Use sub instead of offset (#668)
We're always subtracting here, and we already have a usize, so `sub`
seems like a more appropriate usage to me.
2024-02-06 10:41:44 -08:00
Brad DunbarandGitHub 8bcac21cb4 Restore commented tests (#665)
These seem to have been commented by accident in #298, and are still
passing.
2024-02-06 10:17:01 -08:00
Brad DunbarandGitHub d2e7abdb29 refactor: make parameter mut in From<Vec> (#667)
Instead of re-declaring `vec`, we can just use a mut parameter.
2024-01-31 09:41:23 -05:00
Brad DunbarandGitHub e24587dd61 Remove unreachable else branch (#661) 2024-01-28 15:30:30 +03:30
Brad DunbarandGitHub 9257a6ea08 Remove an unnecessary else branch (#662) 2024-01-28 14:20:56 +03:30
Brad DunbarandGitHub 0ba3b4c4cd Remove unnecessary namespace qualifier (#660) 2024-01-28 14:07:11 +03:30
Cyborus04andGitHub 0864aea970 add Bytes::is_unique (#643) 2024-01-19 23:59:30 +01:00
Brad DunbarandGitHub abb4a2e66c BytesMut: Assert alignment of Shared (#652)
Back in #362, an assertion was added to ensure that the alignment of
bytes::Shared is even so we can use the least significant bit as a flag.
bytes_mut::Shared uses the same technique but has no such assertion so
I've added one here.
2024-01-19 11:08:27 +01:00
Taiki EndoandGitHub 09214ba51b Update CI config (#650) 2024-01-08 01:11:02 +09:00
Taiki EndoandGitHub fbc64bcc67 Update loom to 0.7 (#651) 2024-01-08 01:10:48 +09:00
Alice RyhlandGitHub 3bf6583b5c readme: add security policy (#649) 2024-01-03 17:22:39 +01:00
Brad DunbarandGitHub dbbdb63d76 Use self. instead of Self:: (#642)
I was a little confused about these calls using `Self::` instead of
`self.` here. Is there a reason to use the former instead of the latter?
2023-12-28 14:20:13 +09:00
Luca BrunoandGitHub f73c6c8e85 Simplify UninitSlice::as_uninit_slice_mut() logic (#644)
This reworks `UninitSlice::as_uninit_slice_mut()` using equivalent
simpler logic.
2023-12-28 14:17:53 +09:00
Gabriel GollerandGitHub 72cbb92e0e docs: fix broken links (#639)
Fixed a few broken links and converted a lot of them from the
html-link to intra-doc links.
2023-11-16 06:24:21 -05:00
bde8c50703 docs: typo fix (#637)
Co-authored-by: Daniel Bauman <[email protected]>
2023-10-19 21:50:24 +02:00
Alice RyhlandGitHub fd9243f9e2 Various cleanup (#635) 2023-10-02 15:40:02 +02:00
mxsmandGitHub a4e16a552b docs: fix some spelling mistakes (#633) 2023-09-25 10:47:02 +02:00
Lucas KentandGitHub a14ef4617c Move comment to correct constant (#629) 2023-09-11 11:12:11 +02:00
Alice RyhlandGitHub bd9c164cb6 doc: fix changelog typo (#628) 2023-09-07 14:10:55 +02:00
Alice RyhlandGitHub 74e6e200fd chore: prepare bytes v1.5.0 (#627) 2023-09-07 10:52:15 +02:00
Michal NazarewiczandGitHub 64c4fa2867 Rename UninitSlice constructors for consistency with ReadBuf (#599)
tokio::io::ReadBuf uses names `new` and `uninit` for its constructors.
For consistency with that, rename recently introduced UninitSlice
constructors to match those names.
2023-06-20 10:19:56 +02:00
Taiki EndoandGitHub c7756c3e59 Fix CI failure (#616) 2023-06-05 01:04:59 +09:00
Michal NazarewiczandGitHub b29112ce44 Implement BufMut for &mut [MaybeUninit<u8>] (#597) 2023-02-10 10:28:24 +01:00
Michal NazarewiczandGitHub 99a27542a0 Add a safe way to create UninitSlice from slices (#598)
Introduce UninitSlice::from_slice and UninitSlice::from_uninit_slice
methods which safely create Uninit slice from provided slice of maybe
uninitialised or initialised memory.

In addition, add `From<&mut [T]>` implementations (for `T=u8` and
`T=MaybeUninit<u8>`) which do conversion from slice to UninitSlice.

Closes: #552
2023-02-09 17:24:23 +01:00
Paa Kojo SamanpaandGitHub 74b04c7aae Mark BytesMut::extend_from_slice as inline (#595)
This function can be hot in applications that do a lot of encoding. Ideally would do the same for `<BytesMut as BufMut>::put_slice` and `<BytesMut as BufMut::put_u8`.
2023-02-04 20:16:41 +01:00
Alice RyhlandGitHub 21ed332836 chore: prepare bytes v1.4.0 (#593) 2023-01-31 20:38:32 +01:00
brian m. carlsonandGitHub 05e9d5cab9 Avoid large reallocations when freezing BytesMut (#592)
When we freeze a BytesMut, we turn it into a Vec, and then convert that
to a Bytes.  Currently, this happen using Vec::into_boxed_slice, which
reallocates to a slice of the same length as the Vev if the length and
the capacity are not equal.  This can pose a performance problem if the
Vec is large or if this happens many times in a loop.

Instead, let's compare the length and capacity, and if they're the same,
continue to handle this using into_boxed_slice.  Otherwise, since we
have a type of vtable which can handle a separate capacity, the shared
vtable, let's turn our Vec into that kind of Bytes.  While this does not
avoid allocation altogether, it performs a fixed size allocation and
avoids any need to memcpy.
2023-01-31 20:04:22 +01:00
0xc0001a2040andGitHub f15bba3375 Document which functions require std (#591) 2023-01-31 11:42:28 +01:00
c93a94b974 Fix duplicate "the the" typos (#585)
Co-authored-by: Nicolae Mihalache <[email protected]>
2022-12-20 11:49:55 +01:00
Matthijs van OtterdijkandGitHub 050d65b2ce make IntoIter constructor public (#581) 2022-11-25 22:48:20 +01:00
Sean LynchandGitHub 9b227220df chore: prepare bytes v1.3.0 (#579) 2022-11-21 08:06:49 +01:00
Sean LynchandGitHub 8a8c41f5c2 Implement native-endian get and put functions for Buf and BufMut (#576)
Fixes #549
2022-11-14 10:33:36 +01:00
Sean LynchandGitHub 5c7b4317e0 Update nightly snapshot to the current one (#577) 2022-11-14 10:56:33 +09:00
Yotam OfekandGitHub 6e4b1f244b Rename and expose BytesMut::spare_capacity_mut (#572) 2022-10-04 12:23:07 +02:00
Adam ChalmersandGitHub a36f661354 docs: Bytes::new etc should return Self not Bytes (#568) 2022-08-24 13:30:21 +02:00
Alice RyhlandGitHub d1b5d4ceb1 Don't have important data in unused capacity when calling reserve (#563) 2022-08-12 12:22:43 +02:00
Alice RyhlandGitHub b7249149a9 chore: prepare bytes v1.2.1 (#561) 2022-07-30 11:35:26 +02:00
Matt SchulteandGitHub d6e1999d97 Fix reserve over allocating underlying buffer (#560)
Fixes calls to `reserve` when the underlying shared buffer was already
big enough to fit the requested capacity. Previously a new even larger
buffer was created anyways. This could eventually lead to an OOM
condition.
2022-07-30 11:16:32 +02:00
Alice RyhlandGitHub 38fd42acba chore: prepare bytes v1.2.0 (#556) 2022-07-19 13:39:58 +02:00
7553a67be2 Fix amortized asymptotics of BytesMut (#555)
Signed-off-by: Jiahao XU <[email protected]>
Co-authored-by: Frank Steffahn <[email protected]>
2022-07-19 13:17:53 +02:00
cd188cbd67 Add conversion from Bytes to Vec<u8> (#547)
Signed-off-by: Jiahao XU <[email protected]>
Co-authored-by: Alice Ryhl <[email protected]>
2022-07-13 09:04:23 +02:00
Jiahao XUandGitHub 10d1f6ec5c Fix: From<BytesMut> fo Vec<u8> implementation (#554)
Signed-off-by: Jiahao XU <[email protected]>
2022-07-13 08:59:54 +02:00
Jiahao XUandGitHub 068ed41bc0 Add conversion from BytesMut to Vec<u8> (#543) 2022-07-10 12:44:29 +02:00
Alice RyhlandGitHub f514bd38da miri: don't use int2ptr casts for invalid pointers (#553) 2022-07-09 21:54:34 +02:00
Lucio FrancoandGitHub 28a1eab1e0 chore: Fix unused warnings (#551) 2022-06-23 09:16:03 -07:00
ZettrokeandGitHub 3536017ccf Fix chain remaining_mut(), allowing to chain growing buffer (#488) 2022-06-11 13:12:53 +09:00
Erick TryzelaarandGitHub b8d27c016f Add UninitSlice::as_uninit_slice_mut() (#548)
This adds an unsafe method to convert a `&mut UninitSlice` into a
`&mut [MaybeUninit<u8>]`. This method is unsafe because some of the
bytes in the slice may be initialized, and the caller should not
overwrite them with uninitialized bytes.

This came about when auditing [tokio-util's udp frame], where they want
to pass the unitialized portion of a `BytesMut` to [ReadBuf::uninit].
They need to do this unsafe pointer casting in a few places, which
complicates audits. This method lets us document the safety invariants
the caller needs to maintain when doing this conversion.

[tokio-util's udp frame]: https://github.com/tokio-rs/tokio/blob/master/tokio-util/src/udp/frame.rs#L87
[ReadBuf::uninit]: https://docs.rs/tokio/latest/tokio/io/struct.ReadBuf.html#method.uninit
2022-05-10 11:22:19 +02:00
Taiki EndoandGitHub 0ce4fe3c91 Update actions/checkout action to v3 (#546) 2022-05-01 14:50:55 +02:00
Alice RyhlandGitHub 716a0b189e Only avoid pointer casts when using miri (#545) 2022-04-29 22:01:26 +02:00
Alice Ryhl b4b2c18c27 Revert accidental push directly to master
This reverts commit 89061c3238.

Why am I even able to push to master?
2022-04-29 19:49:28 +02:00
Alice Ryhl 89061c3238 Only avoid pointer casts when using miri 2022-04-29 19:47:34 +02:00
Jiahao XUandGitHub 0a2c43af88 Fix bugs in BytesMut::reserve_inner (#544) 2022-04-28 11:37:33 +02:00
Alice RyhlandGitHub 8198f9e28e Make strict provenance compatible (#542) 2022-04-16 00:26:58 +02:00
Alice RyhlandGitHub 547a32033e Add TSAN support (#541) 2022-04-15 22:46:40 +02:00
Ben KimockandGitHub 724476982b Fix aliasing in Clone by using a raw pointer (#523)
Previously, this code produced a &mut[u8] and a Box<[u8]> to the shared
allocation upon cloning it. If the underlying allocation were actually
shared, such as through a &[u8] from the Deref impl, creating either of
these types incorrectly asserted uniqueness of the allocation.

This fixes the example in #522, but Miri still does not pass on this
test suite with -Zmiri-tag-raw-pointers because Miri does not currently
understand int to pointer casts.
2022-04-06 16:59:20 +02:00
Evan CameronandGitHub 9e6edd18d2 Clarify BytesMut::unsplit docs (#535) 2022-04-06 15:19:00 +02:00
Anthony DeschampsandGitHub e4c723697d docs: redraw layout diagram with box drawing characters. (#539)
I find this diagram very helpful, but a little hard to distinguish
between the boxes and the lines that connect them. This commit redraws
the boxes with line drawing characters so that the boxes appear a
little more solid, and stand out from the other lines.
2022-03-25 10:55:13 +01:00
Jiahao XUandGitHub d4f5023383 Optimize BytesMut::reserve: Reuse vec if possible (#529)
* Optimize `BytesMut::reserve`: Reuse vec if possible

If the `BytesMut` holds a unqiue reference to `KIND_ARC` while the
capacity of the `Vec` is not big enough , reuse the existing `Vec`
instead of allocating a new one.

Signed-off-by: Jiahao XU <[email protected]>
2022-03-16 10:11:42 -04:00
Ralf JungandGitHub 88f5e12350 update Miri CI config (#534) 2022-03-09 10:29:04 +01:00
Rob EdeandGitHub 131dae161f Implement Extend<Bytes> for BytesMut (#527) 2022-01-24 09:58:18 +01:00
Rob EdeandGitHub 0e3b2466f1 Address various clippy warnings (#528) 2022-01-24 09:58:05 +01:00
Donough LiuandGitHub 68afb40df9 Add BytesMut::zeroed (#517) 2021-11-24 10:20:21 +01:00
Cyborus04andGitHub d946ef2e91 const-ify Bytes::len and Bytes::is_empty (#514) 2021-11-09 11:41:40 +01:00
Noah KennedyandGitHub ba5c5c93af Appease miri (#515)
Rewrote the ledger in test_bytes_vec_alloc.rs to not piss off miri. The ledger is now a table within the allocator, which seems to satisfy miri. The old solution was to bundle an extra usize into the beginning of each allocation and then index past the start when deallocating data to get the size.
2021-11-07 10:23:12 -06:00
34 changed files with 3649 additions and 680 deletions
+36 -25
View File
@@ -7,11 +7,13 @@ on:
push: push:
branches: branches:
- master - master
schedule:
- cron: '0 2 * * 0'
env: env:
RUSTFLAGS: -Dwarnings RUSTFLAGS: -Dwarnings
RUST_BACKTRACE: 1 RUST_BACKTRACE: 1
nightly: nightly-2021-04-13 nightly: nightly-2024-09-15
defaults: defaults:
run: run:
@@ -23,11 +25,11 @@ jobs:
name: rustfmt name: rustfmt
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v4
- name: Install Rust - name: Install Rust
run: rustup update stable && rustup default stable run: rustup update stable
- name: Check formatting - name: Check formatting
run: cargo fmt --all -- --check run: cargo fmt --all --check
# TODO # TODO
# # Apply clippy lints # # Apply clippy lints
@@ -35,7 +37,7 @@ jobs:
# name: clippy # name: clippy
# runs-on: ubuntu-latest # runs-on: ubuntu-latest
# steps: # steps:
# - uses: actions/checkout@v2 # - uses: actions/checkout@v4
# - name: Apply clippy lints # - name: Apply clippy lints
# run: cargo clippy --all-features # run: cargo clippy --all-features
@@ -48,11 +50,11 @@ jobs:
name: minrust name: minrust
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v4
- name: Install Rust - name: Install cargo-hack
run: rustup update 1.39.0 && rustup default 1.39.0 uses: taiki-e/install-action@cargo-hack
- name: Check - name: Check
run: . ci/test-stable.sh check run: cargo hack check --feature-powerset --optional-deps --rust-version
# Stable # Stable
stable: stable:
@@ -65,23 +67,27 @@ jobs:
- windows-latest - windows-latest
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v4
- name: Install Rust - name: Install Rust
# --no-self-update is necessary because the windows environment cannot self-update rustup.exe. # --no-self-update is necessary because the windows environment cannot self-update rustup.exe.
run: rustup update stable --no-self-update && rustup default stable run: rustup update stable --no-self-update
- name: Install cargo-hack
uses: taiki-e/install-action@cargo-hack
- name: Test - name: Test
run: . ci/test-stable.sh test run: ci/test-stable.sh test
# Nightly # Nightly
nightly: nightly:
name: nightly name: nightly
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v4
- name: Install Rust - name: Install Rust
run: rustup update $nightly && rustup default $nightly run: rustup update $nightly && rustup default $nightly
- name: Install cargo-hack
uses: taiki-e/install-action@cargo-hack
- name: Test - name: Test
run: . ci/test-stable.sh test run: ci/test-stable.sh test
# Run tests on some extra platforms # Run tests on some extra platforms
cross: cross:
@@ -96,13 +102,14 @@ jobs:
- wasm32-unknown-unknown - wasm32-unknown-unknown
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v4
- name: Install Rust - name: Install Rust
run: rustup update stable && rustup default stable 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 }} - name: cross build --target ${{ matrix.target }}
run: | run: cross build --target ${{ matrix.target }}
cargo install cross
cross build --target ${{ matrix.target }}
if: matrix.target != 'wasm32-unknown-unknown' if: matrix.target != 'wasm32-unknown-unknown'
# WASM support # WASM support
- name: cargo build --target ${{ matrix.target }} - name: cargo build --target ${{ matrix.target }}
@@ -116,18 +123,21 @@ jobs:
name: tsan name: tsan
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v4
- name: Install Rust - name: Install Rust
run: rustup update $nightly && rustup default $nightly run: rustup update $nightly && rustup default $nightly
- name: Install rust-src - name: Install rust-src
run: rustup component add rust-src run: rustup component add rust-src
- name: ASAN / TSAN - name: ASAN / TSAN
run: . ci/tsan.sh run: ci/tsan.sh
miri: miri:
name: miri name: miri
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v4
- name: Install Rust
run: rustup update $nightly && rustup default $nightly
- name: Miri - name: Miri
run: ci/miri.sh run: ci/miri.sh
@@ -136,7 +146,7 @@ jobs:
name: loom name: loom
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v4
- name: Install Rust - name: Install Rust
run: rustup update $nightly && rustup default $nightly run: rustup update $nightly && rustup default $nightly
- name: Loom tests - name: Loom tests
@@ -152,12 +162,13 @@ jobs:
- minrust - minrust
- cross - cross
- tsan - tsan
- miri
- loom - loom
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v4
- name: Install Rust - name: Install Rust
run: rustup update stable && rustup default stable run: rustup update $nightly && rustup default $nightly
- name: Build documentation - name: Build documentation
run: cargo doc --no-deps --all-features run: cargo doc --no-deps --all-features
env: env:
+186
View File
@@ -1,3 +1,189 @@
# 1.9.0 (November 27, 2024)
### Added
- Add `Bytes::from_owner` to enable externally-allocated memory (#742)
### Documented
- Fix typo in Buf::chunk() comment (#744)
### Internal changes
- Replace BufMut::put with BufMut::put_slice in Writer impl (#745)
- Rename hex_impl! to fmt_impl! and reuse it for fmt::Debug (#743)
# 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) # 1.1.0 (August 25, 2021)
### Added ### Added
+4 -3
View File
@@ -4,7 +4,9 @@ name = "bytes"
# When releasing to crates.io: # When releasing to crates.io:
# - Update CHANGELOG.md. # - Update CHANGELOG.md.
# - Create "v1.x.y" git tag. # - Create "v1.x.y" git tag.
version = "1.1.0" version = "1.9.0"
edition = "2018"
rust-version = "1.39"
license = "MIT" license = "MIT"
authors = [ authors = [
"Carl Lerche <[email protected]>", "Carl Lerche <[email protected]>",
@@ -15,7 +17,6 @@ repository = "https://github.com/tokio-rs/bytes"
readme = "README.md" readme = "README.md"
keywords = ["buffers", "zero-copy", "io"] keywords = ["buffers", "zero-copy", "io"]
categories = ["network-programming", "data-structures"] categories = ["network-programming", "data-structures"]
edition = "2018"
[features] [features]
default = ["std"] default = ["std"]
@@ -28,7 +29,7 @@ serde = { version = "1.0.60", optional = true, default-features = false, feature
serde_test = "1.0" serde_test = "1.0"
[target.'cfg(loom)'.dev-dependencies] [target.'cfg(loom)'.dev-dependencies]
loom = "0.5" loom = "0.7"
[package.metadata.docs.rs] [package.metadata.docs.rs]
rustdoc-args = ["--cfg", "docsrs"] rustdoc-args = ["--cfg", "docsrs"]
+9
View File
@@ -36,6 +36,15 @@ Serde support is optional and disabled by default. To enable use the feature `se
bytes = { version = "1", features = ["serde"] } 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 ## License
This project is licensed under the [MIT license](LICENSE). This project is licensed under the [MIT license](LICENSE).
+9
View File
@@ -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 -1
View File
@@ -46,7 +46,7 @@ impl TestBuf {
} }
impl Buf for TestBuf { impl Buf for TestBuf {
fn remaining(&self) -> usize { fn remaining(&self) -> usize {
return self.buf.len() - self.pos; self.buf.len() - self.pos
} }
fn advance(&mut self, cnt: usize) { fn advance(&mut self, cnt: usize) {
self.pos += cnt; self.pos += cnt;
+4 -3
View File
@@ -47,7 +47,7 @@ fn clone_static(b: &mut Bencher) {
b.iter(|| { b.iter(|| {
for _ in 0..1024 { for _ in 0..1024 {
test::black_box(&bytes.clone()); test::black_box(test::black_box(&bytes).clone());
} }
}) })
} }
@@ -58,7 +58,7 @@ fn clone_shared(b: &mut Bencher) {
b.iter(|| { b.iter(|| {
for _ in 0..1024 { for _ in 0..1024 {
test::black_box(&bytes.clone()); test::black_box(test::black_box(&bytes).clone());
} }
}) })
} }
@@ -70,7 +70,7 @@ fn clone_arc_vec(b: &mut Bencher) {
b.iter(|| { b.iter(|| {
for _ in 0..1024 { for _ in 0..1024 {
test::black_box(&bytes.clone()); test::black_box(test::black_box(&bytes).clone());
} }
}) })
} }
@@ -88,6 +88,7 @@ fn from_long_slice(b: &mut Bencher) {
#[bench] #[bench]
fn slice_empty(b: &mut Bencher) { fn slice_empty(b: &mut Bencher) {
b.iter(|| { b.iter(|| {
// `clone` is to convert to ARC
let b = Bytes::from(vec![17; 1024]).clone(); let b = Bytes::from(vec![17; 1024]).clone();
for i in 0..1000 { for i in 0..1000 {
test::black_box(b.slice(i % 100..i % 100)); test::black_box(b.slice(i % 100..i % 100));
+3 -4
View File
@@ -1,11 +1,10 @@
#!/bin/bash #!/bin/bash
set -e set -e
MIRI_NIGHTLY=nightly-$(curl -s https://rust-lang.github.io/rustup-components-history/x86_64-unknown-linux-gnu/miri)
echo "Installing latest nightly with Miri: $MIRI_NIGHTLY"
rustup set profile minimal
rustup default "$MIRI_NIGHTLY"
rustup component add miri rustup component add miri
cargo miri setup
export MIRIFLAGS="-Zmiri-strict-provenance"
cargo miri test cargo miri test
cargo miri test --target mips64-unknown-linux-gnuabi64 cargo miri test --target mips64-unknown-linux-gnuabi64
Regular → Executable
-6
View File
@@ -4,10 +4,6 @@ set -ex
cmd="${1:-test}" cmd="${1:-test}"
# Install cargo-hack for feature flag test
host=$(rustc -Vv | grep host | sed 's/host: //')
curl -LsSf https://github.com/taiki-e/cargo-hack/releases/latest/download/cargo-hack-$host.tar.gz | tar xzf - -C ~/.cargo/bin
# Run with each feature # Run with each feature
# * --each-feature includes both default/no-default features # * --each-feature includes both default/no-default features
# * --optional-deps is needed for serde feature # * --optional-deps is needed for serde feature
@@ -15,8 +11,6 @@ cargo hack "${cmd}" --each-feature --optional-deps
# Run with all features # Run with all features
cargo "${cmd}" --all-features cargo "${cmd}" --all-features
cargo doc --no-deps --all-features
if [[ "${RUST_VERSION}" == "nightly"* ]]; then if [[ "${RUST_VERSION}" == "nightly"* ]]; then
# Check benchmarks # Check benchmarks
cargo check --benches cargo check --benches
Regular → Executable
View File
+1
View File
@@ -0,0 +1 @@
msrv = "1.39"
+458 -60
View File
@@ -1,8 +1,9 @@
#[cfg(feature = "std")] #[cfg(feature = "std")]
use crate::buf::{reader, Reader}; use crate::buf::{reader, Reader};
use crate::buf::{take, Chain, Take}; use crate::buf::{take, Chain, Take};
#[cfg(feature = "std")]
use core::{cmp, mem, ptr}; use crate::{min_u64_usize, saturating_sub_usize_u64};
use crate::{panic_advance, panic_does_not_fit};
#[cfg(feature = "std")] #[cfg(feature = "std")]
use std::io::IoSlice; use std::io::IoSlice;
@@ -11,7 +12,12 @@ use alloc::boxed::Box;
macro_rules! buf_get_impl { macro_rules! buf_get_impl {
($this:ident, $typ:tt::$conv:tt) => {{ ($this:ident, $typ:tt::$conv:tt) => {{
const SIZE: usize = mem::size_of::<$typ>(); const SIZE: usize = core::mem::size_of::<$typ>();
if $this.remaining() < SIZE {
panic_advance(SIZE, $this.remaining());
}
// try to convert directly from the bytes // try to convert directly from the bytes
// this Option<ret> trick is to avoid keeping a borrow on self // this Option<ret> trick is to avoid keeping a borrow on self
// when advance() is called (mut borrow) and to call bytes() only once // when advance() is called (mut borrow) and to call bytes() only once
@@ -32,23 +38,40 @@ macro_rules! buf_get_impl {
} }
}}; }};
(le => $this:ident, $typ:tt, $len_to_read:expr) => {{ (le => $this:ident, $typ:tt, $len_to_read:expr) => {{
debug_assert!(mem::size_of::<$typ>() >= $len_to_read); const SIZE: usize = core::mem::size_of::<$typ>();
// The same trick as above does not improve the best case speed. // The same trick as above does not improve the best case speed.
// It seems to be linked to the way the method is optimised by the compiler // It seems to be linked to the way the method is optimised by the compiler
let mut buf = [0; (mem::size_of::<$typ>())]; let mut buf = [0; SIZE];
$this.copy_to_slice(&mut buf[..($len_to_read)]);
let subslice = match buf.get_mut(..$len_to_read) {
Some(subslice) => subslice,
None => panic_does_not_fit(SIZE, $len_to_read),
};
$this.copy_to_slice(subslice);
return $typ::from_le_bytes(buf); return $typ::from_le_bytes(buf);
}}; }};
(be => $this:ident, $typ:tt, $len_to_read:expr) => {{ (be => $this:ident, $typ:tt, $len_to_read:expr) => {{
debug_assert!(mem::size_of::<$typ>() >= $len_to_read); const SIZE: usize = core::mem::size_of::<$typ>();
let mut buf = [0; (mem::size_of::<$typ>())]; let slice_at = match SIZE.checked_sub($len_to_read) {
$this.copy_to_slice(&mut buf[mem::size_of::<$typ>() - ($len_to_read)..]); Some(slice_at) => slice_at,
None => panic_does_not_fit(SIZE, $len_to_read),
};
let mut buf = [0; SIZE];
$this.copy_to_slice(&mut buf[slice_at..]);
return $typ::from_be_bytes(buf); return $typ::from_be_bytes(buf);
}}; }};
} }
// https://en.wikipedia.org/wiki/Sign_extension
fn sign_extend(val: u64, nbytes: usize) -> i64 {
let shift = (8 - nbytes) * 8;
(val << shift) as i64 >> shift
}
/// Read bytes from a buffer. /// Read bytes from a buffer.
/// ///
/// A buffer stores bytes in memory such that read operations are infallible. /// A buffer stores bytes in memory such that read operations are infallible.
@@ -102,8 +125,8 @@ pub trait Buf {
fn remaining(&self) -> usize; fn remaining(&self) -> usize;
/// Returns a slice starting at the current position and of length between 0 /// Returns a slice starting at the current position and of length between 0
/// and `Buf::remaining()`. Note that this *can* return shorter slice (this allows /// and `Buf::remaining()`. Note that this *can* return a shorter slice (this
/// non-continuous internal representation). /// allows non-continuous internal representation).
/// ///
/// This is a lower level function. Most operations are done with other /// This is a lower level function. Most operations are done with other
/// functions. /// functions.
@@ -124,9 +147,11 @@ pub trait Buf {
/// ///
/// # Implementer notes /// # Implementer notes
/// ///
/// This function should never panic. Once the end of the buffer is reached, /// This function should never panic. `chunk()` should return an empty
/// i.e., `Buf::remaining` returns 0, calls to `chunk()` should return an /// slice **if and only if** `remaining()` returns 0. In other words,
/// empty slice. /// `chunk()` returning an empty slice implies that `remaining()` will
/// return 0 and `remaining()` returning 0 implies that `chunk()` will
/// return an empty slice.
// The `chunk` method was previously called `bytes`. This alias makes the rename // The `chunk` method was previously called `bytes`. This alias makes the rename
// more easily discoverable. // more easily discoverable.
#[cfg_attr(docsrs, doc(alias = "bytes"))] #[cfg_attr(docsrs, doc(alias = "bytes"))]
@@ -160,6 +185,7 @@ pub trait Buf {
/// ///
/// [`writev`]: http://man7.org/linux/man-pages/man2/readv.2.html /// [`writev`]: http://man7.org/linux/man-pages/man2/readv.2.html
#[cfg(feature = "std")] #[cfg(feature = "std")]
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
fn chunks_vectored<'a>(&'a self, dst: &mut [IoSlice<'a>]) -> usize { fn chunks_vectored<'a>(&'a self, dst: &mut [IoSlice<'a>]) -> usize {
if dst.is_empty() { if dst.is_empty() {
return 0; return 0;
@@ -246,23 +272,18 @@ pub trait Buf {
/// ///
/// # Panics /// # Panics
/// ///
/// This function panics if `self.remaining() < dst.len()` /// This function panics if `self.remaining() < dst.len()`.
fn copy_to_slice(&mut self, dst: &mut [u8]) { fn copy_to_slice(&mut self, mut dst: &mut [u8]) {
let mut off = 0; if self.remaining() < dst.len() {
panic_advance(dst.len(), self.remaining());
}
assert!(self.remaining() >= dst.len()); while !dst.is_empty() {
let src = self.chunk();
let cnt = usize::min(src.len(), dst.len());
while off < dst.len() { dst[..cnt].copy_from_slice(&src[..cnt]);
let cnt; dst = &mut dst[cnt..];
unsafe {
let src = self.chunk();
cnt = cmp::min(src.len(), dst.len() - off);
ptr::copy_nonoverlapping(src.as_ptr(), dst[off..].as_mut_ptr(), cnt);
off += cnt;
}
self.advance(cnt); self.advance(cnt);
} }
@@ -285,7 +306,9 @@ pub trait Buf {
/// ///
/// This function panics if there is no more remaining data in `self`. /// This function panics if there is no more remaining data in `self`.
fn get_u8(&mut self) -> u8 { fn get_u8(&mut self) -> u8 {
assert!(self.remaining() >= 1); if self.remaining() < 1 {
panic_advance(1, 0);
}
let ret = self.chunk()[0]; let ret = self.chunk()[0];
self.advance(1); self.advance(1);
ret ret
@@ -308,7 +331,9 @@ pub trait Buf {
/// ///
/// This function panics if there is no more remaining data in `self`. /// This function panics if there is no more remaining data in `self`.
fn get_i8(&mut self) -> i8 { fn get_i8(&mut self) -> i8 {
assert!(self.remaining() >= 1); if self.remaining() < 1 {
panic_advance(1, 0);
}
let ret = self.chunk()[0] as i8; let ret = self.chunk()[0] as i8;
self.advance(1); self.advance(1);
ret ret
@@ -354,6 +379,29 @@ pub trait Buf {
buf_get_impl!(self, u16::from_le_bytes); buf_get_impl!(self, u16::from_le_bytes);
} }
/// Gets an unsigned 16 bit integer from `self` in native-endian byte order.
///
/// The current position is advanced by 2.
///
/// # Examples
///
/// ```
/// use bytes::Buf;
///
/// let mut buf: &[u8] = match cfg!(target_endian = "big") {
/// true => b"\x08\x09 hello",
/// false => b"\x09\x08 hello",
/// };
/// assert_eq!(0x0809, buf.get_u16_ne());
/// ```
///
/// # Panics
///
/// This function panics if there is not enough remaining data in `self`.
fn get_u16_ne(&mut self) -> u16 {
buf_get_impl!(self, u16::from_ne_bytes);
}
/// Gets a signed 16 bit integer from `self` in big-endian byte order. /// Gets a signed 16 bit integer from `self` in big-endian byte order.
/// ///
/// The current position is advanced by 2. /// The current position is advanced by 2.
@@ -394,6 +442,29 @@ pub trait Buf {
buf_get_impl!(self, i16::from_le_bytes); buf_get_impl!(self, i16::from_le_bytes);
} }
/// Gets a signed 16 bit integer from `self` in native-endian byte order.
///
/// The current position is advanced by 2.
///
/// # Examples
///
/// ```
/// use bytes::Buf;
///
/// let mut buf: &[u8] = match cfg!(target_endian = "big") {
/// true => b"\x08\x09 hello",
/// false => b"\x09\x08 hello",
/// };
/// assert_eq!(0x0809, buf.get_i16_ne());
/// ```
///
/// # Panics
///
/// This function panics if there is not enough remaining data in `self`.
fn get_i16_ne(&mut self) -> i16 {
buf_get_impl!(self, i16::from_ne_bytes);
}
/// Gets an unsigned 32 bit integer from `self` in the big-endian byte order. /// Gets an unsigned 32 bit integer from `self` in the big-endian byte order.
/// ///
/// The current position is advanced by 4. /// The current position is advanced by 4.
@@ -434,6 +505,29 @@ pub trait Buf {
buf_get_impl!(self, u32::from_le_bytes); buf_get_impl!(self, u32::from_le_bytes);
} }
/// Gets an unsigned 32 bit integer from `self` in native-endian byte order.
///
/// The current position is advanced by 4.
///
/// # Examples
///
/// ```
/// use bytes::Buf;
///
/// let mut buf: &[u8] = match cfg!(target_endian = "big") {
/// true => b"\x08\x09\xA0\xA1 hello",
/// false => b"\xA1\xA0\x09\x08 hello",
/// };
/// assert_eq!(0x0809A0A1, buf.get_u32_ne());
/// ```
///
/// # Panics
///
/// This function panics if there is not enough remaining data in `self`.
fn get_u32_ne(&mut self) -> u32 {
buf_get_impl!(self, u32::from_ne_bytes);
}
/// Gets a signed 32 bit integer from `self` in big-endian byte order. /// Gets a signed 32 bit integer from `self` in big-endian byte order.
/// ///
/// The current position is advanced by 4. /// The current position is advanced by 4.
@@ -474,6 +568,29 @@ pub trait Buf {
buf_get_impl!(self, i32::from_le_bytes); buf_get_impl!(self, i32::from_le_bytes);
} }
/// Gets a signed 32 bit integer from `self` in native-endian byte order.
///
/// The current position is advanced by 4.
///
/// # Examples
///
/// ```
/// use bytes::Buf;
///
/// let mut buf: &[u8] = match cfg!(target_endian = "big") {
/// true => b"\x08\x09\xA0\xA1 hello",
/// false => b"\xA1\xA0\x09\x08 hello",
/// };
/// assert_eq!(0x0809A0A1, buf.get_i32_ne());
/// ```
///
/// # Panics
///
/// This function panics if there is not enough remaining data in `self`.
fn get_i32_ne(&mut self) -> i32 {
buf_get_impl!(self, i32::from_ne_bytes);
}
/// Gets an unsigned 64 bit integer from `self` in big-endian byte order. /// Gets an unsigned 64 bit integer from `self` in big-endian byte order.
/// ///
/// The current position is advanced by 8. /// The current position is advanced by 8.
@@ -514,6 +631,29 @@ pub trait Buf {
buf_get_impl!(self, u64::from_le_bytes); buf_get_impl!(self, u64::from_le_bytes);
} }
/// Gets an unsigned 64 bit integer from `self` in native-endian byte order.
///
/// The current position is advanced by 8.
///
/// # Examples
///
/// ```
/// use bytes::Buf;
///
/// let mut buf: &[u8] = match cfg!(target_endian = "big") {
/// true => b"\x01\x02\x03\x04\x05\x06\x07\x08 hello",
/// false => b"\x08\x07\x06\x05\x04\x03\x02\x01 hello",
/// };
/// assert_eq!(0x0102030405060708, buf.get_u64_ne());
/// ```
///
/// # Panics
///
/// This function panics if there is not enough remaining data in `self`.
fn get_u64_ne(&mut self) -> u64 {
buf_get_impl!(self, u64::from_ne_bytes);
}
/// Gets a signed 64 bit integer from `self` in big-endian byte order. /// Gets a signed 64 bit integer from `self` in big-endian byte order.
/// ///
/// The current position is advanced by 8. /// The current position is advanced by 8.
@@ -554,6 +694,29 @@ pub trait Buf {
buf_get_impl!(self, i64::from_le_bytes); buf_get_impl!(self, i64::from_le_bytes);
} }
/// Gets a signed 64 bit integer from `self` in native-endian byte order.
///
/// The current position is advanced by 8.
///
/// # Examples
///
/// ```
/// use bytes::Buf;
///
/// let mut buf: &[u8] = match cfg!(target_endian = "big") {
/// true => b"\x01\x02\x03\x04\x05\x06\x07\x08 hello",
/// false => b"\x08\x07\x06\x05\x04\x03\x02\x01 hello",
/// };
/// assert_eq!(0x0102030405060708, buf.get_i64_ne());
/// ```
///
/// # Panics
///
/// This function panics if there is not enough remaining data in `self`.
fn get_i64_ne(&mut self) -> i64 {
buf_get_impl!(self, i64::from_ne_bytes);
}
/// Gets an unsigned 128 bit integer from `self` in big-endian byte order. /// Gets an unsigned 128 bit integer from `self` in big-endian byte order.
/// ///
/// The current position is advanced by 16. /// The current position is advanced by 16.
@@ -594,6 +757,29 @@ pub trait Buf {
buf_get_impl!(self, u128::from_le_bytes); buf_get_impl!(self, u128::from_le_bytes);
} }
/// Gets an unsigned 128 bit integer from `self` in native-endian byte order.
///
/// The current position is advanced by 16.
///
/// # Examples
///
/// ```
/// use bytes::Buf;
///
/// let mut buf: &[u8] = match cfg!(target_endian = "big") {
/// true => b"\x01\x02\x03\x04\x05\x06\x07\x08\x09\x10\x11\x12\x13\x14\x15\x16 hello",
/// false => b"\x16\x15\x14\x13\x12\x11\x10\x09\x08\x07\x06\x05\x04\x03\x02\x01 hello",
/// };
/// assert_eq!(0x01020304050607080910111213141516, buf.get_u128_ne());
/// ```
///
/// # Panics
///
/// This function panics if there is not enough remaining data in `self`.
fn get_u128_ne(&mut self) -> u128 {
buf_get_impl!(self, u128::from_ne_bytes);
}
/// Gets a signed 128 bit integer from `self` in big-endian byte order. /// Gets a signed 128 bit integer from `self` in big-endian byte order.
/// ///
/// The current position is advanced by 16. /// The current position is advanced by 16.
@@ -634,6 +820,29 @@ pub trait Buf {
buf_get_impl!(self, i128::from_le_bytes); buf_get_impl!(self, i128::from_le_bytes);
} }
/// Gets a signed 128 bit integer from `self` in native-endian byte order.
///
/// The current position is advanced by 16.
///
/// # Examples
///
/// ```
/// use bytes::Buf;
///
/// let mut buf: &[u8] = match cfg!(target_endian = "big") {
/// true => b"\x01\x02\x03\x04\x05\x06\x07\x08\x09\x10\x11\x12\x13\x14\x15\x16 hello",
/// false => b"\x16\x15\x14\x13\x12\x11\x10\x09\x08\x07\x06\x05\x04\x03\x02\x01 hello",
/// };
/// assert_eq!(0x01020304050607080910111213141516, buf.get_i128_ne());
/// ```
///
/// # Panics
///
/// This function panics if there is not enough remaining data in `self`.
fn get_i128_ne(&mut self) -> i128 {
buf_get_impl!(self, i128::from_ne_bytes);
}
/// Gets an unsigned n-byte integer from `self` in big-endian byte order. /// Gets an unsigned n-byte integer from `self` in big-endian byte order.
/// ///
/// The current position is advanced by `nbytes`. /// The current position is advanced by `nbytes`.
@@ -674,6 +883,34 @@ pub trait Buf {
buf_get_impl!(le => self, u64, nbytes); buf_get_impl!(le => self, u64, nbytes);
} }
/// Gets an unsigned n-byte integer from `self` in native-endian byte order.
///
/// The current position is advanced by `nbytes`.
///
/// # Examples
///
/// ```
/// use bytes::Buf;
///
/// let mut buf: &[u8] = match cfg!(target_endian = "big") {
/// true => b"\x01\x02\x03 hello",
/// false => b"\x03\x02\x01 hello",
/// };
/// assert_eq!(0x010203, buf.get_uint_ne(3));
/// ```
///
/// # Panics
///
/// This function panics if there is not enough remaining data in `self`, or
/// if `nbytes` is greater than 8.
fn get_uint_ne(&mut self, nbytes: usize) -> u64 {
if cfg!(target_endian = "big") {
self.get_uint(nbytes)
} else {
self.get_uint_le(nbytes)
}
}
/// Gets a signed n-byte integer from `self` in big-endian byte order. /// Gets a signed n-byte integer from `self` in big-endian byte order.
/// ///
/// The current position is advanced by `nbytes`. /// The current position is advanced by `nbytes`.
@@ -689,9 +926,10 @@ pub trait Buf {
/// ///
/// # Panics /// # Panics
/// ///
/// This function panics if there is not enough remaining data in `self`. /// This function panics if there is not enough remaining data in `self`, or
/// if `nbytes` is greater than 8.
fn get_int(&mut self, nbytes: usize) -> i64 { fn get_int(&mut self, nbytes: usize) -> i64 {
buf_get_impl!(be => self, i64, nbytes); sign_extend(self.get_uint(nbytes), nbytes)
} }
/// Gets a signed n-byte integer from `self` in little-endian byte order. /// Gets a signed n-byte integer from `self` in little-endian byte order.
@@ -709,9 +947,38 @@ pub trait Buf {
/// ///
/// # Panics /// # Panics
/// ///
/// This function panics if there is not enough remaining data in `self`. /// This function panics if there is not enough remaining data in `self`, or
/// if `nbytes` is greater than 8.
fn get_int_le(&mut self, nbytes: usize) -> i64 { fn get_int_le(&mut self, nbytes: usize) -> i64 {
buf_get_impl!(le => self, i64, nbytes); sign_extend(self.get_uint_le(nbytes), nbytes)
}
/// Gets a signed n-byte integer from `self` in native-endian byte order.
///
/// The current position is advanced by `nbytes`.
///
/// # Examples
///
/// ```
/// use bytes::Buf;
///
/// let mut buf: &[u8] = match cfg!(target_endian = "big") {
/// true => b"\x01\x02\x03 hello",
/// false => b"\x03\x02\x01 hello",
/// };
/// assert_eq!(0x010203, buf.get_int_ne(3));
/// ```
///
/// # Panics
///
/// This function panics if there is not enough remaining data in `self`, or
/// if `nbytes` is greater than 8.
fn get_int_ne(&mut self, nbytes: usize) -> i64 {
if cfg!(target_endian = "big") {
self.get_int(nbytes)
} else {
self.get_int_le(nbytes)
}
} }
/// Gets an IEEE754 single-precision (4 bytes) floating point number from /// Gets an IEEE754 single-precision (4 bytes) floating point number from
@@ -732,7 +999,7 @@ pub trait Buf {
/// ///
/// This function panics if there is not enough remaining data in `self`. /// This function panics if there is not enough remaining data in `self`.
fn get_f32(&mut self) -> f32 { fn get_f32(&mut self) -> f32 {
f32::from_bits(Self::get_u32(self)) f32::from_bits(self.get_u32())
} }
/// Gets an IEEE754 single-precision (4 bytes) floating point number from /// Gets an IEEE754 single-precision (4 bytes) floating point number from
@@ -753,7 +1020,31 @@ pub trait Buf {
/// ///
/// This function panics if there is not enough remaining data in `self`. /// This function panics if there is not enough remaining data in `self`.
fn get_f32_le(&mut self) -> f32 { fn get_f32_le(&mut self) -> f32 {
f32::from_bits(Self::get_u32_le(self)) f32::from_bits(self.get_u32_le())
}
/// Gets an IEEE754 single-precision (4 bytes) floating point number from
/// `self` in native-endian byte order.
///
/// The current position is advanced by 4.
///
/// # Examples
///
/// ```
/// use bytes::Buf;
///
/// let mut buf: &[u8] = match cfg!(target_endian = "big") {
/// true => b"\x3F\x99\x99\x9A hello",
/// false => b"\x9A\x99\x99\x3F hello",
/// };
/// assert_eq!(1.2f32, buf.get_f32_ne());
/// ```
///
/// # Panics
///
/// This function panics if there is not enough remaining data in `self`.
fn get_f32_ne(&mut self) -> f32 {
f32::from_bits(self.get_u32_ne())
} }
/// Gets an IEEE754 double-precision (8 bytes) floating point number from /// Gets an IEEE754 double-precision (8 bytes) floating point number from
@@ -774,7 +1065,7 @@ pub trait Buf {
/// ///
/// This function panics if there is not enough remaining data in `self`. /// This function panics if there is not enough remaining data in `self`.
fn get_f64(&mut self) -> f64 { fn get_f64(&mut self) -> f64 {
f64::from_bits(Self::get_u64(self)) f64::from_bits(self.get_u64())
} }
/// Gets an IEEE754 double-precision (8 bytes) floating point number from /// Gets an IEEE754 double-precision (8 bytes) floating point number from
@@ -795,7 +1086,31 @@ pub trait Buf {
/// ///
/// This function panics if there is not enough remaining data in `self`. /// This function panics if there is not enough remaining data in `self`.
fn get_f64_le(&mut self) -> f64 { fn get_f64_le(&mut self) -> f64 {
f64::from_bits(Self::get_u64_le(self)) f64::from_bits(self.get_u64_le())
}
/// Gets an IEEE754 double-precision (8 bytes) floating point number from
/// `self` in native-endian byte order.
///
/// The current position is advanced by 8.
///
/// # Examples
///
/// ```
/// use bytes::Buf;
///
/// let mut buf: &[u8] = match cfg!(target_endian = "big") {
/// true => b"\x3F\xF3\x33\x33\x33\x33\x33\x33 hello",
/// false => b"\x33\x33\x33\x33\x33\x33\xF3\x3F hello",
/// };
/// assert_eq!(1.2f64, buf.get_f64_ne());
/// ```
///
/// # Panics
///
/// This function panics if there is not enough remaining data in `self`.
fn get_f64_ne(&mut self) -> f64 {
f64::from_bits(self.get_u64_ne())
} }
/// Consumes `len` bytes inside self and returns new instance of `Bytes` /// Consumes `len` bytes inside self and returns new instance of `Bytes`
@@ -813,10 +1128,16 @@ pub trait Buf {
/// let bytes = (&b"hello world"[..]).copy_to_bytes(5); /// let bytes = (&b"hello world"[..]).copy_to_bytes(5);
/// assert_eq!(&bytes[..], &b"hello"[..]); /// assert_eq!(&bytes[..], &b"hello"[..]);
/// ``` /// ```
///
/// # Panics
///
/// This function panics if `len > self.remaining()`.
fn copy_to_bytes(&mut self, len: usize) -> crate::Bytes { fn copy_to_bytes(&mut self, len: usize) -> crate::Bytes {
use super::BufMut; use super::BufMut;
assert!(len <= self.remaining(), "`len` greater than remaining"); if self.remaining() < len {
panic_advance(len, self.remaining());
}
let mut ret = crate::BytesMut::with_capacity(len); let mut ret = crate::BytesMut::with_capacity(len);
ret.put(self.take(len)); ret.put(self.take(len));
@@ -897,6 +1218,7 @@ pub trait Buf {
/// assert_eq!(&dst[..11], &b"hello world"[..]); /// assert_eq!(&dst[..11], &b"hello world"[..]);
/// ``` /// ```
#[cfg(feature = "std")] #[cfg(feature = "std")]
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
fn reader(self) -> Reader<Self> fn reader(self) -> Reader<Self>
where where
Self: Sized, Self: Sized,
@@ -907,103 +1229,168 @@ pub trait Buf {
macro_rules! deref_forward_buf { macro_rules! deref_forward_buf {
() => { () => {
#[inline]
fn remaining(&self) -> usize { fn remaining(&self) -> usize {
(**self).remaining() (**self).remaining()
} }
#[inline]
fn chunk(&self) -> &[u8] { fn chunk(&self) -> &[u8] {
(**self).chunk() (**self).chunk()
} }
#[cfg(feature = "std")] #[cfg(feature = "std")]
#[inline]
fn chunks_vectored<'b>(&'b self, dst: &mut [IoSlice<'b>]) -> usize { fn chunks_vectored<'b>(&'b self, dst: &mut [IoSlice<'b>]) -> usize {
(**self).chunks_vectored(dst) (**self).chunks_vectored(dst)
} }
#[inline]
fn advance(&mut self, cnt: usize) { fn advance(&mut self, cnt: usize) {
(**self).advance(cnt) (**self).advance(cnt)
} }
#[inline]
fn has_remaining(&self) -> bool { fn has_remaining(&self) -> bool {
(**self).has_remaining() (**self).has_remaining()
} }
#[inline]
fn copy_to_slice(&mut self, dst: &mut [u8]) { fn copy_to_slice(&mut self, dst: &mut [u8]) {
(**self).copy_to_slice(dst) (**self).copy_to_slice(dst)
} }
#[inline]
fn get_u8(&mut self) -> u8 { fn get_u8(&mut self) -> u8 {
(**self).get_u8() (**self).get_u8()
} }
#[inline]
fn get_i8(&mut self) -> i8 { fn get_i8(&mut self) -> i8 {
(**self).get_i8() (**self).get_i8()
} }
#[inline]
fn get_u16(&mut self) -> u16 { fn get_u16(&mut self) -> u16 {
(**self).get_u16() (**self).get_u16()
} }
#[inline]
fn get_u16_le(&mut self) -> u16 { fn get_u16_le(&mut self) -> u16 {
(**self).get_u16_le() (**self).get_u16_le()
} }
#[inline]
fn get_u16_ne(&mut self) -> u16 {
(**self).get_u16_ne()
}
#[inline]
fn get_i16(&mut self) -> i16 { fn get_i16(&mut self) -> i16 {
(**self).get_i16() (**self).get_i16()
} }
#[inline]
fn get_i16_le(&mut self) -> i16 { fn get_i16_le(&mut self) -> i16 {
(**self).get_i16_le() (**self).get_i16_le()
} }
#[inline]
fn get_i16_ne(&mut self) -> i16 {
(**self).get_i16_ne()
}
#[inline]
fn get_u32(&mut self) -> u32 { fn get_u32(&mut self) -> u32 {
(**self).get_u32() (**self).get_u32()
} }
#[inline]
fn get_u32_le(&mut self) -> u32 { fn get_u32_le(&mut self) -> u32 {
(**self).get_u32_le() (**self).get_u32_le()
} }
#[inline]
fn get_u32_ne(&mut self) -> u32 {
(**self).get_u32_ne()
}
#[inline]
fn get_i32(&mut self) -> i32 { fn get_i32(&mut self) -> i32 {
(**self).get_i32() (**self).get_i32()
} }
#[inline]
fn get_i32_le(&mut self) -> i32 { fn get_i32_le(&mut self) -> i32 {
(**self).get_i32_le() (**self).get_i32_le()
} }
#[inline]
fn get_i32_ne(&mut self) -> i32 {
(**self).get_i32_ne()
}
#[inline]
fn get_u64(&mut self) -> u64 { fn get_u64(&mut self) -> u64 {
(**self).get_u64() (**self).get_u64()
} }
#[inline]
fn get_u64_le(&mut self) -> u64 { fn get_u64_le(&mut self) -> u64 {
(**self).get_u64_le() (**self).get_u64_le()
} }
#[inline]
fn get_u64_ne(&mut self) -> u64 {
(**self).get_u64_ne()
}
#[inline]
fn get_i64(&mut self) -> i64 { fn get_i64(&mut self) -> i64 {
(**self).get_i64() (**self).get_i64()
} }
#[inline]
fn get_i64_le(&mut self) -> i64 { fn get_i64_le(&mut self) -> i64 {
(**self).get_i64_le() (**self).get_i64_le()
} }
#[inline]
fn get_i64_ne(&mut self) -> i64 {
(**self).get_i64_ne()
}
#[inline]
fn get_uint(&mut self, nbytes: usize) -> u64 { fn get_uint(&mut self, nbytes: usize) -> u64 {
(**self).get_uint(nbytes) (**self).get_uint(nbytes)
} }
#[inline]
fn get_uint_le(&mut self, nbytes: usize) -> u64 { fn get_uint_le(&mut self, nbytes: usize) -> u64 {
(**self).get_uint_le(nbytes) (**self).get_uint_le(nbytes)
} }
#[inline]
fn get_uint_ne(&mut self, nbytes: usize) -> u64 {
(**self).get_uint_ne(nbytes)
}
#[inline]
fn get_int(&mut self, nbytes: usize) -> i64 { fn get_int(&mut self, nbytes: usize) -> i64 {
(**self).get_int(nbytes) (**self).get_int(nbytes)
} }
#[inline]
fn get_int_le(&mut self, nbytes: usize) -> i64 { fn get_int_le(&mut self, nbytes: usize) -> i64 {
(**self).get_int_le(nbytes) (**self).get_int_le(nbytes)
} }
#[inline]
fn get_int_ne(&mut self, nbytes: usize) -> i64 {
(**self).get_int_ne(nbytes)
}
#[inline]
fn copy_to_bytes(&mut self, len: usize) -> crate::Bytes { fn copy_to_bytes(&mut self, len: usize) -> crate::Bytes {
(**self).copy_to_bytes(len) (**self).copy_to_bytes(len)
} }
@@ -1031,41 +1418,52 @@ impl Buf for &[u8] {
#[inline] #[inline]
fn advance(&mut self, cnt: usize) { fn advance(&mut self, cnt: usize) {
if self.len() < cnt {
panic_advance(cnt, self.len());
}
*self = &self[cnt..]; *self = &self[cnt..];
} }
#[inline]
fn copy_to_slice(&mut self, dst: &mut [u8]) {
if self.len() < dst.len() {
panic_advance(dst.len(), self.len());
}
dst.copy_from_slice(&self[..dst.len()]);
self.advance(dst.len());
}
} }
#[cfg(feature = "std")] #[cfg(feature = "std")]
impl<T: AsRef<[u8]>> Buf for std::io::Cursor<T> { impl<T: AsRef<[u8]>> Buf for std::io::Cursor<T> {
#[inline]
fn remaining(&self) -> usize { fn remaining(&self) -> usize {
let len = self.get_ref().as_ref().len(); saturating_sub_usize_u64(self.get_ref().as_ref().len(), self.position())
let pos = self.position();
if pos >= len as u64 {
return 0;
}
len - pos as usize
} }
#[inline]
fn chunk(&self) -> &[u8] { fn chunk(&self) -> &[u8] {
let slice = self.get_ref().as_ref();
let pos = min_u64_usize(self.position(), slice.len());
&slice[pos..]
}
#[inline]
fn advance(&mut self, cnt: usize) {
let len = self.get_ref().as_ref().len(); let len = self.get_ref().as_ref().len();
let pos = self.position(); let pos = self.position();
if pos >= len as u64 { // We intentionally allow `cnt == 0` here even if `pos > len`.
return &[]; let max_cnt = saturating_sub_usize_u64(len, pos);
if cnt > max_cnt {
panic_advance(cnt, max_cnt);
} }
&self.get_ref().as_ref()[pos as usize..] // This will not overflow because either `cnt == 0` or the sum is not
} // greater than `len`.
self.set_position(pos + cnt as u64);
fn advance(&mut self, cnt: usize) {
let pos = (self.position() as usize)
.checked_add(cnt)
.expect("overflow");
assert!(pos <= self.get_ref().as_ref().len());
self.set_position(pos as u64);
} }
} }
+573 -74
View File
File diff suppressed because it is too large Load Diff
+3 -6
View File
@@ -25,9 +25,7 @@ use std::io::IoSlice;
/// assert_eq!(full[..], b"hello world"[..]); /// assert_eq!(full[..], b"hello world"[..]);
/// ``` /// ```
/// ///
/// [`Buf::chain`]: trait.Buf.html#method.chain /// [`Buf::chain`]: Buf::chain
/// [`Buf`]: trait.Buf.html
/// [`BufMut`]: trait.BufMut.html
#[derive(Debug)] #[derive(Debug)]
pub struct Chain<T, U> { pub struct Chain<T, U> {
a: T, a: T,
@@ -135,7 +133,7 @@ where
U: Buf, U: Buf,
{ {
fn remaining(&self) -> usize { fn remaining(&self) -> usize {
self.a.remaining().checked_add(self.b.remaining()).unwrap() self.a.remaining().saturating_add(self.b.remaining())
} }
fn chunk(&self) -> &[u8] { fn chunk(&self) -> &[u8] {
@@ -198,8 +196,7 @@ where
fn remaining_mut(&self) -> usize { fn remaining_mut(&self) -> usize {
self.a self.a
.remaining_mut() .remaining_mut()
.checked_add(self.b.remaining_mut()) .saturating_add(self.b.remaining_mut())
.unwrap()
} }
fn chunk_mut(&mut self) -> &mut UninitSlice { fn chunk_mut(&mut self) -> &mut UninitSlice {
+1 -6
View File
@@ -2,8 +2,6 @@ use crate::Buf;
/// Iterator over the bytes contained by the buffer. /// Iterator over the bytes contained by the buffer.
/// ///
/// This struct is created by the [`iter`] method on [`Buf`].
///
/// # Examples /// # Examples
/// ///
/// Basic usage: /// Basic usage:
@@ -19,9 +17,6 @@ use crate::Buf;
/// assert_eq!(iter.next(), Some(b'c')); /// assert_eq!(iter.next(), Some(b'c'));
/// assert_eq!(iter.next(), None); /// assert_eq!(iter.next(), None);
/// ``` /// ```
///
/// [`iter`]: trait.Buf.html#method.iter
/// [`Buf`]: trait.Buf.html
#[derive(Debug)] #[derive(Debug)]
pub struct IntoIter<T> { pub struct IntoIter<T> {
inner: T, inner: T,
@@ -43,7 +38,7 @@ impl<T> IntoIter<T> {
/// assert_eq!(iter.next(), Some(b'c')); /// assert_eq!(iter.next(), Some(b'c'));
/// assert_eq!(iter.next(), None); /// assert_eq!(iter.next(), None);
/// ``` /// ```
pub(crate) fn new(inner: T) -> IntoIter<T> { pub fn new(inner: T) -> IntoIter<T> {
IntoIter { inner } IntoIter { inner }
} }
-2
View File
@@ -13,8 +13,6 @@
//! See [`Buf`] and [`BufMut`] for more details. //! See [`Buf`] and [`BufMut`] for more details.
//! //!
//! [rope]: https://en.wikipedia.org/wiki/Rope_(data_structure) //! [rope]: https://en.wikipedia.org/wiki/Rope_(data_structure)
//! [`Buf`]: trait.Buf.html
//! [`BufMut`]: trait.BufMut.html
mod buf_impl; mod buf_impl;
mod buf_mut; mod buf_mut;
+1 -1
View File
@@ -5,7 +5,7 @@ use std::{cmp, io};
/// A `Buf` adapter which implements `io::Read` for the inner value. /// A `Buf` adapter which implements `io::Read` for the inner value.
/// ///
/// This struct is generally created by calling `reader()` on `Buf`. See /// This struct is generally created by calling `reader()` on `Buf`. See
/// documentation of [`reader()`](trait.Buf.html#method.reader) for more /// documentation of [`reader()`](Buf::reader) for more
/// details. /// details.
#[derive(Debug)] #[derive(Debug)]
pub struct Reader<B> { pub struct Reader<B> {
+1 -1
View File
@@ -5,7 +5,7 @@ use core::cmp;
/// A `Buf` adapter which limits the bytes read from an underlying buffer. /// A `Buf` adapter which limits the bytes read from an underlying buffer.
/// ///
/// This struct is generally created by calling `take()` on `Buf`. See /// This struct is generally created by calling `take()` on `Buf`. See
/// documentation of [`take()`](trait.Buf.html#method.take) for more details. /// documentation of [`take()`](Buf::take) for more details.
#[derive(Debug)] #[derive(Debug)]
pub struct Take<T> { pub struct Take<T> {
inner: T, inner: T,
+80 -6
View File
@@ -22,6 +22,44 @@ use core::ops::{
pub struct UninitSlice([MaybeUninit<u8>]); pub struct UninitSlice([MaybeUninit<u8>]);
impl UninitSlice { 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. /// Create a `&mut UninitSlice` from a pointer and a length.
/// ///
/// # Safety /// # Safety
@@ -44,7 +82,7 @@ impl UninitSlice {
pub unsafe fn from_raw_parts_mut<'a>(ptr: *mut u8, len: usize) -> &'a mut UninitSlice { pub unsafe fn from_raw_parts_mut<'a>(ptr: *mut u8, len: usize) -> &'a mut UninitSlice {
let maybe_init: &mut [MaybeUninit<u8>] = let maybe_init: &mut [MaybeUninit<u8>] =
core::slice::from_raw_parts_mut(ptr as *mut _, len); core::slice::from_raw_parts_mut(ptr as *mut _, len);
&mut *(maybe_init as *mut [MaybeUninit<u8>] as *mut UninitSlice) Self::uninit(maybe_init)
} }
/// Write a single byte at the specified offset. /// Write a single byte at the specified offset.
@@ -72,7 +110,7 @@ impl UninitSlice {
unsafe { self[index..].as_mut_ptr().write(byte) } unsafe { self[index..].as_mut_ptr().write(byte) }
} }
/// Copies bytes from `src` into `self`. /// Copies bytes from `src` into `self`.
/// ///
/// The length of `src` must be the same as `self`. /// The length of `src` must be the same as `self`.
/// ///
@@ -124,6 +162,32 @@ impl UninitSlice {
self.0.as_mut_ptr() as *mut _ 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. /// Returns the number of bytes in the slice.
/// ///
/// # Examples /// # Examples
@@ -149,6 +213,18 @@ impl fmt::Debug for UninitSlice {
} }
} }
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 { macro_rules! impl_index {
($($t:ty),*) => { ($($t:ty),*) => {
$( $(
@@ -157,16 +233,14 @@ macro_rules! impl_index {
#[inline] #[inline]
fn index(&self, index: $t) -> &UninitSlice { fn index(&self, index: $t) -> &UninitSlice {
let maybe_uninit: &[MaybeUninit<u8>] = &self.0[index]; UninitSlice::uninit_ref(&self.0[index])
unsafe { &*(maybe_uninit as *const [MaybeUninit<u8>] as *const UninitSlice) }
} }
} }
impl IndexMut<$t> for UninitSlice { impl IndexMut<$t> for UninitSlice {
#[inline] #[inline]
fn index_mut(&mut self, index: $t) -> &mut UninitSlice { fn index_mut(&mut self, index: $t) -> &mut UninitSlice {
let maybe_uninit: &mut [MaybeUninit<u8>] = &mut self.0[index]; UninitSlice::uninit(&mut self.0[index])
unsafe { &mut *(maybe_uninit as *mut [MaybeUninit<u8>] as *mut UninitSlice) }
} }
} }
)* )*
+2 -2
View File
@@ -5,7 +5,7 @@ use std::{cmp, io};
/// A `BufMut` adapter which implements `io::Write` for the inner value. /// A `BufMut` adapter which implements `io::Write` for the inner value.
/// ///
/// This struct is generally created by calling `writer()` on `BufMut`. See /// This struct is generally created by calling `writer()` on `BufMut`. See
/// documentation of [`writer()`](trait.BufMut.html#method.writer) for more /// documentation of [`writer()`](BufMut::writer) for more
/// details. /// details.
#[derive(Debug)] #[derive(Debug)]
pub struct Writer<B> { pub struct Writer<B> {
@@ -78,7 +78,7 @@ impl<B: BufMut + Sized> io::Write for Writer<B> {
fn write(&mut self, src: &[u8]) -> io::Result<usize> { fn write(&mut self, src: &[u8]) -> io::Result<usize> {
let n = cmp::min(self.buf.remaining_mut(), src.len()); let n = cmp::min(self.buf.remaining_mut(), src.len());
self.buf.put(&src[0..n]); self.buf.put_slice(&src[..n]);
Ok(n) Ok(n)
} }
+622 -90
View File
File diff suppressed because it is too large Load Diff
+515 -195
View File
File diff suppressed because it is too large Load Diff
+3 -12
View File
@@ -25,7 +25,7 @@ impl Debug for BytesRef<'_> {
} else if b == b'\0' { } else if b == b'\0' {
write!(f, "\\0")?; write!(f, "\\0")?;
// ASCII printable // ASCII printable
} else if b >= 0x20 && b < 0x7f { } else if (0x20..0x7f).contains(&b) {
write!(f, "{}", b as char)?; write!(f, "{}", b as char)?;
} else { } else {
write!(f, "\\x{:02x}", b)?; write!(f, "\\x{:02x}", b)?;
@@ -36,14 +36,5 @@ impl Debug for BytesRef<'_> {
} }
} }
impl Debug for Bytes { fmt_impl!(Debug, Bytes);
fn fmt(&self, f: &mut Formatter<'_>) -> Result { fmt_impl!(Debug, BytesMut);
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)
}
}
+4 -14
View File
@@ -21,17 +21,7 @@ impl UpperHex for BytesRef<'_> {
} }
} }
macro_rules! hex_impl { fmt_impl!(LowerHex, Bytes);
($tr:ident, $ty:ty) => { fmt_impl!(LowerHex, BytesMut);
impl $tr for $ty { fmt_impl!(UpperHex, Bytes);
fn fmt(&self, f: &mut Formatter<'_>) -> Result { fmt_impl!(UpperHex, BytesMut);
$tr::fmt(&BytesRef(self.as_ref()), f)
}
}
};
}
hex_impl!(LowerHex, Bytes);
hex_impl!(LowerHex, BytesMut);
hex_impl!(UpperHex, Bytes);
hex_impl!(UpperHex, BytesMut);
+10
View File
@@ -1,3 +1,13 @@
macro_rules! fmt_impl {
($tr:ident, $ty:ty) => {
impl $tr for $ty {
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
$tr::fmt(&BytesRef(self.as_ref()), f)
}
}
};
}
mod debug; mod debug;
mod hex; mod hex;
+57 -8
View File
@@ -1,19 +1,18 @@
#![allow(unknown_lints, unexpected_cfgs)]
#![warn(missing_docs, missing_debug_implementations, rust_2018_idioms)] #![warn(missing_docs, missing_debug_implementations, rust_2018_idioms)]
#![doc(test( #![doc(test(
no_crate_inject, no_crate_inject,
attr(deny(warnings, rust_2018_idioms), allow(dead_code, unused_variables)) attr(deny(warnings, rust_2018_idioms), allow(dead_code, unused_variables))
))] ))]
#![no_std] #![no_std]
#![cfg_attr(docsrs, feature(doc_cfg))]
//! Provides abstractions for working with bytes. //! Provides abstractions for working with bytes.
//! //!
//! The `bytes` crate provides an efficient byte buffer structure //! The `bytes` crate provides an efficient byte buffer structure
//! ([`Bytes`](struct.Bytes.html)) and traits for working with buffer //! ([`Bytes`]) and traits for working with buffer
//! implementations ([`Buf`], [`BufMut`]). //! implementations ([`Buf`], [`BufMut`]).
//! //!
//! [`Buf`]: trait.Buf.html
//! [`BufMut`]: trait.BufMut.html
//!
//! # `Bytes` //! # `Bytes`
//! //!
//! `Bytes` is an efficient container for storing and operating on contiguous //! `Bytes` is an efficient container for storing and operating on contiguous
@@ -51,9 +50,7 @@
//! `a` and `b` will share the underlying buffer and maintain indices tracking //! `a` and `b` will share the underlying buffer and maintain indices tracking
//! the view into the buffer represented by the handle. //! the view into the buffer represented by the handle.
//! //!
//! See the [struct docs] for more details. //! See the [struct docs](`Bytes`) for more details.
//!
//! [struct docs]: struct.Bytes.html
//! //!
//! # `Buf`, `BufMut` //! # `Buf`, `BufMut`
//! //!
@@ -69,7 +66,7 @@
//! ## Relation with `Read` and `Write` //! ## Relation with `Read` and `Write`
//! //!
//! At first glance, it may seem that `Buf` and `BufMut` overlap in //! At first glance, it may seem that `Buf` and `BufMut` overlap in
//! functionality with `std::io::Read` and `std::io::Write`. However, they //! functionality with [`std::io::Read`] and [`std::io::Write`]. However, they
//! serve different purposes. A buffer is the value that is provided as an //! 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 //! argument to `Read::read` and `Write::write`. `Read` and `Write` may then
//! perform a syscall, which has the potential of failing. Operations on `Buf` //! perform a syscall, which has the potential of failing. Operations on `Buf`
@@ -114,3 +111,55 @@ fn abort() -> ! {
panic!("abort"); panic!("abort");
} }
} }
#[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,
}
}
#[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,
}
}
/// 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
);
}
#[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
);
}
/// 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
}
+2 -2
View File
@@ -1,7 +1,7 @@
#[cfg(not(all(test, loom)))] #[cfg(not(all(test, loom)))]
pub(crate) mod sync { pub(crate) mod sync {
pub(crate) mod atomic { pub(crate) mod atomic {
pub(crate) use core::sync::atomic::{fence, AtomicPtr, AtomicUsize, Ordering}; pub(crate) use core::sync::atomic::{AtomicPtr, AtomicUsize, Ordering};
pub(crate) trait AtomicMut<T> { pub(crate) trait AtomicMut<T> {
fn with_mut<F, R>(&mut self, f: F) -> R fn with_mut<F, R>(&mut self, f: F) -> R
@@ -23,7 +23,7 @@ pub(crate) mod sync {
#[cfg(all(test, loom))] #[cfg(all(test, loom))]
pub(crate) mod sync { pub(crate) mod sync {
pub(crate) mod atomic { pub(crate) mod atomic {
pub(crate) use loom::sync::atomic::{fence, AtomicPtr, AtomicUsize, Ordering}; pub(crate) use loom::sync::atomic::{AtomicPtr, AtomicUsize, Ordering};
pub(crate) trait AtomicMut<T> {} pub(crate) trait AtomicMut<T> {}
} }
+14
View File
@@ -36,6 +36,19 @@ fn test_get_u16() {
assert_eq!(0x5421, buf.get_u16_le()); 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] #[test]
#[should_panic] #[should_panic]
fn test_get_u16_buffer_underflow() { fn test_get_u16_buffer_underflow() {
@@ -72,6 +85,7 @@ fn test_vec_deque() {
assert_eq!(b"world piece", &out[..]); assert_eq!(b"world piece", &out[..]);
} }
#[allow(unused_allocation)] // This is intentional.
#[test] #[test]
fn test_deref_buf_forwards() { fn test_deref_buf_forwards() {
struct Special; struct Special;
+113 -15
View File
@@ -3,6 +3,7 @@
use bytes::buf::UninitSlice; use bytes::buf::UninitSlice;
use bytes::{BufMut, BytesMut}; use bytes::{BufMut, BytesMut};
use core::fmt::Write; use core::fmt::Write;
use core::mem::MaybeUninit;
use core::usize; use core::usize;
#[test] #[test]
@@ -82,7 +83,7 @@ fn test_put_int_le_nbytes_overflow() {
} }
#[test] #[test]
#[should_panic(expected = "cannot advance")] #[should_panic(expected = "advance out of bounds: the len is 8 but advancing by 12")]
fn test_vec_advance_mut() { fn test_vec_advance_mut() {
// Verify fix for #354 // Verify fix for #354
let mut buf = Vec::with_capacity(8); let mut buf = Vec::with_capacity(8);
@@ -101,26 +102,123 @@ fn test_clone() {
assert!(buf != buf2); assert!(buf != buf2);
} }
#[test] fn do_test_slice_small<T: ?Sized>(make: impl Fn(&mut [u8]) -> &mut T)
fn test_mut_slice() { where
let mut v = vec![0, 0, 0, 0]; for<'r> &'r mut T: BufMut,
let mut s = &mut v[..]; {
s.put_u32(42); let mut buf = [b'X'; 8];
assert_eq!(s.len(), 0); let mut slice = make(&mut buf[..]);
assert_eq!(&v, &[0, 0, 0, 42]); 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] #[test]
fn test_slice_put_bytes() { fn test_slice_buf_mut_small() {
let mut v = [0, 0, 0, 0]; do_test_slice_small(|x| x);
let mut s = &mut v[..];
s.put_u8(17);
s.put_bytes(19, 2);
assert_eq!(1, s.remaining_mut());
assert_eq!(&[17, 19, 19, 0], &v[..]);
} }
#[test]
fn test_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] #[test]
fn test_deref_bufmut_forwards() { fn test_deref_bufmut_forwards() {
struct Special; struct Special;
+727 -98
View File
@@ -1,11 +1,14 @@
#![warn(rust_2018_idioms)] #![warn(rust_2018_idioms)]
use bytes::{Buf, BufMut, Bytes, BytesMut}; use bytes::{Buf, BufMut, Bytes, BytesMut};
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc;
use std::panic::{self, AssertUnwindSafe};
use std::usize; use std::usize;
const LONG: &'static [u8] = b"mary had a little lamb, little lamb, little lamb"; const LONG: &[u8] = b"mary had a little lamb, little lamb, little lamb";
const SHORT: &'static [u8] = b"hello world"; const SHORT: &[u8] = b"hello world";
fn is_sync<T: Sync>() {} fn is_sync<T: Sync>() {}
fn is_send<T: Send>() {} fn is_send<T: Send>() {}
@@ -411,8 +414,8 @@ fn freeze_after_split_off() {
fn fns_defined_for_bytes_mut() { fn fns_defined_for_bytes_mut() {
let mut bytes = BytesMut::from(&b"hello world"[..]); let mut bytes = BytesMut::from(&b"hello world"[..]);
bytes.as_ptr(); let _ = bytes.as_ptr();
bytes.as_mut_ptr(); let _ = bytes.as_mut_ptr();
// Iterator // Iterator
let v: Vec<u8> = bytes.as_ref().iter().cloned().collect(); let v: Vec<u8> = bytes.as_ref().iter().cloned().collect();
@@ -443,7 +446,7 @@ fn reserve_growth() {
let _ = bytes.split(); let _ = bytes.split();
bytes.reserve(65); bytes.reserve(65);
assert_eq!(bytes.capacity(), 128); assert_eq!(bytes.capacity(), 117);
} }
#[test] #[test]
@@ -515,6 +518,34 @@ fn reserve_in_arc_unique_doubles() {
assert_eq!(2000, bytes.capacity()); assert_eq!(2000, bytes.capacity());
} }
#[test]
fn reserve_in_arc_unique_does_not_overallocate_after_split() {
let mut bytes = BytesMut::from(LONG);
let orig_capacity = bytes.capacity();
drop(bytes.split_off(LONG.len() / 2));
// now bytes is Arc and refcount == 1
let new_capacity = bytes.capacity();
bytes.reserve(orig_capacity - new_capacity);
assert_eq!(bytes.capacity(), orig_capacity);
}
#[test]
fn reserve_in_arc_unique_does_not_overallocate_after_multiple_splits() {
let mut bytes = BytesMut::from(LONG);
let orig_capacity = bytes.capacity();
for _ in 0..10 {
drop(bytes.split_off(LONG.len() / 2));
// now bytes is Arc and refcount == 1
let new_capacity = bytes.capacity();
bytes.reserve(orig_capacity - new_capacity);
}
assert_eq!(bytes.capacity(), orig_capacity);
}
#[test] #[test]
fn reserve_in_arc_nonunique_does_not_overallocate() { fn reserve_in_arc_nonunique_does_not_overallocate() {
let mut bytes = BytesMut::with_capacity(1000); let mut bytes = BytesMut::with_capacity(1000);
@@ -527,6 +558,25 @@ fn reserve_in_arc_nonunique_does_not_overallocate() {
assert_eq!(2001, bytes.capacity()); assert_eq!(2001, bytes.capacity());
} }
/// This function tests `BytesMut::reserve_inner`, where `BytesMut` holds
/// a unique reference to the shared vector and decide to reuse it
/// by reallocating the `Vec`.
#[test]
fn reserve_shared_reuse() {
let mut bytes = BytesMut::with_capacity(1000);
bytes.put_slice(b"Hello, World!");
drop(bytes.split());
bytes.put_slice(b"!123ex123,sadchELLO,_wORLD!");
// Use split_off so that v.capacity() - self.cap != off
drop(bytes.split_off(9));
assert_eq!(&*bytes, b"!123ex123");
bytes.reserve(2000);
assert_eq!(&*bytes, b"!123ex123");
assert_eq!(bytes.capacity(), 2009);
}
#[test] #[test]
fn extend_mut() { fn extend_mut() {
let mut bytes = BytesMut::with_capacity(0); let mut bytes = BytesMut::with_capacity(0);
@@ -544,6 +594,35 @@ fn extend_from_slice_mut() {
} }
} }
#[test]
fn extend_mut_from_bytes() {
let mut bytes = BytesMut::with_capacity(0);
bytes.extend([Bytes::from(LONG)]);
assert_eq!(*bytes, LONG[..]);
}
#[test]
fn extend_past_lower_limit_of_size_hint() {
// See https://github.com/tokio-rs/bytes/pull/674#pullrequestreview-1913035700
struct Iter<I>(I);
impl<I: Iterator<Item = u8>> Iterator for Iter<I> {
type Item = u8;
fn next(&mut self) -> Option<Self::Item> {
self.0.next()
}
fn size_hint(&self) -> (usize, Option<usize>) {
(5, None)
}
}
let mut bytes = BytesMut::with_capacity(5);
bytes.extend(Iter(std::iter::repeat(0).take(10)));
assert_eq!(bytes.len(), 10);
}
#[test] #[test]
fn extend_mut_without_size_hint() { fn extend_mut_without_size_hint() {
let mut bytes = BytesMut::with_capacity(0); let mut bytes = BytesMut::with_capacity(0);
@@ -600,6 +679,43 @@ fn advance_bytes_mut() {
assert_eq!(a, b"d zomg wat wat"[..]); assert_eq!(a, b"d zomg wat wat"[..]);
} }
// Ensures BytesMut::advance reduces always capacity
//
// See https://github.com/tokio-rs/bytes/issues/725
#[test]
fn advance_bytes_mut_remaining_capacity() {
// reduce the search space under miri
let max_capacity = if cfg!(miri) { 16 } else { 256 };
for capacity in 0..=max_capacity {
for len in 0..=capacity {
for advance in 0..=len {
eprintln!("testing capacity={capacity}, len={len}, advance={advance}");
let mut buf = BytesMut::with_capacity(capacity);
buf.resize(len, 42);
assert_eq!(buf.len(), len, "resize should write `len` bytes");
assert_eq!(
buf.remaining(),
len,
"Buf::remaining() should equal BytesMut::len"
);
buf.advance(advance);
assert_eq!(
buf.remaining(),
len - advance,
"Buf::advance should reduce the remaining len"
);
assert_eq!(
buf.capacity(),
capacity - advance,
"Buf::advance should reduce the remaining capacity"
);
}
}
}
}
#[test] #[test]
#[should_panic] #[should_panic]
fn advance_past_len() { fn advance_past_len() {
@@ -656,97 +772,6 @@ fn partial_eq_bytesmut() {
assert!(bytesmut != bytes2); assert!(bytesmut != bytes2);
} }
/*
#[test]
fn bytes_unsplit_basic() {
let buf = Bytes::from(&b"aaabbbcccddd"[..]);
let splitted = buf.split_off(6);
assert_eq!(b"aaabbb", &buf[..]);
assert_eq!(b"cccddd", &splitted[..]);
buf.unsplit(splitted);
assert_eq!(b"aaabbbcccddd", &buf[..]);
}
#[test]
fn bytes_unsplit_empty_other() {
let buf = Bytes::from(&b"aaabbbcccddd"[..]);
// empty other
let other = Bytes::new();
buf.unsplit(other);
assert_eq!(b"aaabbbcccddd", &buf[..]);
}
#[test]
fn bytes_unsplit_empty_self() {
// empty self
let mut buf = Bytes::new();
let mut other = Bytes::with_capacity(64);
other.extend_from_slice(b"aaabbbcccddd");
buf.unsplit(other);
assert_eq!(b"aaabbbcccddd", &buf[..]);
}
#[test]
fn bytes_unsplit_arc_different() {
let mut buf = Bytes::with_capacity(64);
buf.extend_from_slice(b"aaaabbbbeeee");
buf.split_off(8); //arc
let mut buf2 = Bytes::with_capacity(64);
buf2.extend_from_slice(b"ccccddddeeee");
buf2.split_off(8); //arc
buf.unsplit(buf2);
assert_eq!(b"aaaabbbbccccdddd", &buf[..]);
}
#[test]
fn bytes_unsplit_arc_non_contiguous() {
let mut buf = Bytes::with_capacity(64);
buf.extend_from_slice(b"aaaabbbbeeeeccccdddd");
let mut buf2 = buf.split_off(8); //arc
let buf3 = buf2.split_off(4); //arc
buf.unsplit(buf3);
assert_eq!(b"aaaabbbbccccdddd", &buf[..]);
}
#[test]
fn bytes_unsplit_two_split_offs() {
let mut buf = Bytes::with_capacity(64);
buf.extend_from_slice(b"aaaabbbbccccdddd");
let mut buf2 = buf.split_off(8); //arc
let buf3 = buf2.split_off(4); //arc
buf2.unsplit(buf3);
buf.unsplit(buf2);
assert_eq!(b"aaaabbbbccccdddd", &buf[..]);
}
#[test]
fn bytes_unsplit_overlapping_references() {
let mut buf = Bytes::with_capacity(64);
buf.extend_from_slice(b"abcdefghijklmnopqrstuvwxyz");
let mut buf0010 = buf.slice(0..10);
let buf1020 = buf.slice(10..20);
let buf0515 = buf.slice(5..15);
buf0010.unsplit(buf1020);
assert_eq!(b"abcdefghijklmnopqrst", &buf0010[..]);
assert_eq!(b"fghijklmno", &buf0515[..]);
}
*/
#[test] #[test]
fn bytes_mut_unsplit_basic() { fn bytes_mut_unsplit_basic() {
let mut buf = BytesMut::with_capacity(64); let mut buf = BytesMut::with_capacity(64);
@@ -874,7 +899,7 @@ fn from_iter_no_size_hint() {
fn test_slice_ref(bytes: &Bytes, start: usize, end: usize, expected: &[u8]) { fn test_slice_ref(bytes: &Bytes, start: usize, end: usize, expected: &[u8]) {
let slice = &(bytes.as_ref()[start..end]); let slice = &(bytes.as_ref()[start..end]);
let sub = bytes.slice_ref(&slice); let sub = bytes.slice_ref(slice);
assert_eq!(&sub[..], expected); assert_eq!(&sub[..], expected);
} }
@@ -894,7 +919,7 @@ fn slice_ref_empty() {
let bytes = Bytes::from(&b""[..]); let bytes = Bytes::from(&b""[..]);
let slice = &(bytes.as_ref()[0..0]); let slice = &(bytes.as_ref()[0..0]);
let sub = bytes.slice_ref(&slice); let sub = bytes.slice_ref(slice);
assert_eq!(&sub[..], b""); assert_eq!(&sub[..], b"");
} }
@@ -1002,3 +1027,607 @@ fn box_slice_empty() {
let b = Bytes::from(empty); let b = Bytes::from(empty);
assert!(b.is_empty()); assert!(b.is_empty());
} }
#[test]
fn bytes_into_vec() {
// Test kind == KIND_VEC
let content = b"helloworld";
let mut bytes = BytesMut::new();
bytes.put_slice(content);
let vec: Vec<u8> = bytes.into();
assert_eq!(&vec, content);
// Test kind == KIND_ARC, shared.is_unique() == True
let mut bytes = BytesMut::new();
bytes.put_slice(b"abcdewe23");
bytes.put_slice(content);
// Overwrite the bytes to make sure only one reference to the underlying
// Vec exists.
bytes = bytes.split_off(9);
let vec: Vec<u8> = bytes.into();
assert_eq!(&vec, content);
// Test kind == KIND_ARC, shared.is_unique() == False
let prefix = b"abcdewe23";
let mut bytes = BytesMut::new();
bytes.put_slice(prefix);
bytes.put_slice(content);
let vec: Vec<u8> = bytes.split_off(prefix.len()).into();
assert_eq!(&vec, content);
let vec: Vec<u8> = bytes.into();
assert_eq!(&vec, prefix);
}
#[test]
fn test_bytes_into_vec() {
// Test STATIC_VTABLE.to_vec
let bs = b"1b23exfcz3r";
let vec: Vec<u8> = Bytes::from_static(bs).into();
assert_eq!(&*vec, bs);
// Test bytes_mut.SHARED_VTABLE.to_vec impl
eprintln!("1");
let mut bytes_mut: BytesMut = bs[..].into();
// Set kind to KIND_ARC so that after freeze, Bytes will use bytes_mut.SHARED_VTABLE
eprintln!("2");
drop(bytes_mut.split_off(bs.len()));
eprintln!("3");
let b1 = bytes_mut.freeze();
eprintln!("4");
let b2 = b1.clone();
eprintln!("{:#?}", (&*b1).as_ptr());
// shared.is_unique() = False
eprintln!("5");
assert_eq!(&*Vec::from(b2), bs);
// shared.is_unique() = True
eprintln!("6");
assert_eq!(&*Vec::from(b1), bs);
// Test bytes_mut.SHARED_VTABLE.to_vec impl where offset != 0
let mut bytes_mut1: BytesMut = bs[..].into();
let bytes_mut2 = bytes_mut1.split_off(9);
let b1 = bytes_mut1.freeze();
let b2 = bytes_mut2.freeze();
assert_eq!(Vec::from(b2), bs[9..]);
assert_eq!(Vec::from(b1), bs[..9]);
}
#[test]
fn test_bytes_into_vec_promotable_even() {
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_bytes_vec_conversion() {
let mut vec = Vec::with_capacity(10);
vec.extend(b"abcdefg");
let b = Bytes::from(vec);
let v = Vec::from(b);
assert_eq!(v.len(), 7);
assert_eq!(v.capacity(), 10);
let mut b = Bytes::from(v);
b.advance(1);
let v = Vec::from(b);
assert_eq!(v.len(), 6);
assert_eq!(v.capacity(), 10);
assert_eq!(v.as_slice(), b"bcdefg");
}
#[test]
fn test_bytes_mut_conversion() {
let mut b1 = BytesMut::with_capacity(10);
b1.extend(b"abcdefg");
let b2 = Bytes::from(b1);
let v = Vec::from(b2);
assert_eq!(v.len(), 7);
assert_eq!(v.capacity(), 10);
let mut b = Bytes::from(v);
b.advance(1);
let v = Vec::from(b);
assert_eq!(v.len(), 6);
assert_eq!(v.capacity(), 10);
assert_eq!(v.as_slice(), b"bcdefg");
}
#[test]
fn test_bytes_capacity_len() {
for cap in 0..100 {
for len in 0..=cap {
let mut v = Vec::with_capacity(cap);
v.resize(len, 0);
let _ = Bytes::from(v);
}
}
}
#[test]
fn static_is_unique() {
let b = Bytes::from_static(LONG);
assert!(!b.is_unique());
}
#[test]
fn vec_is_unique() {
let v: Vec<u8> = LONG.to_vec();
let b = Bytes::from(v);
assert!(b.is_unique());
}
#[test]
fn arc_is_unique() {
let v: Vec<u8> = LONG.to_vec();
let b = Bytes::from(v);
let c = b.clone();
assert!(!b.is_unique());
drop(c);
assert!(b.is_unique());
}
#[test]
fn shared_is_unique() {
let v: Vec<u8> = LONG.to_vec();
let b = Bytes::from(v);
let c = b.clone();
assert!(!c.is_unique());
drop(b);
assert!(c.is_unique());
}
#[test]
fn mut_shared_is_unique() {
let mut b = BytesMut::from(LONG);
let c = b.split().freeze();
assert!(!c.is_unique());
drop(b);
assert!(c.is_unique());
}
#[test]
fn test_bytesmut_from_bytes_static() {
let bs = b"1b23exfcz3r";
// Test STATIC_VTABLE.to_mut
let bytes_mut = BytesMut::from(Bytes::from_static(bs));
assert_eq!(bytes_mut, bs[..]);
}
#[test]
fn test_bytesmut_from_bytes_bytes_mut_vec() {
let bs = b"1b23exfcz3r";
let bs_long = b"1b23exfcz3r1b23exfcz3r";
// Test case where kind == KIND_VEC
let mut bytes_mut: BytesMut = bs[..].into();
bytes_mut = BytesMut::from(bytes_mut.freeze());
assert_eq!(bytes_mut, bs[..]);
bytes_mut.extend_from_slice(&bs[..]);
assert_eq!(bytes_mut, bs_long[..]);
}
#[test]
fn test_bytesmut_from_bytes_bytes_mut_shared() {
let bs = b"1b23exfcz3r";
// Set kind to KIND_ARC so that after freeze, Bytes will use bytes_mut.SHARED_VTABLE
let mut bytes_mut: BytesMut = bs[..].into();
drop(bytes_mut.split_off(bs.len()));
let b1 = bytes_mut.freeze();
let b2 = b1.clone();
// shared.is_unique() = False
let mut b1m = BytesMut::from(b1);
assert_eq!(b1m, bs[..]);
b1m[0] = b'9';
// shared.is_unique() = True
let b2m = BytesMut::from(b2);
assert_eq!(b2m, bs[..]);
}
#[test]
fn test_bytesmut_from_bytes_bytes_mut_offset() {
let bs = b"1b23exfcz3r";
// Test bytes_mut.SHARED_VTABLE.to_mut impl where offset != 0
let mut bytes_mut1: BytesMut = bs[..].into();
let bytes_mut2 = bytes_mut1.split_off(9);
let b1 = bytes_mut1.freeze();
let b2 = bytes_mut2.freeze();
let b1m = BytesMut::from(b1);
let b2m = BytesMut::from(b2);
assert_eq!(b2m, bs[9..]);
assert_eq!(b1m, bs[..9]);
}
#[test]
fn test_bytesmut_from_bytes_promotable_even_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_promotable_even_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_promotable_even_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_promotable_even_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]);
}
#[test]
fn try_reclaim_empty() {
let mut buf = BytesMut::new();
assert_eq!(false, buf.try_reclaim(6));
buf.reserve(6);
assert_eq!(true, buf.try_reclaim(6));
let cap = buf.capacity();
assert!(cap >= 6);
assert_eq!(false, buf.try_reclaim(cap + 1));
let mut buf = BytesMut::new();
buf.reserve(6);
let cap = buf.capacity();
assert!(cap >= 6);
let mut split = buf.split();
drop(buf);
assert_eq!(0, split.capacity());
assert_eq!(true, split.try_reclaim(6));
assert_eq!(false, split.try_reclaim(cap + 1));
}
#[test]
fn try_reclaim_vec() {
let mut buf = BytesMut::with_capacity(6);
buf.put_slice(b"abc");
// Reclaiming a ludicrous amount of space should calmly return false
assert_eq!(false, buf.try_reclaim(usize::MAX));
assert_eq!(false, buf.try_reclaim(6));
buf.advance(2);
assert_eq!(4, buf.capacity());
// We can reclaim 5 bytes, because the byte in the buffer can be moved to the front. 6 bytes
// cannot be reclaimed because there is already one byte stored
assert_eq!(false, buf.try_reclaim(6));
assert_eq!(true, buf.try_reclaim(5));
buf.advance(1);
assert_eq!(true, buf.try_reclaim(6));
assert_eq!(6, buf.capacity());
}
#[test]
fn try_reclaim_arc() {
let mut buf = BytesMut::with_capacity(6);
buf.put_slice(b"abc");
let x = buf.split().freeze();
buf.put_slice(b"def");
// Reclaiming a ludicrous amount of space should calmly return false
assert_eq!(false, buf.try_reclaim(usize::MAX));
let y = buf.split().freeze();
let z = y.clone();
assert_eq!(false, buf.try_reclaim(6));
drop(x);
drop(z);
assert_eq!(false, buf.try_reclaim(6));
drop(y);
assert_eq!(true, buf.try_reclaim(6));
assert_eq!(6, buf.capacity());
assert_eq!(0, buf.len());
buf.put_slice(b"abc");
buf.put_slice(b"def");
assert_eq!(6, buf.capacity());
assert_eq!(6, buf.len());
assert_eq!(false, buf.try_reclaim(6));
buf.advance(4);
assert_eq!(true, buf.try_reclaim(4));
buf.advance(2);
assert_eq!(true, buf.try_reclaim(6));
}
#[test]
fn split_off_empty_addr() {
let mut buf = Bytes::from(vec![0; 1024]);
let ptr_start = buf.as_ptr();
let ptr_end = ptr_start.wrapping_add(1024);
let empty_end = buf.split_off(1024);
assert_eq!(empty_end.len(), 0);
assert_eq!(empty_end.as_ptr(), ptr_end);
let _ = buf.split_off(0);
assert_eq!(buf.len(), 0);
assert_eq!(buf.as_ptr(), ptr_start);
// Is miri happy about the provenance?
let _ = &empty_end[..];
let _ = &buf[..];
}
#[test]
fn split_to_empty_addr() {
let mut buf = Bytes::from(vec![0; 1024]);
let ptr_start = buf.as_ptr();
let ptr_end = ptr_start.wrapping_add(1024);
let empty_start = buf.split_to(0);
assert_eq!(empty_start.len(), 0);
assert_eq!(empty_start.as_ptr(), ptr_start);
let _ = buf.split_to(1024);
assert_eq!(buf.len(), 0);
assert_eq!(buf.as_ptr(), ptr_end);
// Is miri happy about the provenance?
let _ = &empty_start[..];
let _ = &buf[..];
}
#[test]
fn split_off_empty_addr_mut() {
let mut buf = BytesMut::from([0; 1024].as_slice());
let ptr_start = buf.as_ptr();
let ptr_end = ptr_start.wrapping_add(1024);
let empty_end = buf.split_off(1024);
assert_eq!(empty_end.len(), 0);
assert_eq!(empty_end.as_ptr(), ptr_end);
let _ = buf.split_off(0);
assert_eq!(buf.len(), 0);
assert_eq!(buf.as_ptr(), ptr_start);
// Is miri happy about the provenance?
let _ = &empty_end[..];
let _ = &buf[..];
}
#[test]
fn split_to_empty_addr_mut() {
let mut buf = BytesMut::from([0; 1024].as_slice());
let ptr_start = buf.as_ptr();
let ptr_end = ptr_start.wrapping_add(1024);
let empty_start = buf.split_to(0);
assert_eq!(empty_start.len(), 0);
assert_eq!(empty_start.as_ptr(), ptr_start);
let _ = buf.split_to(1024);
assert_eq!(buf.len(), 0);
assert_eq!(buf.as_ptr(), ptr_end);
// Is miri happy about the provenance?
let _ = &empty_start[..];
let _ = &buf[..];
}
#[derive(Clone)]
struct SharedAtomicCounter(Arc<AtomicUsize>);
impl SharedAtomicCounter {
pub fn new() -> Self {
SharedAtomicCounter(Arc::new(AtomicUsize::new(0)))
}
pub fn increment(&self) {
self.0.fetch_add(1, Ordering::AcqRel);
}
pub fn get(&self) -> usize {
self.0.load(Ordering::Acquire)
}
}
#[derive(Clone)]
struct OwnedTester<const L: usize> {
buf: [u8; L],
drop_count: SharedAtomicCounter,
pub panic_as_ref: bool,
}
impl<const L: usize> OwnedTester<L> {
fn new(buf: [u8; L], drop_count: SharedAtomicCounter) -> Self {
Self {
buf,
drop_count,
panic_as_ref: false,
}
}
}
impl<const L: usize> AsRef<[u8]> for OwnedTester<L> {
fn as_ref(&self) -> &[u8] {
if self.panic_as_ref {
panic!("test-triggered panic in `AsRef<[u8]> for OwnedTester`");
}
self.buf.as_slice()
}
}
impl<const L: usize> Drop for OwnedTester<L> {
fn drop(&mut self) {
self.drop_count.increment();
}
}
#[test]
fn owned_is_unique_always_false() {
let b1 = Bytes::from_owner([1, 2, 3, 4, 5, 6, 7]);
assert!(!b1.is_unique()); // even if ref_cnt == 1
let b2 = b1.clone();
assert!(!b1.is_unique());
assert!(!b2.is_unique());
drop(b1);
assert!(!b2.is_unique()); // even if ref_cnt == 1
}
#[test]
fn owned_buf_sharing() {
let buf = [1, 2, 3, 4, 5, 6, 7];
let b1 = Bytes::from_owner(buf);
let b2 = b1.clone();
assert_eq!(&buf[..], &b1[..]);
assert_eq!(&buf[..], &b2[..]);
assert_eq!(b1.as_ptr(), b2.as_ptr());
assert_eq!(b1.len(), b2.len());
assert_eq!(b1.len(), buf.len());
}
#[test]
fn owned_buf_slicing() {
let b1 = Bytes::from_owner(SHORT);
assert_eq!(SHORT, &b1[..]);
let b2 = b1.slice(1..(b1.len() - 1));
assert_eq!(&SHORT[1..(SHORT.len() - 1)], b2);
assert_eq!(unsafe { SHORT.as_ptr().add(1) }, b2.as_ptr());
assert_eq!(SHORT.len() - 2, b2.len());
}
#[test]
fn owned_dropped_exactly_once() {
let buf: [u8; 5] = [1, 2, 3, 4, 5];
let drop_counter = SharedAtomicCounter::new();
let owner = OwnedTester::new(buf, drop_counter.clone());
let b1 = Bytes::from_owner(owner);
let b2 = b1.clone();
assert_eq!(drop_counter.get(), 0);
drop(b1);
assert_eq!(drop_counter.get(), 0);
let b3 = b2.slice(1..b2.len() - 1);
drop(b2);
assert_eq!(drop_counter.get(), 0);
drop(b3);
assert_eq!(drop_counter.get(), 1);
}
#[test]
fn owned_to_mut() {
let buf: [u8; 10] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
let drop_counter = SharedAtomicCounter::new();
let owner = OwnedTester::new(buf, drop_counter.clone());
let b1 = Bytes::from_owner(owner);
// Holding an owner will fail converting to a BytesMut,
// even when the bytes instance has a ref_cnt == 1.
let b1 = b1.try_into_mut().unwrap_err();
// That said, it's still possible, just not cheap.
let bm1: BytesMut = b1.into();
let new_buf = &bm1[..];
assert_eq!(new_buf, &buf[..]);
// `.into::<BytesMut>()` has correctly dropped the owner
assert_eq!(drop_counter.get(), 1);
}
#[test]
fn owned_to_vec() {
let buf: [u8; 10] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
let drop_counter = SharedAtomicCounter::new();
let owner = OwnedTester::new(buf, drop_counter.clone());
let b1 = Bytes::from_owner(owner);
let v1 = b1.to_vec();
assert_eq!(&v1[..], &buf[..]);
assert_eq!(&v1[..], &b1[..]);
drop(b1);
assert_eq!(drop_counter.get(), 1);
}
#[test]
fn owned_safe_drop_on_as_ref_panic() {
let buf: [u8; 10] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
let drop_counter = SharedAtomicCounter::new();
let mut owner = OwnedTester::new(buf, drop_counter.clone());
owner.panic_as_ref = true;
let result = panic::catch_unwind(AssertUnwindSafe(|| {
let _ = Bytes::from_owner(owner);
}));
assert!(result.is_err());
assert_eq!(drop_counter.get(), 1);
}
+81 -3
View File
@@ -6,7 +6,7 @@
use std::alloc::{GlobalAlloc, Layout, System}; use std::alloc::{GlobalAlloc, Layout, System};
use std::ptr; use std::ptr;
use bytes::Bytes; use bytes::{Bytes, BytesMut};
#[global_allocator] #[global_allocator]
static ODD: Odd = Odd; static ODD: Odd = Odd;
@@ -24,8 +24,7 @@ unsafe impl GlobalAlloc for Odd {
}; };
let ptr = System.alloc(new_layout); let ptr = System.alloc(new_layout);
if !ptr.is_null() { if !ptr.is_null() {
let ptr = ptr.offset(1); ptr.offset(1)
ptr
} else { } else {
ptr ptr
} }
@@ -67,3 +66,82 @@ fn test_bytes_clone_drop() {
let b1 = Bytes::from(vec); let b1 = Bytes::from(vec);
let _b2 = b1.clone(); 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]);
}
+103 -39
View File
@@ -1,61 +1,87 @@
use std::alloc::{GlobalAlloc, Layout, System}; use std::alloc::{GlobalAlloc, Layout, System};
use std::{mem, ptr}; use std::ptr::null_mut;
use std::sync::atomic::{AtomicPtr, AtomicUsize, Ordering};
use bytes::{Buf, Bytes}; use bytes::{Buf, Bytes};
#[global_allocator] #[global_allocator]
static LEDGER: Ledger = Ledger; static LEDGER: Ledger = Ledger::new();
struct Ledger; const LEDGER_LENGTH: usize = 2048;
const USIZE_SIZE: usize = mem::size_of::<usize>(); struct Ledger {
alloc_table: [(AtomicPtr<u8>, AtomicUsize); LEDGER_LENGTH],
}
unsafe impl GlobalAlloc for Ledger { impl Ledger {
unsafe fn alloc(&self, layout: Layout) -> *mut u8 { const fn new() -> Self {
if layout.align() == 1 && layout.size() > 0 { const ELEM: (AtomicPtr<u8>, AtomicUsize) =
// Allocate extra space to stash a record of (AtomicPtr::new(null_mut()), AtomicUsize::new(0));
// how much space there was. let alloc_table = [ELEM; LEDGER_LENGTH];
let orig_size = layout.size();
let size = orig_size + USIZE_SIZE; Self { alloc_table }
let new_layout = match Layout::from_size_align(size, 1) { }
Ok(layout) => layout,
Err(_err) => return ptr::null_mut(), /// Iterate over our table until we find an open entry, then insert into said entry
}; fn insert(&self, ptr: *mut u8, size: usize) {
let ptr = System.alloc(new_layout); for (entry_ptr, entry_size) in self.alloc_table.iter() {
if !ptr.is_null() { // SeqCst is good enough here, we don't care about perf, i just want to be correct!
(ptr as *mut usize).write(orig_size); if entry_ptr
let ptr = ptr.offset(USIZE_SIZE as isize); .compare_exchange(null_mut(), ptr, Ordering::SeqCst, Ordering::SeqCst)
ptr .is_ok()
} else { {
ptr entry_size.store(size, Ordering::SeqCst);
break;
} }
} else {
System.alloc(layout)
} }
} }
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) { fn remove(&self, ptr: *mut u8) -> usize {
if layout.align() == 1 && layout.size() > 0 { for (entry_ptr, entry_size) in self.alloc_table.iter() {
let off_ptr = (ptr as *mut usize).offset(-1); // set the value to be something that will never try and be deallocated, so that we
let orig_size = off_ptr.read(); // don't have any chance of a race condition
if orig_size != layout.size() { //
panic!( // dont worry, LEDGER_LENGTH is really long to compensate for us not reclaiming space
"bad dealloc: alloc size was {}, dealloc size is {}", if entry_ptr
orig_size, .compare_exchange(
layout.size() ptr,
); invalid_ptr(usize::MAX),
Ordering::SeqCst,
Ordering::SeqCst,
)
.is_ok()
{
return entry_size.load(Ordering::SeqCst);
} }
}
let new_layout = match Layout::from_size_align(layout.size() + USIZE_SIZE, 1) { panic!("Couldn't find a matching entry for {:x?}", ptr);
Ok(layout) => layout, }
Err(_err) => std::process::abort(), }
};
System.dealloc(off_ptr as *mut u8, new_layout); 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 { } else {
System.dealloc(ptr, layout); System.dealloc(ptr, layout);
} }
} }
} }
#[test] #[test]
fn test_bytes_advance() { fn test_bytes_advance() {
let mut bytes = Bytes::from(vec![10, 20, 30]); let mut bytes = Bytes::from(vec![10, 20, 30]);
@@ -77,3 +103,41 @@ fn test_bytes_truncate_and_advance() {
bytes.advance(1); bytes.advance(1);
drop(bytes); 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]);
}
+22
View File
@@ -133,6 +133,28 @@ fn vectored_read() {
} }
} }
#[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] #[test]
fn chain_get_bytes() { fn chain_get_bytes() {
let mut ab = Bytes::copy_from_slice(b"ab"); let mut ab = Bytes::copy_from_slice(b"ab");
+4 -4
View File
@@ -1,11 +1,11 @@
#![warn(rust_2018_idioms)] #![warn(rust_2018_idioms)]
use bytes::Bytes; use bytes::{buf::IntoIter, Bytes};
#[test] #[test]
fn iter_len() { fn iter_len() {
let buf = Bytes::from_static(b"hello world"); let buf = Bytes::from_static(b"hello world");
let iter = buf.iter(); let iter = IntoIter::new(buf);
assert_eq!(iter.size_hint(), (11, Some(11))); assert_eq!(iter.size_hint(), (11, Some(11)));
assert_eq!(iter.len(), 11); assert_eq!(iter.len(), 11);
@@ -13,8 +13,8 @@ fn iter_len() {
#[test] #[test]
fn empty_iter_len() { fn empty_iter_len() {
let buf = Bytes::from_static(b""); let buf = Bytes::new();
let iter = buf.iter(); let iter = IntoIter::new(buf);
assert_eq!(iter.size_hint(), (0, Some(0))); assert_eq!(iter.size_hint(), (0, Some(0)));
assert_eq!(iter.len(), 0); assert_eq!(iter.len(), 0);