Compare commits

...
206 Commits
Author SHA1 Message Date
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
Alice RyhlandGitHub ebc61e5af1 chore: prepare bytes v1.1.0 (#509) 2021-08-25 17:48:41 +02:00
Christopher HotchkissandGitHub 55e296850d Clarifying actions of clear and truncate. (#508) 2021-08-24 16:12:20 +02:00
Ian JacksonandGitHub 0e9fa0b602 impl From<Box<[u8]>> for Bytes (#504) 2021-08-24 12:42:22 +02:00
ee24be7fa0 ci: fetch cargo hack from github release (#507)
Co-authored-by: Taiki Endo <[email protected]>
2021-08-24 12:33:16 +02:00
Stepan KoltsovandGitHub 2697fa7a9d BufMut::put_bytes(self, val, cnt) (#487)
Equivalent to

```
for _ in 0..cnt {
    self.put_u8(val);
}
```

but may work faster.

Name and signature is chosen to be consistent with `ptr::write_bytes`.

Include three specializations:
* `Vec<u8>`
* `&mut [u8]`
* `BytesMut`

`BytesMut` and `&mut [u8]` specializations use `ptr::write`, `Vec<u8>`
specialization uses `Vec::resize`.
2021-08-09 02:43:53 +09:00
Stepan KoltsovandGitHub fa9cbf1258 Clarify BufPut::put_int behavior (#486)
* writes low bytes, discards high bytes
* panics if `nbytes` is greater than 8
2021-08-09 02:43:09 +09:00
Alice RyhlandGitHub ab8e3c01a8 Clarify BufMut allocation guarantees (#501) 2021-08-07 08:22:18 +02:00
Taiki EndoandGitHub f34dc5c3f9 Remove doc URLs (#498) 2021-08-07 02:06:57 +09:00
GbillouandGitHub baaf12d22a Keep capacity when unsplit on empty other buf (#502) 2021-07-05 16:46:17 +02:00
Taiki EndoandGitHub ed1d24e570 Use ubuntu-latest instead of ubuntu-16.04 (#497) 2021-05-23 23:09:26 +09:00
Taiki EndoandGitHub b89247c713 Update loom to 0.5 (#494) 2021-04-13 23:58:18 +09:00
NoahandGitHub 9c770188fd Fully inline BytesMut::new (#493) 2021-04-11 05:49:33 +09:00
Stepan KoltsovandGitHub b9eade12a5 Specialize copy_to_bytes for Chain and Take (#481)
Avoid allocation when `Take` or `Chain` is composed of `Bytes`
objects.

This works now for `Take`.

`Chain` it works if the requested bytes does not cross boundary
between `Chain` members.
2021-04-11 03:56:35 +09:00
Dan BurkertandGitHub 3d5624a452 Add inline tags to UninitSlice methods (#443)
This appears to be the primary cause of significant performance
regressions in the `prost` test suite in the 0.5 to 0.6 transition.  See
danburkert/prost#381.
2021-04-11 03:19:30 +09:00
Stepan KoltsovandGitHub 2428c152a6 Panic on integer overflow in Chain::remaining (#482)
Make it safer.
2021-02-16 12:44:33 -08:00
ZettrokeandGitHub 268f6f80b4 override put_slice for &mut [u8] (#483) 2021-02-15 16:35:01 -08:00
Alice RyhlandGitHub e4182808df Make bytes_mut -> chunk_mut rename more easily discoverable (#471) 2021-01-23 15:22:43 +09:00
Christopher BunnandGitHub 8daf43e9bd docs: fix broken Take link (#466) 2021-01-20 14:39:23 +09:00
Alice RyhlandGitHub 7b18c1c076 prepare 1.0.1 release (#460) 2021-01-11 18:07:46 +01:00
Ralf JungandGitHub df20a68356 use Box::into_raw instead of mem-forget-in-disguise (#458) 2020-12-31 15:07:28 +01:00
laizyandGitHub 8758a1aba5 add inline for Vec::put_slice (#459) 2020-12-31 12:34:39 +01:00
Ralf JungandGitHub 27a0f9ca6e CI: run test suite in Miri (#456) 2020-12-29 22:54:48 +01:00
Alice RyhlandGitHub ed71a7beb3 Fix deprecation warning (#457) 2020-12-29 22:46:39 +01:00
Carl LercheandGitHub 064ad9a1a0 chore: prepare v1.0.0 release (#453) 2020-12-22 15:30:20 -08:00
Taiki EndoandGitHub ed1d194660 deps: update loom to 0.4 (#452) 2020-12-22 10:30:50 +01:00
Arve KnudsenandGitHub e398b0a209 Update readme / changelog (#451) 2020-12-20 07:31:22 -08:00
Carl LercheandGitHub 06907f3e7b Rename Buf/BufMut, methods to chunk/chunk_mut (#450)
The `bytes()` / `bytes_mut()` name implies the method returns the full
set of bytes represented by `Buf`/`BufMut`. To rectify this, the methods
are renamed to `chunk()` and `chunk_mut()` to reflect the partial nature
of the returned byte slice.

`bytes_vectored()` is renamed `chunks_vectored()`.

Closes #447
2020-12-18 11:04:31 -08:00
Carl LercheandGitHub 54f5ced6c5 remove unused Buf implementation. (#449)
The implementation of `Buf` for `Option<[u8; 1]>` was added to support
`IntoBuf`. The `IntoBuf` trait has since been removed.

Closes #444
2020-12-16 21:51:13 -08:00
Carl LercheandGitHub bd78f19393 chore: prepare for v1.0.0 work (#448) 2020-12-12 08:25:14 -08:00
Ibraheem AhmedandGitHub 39c6d7a512 Upgrade bytes version from 0.5 to 0.6.0 in README (#441) 2020-11-02 00:10:51 +09:00
Carl LercheandGitHub b7f75829ab prepare v0.6.0 release (#440) 2020-10-20 16:08:25 -07:00
Carl LercheandGitHub 39de065a1e Add Buf::copy_to_bytes(len) (#439)
This method replaces `Buf::to_bytes()`, providing a method that copies a
subset of the remaining buffer into a `Bytes` value. As this is strictly
more flexible, `to_bytes()` is removed.

Fixes: #129, #398
2020-10-20 11:00:35 -07:00
Carl LercheandGitHub 5866839e45 use checked addition with range (#438) 2020-10-20 10:26:38 -07:00
Carl LercheandGitHub e0d8413d53 Switch BufMut::bytes_mut to&mut UninitSlice (#433)
The way BufMut uses MaybeUninit can lead to unsoundness. This replaces
MaybeUnit with a type owned by bytes so we can ensure the usage patterns
are sound.

Refs: #328
2020-10-19 15:48:23 -07:00
Matthias EinwagandGitHub 5a11c783ec De-emphasize Arc implementation in Bytes description (#436)
The previous description focussed a lot on the `Arc` based implementation
of `Bytes`. Given the vtable based implemetation, this is however not the
only valid implementation. This changes the description a bit in order
to de-emaphasize the `Arc` part, and to describe that other implementations
are possible.

This should also be necessary if the vtable gets public.
2020-10-19 12:32:20 -07:00
Carl LercheandGitHub 4724c7e8a0 remove new fns from combinator structs (#434)
This is not idiomatic.
2020-10-18 09:55:19 -07:00
Carl LercheandGitHub ced050730c Make BufMut an unsafe trait (#432)
Users of `BufMut` are unable to defend against incorrect implementations
of `BufMut`, this makes the trait unsafe to implement.

Fixes #329
2020-10-16 15:45:38 -07:00
Carl LercheandGitHub 94c543f74b remove ext traits (#431) 2020-10-16 15:16:23 -07:00
Carl LercheandGitHub 447530b8a6 Remove BufMut::bytes_vectored_mut() (#430)
There are issues with regard to uninitialized memory. We are avoiding
stabilizing this function for now.
2020-10-16 11:56:03 -07:00
Carl LercheandGitHub 422048eb24 prepare for 0.6 work (#428) 2020-10-16 11:49:27 -07:00
Sean McArthur 6fdb7391ce v0.5.6 2020-07-13 17:58:36 -07:00
Sean McArthurandGitHub 025bec2954 Move loom to dev-dependencies (#416) 2020-07-13 16:55:47 -07:00
Taiki EndoandGitHub 2d51809bd7 Fix CI failure on Windows (#415)
--no-self-update is necessary because the windows environment cannot
self-update rustup.exe.
2020-07-13 12:33:30 +09:00
Taiki EndoandGitHub 7daa7fe053 Change default lint level to warning and deny warnings in CI (#397) 2020-07-09 09:12:39 -07:00
Sean LeatherandGitHub 972f538b7e docs: Clarify what BytesMut is (#375) 2020-07-09 09:11:45 -07:00
Bryan DonlanandSean McArthur 81550da474 BytesMut: Reuse buffer when data fully consumed via Buf
Closes #412
2020-07-08 15:28:36 -07:00
Tomasz MiąskoandGitHub 90e7e650c9 Use ThreadSanitizer CI setup that avoids false positives (#406) 2020-07-07 01:28:47 +09:00
Juan AguilarandGitHub bc4a6d56f4 Add inline attribute to BytesMut::as_mut (#410) 2020-07-05 17:43:26 -07:00
Juan AguilarandGitHub 3603cec7c2 Add inline attribute to BytesMut::set_len (#408) 2020-07-03 16:47:32 -07:00
Tomasz MiąskoandGitHub 5cde647c29 Remove unnecessary synchronization when cloning shared representation (#404) 2020-07-02 18:55:16 -07:00
Sean McArthur 008d3e508e v0.5.5 2020-06-18 14:30:11 -07:00
Mikhail ZabaluevandGitHub a3304e8b8b Remove outdated info on BytesMut::with_capacity (#394)
Remove a remark from the doc that pertained to the inline
layout and is no longer true.
2020-05-27 22:02:45 -07:00
Taiki EndoandGitHub 64fe7e10ab Migrate CI to GitHub Actions (#392) 2020-05-25 01:41:45 +09:00
Taiki EndoandGitHub e9877e7a3d Deny warnings for doc tests (#391) 2020-05-24 06:30:50 +09:00
Kirill FomichevandGitHub 08ec01d1e7 Fix reference in Take docs (#383) 2020-05-22 14:33:06 +09:00
Taiki EndoandGitHub 1fbf83816b Format with rustfmt (#389)
* Format with rustfmt

* Add rustfmt check to CI
2020-05-22 13:17:30 +09:00
Sean McArthurandGitHub 5e93fa4c6b Update to loom v0.3 (#381) 2020-05-22 11:23:22 +09:00
Cheng XUandGitHub 9f40abc12a Allow using serde feature in no_std environment (#385)
When `serde` is used, it would enable its default feature `std`.
This of course breaks no_std build.

Fix this by disabling serde's default features. This should work for
both serde + std and serde + no_std case.
2020-05-22 11:19:46 +09:00
Cheng XUandGitHub e8fa2511ff Fix tests for no_std build (#384)
This fixes `cargo test --no-default-features`.
2020-05-22 11:18:20 +09:00
Taiki EndoandGitHub fa464ca483 Fix CI failure on MacOS (#388)
macOS-10.13 has been removed.
2020-05-22 10:54:52 +09:00
Tim HambourgerandSean McArthur b4ebe8432e Fix #354 -- Make advance_mut impl of BufMut for Vec<u8> panic if cnt > remaining 2020-03-25 12:30:15 -07:00
Tim HambourgerandSean McArthur 8bbe9dd87b Fix #352 -- Make freeze respect the start offset for BytesMuts in Vec mode 2020-03-24 11:14:16 -07:00
Sean McArthur fe6e673864 v0.5.4 2020-01-23 10:41:50 -08:00
Stepan KoltsovandSean McArthur f330ef6c4d Do not panic on Bytes::slice_ref on empty slice (#355)
Use case:

```
let bytes: Bytes = ...
let subbytes = bytes.slice(a..b); // where a == b
let slice = &subbytes[..];
let slice_bytes = bytes.slice_ref(slice);
```

Last line should not panic, because `slice` object is derived from
the original `Bytes` object.

Before this commit it panics, because `Bytes::slice` returns a fresh
`Bytes` object when `begin == end`.
2020-01-23 10:29:42 -08:00
Sean McArthurandGitHub 87b75cce16 Disable loom on Windows (#366) 2020-01-23 10:10:15 -08:00
南浦月andSean McArthur 3853a1fac4 merge hex & debug into fmt (#357) 2020-01-23 10:08:40 -08:00
Nikhil BeneschandSean McArthur f9ebf74091 Minor documentation fixes (#351)
* Remove incorrect comment about behavior of put_slice
* Improve grammar and clarity of BytesMut documentation
2020-01-23 10:06:49 -08:00
Andrew Tunnell-JonesandSean McArthur 939a5edf3d Fix reversed arguments in PartialOrd impls (#358) 2020-01-23 10:06:00 -08:00
John-John TedroandSean McArthur 788cb158ce Assert that the alignment of Shared is appropriate (#362) 2020-01-23 10:05:20 -08:00
Stepan KoltsovandSean McArthur ab028eb6a8 rebuild_boxed_slice instead of rebuild_boxed_vec (#364)
"Promotable" `Bytes` object is constructed from disassembling a
boxed slice object, not a vec.

Thus we should reassemble data into a boxed slice, not into a vec.

Although, it does not create any problems in practice (`Box<[u8]>`
is allocated exactly the same way as `Vec<u8>`), technically it is
a violation of `Vec::from_raw_parts` spec which says that a pointer
"needs to have been previously allocated via `String`/`Vec<T>`".
2020-01-23 10:04:13 -08:00
Sean McArthurandCarl Lerche e0eebde993 Fix Bytes::truncate losing the original Vec's capacity (#361) 2020-01-22 16:37:53 -08:00
Stepan KoltsovandSean McArthur 729bc7c208 Make Bytes::new const fn (#356) 2020-01-09 14:27:28 -08:00
Sean McArthurandCarl Lerche 8695c08bcc Improve assertion messages (#349) 2020-01-07 21:29:36 -08:00
Thayne McCombsandSean McArthur 39b6646e66 Re-add impl From<BytesMut> for Bytes (#348) 2019-12-19 11:09:14 -08:00
Sean McArthurandGitHub c7cf716180 Fix Bytes when Vec pointer's LSB is set (#346)
This separates the `SharedVtable` into 3:

- `PromotableEvenVtable`: The original `SharedVtable`, which will
  promote the `Vec` to `Shared` on the first clone, and is selected when
  the `Vec`'s pointer has the LSB unset.
- `PromotableOddVtable`: Similar to the `PromotableEvenVtable`, but
  selected when the `Vec`'s pointer has the LSB set. This vtable differs
  in the masking used when reconstructing the `Vec`.
- `SharedVtable`: This no longer checks if its current kind is `VEC` or
  `ARC`, and is only created by the "promotable" vtables.

This also adds a test using an "odd" global allocator that purposefully
bumps all pointers with alignment of 1.

Closes #343
2019-12-17 13:23:15 -08:00
Sean McArthur 8ae3bb2104 v0.5.3 2019-12-12 12:00:21 -08:00
Sean McArthur 8733f74d59 Assert the LSB is 0 when converting Vec into Bytes 2019-12-12 11:46:51 -08:00
Steven FacklerandSean McArthur 17a8ac91e0 Fix conversion of empty vectors to Bytes
Closes #340
2019-12-12 08:33:07 -08:00
Sean McArthur a7fc5274ad Make Deref impls of Buf and BufMut forward more methods 2019-12-10 13:35:26 -08:00
Sean McArthurandCarl Lerche 7e80f3b646 Optimize BufMut for Vec and BytesMut (#338) 2019-12-10 13:30:49 -08:00
Sean McArthur a4908213a6 Add must_use to split, split_off, and split_to 2019-12-04 12:39:48 -08:00
Mikhail ZabaluevandCarl Lerche af606aab9b Fix regression in Bytes::truncate (#333)
When the length to truncate is greater than the buffer's current
length, do nothing instead of clearing the contents.
2019-12-01 14:00:42 -08:00
Sean McArthur 98951ba26c v0.5.2 2019-11-27 12:59:28 -08:00
Steven FacklerandSean McArthur 171cffa505 Update README.md (#320) 2019-11-27 12:06:33 -08:00
Sean McArthurandCarl Lerche a642e1c075 Add accessors to Limit combinator (#325) 2019-11-26 18:08:39 -08:00
Steven FacklerandCarl Lerche 3cf91283f8 chore: prepare v0.5.1 release (#322) 2019-11-26 14:15:57 -08:00
Steven FacklerandCarl Lerche 1db67b4a87 doc: fix BytesMut growth documentation. (#321) 2019-11-25 11:40:40 -08:00
Carl LercheandGitHub b7c1f2a135 prepare v0.5.0 release (#319) 2019-11-25 11:19:30 -08:00
Sean McArthurandCarl Lerche cdd9fc09cd Export public the combinator types (#318) 2019-11-25 10:47:37 -08:00
Sean McArthurandCarl Lerche 44fb206148 add BufMutExt::limit (#309)
This type is the counterpart to BufExt::take. It limits how many bytes
some `BufMut` can actually be filled with.
2019-11-20 15:10:30 -08:00
Carl LercheandGitHub b3f86d8654 remove either feature (#315)
remove either feature
2019-11-20 12:59:44 -08:00
Carl LercheandGitHub 8135c1f606 implicitly grow BytesMut; add BufMutExt::chain_mut (#316)
This brings `BytesMut` in line with `Vec<u8>` behavior.

This also fixes an existing bug in BytesMut::bytes_mut that exposes
invalid slices. The bug was recently introduced and was only on master
and never released to `crates.io`.

In order to fix a test, `BufMutExt::chain_mut` is provided. Withou this,
it is not possible to chain two `&mut [u8]`.

Closes #170
2019-11-20 12:11:40 -08:00
Andrew Tunnell-JonesandCarl Lerche 59aea9e871 Make Bytes::from_static a const fn (#311)
Rust versions bumped to the minimum needed for const slice len.
2019-11-20 11:10:03 -08:00
Sean McArthurandGitHub 9a10addb44 Change loom tests to use cfg(loom) internally (#314) 2019-11-13 14:55:25 -08:00
Sean McArthurandGitHub b32f6298e2 Improve performance of BytesMut::reserve (#313)
Makes the short-circuit checks inline-able, and the moves the actual
reserving code to an inner function.
2019-11-12 14:52:02 -08:00
Sean McArthurandGitHub 856ed7c43d implement Buf for std::io::Cursor (#308) 2019-11-04 17:23:40 -08:00
Sean McArthurandGitHub 96268a80d4 Move "extra" methods to extension traits (#306) 2019-10-31 09:39:58 -07:00
Sean McArthurandGitHub 2ac72333fa Change BufMut methods that expose maybe-uninitialized bytes (#305)
- The return type of `BufMut::bytes_mut` is now
  `&mut [MaybeUninit<u8>]`.
- The argument type of `BufMut::bytes_vectored_mut` is now
  `&mut [bytes::buf::IoSliceMut]`.
- `bytes::buf::IoSliceMut` is a `repr(transparent)` wrapper around an
  `std::io::IoSliceMut`, but does not expose the inner bytes with a safe
  API, since they might be uninitialized.
- `BufMut::bytesMut` and `BufMut::bytes_vectored_mut` are no longer
  `unsafe fn`, since the types encapsulate the unsafety instead.
2019-10-24 14:40:45 -07:00
Sean McArthurandGitHub fe2183dc2f Add benchmarks for BytesMut vs Vec (#303) 2019-10-23 13:40:04 -07:00
Sean McArthurandCarl Lerche 491ebbf79a Remove Buf impl for &str (#301)
A `&str` cannot arbitrarily advance bytes, since it will panic if
advanced to the middle of a Unicode segment.
2019-10-16 11:28:50 -07:00
Sean McArthurandGitHub 43ac8e5494 Refactor Bytes to use an internal vtable (#298)
Bytes is a useful tool for managing multiple slices into the same region
of memory, and the other things it used to have been removed to reduce
complexity. The exact strategy for managing the multiple references is
no longer hard-coded, but instead backing by a customizable vtable.

- Removed ability to mutate the underlying memory from the `Bytes` type.
- Removed the "inline" (SBO) mechanism in `Bytes`. The reduces a large
  amount of complexity, and improves performance when accessing the
  slice of bytes, since a branch is no longer needed to check if the
  data is inline.
- Removed `Bytes` knowledge of `BytesMut` (`BytesMut` may grow that
  knowledge back at a future point.)
2019-10-16 09:53:36 -07:00
Taiki EndoandDouman ebe96021b0 Fix build fail with serde feature (#293)
Verify no-std build and all features build
2019-09-08 22:10:46 +02:00
Taiki EndoandDouman 97c1338833 Remove a patch for cross 2019-09-08 17:58:32 +02:00
Chris BeckandCarl Lerche c17e40115f Add no_std support, by adding an std feature (#281)
To make the library work as `no_std` we add an `std` feature which
is on by default. When it is off, we compile as `no_std` and make
parts of the API that require `std::io` conditional on the `std`
feature.
2019-09-05 14:00:23 -07:00
Taiki EndoandGitHub 73426dfaa3 Fix one use of MaybeUninit (#291) 2019-09-01 01:33:10 +09:00
Ralf JungandCarl Lerche 425432ba6c use raw ptr for racy load and add comment (#289) 2019-08-28 14:41:04 -07:00
DoumanandCarl Lerche 4f5ed82b3c Fix clippy (#285) 2019-08-27 14:19:44 -07:00
Douman ae9991f3ba Make From only for static slices to Bytes 2019-08-27 22:17:26 +02:00
DoumanandCarl Lerche b6cb346adf Remove IntoBuf/FromBuf (#288)
As consequence Buf::collect is removed as well, which is replaced with `Buf::into_bytes`. The advantage of `Buf::into_bytes` is that it can be optimized in cases where converting a `T: Buf` into a `Bytes` instance is efficient.
2019-08-27 13:09:43 -07:00
nanpuyueandDouman 79e4b2847f use mem::MaybeUninit instead of mem::uninitialized 2019-08-16 15:49:37 +02:00
nanpuyueandDouman b1c17169d9 impl LowerHex/UpperHex for Bytes/BytesMut 2019-08-16 15:49:37 +02:00
DoumanandCarl Lerche 234d814122 Remove byteorder dependency (#280) 2019-08-11 10:16:03 -07:00
Taiki EndoandCarl Lerche b5d4f87e7e Remove i128 feature (#276) 2019-07-30 11:19:46 -07:00
Carl LercheandGitHub e07a949665 Set up CI with Azure Pipelines (#275) 2019-07-30 10:29:00 -07:00
Taiki EndoandGitHub ae7d884582 Update Bytes to Rust 2018 (#274) 2019-07-26 05:01:22 +09:00
Taiki EndoandCarl Lerche ecdde1a996 Update travis config to test on stable (#273) 2019-07-24 08:25:03 -07:00
Bruce MitchenerandSean McArthur e25b75a28e Fix typos. 2019-07-16 11:18:49 -07:00
Bruce MitchenerandSean McArthur 9b5e33d6f0 Remove merge conflict marker. 2019-07-16 11:18:49 -07:00
Sean McArthur dea868a4b0 Replace iovec with std::io::IoSlice
- Renames `bytes_vec` to `bytes_vectored` and `bytes_vec_mut` to
  `bytes_vectored_mut`.
2019-06-11 11:58:43 -07:00
Sean McArthur ac4e8f2fc5 Use RangeBounds trait for Bytes::slice
- Removes `slice_to` and `slice_from`.
2019-06-10 09:39:27 -07:00
Taiki EndoandSean McArthur ed7c7b5c58 Replace try! macro with ? operator 2019-06-10 09:05:11 -07:00
Sean McArthur 09772c4e77 fix benches after cursor removal 2019-06-07 15:09:06 -07:00
Sean McArthurandCarl Lerche 47fdf06e34 Make serde module private (#262) 2019-06-07 12:31:44 -07:00
Sean McArthurandCarl Lerche 55aa530dc1 Remove io::Cursor, and implement Buf/BufMut for slices instead (#261) 2019-06-07 12:31:10 -07:00
YetAnotherMinionandSean McArthur d8134903de feat: remove impl IntoBuf for Cursor<Self>, impl Buf for Bytes, BytesMut, refactor iterators 2019-06-06 16:59:44 -07:00
Sean McArthur 654a11c84c bump CI minimum Rust to 1.27 for 'dyn' keyword 2019-06-06 14:29:35 -07:00
Sean McArthur 5759211ff8 Merge branch 'v0.4.x' into uplift-0.4-commits 2019-06-06 14:08:29 -07:00
Sean McArthurandCarl Lerche 60aceba2bb set publish to false, update meta links (#258) 2019-06-06 13:58:22 -07:00
Pavel StrakhovandCarl Lerche d43e283e5e Panic in BytesMut::split_to when out of bounds (#252) (#253) 2019-04-02 16:24:30 -07:00
南浦月andCarl Lerche e0e30f00a1 Fix a typo in CHANGELOG.md (#251) 2019-03-29 13:54:25 -07:00
Carl LercheandGitHub 4948b1053b Bump version to v0.4.12 (#250) 2019-03-06 12:42:20 -08:00
Michal 'vorner' VanerandCarl Lerche 0e8b440650 Implementation of Buf for VecDeque (#249) 2019-03-06 11:46:42 -08:00
Sangguk LeeandCarl Lerche e13d2a783e Use constants in bytes.rs test code (#247) 2019-02-27 10:41:11 -08:00
南浦月andCarl Lerche 55dfea8c18 Impl FromIterator<&'a u8> for BytesMut/Bytes (#244) 2019-01-30 11:05:15 -08:00
Dax HuibertsandCarl Lerche f3b363a385 Fix typo in bytes.rs (#243) 2019-01-28 10:06:28 -08:00
Ralf JungandCarl Lerche 42b669690a use raw ptr for potentially racy load (#240) 2018-12-21 11:07:20 -08:00
Ralf JungandCarl Lerche 9504447adc Be clear about Inner::kind being deliberate UB (#236) 2018-11-25 22:49:35 -08:00
Carl LercheandGitHub b3248c8807 Bump version to v0.4.11 (#235) 2018-11-17 14:33:25 -08:00
Ralf JungandCarl Lerche c6c5b8fb54 Use raw pointers for potentially racy loads (#233)
Shared references assert immutability, so any concurrent access would be UB
disregarding data race concerns.
2018-11-17 07:51:50 -08:00
Michal 'vorner' VanerandCarl Lerche 7c3085aaec The Reader can implement BufReader naturally (#232)
There's no reason the user should be forced to wrap it in BufReader in
case the trait is needed, because the Reader has all the bits for
supporting it naturally.
2018-11-17 07:51:41 -08:00
Michal 'vorner' VanerandCarl Lerche e64a123d00 Bring more attention to short reads/slices on Buff/BuffMut (#231)
The property the Buff and BuffMut can return shorter slice is quite an
important detail. Nevertheless, while it is mentioned in the
documentation, the wording makes it relatively easy to overlook. This
tries to bring more attention to it.
2018-11-17 07:51:28 -08:00
Carl LercheandGitHub e5304410a4 Whitelist false positive std (#234) 2018-11-17 07:27:00 -08:00
Carl LercheandGitHub 456221d165 Bump version to v0.4.10 (#227) 2018-09-04 13:31:26 -07:00
Carl LercheandGitHub f09c51c34e White list allocation (#226) 2018-09-03 13:36:13 -07:00
Carl LercheandGitHub ad35fbef03 implement Buf and BufMut for Either (#225) 2018-09-03 10:23:00 -07:00
Federico Mena QuinteroandCarl Lerche 79f05591c9 Add a subslice function for Bytes (#198) (#208)
This lets us take Bytes and a &[u8] slice that is contained in it, and
create a new Bytes that corresponds to that subset slice.

Closes #198
2018-09-01 19:57:31 -07:00
Carl LercheandGitHub ed244d3b54 Bump version to v0.4.9 (#220) 2018-07-22 19:30:41 -07:00
Carl Lerche dc961c3e78 Merge branch 'v0.4.x' 2018-07-12 20:19:56 -07:00
Sean McArthurandCarl Lerche 890812af1b inline Bytes::len and Bytes::is_empty (#211) 2018-07-12 20:17:27 -07:00
Rafael Ávila de EspíndolaandCarl Lerche 052648c3f5 Implement IntoBuf for mut slices. (#214)
With this if foo is a mutable slice, it is possible to do

foo.into_buf().put_u32_le(42);

Before this patch into_buf would create a Cursor<&'a [u8]> and it
would not be possible to write into it.
2018-07-12 20:16:08 -07:00
RomanandCarl Lerche 042aa9023b Fix cargo doc error on nightly caused by broken link to footnote (#218) 2018-07-12 20:15:53 -07:00
Carl Lerche f4100841f8 Merge branch 'v0.4.x' 2018-07-12 20:11:51 -07:00
Sean McArthurandCarl Lerche cdfd25f314 inline Bytes::len and Bytes::is_empty (#211) 2018-07-12 19:05:35 -07:00
Geoffry SongandCarl Lerche 1ba5266bd9 Put type names in backticks. (#212)
I noticed that the bare `[u8]` made rustdoc nightly unhappy.
2018-07-12 19:05:02 -07:00
Rafael Ávila de EspíndolaandCarl Lerche 83f68a013e Implement IntoBuf for mut slices. (#214)
With this if foo is a mutable slice, it is possible to do

foo.into_buf().put_u32_le(42);

Before this patch into_buf would create a Cursor<&'a [u8]> and it
would not be possible to write into it.
2018-07-12 19:03:47 -07:00
RomanandCarl Lerche 63211d8c82 Fix cargo doc error on nightly caused by broken link to footnote (#218) 2018-07-05 10:13:01 -07:00
Sean McArthurandCarl Lerche 886dda0962 Optimize Inner::shallow_clone (#217)
- Clones when the kind is INLINE or STATIC are sped up by over double.
- Clones when the kind is ARC are spec up by about 1/3.
2018-07-03 15:21:26 -07:00
luben karavelovandCarl Lerche 6414efe83b Fix documentation (#219) 2018-07-02 12:10:16 -07:00
Ashley MannixandCarl Lerche 7785cde587 add support for 128bit numbers (#209) 2018-06-18 17:37:51 -07:00
Carl Lerche d98f49e67b Merge branch 'v0.4.x' 2018-06-18 12:52:00 -07:00
Carl LercheandGitHub a6b9844296 Clarify license as MIT (#216)
The intent of the license was to dual license MIT & Apache 2.0. However,
the messaging was copy / pasted from rust-lang.

Clarify the license as exclusively MIT.

Fixes #215
2018-06-18 12:49:34 -07:00
Carl Lerche 8d5b46cd10 Merge branch 'v0.4.x' 2018-05-25 16:56:31 -07:00
Carl LercheandGitHub 3557bafa5c Filter out tsan warnings in test harness (#205) 2018-05-25 15:32:39 -07:00
Carl Lerche c87739bb55 Merge branch 'v0.4.x' 2018-05-25 14:15:00 -07:00
Noah ZentzisandCarl Lerche 2d95683bd5 Recycle space when reserving from Vec-backed Bytes (#197)
* Recycle space when reserving from Vec-backed Bytes

BytesMut::reserve, when called on a BytesMut instance which is backed by
a non-shared Vec<u8>, would previously just delegate to Vec::reserve
regardless of the current location in the buffer. If the Bytes is
actually the trailing component of a larger Vec, then the unused space
won't be recycled. In applications which continually move the pointer
forward to consume data as it comes in, this can cause the underlying
buffer to get extremely large.

This commit checks whether there's extra space at the start of the
backing Vec in this case, and reuses the unused space if possible
instead of allocating.

* Avoid excessive copying when reusing Vec space

Only reuse space in a Vec-backed Bytes when doing so would gain back
more than half of the current capacity. This avoids excessive copy
operations when a large buffer is almost (but not completely) full.
2018-05-24 14:50:31 -07:00
Carl Lerche d656d37180 Merge branch 'v0.4.x' 2018-04-27 10:42:00 -07:00
kohensuandCarl Lerche e444722098 Improve performance of Buf::get_*() (#195)
The new implementation tries to get the data directly from bytes() (this is
possible most of the time) and if there is not enough data in bytes() use the
previous code: copy the needed bytes in a temporary buffer before returning
the data

Here the bench results:
                               Before                After           x-faster
get_f32::cursor             64 ns/iter (+/- 0)    20 ns/iter (+/- 0)    3.2
get_f32::tbuf_1             77 ns/iter (+/- 1)    34 ns/iter (+/- 0)    2.3
get_f32::tbuf_1_costly      87 ns/iter (+/- 0)    62 ns/iter (+/- 0)    1.4
get_f32::tbuf_2            151 ns/iter (+/- 18)  160 ns/iter (+/- 1)    0.9
get_f32::tbuf_2_costly     180 ns/iter (+/- 2)   187 ns/iter (+/- 2)    1.0

get_f64::cursor             67 ns/iter (+/- 0)    21 ns/iter (+/- 0)    3.2
get_f64::tbuf_1             80 ns/iter (+/- 0)    35 ns/iter (+/- 0)    2.3
get_f64::tbuf_1_costly      82 ns/iter (+/- 3)    60 ns/iter (+/- 0)    1.4
get_f64::tbuf_2            154 ns/iter (+/- 1)   164 ns/iter (+/- 0)    0.9
get_f64::tbuf_2_costly     170 ns/iter (+/- 2)   187 ns/iter (+/- 1)    0.9

get_u16::cursor             66 ns/iter (+/- 0)    20 ns/iter (+/- 0)    3.3
get_u16::tbuf_1             77 ns/iter (+/- 0)    35 ns/iter (+/- 0)    2.2
get_u16::tbuf_1_costly      85 ns/iter (+/- 2)    62 ns/iter (+/- 0)    1.4
get_u16::tbuf_2            147 ns/iter (+/- 0)   154 ns/iter (+/- 0)    1.0
get_u16::tbuf_2_costly     160 ns/iter (+/- 1)   177 ns/iter (+/- 0)    0.9

get_u32::cursor             64 ns/iter (+/- 0)    20 ns/iter (+/- 0)    3.2
get_u32::tbuf_1             77 ns/iter (+/- 0)    35 ns/iter (+/- 0)    2.2
get_u32::tbuf_1_costly      91 ns/iter (+/- 2)    63 ns/iter (+/- 0)    1.4
get_u32::tbuf_2            151 ns/iter (+/- 40)  157 ns/iter (+/- 0)    1.0
get_u32::tbuf_2_costly     162 ns/iter (+/- 0)   180 ns/iter (+/- 0)    0.9

get_u64::cursor             67 ns/iter (+/- 0)    20 ns/iter (+/- 0)    3.4
get_u64::tbuf_1             78 ns/iter (+/- 0)    35 ns/iter (+/- 1)    2.2
get_u64::tbuf_1_costly      87 ns/iter (+/- 1)    59 ns/iter (+/- 1)    1.5
get_u64::tbuf_2            154 ns/iter (+/- 0)   160 ns/iter (+/- 0)    1.0
get_u64::tbuf_2_costly     168 ns/iter (+/- 0)   184 ns/iter (+/- 0)    0.9

get_u8::cursor              64 ns/iter (+/- 0)    19 ns/iter (+/- 0)    3.4
get_u8::tbuf_1              77 ns/iter (+/- 0)    35 ns/iter (+/- 0)    2.2
get_u8::tbuf_1_costly       68 ns/iter (+/- 0)    51 ns/iter (+/- 0)    1.3
get_u8::tbuf_2              85 ns/iter (+/- 0)    43 ns/iter (+/- 0)    2.0
get_u8::tbuf_2_costly       75 ns/iter (+/- 0)    61 ns/iter (+/- 0)    1.2
get_u8::option              77 ns/iter (+/- 0)    59 ns/iter (+/- 0)    1.3

Improvement on the basic std::Cursor implementation are clearly visible.

Other implementations are specific to the bench tests and just map a static
slice. Different variant are:
 - tbuf_1: only one call of 'bytes()' is needed.
 - tbuf_2: two calls of 'bytes()' is needed to read more than one byte.
 - _costly version are implemented with #[inline(never)] on 'bytes()',
   'remaining()' and 'advance()'.

The cases that are slower (slightly) correspond to implementations that are not
really realistic: more than one byte is never possible in one time
2018-04-27 10:07:27 -07:00
kohensuandCarl Lerche d561006290 Add a bench for Buf::get_*() (#194) 2018-04-27 09:53:57 -07:00
Anthony RamineandCarl Lerche 2c27ddaf7e Introduce Bytes::to_mut (#188) 2018-03-12 09:51:10 -07:00
Alan SomersandCarl Lerche ae1b45495b impl BorrowMut for BytesMut (#185) 2018-03-12 09:46:16 -07:00
Carl Lerche ebe522731f Fix copy_to_slice to use correct increment var
This patch fixes the `copy_to_slice` function, rectifying the logic.
However, the incorrect code does not result in incorrect behavior as the
only case `cnt != src.len()` is during the final iteration, and since
`src.len()` is greater than `cnt` in that case, `off` will be
incremented by too much, but this will still trigger the `off <
dst.len()` condition.

The only danger is `src.len()` could cause an overflow.
2018-03-12 09:39:33 -07:00
Carl Lerche bd4630a321 Merge remote-tracking branch 'origin/v0.4.x' 2018-03-12 09:34:35 -07:00
Sean McArthurandCarl Lerche 025d53342e Remove ByteOrder generic methods from Buf and BufMut (#187)
* make Buf and BufMut usable as trait objects

- All the `get_*` and `put_*` methods that take `T: ByteOrder` have
  a `where Self: Sized` bound added, so that they are only usable from
  sized types. It was impossible to make `Buf` or `BufMut` into trait
  objects before, so this change doesn't break anyone.
- Add `get_n_be`/`get_n_le`/`put_n_be`/`put_n_le` methods that can be
  used on trait objects.
- Deprecate the export of `ByteOrder` and methods generic on it.

* remove deprecated ByteOrder methods

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