Compare commits

...
332 Commits
Author SHA1 Message Date
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 406b048ae6 Bump version to v0.4.8 (#206) 2018-05-25 16:50:42 -07:00
Carl Lerche 8c041142a0 Filter out tsan warnings in test harness (#205) 2018-05-25 15:54:13 -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
Luke HorsleyandCarl Lerche e9a7098658 Added a resize function for BytesMut (#203) 2018-05-25 13:54:32 -07:00
Carl LercheandGitHub 32ea8281b3 Use sanitizers in CI (#204) 2018-05-25 12:40:37 -07:00
Noah ZentzisandCarl Lerche dfce95b89d 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 16:37:13 -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 b68fa46e3d Fix panic in FromIterator for BytesMut 2018-05-11 08:45:04 -07:00
Carl Lerche ef09e98fbc Bump version to v0.4.7 2018-04-27 10:51:09 -07:00
Carl Lerche d656d37180 Merge branch 'v0.4.x' 2018-04-27 10:42:00 -07:00
kohensuandCarl Lerche 51e435b7e0 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:18:52 -07:00
Alan SomersandCarl Lerche 15050b1da5 impl BorrowMut for BytesMut (#185) (#192) 2018-04-27 10:08:50 -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
Sean McArthurandCarl Lerche ce79f0a268 Make Buf and BufMut usable as trait objects (#186)
- 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.

Fixes #163
2018-03-12 09:25:59 -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 LercheandGitHub 86c83959dc Have Travis build WASM target (#180) 2018-01-29 10:18:52 -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
Carl Lerche e5c4c6028d Bump version to v0.4.6 2018-01-08 09:11:42 -08:00
jq-rsandCarl Lerche ba9a975358 Unsplit improvements (#173)
* Handle empty self and other for unsplit.
* Change extend() to extend_from_slice().
2018-01-05 16:20:59 -08:00
Stepan KoltsovandCarl Lerche 6a3d20bb8d Optimize shallow_clone for Bytes::split_{off,to} (#92)
If `shallow_clone` is called with `&mut self`, and `Bytes` contains
`Vec`, then expensive CAS can be avoided, because no other thread
have references to this `Bytes` object.

Bench `split_off_and_drop` difference:

Before the diff:

```
test split_off_and_drop             ... bench:      91,858 ns/iter (+/- 17,401)
```

With the diff:

```
test split_off_and_drop             ... bench:      81,162 ns/iter (+/- 17,603)
```
2018-01-03 11:41:33 -08:00
jq-rsandCarl Lerche 2ca61d881d Add support for unsplit() to BytesMut (#162)
Add support for unsplit() to BytesMut which combines splitted contiguous memory blocks efficiently.
2018-01-03 09:54:51 -08:00
Carl LercheandGitHub 8d6c2b61cc Document correct inline capacity in bytes.rs (#171)
Fixes #164
2017-12-15 18:10:30 -06:00
Carl LercheandGitHub 02891144be Add advance on Bytes and BytesMut (#166)
* Compact Bytes original capacity representation

In order to avoid unnecessary allocations, a `Bytes` structure remembers
the capacity with which it was first created. When a reserve operation
is issued, this original capacity value is used to as a baseline for
reallocating new storage.

Previously, this original capacity value was stored in its raw form. In
other words, the original capacity `usize` was stored as is. In order to
reclaim some `Bytes` internal storage space for additional features,
this original capacity value is compressed from requiring 16 bits to 3.

To do this, instead of storing the exact original capacity. The original
capacity is rounded down to the nearest power of two. If the original
capacity is less than 1024, then it is rounded down to zero. This
roughly means that the original capacity is now stored as a table:

0 => 0
1 => 1k
2 => 2k
3 => 4k
4 => 8k
5 => 16k
6 => 32k
7 => 64k

For the purposes that the original capacity feature was introduced, this
is sufficient granularity.

* Provide `advance` on Bytes and BytesMut

This is the `advance` function that would be part of a `Buf`
implementation. However, `Bytes` and `BytesMut` cannot impl `Buf` until
the next breaking release.

The implementation uses the additional storage made available by the
previous commit to store the number of bytes that the view was advanced.
The `ptr` pointer will point to the start of the window, avoiding any
pointer arithmetic when dereferencing the `Bytes` handle.
2017-12-13 13:30:03 -06:00
Carl Lerche 149922d7cf Get test passing again 2017-10-21 15:47:45 -07:00
Dan BurkertandCarl Lerche 03d501b18d small fixups in bytes.rs (#145)
* Inner: make uninitialized construction explicit
* Remove Inner2
* Remove unnecessary transmutes
* Use AtomicPtr::get_mut where possible
* Some minor tweaks
2017-08-18 08:33:28 -07:00
JefandCarl Lerche 34540be54c Add FromIterator impl (#148) 2017-08-17 10:32:59 -07:00
Sean McArthurandCarl Lerche cfca1c04fa print space normally in Debug for Bytes (#155) 2017-08-17 10:28:06 -07:00
Carl Lerche c8c46d8513 Bump version to v0.4.5 2017-08-12 10:59:31 -07:00
Alex CrichtonandCarl Lerche 7839100389 Inline as_ref functions on Bytes and BytesMut (#154) 2017-08-05 21:12:26 -07:00
Paul CollierandCarl Lerche 6750a26fd0 impl AsMut<[u8]> for BytesMut (#143) (#144) 2017-07-02 14:21:30 -07:00
Stepan KoltsovandCarl Lerche b9ccd2a866 Optimize Bytes::slice for short slices (#136)
Slice operation should return inline when possible

It is cheaper than atomic increment/decrement.

Before this patch:

```
test slice_avg_le_inline_from_arc   ... bench:      28,582 ns/iter (+/- 3,880)
test slice_empty                    ... bench:       8,797 ns/iter (+/- 1,325)
test slice_large_le_inline_from_arc ... bench:      27,684 ns/iter (+/- 5,920)
test slice_short_from_arc           ... bench:      27,439 ns/iter (+/- 5,783)
```

After this patch:

```
test slice_avg_le_inline_from_arc   ... bench:      18,872 ns/iter (+/- 2,937)
test slice_empty                    ... bench:       9,136 ns/iter (+/- 1,908)
test slice_large_le_inline_from_arc ... bench:      18,052 ns/iter (+/- 2,981)
test slice_short_from_arc           ... bench:      18,200 ns/iter (+/- 2,534)
```
2017-07-01 14:10:09 -07:00
Georg BrandlandCarl Lerche 544997958f Minor doc spelling and consistency fixes (#142) 2017-07-01 14:03:23 -07:00
Stepan KoltsovandCarl Lerche d315d00a3b Bytes::with_capacity (#137) 2017-06-30 20:33:35 -07:00
Clint ByrumandCarl Lerche fb2d8cf1c0 Add convenience PartialEq for BytesMut and Bytes (#141)
Saves the cognitive load of having to wrap them in slices to compare
them when that seems like what one would expect.

Signed-off-by: Clint Byrum <[email protected]>
2017-06-30 20:33:01 -07:00
Dan BurkertandCarl Lerche 7ed78cef47 Fix index-oob panic in Take::bytes (#138)
The panic happens when `inner.bytes()` returns a slice smaller than the
limit.
2017-06-27 11:23:29 -07:00
Igor GnatenkoandCarl Lerche aab71ef82c reference Apache-2.0 in Cargo.toml (#134) 2017-06-26 10:33:17 -07:00
Sean McArthurandCarl Lerche 7e8373da8d Faster From<[u8]> for BytesMut, remove panic in fmt::Write (#133)
* use slice.to_vec instead of buf.put in From<[u8]>

* don't panic in fmt::Write for BytesMut
2017-06-15 10:55:02 -07:00
Carl Lerche 3240fb9cd9 Bump version to v0.4.4 2017-05-26 10:09:43 -07:00
Stepan KoltsovandCarl Lerche 9ae51c9f0c Implement truncate, clear for Bytes (#128) 2017-05-26 09:29:31 -07:00
brianwpandCarl Lerche 2b0602e756 impl ExactSizeIterator for Iter<T: Buf> (#127) 2017-05-24 08:13:19 -07:00
Stepan KoltsovandCarl Lerche 3f5890be70 Optimize Bytes::slice(n, n) (#123)
Return empty `Bytes` object

Bench for `slice_empty` difference is

```
55 ns/iter (+/- 1) # before this patch
17 ns/iter (+/- 5) # with this patch
```

Bench for `slice_not_empty` is

```
25,058 ns/iter (+/- 1,099) # before this patch
25,072 ns/iter (+/- 1,593) # with this patch
```
2017-05-22 13:15:08 -07:00
Carl Lerche 70ee87ea29 Fix benchmarks 2017-05-22 12:02:51 -07:00
Stepan KoltsovandCarl Lerche edf1af958a Minor doc fixes (#124) 2017-05-22 11:30:34 -07:00
Stepan KoltsovandCarl Lerche 7110d57b2f BytesMut::reserve should not overallocate (#117)
Round up to power of 2 is not necessary, because `reserve` already
doubles previous capacity in

```
	new_cap = cmp::max(
		cmp::max(v.capacity() << 1, new_cap),
		original_capacity);
```

which makes `reserve` calls constant in average. Avoiding rounding
up prevents `reserve` from wasting space when caller knows exactly
what space they need.

Patch adds three tests which would fail before this test. The most
important is this:

```
#[test]
fn reserve_in_arc_unique_does_not_overallocate() {
    let mut bytes = BytesMut::with_capacity(1000);
    bytes.take();

    // now bytes is Arc and refcount == 1

    assert_eq!(1000, bytes.capacity());
    bytes.reserve(2001);
    assert_eq!(2001, bytes.capacity());
}
```

It asserts that when user requests more than double of current
capacity, exactly the requested amount of memory is allocated and
is not wasted to next power of two.
2017-05-15 11:28:12 -07:00
Stepan KoltsovandCarl Lerche 07db74b009 Bytes::extend_from_slice (#120)
`extend_with_slice` is super-convenient operation on `Bytes`.

While `put_u8` would be expensive on `Bytes`, `extend_from_slice`
is OK, because it is batch, and it checks for kind only once.

Patch also adds `impl Extend for Bytes`.

cc #116
2017-05-15 11:27:45 -07:00
Jack O'ConnorandCarl Lerche 6af66c4f21 fix a docs typo (#115) 2017-05-02 12:35:06 -07:00
Stepan KoltsovandCarl Lerche fa44c7e355 BytesMut::extend_from_slice shortcut (#112)
Similar to `Vec::extend_from_slice`: it a reserve followed by
memcopy.
2017-05-02 11:28:12 -07:00
Stepan KoltsovandCarl Lerche 2c0cb1b6b8 BytesMut::new constructor (#114) 2017-05-02 11:23:20 -07:00
Arthur SilvaandCarl Lerche b196559818 Add serde support behind serde feature (#96) 2017-05-02 10:51:52 -07:00
Sean McArthurandCarl Lerche 37f6cabd96 implement Default for Bytes and BytesMut (#110) 2017-05-01 12:53:27 -07:00
Carl Lerche e5c7ef3b86 Bump version to v0.4.3 2017-04-30 16:25:54 -07:00
Dan BurkertandCarl Lerche 30bd7c1f21 Vec::advance_mut can advance past the end of the buffer (#108) 2017-04-30 16:14:54 -07:00
Arthur SilvaandCarl Lerche 923d927bd1 Bump minimum rust version to 1.15 (#107) 2017-04-26 11:35:10 -07:00
Phil RuffwindandCarl Lerche 0b4185c716 Fix typos in src/bytes.rs (#106) 2017-04-24 12:47:24 -07:00
jaystrictorandCarl Lerche e158160418 Remove calls to deprecated drain* methods from docs (#102) 2017-04-14 09:06:58 -07:00
Sean McArthurandCarl Lerche 4645f6ec4b implement put_u8 for BytesMut (#101) 2017-04-06 08:59:13 -07:00
Carl Lerche 1a6901cdcd Bump version to v0.4.2 2017-04-05 12:12:05 -07:00
Carl LercheandGitHub 9aa24ebea1 Bytes: only the vec repr is not shared (#100)
The shared debug_assert is to ensure that the internal Bytes
representation is such that offset views are supported. The only
representation that does not support offset views is vec.

Fixes #97
2017-03-30 14:49:30 -07:00
Stepan KoltsovandCarl Lerche 627864187c Bytes::split_{off,to} should panic if at > len (#91) 2017-03-28 12:38:48 -07:00
Stepan KoltsovandCarl Lerche b78bb3baaa Handle corner cases of Bytes::split_{off,to} (#87)
Before this commit `Bytes::split_{off,to}` always created a shallow copy if `self` is arc or vec.

However, in certain cases `split_off` or `split_to` is called with `len` or `0` parameter. E. g. if you are reading a frame from buffered stream, it is likely that buffer contains exactly the frame size bytes, so `split_to` will be called with `len` param.

Although, `split_off` and `split_to` functions are `O(1)`, shallow copy have downsides:

* shallow copy on vector does malloc and atomic cmpxchg
* after shallow copy, following operations (e. g. `drop`) on both `bytes` objects require atomics
* memory will be probably released to the system later
* `try_mut` will fail
* [into_vec](https://github.com/carllerche/bytes/issues/86) will copy
2017-03-27 20:45:22 -07:00
Alex CrichtonandCarl Lerche 6c6c55d8e1 Flag Deref methods as #[inline] (#93) 2017-03-24 07:39:57 -07:00
Stepan KoltsovandCarl Lerche 613d4bd5d5 Reimplement fmt::Debug for Bytes and BytesMut (#84)
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.
2017-03-20 21:09:44 -07:00
Carl LercheandGitHub dc9c8e304e Misc CI fixes (#89)
Limit the number of threads when using qemu to 1. Also, don't bother
running the stress test as this will trigger qemu bugs. Finally, also
make the stress test actually stress test.
2017-03-20 10:12:23 -07:00
Carl Lerche bed128b2c0 Clarify when BufMut::bytes_mut can return &[]
Closes #79
2017-03-19 13:58:44 -07:00
Dan BurkertandCarl Lerche 5a265cc8eb Add inline attributes to Vec's MutBuf methods (#80)
I found this significantly improved a
[benchmark](https://gist.github.com/danburkert/34a7d6680d97bc86dca7f396eb8d0abf)
which calls `bytes_mut`, writes 1 byte, and advances the pointer with
`advance_mut` in a pretty tight loop. In particular, it seems to be the
inline annotation on `bytes_mut` which had the most effect. I also took
the opportunity to simplify the bounds checking in advance_mut.

before:

```
test encode_varint_small  ... bench:         540 ns/iter (+/- 85) = 1481 MB/s
```

after:

```
test encode_varint_small  ... bench:         422 ns/iter (+/- 24) = 1895 MB/s
```

As you can see, the variance is also significantly improved.

Interestingly, I tried to change the last statement in `bytes_mut` from

```
&mut slice::from_raw_parts_mut(ptr, cap)[len..]
```

to

```
slice::from_raw_parts_mut(ptr.offset(len as isize), cap - len)
```

but, this caused a very measurable perf regression (almost completely
negating the gains from marking bytes_mut inline).
2017-03-19 13:54:09 -07:00
Dan BurkertandCarl Lerche 4fe4e9429a Clarify BufMut::advance_mut docs (#78)
Also fixes an issue with a line wrap in the middle of an inline code
block.
2017-03-19 13:53:33 -07:00
Carl Lerche 9a4018e757 Fix tests on nightly
Closes #83
2017-03-19 09:08:41 -07:00
Carl LercheandGitHub 99fba239db Tweak docs (#76) 2017-03-16 12:11:10 -07:00
Carl Lerche dcd6c184e4 Bump version to v0.4.1 2017-03-15 09:36:52 -07:00
Carl Lerche 9e6d65a1d6 Add a changelog 2017-03-15 09:36:11 -07:00
Carl Lerche 02b6144644 Depend on released iovec crate 2017-03-15 09:23:10 -07:00
Carl Lerche 2e319b51be Impl Extend for BytesMut 2017-03-07 15:06:47 -08:00
Carl Lerche 06b94c55b0 Remove buf::Source in favor of buf::IntoBuf
The `Source` trait was essentially covering the same case as `IntoBuf`,
so remove it.

While technically a breaking change, this should not have any impact due
to:

1) There are no reverse dependencies that currently depend on `bytes`
2) Source was not supposed to be implemented externally
3) IntoBuf provides the same implementations as `Source`

Given these points, the change should be safe to apply.
2017-03-07 11:30:08 -08:00
Carl Lerche d70f575afd Provide Debug impls for all types 2017-03-07 10:20:58 -08:00
Carl Lerche 933b8b26f6 BytesMut::reserve should avoid small allocations
This change tracks the original capacity requested when `BytesMut` is
first created. This capacity is used when a `reserve` needs to allocate
due to the current view being too small. The newly allocated buffer will
be sized the same as the original allocation.
2017-03-02 16:14:14 -08:00
Carl Lerche b44fc31463 Move Inner constructions to struct fns 2017-03-02 13:46:14 -08:00
Carl Lerche d0142aa6da Clarify API edge cases 2017-03-01 18:30:58 -08:00
Carl Lerche 94396162b2 Implement chain combinator for Buf 2017-03-01 14:22:53 -08:00
Carl Lerche bb9bf7ee3e Add vectored support to Buf and BufMut 2017-03-01 13:18:29 -08:00
Carl Lerche 4462056e26 Move stray impls into appropriate file 2017-03-01 13:15:11 -08:00
Carl Lerche 30c0e4e9c8 Merge remote-tracking branch 'alexcrichton/more-object-safe' 2017-03-01 10:44:22 -08:00
Alex Crichton d19c929018 Expand object-safe impls slightly
Add `?Sized` bounds to work for DST objects and also add impls for `Box` as well
as `&mut`
2017-03-01 10:37:30 -08:00
Carl Lerche 8fec8a92ad Implement iterator adapter for Buf 2017-03-01 10:03:28 -08:00
Carl Lerche 4f8c565111 Implement FromBuf and Buf::collect
Enables collecting the contents of a `Buf` value into a relevant
concrete buffer implementation.
2017-03-01 09:30:13 -08:00
Carl Lerche fd8f716e68 Rename a test file to match lib naming 2017-02-28 19:10:30 -08:00
Carl Lerche 22a5fb8d9b Rename some functions on Bytes 2017-02-28 19:05:25 -08:00
Carl Lerche e842296c4d Implement IntoBuf for T: Buf 2017-02-28 19:02:45 -08:00
Carl Lerche f7f8d6c9ef Don't re-export everything from buf module 2017-02-28 17:09:43 -08:00
Alex CrichtonandCarl Lerche 87160b6232 Add doc(html_root_url)
Allows links in other crates to link to crates.io docs of bytes itself.
2017-02-28 16:55:10 -08:00
Carl Lerche 4466b75ae4 Split buf.rs into separate files 2017-02-28 15:21:20 -08:00
Carl Lerche 9eb5bd50b8 Bump version to 0.4 2017-02-24 10:35:53 -08:00
Carl Lerche b46d3fd32e Tweak growth algorithm in BytesMut::reserve 2017-02-20 21:07:25 -08:00
Carl Lerche 8c11456185 Combine reserve and try_reclaim
Instead of providing a separate `try_reclaim` function, `reserve` will
attempt to reclaim the existing buffer before allocating.
2017-02-20 19:31:02 -08:00
Carl Lerche 128c56ddc4 Fix link to documentation 2017-02-20 14:33:35 -08:00
Carl Lerche 5c6eadfcb0 More docs and polish 2017-02-20 14:31:26 -08:00
Carl Lerche c6fe5a1e4f Add some missing Bytes impls and fns 2017-02-20 14:03:37 -08:00
Carl Lerche 99aafb0a22 Fix uploading master docs 2017-02-20 12:43:15 -08:00
Carl Lerche cf5a1bc4f1 Rewrite Bytes / BytesMut core implementation
The previous implementation didn't factor in a single `Bytes` handle
being stored in an `Arc`. This new implementation correctly impelments
both `Bytes` and `BytesMut` such that both are `Sync`.

The rewrite also increases the number of bytes that can be stored
inline.
2017-02-20 10:41:20 -08:00
Carl Lerche 0360f191f8 Finish up docs 2017-02-17 12:23:09 -08:00
Carl Lerche aa06b6dd6a More docs 2017-02-17 11:37:19 -08:00
Carl Lerche 5048eec143 Docs & polish for Buf 2017-02-16 22:15:17 -08:00
Carl Lerche 268226051d Implement Hash and Borrow for Bytes / BytesMut 2017-02-16 16:52:56 -08:00
Carl Lerche 646624c130 Polish API surface 2017-02-16 16:44:38 -08:00
Carl Lerche bababa8797 Remove Take/TakeMut 2017-02-16 10:36:00 -08:00
Carl Lerche 0e0066e8a0 Write docs and remove unecessary fns and types 2017-02-16 10:26:48 -08:00
Carl Lerche 53d1c788e0 Start writing docs for bytes 2017-02-15 14:43:11 -08:00
Carl Lerche 4c6ebeba87 Provide two versions of drain_to and split_off
* `drain_to` and `split_off` take &self and return Bytes.
* `drain_to_mut` and `split_off_mut` take &mut self and return BytesMut
2017-02-15 12:46:27 -08:00
Carl Lerche 8da9e81469 Tweak CI settings 2017-02-15 09:45:30 -08:00
Carl Lerche 36c9a8c287 Support static refs and inline short byte slices 2017-02-15 09:38:55 -08:00
Carl Lerche 44d40d34d7 Cleanup Bytes 2017-02-10 12:04:32 -08:00
Aaron J. ToddandCarl Lerche 70fed562eb Update byteorder to 1.0 2017-02-06 11:58:44 -08:00
Carl Lerche accc8a460d Add explicit inlines 2017-02-03 11:22:16 -08:00
Carl Lerche 8b01298806 Support older Rust versions 2017-01-26 14:54:25 -08:00
Carl Lerche a8320da0f8 Lazily allocate the Arc 2017-01-26 12:56:38 -08:00
Carl Lerche 93c08064bb Fix BytesMut refcounting 2016-11-22 10:31:17 -08:00
Rick Richardson 2b796d40e9 added clone to ByteBuf and BytesMut along with simple clone test 2016-11-21 15:43:59 -08:00
Carl Lerche 12d0804f17 Fix building docs 2016-11-18 10:14:03 -08:00
Carl Lerche 4886b44516 Add more conversion impls 2016-11-02 22:27:00 -07:00
Carl Lerche a367a723d8 Impl IntoBuf for Bytes and BytesMut 2016-11-02 14:33:42 -07:00
Carl Lerche 11fe277c0d Remove default for SliceBuf<T> 2016-11-02 14:31:44 -07:00
Carl Lerche 57e84f267b Restructure and trim down the library
This commit is a significant overhaul of the library in an effort to head
towards a stable API. The rope implementation as well as a number of buffer
implementations have been removed from the library and will live at
https://github.com/carllerche/bytes-more while they incubate.

**Bytes / BytesMut**

`Bytes` is now an atomic ref counted byte slice. As it is contigous, it offers
a richer API than before.

`BytesMut` is a mutable variant. It is safe by ensuring that it is the only
handle to a given byte slice.

**AppendBuf -> ByteBuf**

`AppendBuf` has been replaced by `ByteBuf`. The API is not identical, but is
close enough to be considered a suitable replacement.

**Removed types**

The following types have been removed in favor of living in bytes-more

* RingBuf
* BlockBuf
* `Bytes` as a rope implementation
* ReadExt
* WriteExt
2016-11-02 14:23:45 -07:00
Carl Lerche d717fde5ca Fix remaining 2016-10-25 20:09:54 -07:00
Carl Lerche b42d94c33b Add BoundBuf 2016-10-14 20:42:32 -07:00
Carl Lerche 8d2508bfeb Tweak Bytes helpers 2016-10-14 20:42:16 -07:00
Carl Lerche ec7d7f27fe Add Bytes::from_vec 2016-10-14 20:07:57 -07:00
Carl Lerche d7306d949b Rename slice_buf.rs -> slice.rs 2016-10-14 20:07:42 -07:00
Carl Lerche a4bfc63de7 Tweak Sink / Source 2016-10-07 15:37:12 -07:00
Carl Lerche 6f97d04077 Add IntoBuf impls for non-ref types 2016-10-07 14:44:29 -07:00
Carl Lerche e00c08c6c7 Impl IntoBuf for &'static [u8] 2016-10-07 12:55:18 -07:00
Carl Lerche e1c7f183ca Impl IntoBuf for () 2016-09-30 09:58:41 -07:00
Carl Lerche 4ca7e0fabf Add IntoBuf trait 2016-09-25 22:40:39 -07:00
Carl Lerche b10992a5e8 Refactor RingBuf 2016-09-25 22:40:39 -07:00
Carl Lerche b1dc10e907 Rename & refactor ByteBuf -> SliceBuf 2016-09-25 22:40:35 -07:00
Carl Lerche c16ad2bc9d Add some docs 2016-09-23 14:53:14 -07:00
Carl Lerche a7d38e29e5 Remove extra lifetime sigils 2016-09-23 14:51:48 -07:00
Carl Lerche 98e0d954b5 Reorganize crate 2016-09-23 12:05:32 -07:00
Carl Lerche d05bfb6346 Add more Buf helpers 2016-09-23 07:53:17 -07:00
Carl Lerche 3c58b0c75c Add take fn to Buf & MutBuf 2016-09-21 20:41:21 -07:00
Carl Lerche 4105901244 Rename RingBuf::new -> with_capacity 2016-09-20 13:42:24 -07:00
Nikolay Kim 1f188b5628 fix dropping front block in BlockBuf 2016-09-13 15:30:44 -07:00
Stefan BühlerandCarl Lerche f693e038d9 Fix buffer overflow in Sink for Vec<u8>
Fixes #46
2016-09-03 13:25:40 -07:00
Carl Lerche d0d27bd540 Bump min supported Rust version 2016-09-03 13:24:52 -07:00
Carl Lerche 046c864543 Integrate with byteorder 2016-08-31 12:07:44 -07:00
Carl Lerche 38abb8074b Create ByteBuf with MutByteBuf::with_capacity 2016-08-23 14:22:39 -07:00
Carl Lerche be23af6bb7 Remove stable heap for now 2016-08-11 01:38:15 -07:00
Carl Lerche fbebb19a02 Simplify allocation strategy for now
Not having `unsafe_no_drop_flag` caused some weirdness with optimizing buffers
and bytes. For now, remeove it.
2016-08-11 01:36:16 -07:00
Carl Lerche 04e0ac75e2 Huge overhaul of bytes
* Get rid of `ByteStr` trait
* `Bytes` is not a concrete type
* Add `BlockBuf`
* Delete lots of cruft
* Performance work
2016-08-10 15:45:31 -07:00
Carl Lerche b2efe63c70 Get rid of SliceBuf 2016-08-05 22:49:41 -07:00
Carl Lerche 16b4266c3c Improve Buf/MutBuf impl for Cursor 2016-08-05 22:19:37 -07:00
Carl Lerche b6a424d892 Get rid of BufError 2016-08-05 21:54:29 -07:00
Carl Lerche 6529f6392a Remove traits mod 2016-08-05 21:42:07 -07:00
Carl Lerche 3f68c4bd27 Bump minimum supported Rust version 2016-07-23 10:03:30 -07:00
Carl Lerche eec203c118 Use latest stable-heap git 2016-07-23 10:00:15 -07:00
Carl Lerche 41b722dee8 Allow checking out AppendBufs from Pool 2016-07-23 09:54:18 -07:00
Carl Lerche d650404bb8 Add an AppendBuf 2016-07-23 09:49:59 -07:00
Carl Lerche 1c2234f7fe Initial stab at a buffer pool 2016-07-20 22:47:41 +02:00
Carl Lerche dc25c7564e Refactor heap allocation 2016-07-20 13:27:41 +02:00
Carl Lerche b10b1cd2e2 Bump version to v0.4.0-dev 2016-07-19 14:10:07 +02:00
Carl Lerche 3ca009577b Bytes reader should be Send 2016-06-19 21:32:18 +01:00
Carl Lerche 270d2e2844 Freshen up buf API 2016-06-08 14:48:49 -07:00
66 changed files with 9094 additions and 3363 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-04-13
defaults:
run:
shell: bash
jobs:
# Check formatting
rustfmt:
name: rustfmt
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- 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@v2
# - 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@v2
- 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@v2
- 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@v2
- 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@v2
- 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@v2
- 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@v2
- name: Miri
run: ci/miri.sh
# Loom
loom:
name: loom
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- 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@v2
- 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'
-17
View File
@@ -1,17 +0,0 @@
---
language: rust
sudo: false
rust:
- nightly
- 1.1.0
script:
- cargo test
- cargo doc --no-deps
after_success:
- test $TRAVIS_PULL_REQUEST == "false" && test $TRAVIS_BRANCH == "master" && bash deploy.sh
env:
global:
secure: "mBLJANLvtmyWCXw4zMquptqHQnws0pF+C/u4zL1Jfwz8T4UnUjmBUMxSOgSEIzrOM3qb+CTCjY2/j6BM21+/Zfdl8k8CvFWtkqQUPwIfrtwddCgI+P8Hlrk8G43drz/8XAbZ7dOl+Ovwhr0xnSD9ImfyXJec1kDWhubmgyt47Fs="
+220
View File
@@ -0,0 +1,220 @@
# 1.1.0 (August 25, 2021)
### Added
- `BufMut::put_bytes(self, val, cnt)` (#487)
- Implement `From<Box<[u8]>>` for `Bytes` (#504)
### Changed
- Override `put_slice` for `&mut [u8]` (#483)
- Panic on integer overflow in `Chain::remaining` (#482)
- Add inline tags to `UninitSlice` methods (#443)
- Override `copy_to_bytes` for Chain and Take (#481)
- Keep capacity when unsplit on empty other buf (#502)
### Documented
- Clarify `BufMut` allocation guarantees (#501)
- Clarify `BufMut::put_int` behavior (#486)
- Clarify actions of `clear` and `truncate`. (#508)
# 1.0.1 (January 11, 2021)
### Changed
- mark `Vec::put_slice` with `#[inline]` (#459)
### Fixed
- Fix deprecation warning (#457)
- use `Box::into_raw` instead of `mem::forget`-in-disguise (#458)
# 1.0.0 (December 22, 2020)
### Changed
- Rename `Buf`/`BufMut` methods `bytes()` and `bytes_mut()` to `chunk()` and `chunk_mut()` (#450)
### Removed
- remove unused Buf implementation. (#449)
# 0.6.0 (October 21, 2020)
API polish in preparation for a 1.0 release.
### Changed
- `BufMut` is now an `unsafe` trait (#432).
- `BufMut::bytes_mut()` returns `&mut UninitSlice`, a type owned by `bytes` to
avoid undefined behavior (#433).
- `Buf::copy_to_bytes(len)` replaces `Buf::into_bytes()` (#439).
- `Buf`/`BufMut` utility methods are moved onto the trait and `*Ext` traits are
removed (#431).
### Removed
- `BufMut::bytes_vectored_mut()` (#430).
- `new` methods on combinator types (#434).
# 0.5.6 (July 13, 2020)
- Improve `BytesMut` to reuse buffer when fully `advance`d.
- Mark `BytesMut::{as_mut, set_len}` with `#[inline]`.
- Relax synchronization when cloning in shared vtable of `Bytes`.
- Move `loom` to `dev-dependencies`.
# 0.5.5 (June 18, 2020)
### Added
- Allow using the `serde` feature in `no_std` environments (#385).
### Fix
- Fix `BufMut::advance_mut` to panic if advanced passed the capacity (#354)..
- Fix `BytesMut::freeze` ignoring amount previously `advance`d (#352).
# 0.5.4 (January 23, 2020)
### Added
- Make `Bytes::new` a `const fn`.
- Add `From<BytesMut>` for `Bytes`.
### Fix
- Fix reversed arguments in `PartialOrd` for `Bytes`.
- Fix `Bytes::truncate` losing original capacity when repr is an unshared `Vec`.
- Fix `Bytes::from(Vec)` when allocator gave `Vec` a pointer with LSB set.
- Fix panic in `Bytes::slice_ref` if argument is an empty slice.
# 0.5.3 (December 12, 2019)
### Added
- `must_use` attributes to `split`, `split_off`, and `split_to` methods (#337).
### Fix
- Potential freeing of a null pointer in `Bytes` when constructed with an empty `Vec<u8>` (#341, #342).
- Calling `Bytes::truncate` with a size large than the length will no longer clear the `Bytes` (#333).
# 0.5.2 (November 27, 2019)
### Added
- `Limit` methods `into_inner`, `get_ref`, `get_mut`, `limit`, and `set_limit` (#325).
# 0.5.1 (November 25, 2019)
### Fix
- Growth documentation for `BytesMut` (#321)
# 0.5.0 (November 25, 2019)
### Fix
- Potential overflow in `copy_to_slice`
### Changed
- Increased minimum supported Rust version to 1.39.
- `Bytes` is now a "trait object", allowing for custom allocation strategies (#298)
- `BytesMut` implicitly grows internal storage. `remaining_mut()` returns
`usize::MAX` (#316).
- `BufMut::bytes_mut` returns `&mut [MaybeUninit<u8>]` to reflect the unknown
initialization state (#305).
- `Buf` / `BufMut` implementations for `&[u8]` and `&mut [u8]`
respectively (#261).
- Move `Buf` / `BufMut` "extra" functions to an extension trait (#306).
- `BufMutExt::limit` (#309).
- `Bytes::slice` takes a `RangeBounds` argument (#265).
- `Bytes::from_static` is now a `const fn` (#311).
- A multitude of smaller performance optimizations.
### Added
- `no_std` support (#281).
- `get_*`, `put_*`, `get_*_le`, and `put_*le` accessors for handling byte order.
- `BorrowMut` implementation for `BytesMut` (#185).
### Removed
- `IntoBuf` (#288).
- `Buf` implementation for `&str` (#301).
- `byteorder` dependency (#280).
- `iovec` dependency, use `std::IoSlice` instead (#263).
- optional `either` dependency (#315).
- optional `i128` feature -- now available on stable. (#276).
# 0.4.12 (March 6, 2019)
### Added
- Implement `FromIterator<&'a u8>` for `BytesMut`/`Bytes` (#244).
- Implement `Buf` for `VecDeque` (#249).
# 0.4.11 (November 17, 2018)
* Use raw pointers for potentially racy loads (#233).
* Implement `BufRead` for `buf::Reader` (#232).
* Documentation tweaks (#234).
# 0.4.10 (September 4, 2018)
* impl `Buf` and `BufMut` for `Either` (#225).
* Add `Bytes::slice_ref` (#208).
# 0.4.9 (July 12, 2018)
* Add 128 bit number support behind a feature flag (#209).
* Implement `IntoBuf` for `&mut [u8]`
# 0.4.8 (May 25, 2018)
* Fix panic in `BytesMut` `FromIterator` implementation.
* Bytes: Recycle space when reserving space in vec mode (#197).
* Bytes: Add resize fn (#203).
# 0.4.7 (April 27, 2018)
* Make `Buf` and `BufMut` usable as trait objects (#186).
* impl BorrowMut for BytesMut (#185).
* Improve accessor performance (#195).
# 0.4.6 (Janary 8, 2018)
* Implement FromIterator for Bytes/BytesMut (#148).
* Add `advance` fn to Bytes/BytesMut (#166).
* Add `unsplit` fn to `BytesMut` (#162, #173).
* Improvements to Bytes split fns (#92).
# 0.4.5 (August 12, 2017)
* Fix range bug in `Take::bytes`
* Misc performance improvements
* Add extra `PartialEq` implementations.
* Add `Bytes::with_capacity`
* Implement `AsMut[u8]` for `BytesMut`
# 0.4.4 (May 26, 2017)
* Add serde support behind feature flag
* Add `extend_from_slice` on `Bytes` and `BytesMut`
* Add `truncate` and `clear` on `Bytes`
* Misc additional std trait implementations
* Misc performance improvements
# 0.4.3 (April 30, 2017)
* Fix Vec::advance_mut bug
* Bump minimum Rust version to 1.15
* Misc performance tweaks
# 0.4.2 (April 5, 2017)
* Misc performance tweaks
* Improved `Debug` implementation for `Bytes`
* Avoid some incorrect assert panics
# 0.4.1 (March 15, 2017)
* Expose `buf` module and have most types available from there vs. root.
* Implement `IntoBuf` for `T: Buf`.
* Add `FromBuf` and `Buf::collect`.
* Add iterator adapter for `Buf`.
* Add scatter/gather support to `Buf` and `BufMut`.
* Add `Buf::chain`.
* Reduce allocations on repeated calls to `BytesMut::reserve`.
* Implement `Debug` for more types.
* Remove `Source` in favor of `IntoBuf`.
* Implement `Extend` for `BytesMut`.
# 0.4.0 (February 24, 2017)
* Initial release
+27 -25
View File
@@ -1,32 +1,34 @@
[package]
name = "bytes"
version = "0.3.0"
license = "MIT"
authors = ["Carl Lerche <[email protected]>"]
description = "Types and traits for working with bytes"
documentation = "https://carllerche.github.io/bytes/bytes"
homepage = "https://github.com/carllerche/bytes"
repository = "https://github.com/carllerche/bytes"
readme = "README.md"
keywords = ["buffers", "rope", "io"]
exclude = [
".gitignore",
".travis.yml",
"deploy.sh",
"bench/**/*",
"test/**/*"
name = "bytes"
# When releasing to crates.io:
# - Update CHANGELOG.md.
# - Create "v1.x.y" git tag.
version = "1.1.0"
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]
serde = { version = "1.0.60", optional = true, default-features = false, features = ["alloc"] }
[dev-dependencies]
rand = "0.3.5"
serde_test = "1.0"
[[bench]]
[target.'cfg(loom)'.dev-dependencies]
loom = "0.5"
name = "bench"
path = "bench/bench.rs"
[[test]]
name = "test"
path = "test/test.rs"
[package.metadata.docs.rs]
rustdoc-args = ["--cfg", "docsrs"]
+22 -49
View File
@@ -1,52 +1,25 @@
Copyright (c) 2015 Carl Lerche
Copyright (c) 2018 Carl Lerche
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
Permission is hereby granted, free of charge, to any
person obtaining a copy of this software and associated
documentation files (the "Software"), to deal in the
Software without restriction, including without
limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software
is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
The above copyright notice and this permission notice
shall be included in all copies or substantial portions
of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
---
Additionally, the Rope implementation is heavily inspired by ByteString found
in the Google protobuf library. The following applies to this code:
Copyright 2014, Google Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
+35 -5
View File
@@ -2,16 +2,46 @@
A utility library for working with bytes.
[![crates.io](http://meritbadge.herokuapp.com/bytes)](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]
- [API documentation](http://carllerche.github.io/bytes/bytes/index.html)
[crates-badge]: https://img.shields.io/crates/v/bytes.svg
[crates-url]: https://crates.io/crates/bytes
[ci-badge]: https://github.com/tokio-rs/bytes/workflows/CI/badge.svg
[ci-url]: https://github.com/tokio-rs/bytes/actions
[Documentation](https://docs.rs/bytes)
## Usage
To use `bytes`, first add this to your `Cargo.toml`:
```toml
[dependencies.bytes]
git = "https://github.com/carllerche/bytes"
[dependencies]
bytes = "1"
```
Next, add this to your crate:
```rust
use bytes::{Bytes, BytesMut, Buf, BufMut};
```
## Serde support
Serde support is optional and disabled by default. To enable use the feature `serde`.
```toml
[dependencies]
bytes = { version = "1", features = ["serde"] }
```
## License
This project is licensed under the [MIT license](LICENSE).
### Contribution
Unless you explicitly state otherwise, any contribution intentionally submitted
for inclusion in `bytes` by you, shall be licensed as MIT, without any additional
terms or conditions.
-34
View File
@@ -1,34 +0,0 @@
#![feature(test, core)]
use bytes::ByteBuf;
use bytes::traits::*;
use iobuf::{RWIobuf};
use test::Bencher;
extern crate bytes;
extern crate iobuf;
extern crate test;
const SIZE:usize = 4_096;
#[bench]
pub fn bench_byte_buf_fill_4kb(b: &mut Bencher) {
b.iter(|| {
let mut buf = ByteBuf::mut_with_capacity(SIZE);
for _ in 0..SIZE {
buf.write_slice(&[0]);
}
});
}
#[bench]
pub fn bench_rw_iobuf_fill_4kb(b: &mut Bencher) {
b.iter(|| {
let mut buf = RWIobuf::new(SIZE);
for _ in 0..SIZE {
let _ = buf.fill(&[0]);
}
});
}
+186
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 {
return 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);
}
+119
View File
@@ -0,0 +1,119 @@
#![feature(test)]
#![warn(rust_2018_idioms)]
extern crate test;
use bytes::Bytes;
use test::Bencher;
#[bench]
fn deref_unique(b: &mut Bencher) {
let buf = Bytes::from(vec![0; 1024]);
b.iter(|| {
for _ in 0..1024 {
test::black_box(&buf[..]);
}
})
}
#[bench]
fn deref_shared(b: &mut Bencher) {
let buf = Bytes::from(vec![0; 1024]);
let _b2 = buf.clone();
b.iter(|| {
for _ in 0..1024 {
test::black_box(&buf[..]);
}
})
}
#[bench]
fn deref_static(b: &mut Bencher) {
let buf = Bytes::from_static(b"hello world");
b.iter(|| {
for _ in 0..1024 {
test::black_box(&buf[..]);
}
})
}
#[bench]
fn clone_static(b: &mut Bencher) {
let bytes =
Bytes::from_static("hello world 1234567890 and have a good byte 0987654321".as_bytes());
b.iter(|| {
for _ in 0..1024 {
test::black_box(&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(|| {
let b = Bytes::from(vec![17; 1024]).clone();
for i in 0..1000 {
test::black_box(b.slice(i % 100..i % 100));
}
})
}
#[bench]
fn slice_short_from_arc(b: &mut Bencher) {
b.iter(|| {
// `clone` is to convert to ARC
let b = Bytes::from(vec![17; 1024]).clone();
for i in 0..1000 {
test::black_box(b.slice(1..2 + i % 10));
}
})
}
#[bench]
fn split_off_and_drop(b: &mut Bencher) {
b.iter(|| {
for _ in 0..1024 {
let v = vec![10; 200];
let mut b = Bytes::from(v);
test::black_box(b.split_off(100));
test::black_box(b);
}
})
}
+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);
}
});
}
Executable
+11
View File
@@ -0,0 +1,11 @@
#!/bin/bash
set -e
MIRI_NIGHTLY=nightly-$(curl -s https://rust-lang.github.io/rustup-components-history/x86_64-unknown-linux-gnu/miri)
echo "Installing latest nightly with Miri: $MIRI_NIGHTLY"
rustup set profile minimal
rustup default "$MIRI_NIGHTLY"
rustup component add miri
cargo miri test
cargo miri test --target mips64-unknown-linux-gnuabi64
+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
+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
-18
View File
@@ -1,18 +0,0 @@
#!/bin/bash
rev=$(git rev-parse --short HEAD)
cd target/doc
git init
git config user.name "Carl Lerche"
git config user.email "[email protected]"
git remote add upstream "https://$GH_TOKEN@github.com/carllerche/bytes"
git fetch upstream && git reset upstream/gh-pages
touch .
git add -A .
git commit -m "rebuild pages at ${rev}"
git push -q upstream HEAD:gh-pages
-52
View File
@@ -1,52 +0,0 @@
use alloc::{Allocator, Mem, MemRef};
use std::{mem, ptr, usize};
use std::ops::DerefMut;
const MAX_ALLOC_SIZE: usize = usize::MAX;
pub struct Heap;
impl Heap {
pub fn allocate(&self, len: usize) -> MemRef {
// Make sure that the allocation is within the permitted range
if len > MAX_ALLOC_SIZE {
return MemRef::none();
}
let alloc_len = len +
mem::size_of::<Mem>() +
mem::size_of::<Vec<u8>>();
unsafe {
let mut vec: Vec<u8> = Vec::with_capacity(alloc_len);
vec.set_len(alloc_len);
let ptr = vec.deref_mut().as_mut_ptr();
ptr::write(ptr as *mut Vec<u8>, vec);
let ptr = ptr.offset(mem::size_of::<Vec<u8>>() as isize);
ptr::write(ptr as *mut Mem, Mem::new(len, mem::transmute(self as &Allocator)));
// Return the info
MemRef::new(ptr as *mut Mem)
}
}
pub fn deallocate(&self, mem: *mut Mem) {
unsafe {
let ptr = mem as *mut u8;
let _ = ptr::read(ptr.offset(-(mem::size_of::<Vec<u8>>() as isize)) as *const Vec<u8>);
}
}
}
impl Allocator for Heap {
fn allocate(&self, len: usize) -> MemRef {
Heap::allocate(self, len)
}
fn deallocate(&self, mem: *mut Mem) {
Heap::deallocate(self, mem)
}
}
-131
View File
@@ -1,131 +0,0 @@
mod heap;
pub use self::heap::{Heap};
use std::{mem, ptr};
use std::sync::atomic::{AtomicUsize, Ordering};
pub fn heap(len: usize) -> MemRef {
Heap.allocate(len)
}
/// Allocates memory to be used by Bufs or Bytes. Allows allocating memory
/// using alternate stratgies than the default Rust heap allocator. Also does
/// not require that allocations are continuous in memory.
///
/// For example, an alternate allocator could use a slab of 4kb chunks of
/// memory and return as many chunks as needed to satisfy the length
/// requirement.
pub trait Allocator: Sync + Send {
/// Allocate memory. May or may not be contiguous.
fn allocate(&self, len: usize) -> MemRef;
/// Deallocate a chunk of memory
fn deallocate(&self, mem: *mut Mem);
}
pub struct MemRef {
ptr: *mut u8,
}
impl MemRef {
pub fn new(mem: *mut Mem) -> MemRef {
let ptr = mem as *mut u8;
unsafe {
MemRef {
ptr: ptr.offset(mem::size_of::<Mem>() as isize),
}
}
}
#[inline]
pub fn none() -> MemRef {
MemRef { ptr: ptr::null_mut() }
}
#[inline]
pub fn is_none(&self) -> bool {
self.ptr.is_null()
}
#[inline]
pub fn ptr(&self) -> *mut u8 {
self.ptr
}
pub fn bytes(&self) -> &[u8] {
use std::slice;
unsafe {
slice::from_raw_parts(self.ptr(), self.mem().len)
}
}
#[inline]
pub fn bytes_mut(&mut self) -> &mut [u8] {
use std::slice;
unsafe {
slice::from_raw_parts_mut(self.ptr(), self.mem().len)
}
}
#[inline]
fn mem_ptr(&self) -> *mut Mem {
unsafe {
self.ptr.offset(-(mem::size_of::<Mem>() as isize)) as *mut Mem
}
}
#[inline]
fn mem(&self) -> &Mem {
unsafe {
mem::transmute(self.mem_ptr())
}
}
}
impl Clone for MemRef {
#[inline]
fn clone(&self) -> MemRef {
self.mem().refs.fetch_add(1, Ordering::Relaxed);
MemRef { ptr: self.ptr }
}
}
impl Drop for MemRef {
fn drop(&mut self) {
// Guard against the ref having already been dropped
if self.ptr.is_null() { return; }
// Decrement the ref count
if 1 == self.mem().refs.fetch_sub(1, Ordering::Relaxed) {
// Last ref dropped, free the memory
unsafe {
let alloc: &Allocator = mem::transmute(self.mem().allocator);
alloc.deallocate(self.mem_ptr());
}
}
}
}
unsafe impl Send for MemRef { }
unsafe impl Sync for MemRef { }
/// Memory allocated by an Allocator must be prefixed with Mem
pub struct Mem {
// TODO: It should be possible to reduce the size of this struct
allocator: *const Allocator,
refs: AtomicUsize,
len: usize,
}
impl Mem {
pub fn new(len: usize, allocator: *const Allocator) -> Mem {
Mem {
allocator: allocator,
refs: AtomicUsize::new(1),
len: len,
}
}
}
+1074
View File
File diff suppressed because it is too large Load Diff
+1142
View File
File diff suppressed because it is too large Load Diff
-347
View File
@@ -1,347 +0,0 @@
use {alloc, Bytes, SeqByteStr, MAX_CAPACITY};
use traits::{Buf, MutBuf, MutBufExt, ByteStr};
use std::{cmp, fmt, ptr};
/*
*
* ===== ByteBuf =====
*
*/
/// A `Buf` backed by a contiguous region of memory.
///
/// This `Buf` is better suited for cases where there is a clear delineation
/// between reading and writing.
pub struct ByteBuf {
mem: alloc::MemRef,
cap: u32,
pos: u32,
lim: u32,
mark: Option<u32>,
}
impl ByteBuf {
/// Create a new `ByteBuf` by copying the contents of the given slice.
pub fn from_slice(bytes: &[u8]) -> ByteBuf {
let mut buf = ByteBuf::mut_with_capacity(bytes.len());
buf.write(bytes).ok().expect("unexpected failure");
buf.flip()
}
pub fn mut_with_capacity(capacity: usize) -> MutByteBuf {
assert!(capacity <= MAX_CAPACITY);
MutByteBuf { buf: ByteBuf::new(capacity as u32) }
}
pub fn none() -> ByteBuf {
ByteBuf {
mem: alloc::MemRef::none(),
cap: 0,
pos: 0,
lim: 0,
mark: None,
}
}
pub unsafe fn from_mem_ref(mem: alloc::MemRef, cap: u32, pos: u32, lim: u32) -> ByteBuf {
debug_assert!(pos <= lim && lim <= cap, "invalid arguments; cap={}; pos={}; lim={}", cap, pos, lim);
ByteBuf {
mem: mem,
cap: cap,
pos: pos,
lim: lim,
mark: None,
}
}
fn new(mut capacity: u32) -> ByteBuf {
// Handle 0 capacity case
if capacity == 0 {
return ByteBuf::none();
}
// Round the capacity to the closest power of 2
capacity = capacity.next_power_of_two();
// Allocate the memory
let mem = alloc::heap(capacity as usize);
// If the allocation failed, return a blank buf
if mem.is_none() {
return ByteBuf::none();
}
ByteBuf {
mem: mem,
cap: capacity,
pos: 0,
lim: capacity,
mark: None,
}
}
pub fn capacity(&self) -> usize {
self.cap as usize
}
pub fn flip(self) -> MutByteBuf {
let mut buf = MutByteBuf { buf: self };
buf.clear();
buf
}
/// Flips the buffer back to mutable, resetting the write position
/// to the byte after the previous write.
pub fn resume(mut self) -> MutByteBuf {
self.pos = self.lim;
self.lim = self.cap;
MutByteBuf { buf: self }
}
pub fn read_slice(&mut self, dst: &mut [u8]) -> usize {
let len = cmp::min(dst.len(), self.remaining());
let cnt = len as u32;
unsafe {
ptr::copy_nonoverlapping(
self.mem.ptr().offset(self.pos as isize),
dst.as_mut_ptr(),
len);
}
self.pos += cnt;
len
}
pub fn to_seq_byte_str(self) -> SeqByteStr {
unsafe {
let ByteBuf { mem, pos, lim, .. } = self;
SeqByteStr::from_mem_ref(
mem, pos, lim - pos)
}
}
#[inline]
pub fn to_bytes(self) -> Bytes {
Bytes::of(self.to_seq_byte_str())
}
/// Marks the current read location.
///
/// Together with `reset`, this can be used to read from a section of the
/// buffer multiple times. The marked location will be cleared when the
/// buffer is flipped.
pub fn mark(&mut self) {
self.mark = Some(self.pos);
}
/// Resets the read position to the previously marked position.
///
/// Together with `mark`, this can be used to read from a section of the
/// buffer multiple times.
///
/// # Panics
///
/// This method will panic if no mark has been set.
pub fn reset(&mut self) {
self.pos = self.mark.take().expect("no mark set");
}
#[inline]
fn pos(&self) -> usize {
self.pos as usize
}
#[inline]
fn lim(&self) -> usize {
self.lim as usize
}
#[inline]
fn remaining_u32(&self) -> u32 {
self.lim - self.pos
}
}
impl Buf for ByteBuf {
#[inline]
fn remaining(&self) -> usize {
self.remaining_u32() as usize
}
#[inline]
fn bytes<'a>(&'a self) -> &'a [u8] {
&self.mem.bytes()[self.pos()..self.lim()]
}
#[inline]
fn advance(&mut self, mut cnt: usize) {
cnt = cmp::min(cnt, self.remaining());
self.pos += cnt as u32;
}
#[inline]
fn read_slice(&mut self, dst: &mut [u8]) -> usize {
ByteBuf::read_slice(self, dst)
}
}
impl fmt::Debug for ByteBuf {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
self.bytes().fmt(fmt)
}
}
/*
*
* ===== ROByteBuf =====
*
*/
/// Same as `ByteBuf` but cannot be flipped to a `MutByteBuf`.
pub struct ROByteBuf {
buf: ByteBuf,
}
impl ROByteBuf {
pub unsafe fn from_mem_ref(mem: alloc::MemRef, cap: u32, pos: u32, lim: u32) -> ROByteBuf {
ROByteBuf {
buf: ByteBuf::from_mem_ref(mem, cap, pos, lim)
}
}
pub fn to_seq_byte_str(self) -> SeqByteStr {
self.buf.to_seq_byte_str()
}
pub fn to_bytes(self) -> Bytes {
self.buf.to_bytes()
}
/// Marks the current read location.
///
/// Together with `reset`, this can be used to read from a section of the
/// buffer multiple times.
pub fn mark(&mut self) {
self.buf.mark = Some(self.buf.pos);
}
/// Resets the read position to the previously marked position.
///
/// Together with `mark`, this can be used to read from a section of the
/// buffer multiple times.
///
/// # Panics
///
/// This method will panic if no mark has been set.
pub fn reset(&mut self) {
self.buf.pos = self.buf.mark.take().expect("no mark set");
}
}
impl Buf for ROByteBuf {
fn remaining(&self) -> usize {
self.buf.remaining()
}
fn bytes<'a>(&'a self) -> &'a [u8] {
self.buf.bytes()
}
fn advance(&mut self, cnt: usize) {
self.buf.advance(cnt)
}
fn read_slice(&mut self, dst: &mut [u8]) -> usize {
self.buf.read_slice(dst)
}
}
impl fmt::Debug for ROByteBuf {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
self.bytes().fmt(fmt)
}
}
/*
*
* ===== MutByteBuf =====
*
*/
pub struct MutByteBuf {
buf: ByteBuf,
}
impl MutByteBuf {
pub fn capacity(&self) -> usize {
self.buf.capacity() as usize
}
pub fn flip(self) -> ByteBuf {
let mut buf = self.buf;
buf.lim = buf.pos;
buf.pos = 0;
buf
}
pub fn clear(&mut self) {
self.buf.pos = 0;
self.buf.lim = self.buf.cap;
}
#[inline]
pub fn write_slice(&mut self, src: &[u8]) -> usize {
let cnt = src.len() as u32;
let rem = self.buf.remaining_u32();
if rem < cnt {
self.write_ptr(src.as_ptr(), rem)
} else {
self.write_ptr(src.as_ptr(), cnt)
}
}
#[inline]
fn write_ptr(&mut self, src: *const u8, len: u32) -> usize {
unsafe {
ptr::copy_nonoverlapping(
src,
self.buf.mem.ptr().offset(self.buf.pos as isize),
len as usize);
self.buf.pos += len;
len as usize
}
}
pub fn bytes<'a>(&'a self) -> &'a [u8] {
&self.buf.mem.bytes()[..self.buf.pos()]
}
}
impl MutBuf for MutByteBuf {
fn remaining(&self) -> usize {
self.buf.remaining()
}
unsafe fn advance(&mut self, cnt: usize) {
self.buf.advance(cnt)
}
unsafe fn mut_bytes<'a>(&'a mut self) -> &'a mut [u8] {
let pos = self.buf.pos();
let lim = self.buf.lim();
&mut self.buf.mem.bytes_mut()[pos..lim]
}
}
impl fmt::Debug for MutByteBuf {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
self.bytes().fmt(fmt)
}
}
+243
View File
@@ -0,0 +1,243 @@
use crate::buf::{IntoIter, UninitSlice};
use crate::{Buf, BufMut, Bytes};
#[cfg(feature = "std")]
use std::io::IoSlice;
/// A `Chain` sequences two buffers.
///
/// `Chain` is an adapter that links two underlying buffers and provides a
/// continuous view across both buffers. It is able to sequence either immutable
/// buffers ([`Buf`] values) or mutable buffers ([`BufMut`] values).
///
/// This struct is generally created by calling [`Buf::chain`]. Please see that
/// function's documentation for more detail.
///
/// # Examples
///
/// ```
/// use bytes::{Bytes, Buf};
///
/// let mut buf = (&b"hello "[..])
/// .chain(&b"world"[..]);
///
/// let full: Bytes = buf.copy_to_bytes(11);
/// assert_eq!(full[..], b"hello world"[..]);
/// ```
///
/// [`Buf::chain`]: trait.Buf.html#method.chain
/// [`Buf`]: trait.Buf.html
/// [`BufMut`]: trait.BufMut.html
#[derive(Debug)]
pub struct Chain<T, U> {
a: T,
b: U,
}
impl<T, U> Chain<T, U> {
/// Creates a new `Chain` sequencing the provided values.
pub(crate) fn new(a: T, b: U) -> Chain<T, U> {
Chain { a, b }
}
/// Gets a reference to the first underlying `Buf`.
///
/// # Examples
///
/// ```
/// use bytes::Buf;
///
/// let buf = (&b"hello"[..])
/// .chain(&b"world"[..]);
///
/// assert_eq!(buf.first_ref()[..], b"hello"[..]);
/// ```
pub fn first_ref(&self) -> &T {
&self.a
}
/// Gets a mutable reference to the first underlying `Buf`.
///
/// # Examples
///
/// ```
/// use bytes::Buf;
///
/// let mut buf = (&b"hello"[..])
/// .chain(&b"world"[..]);
///
/// buf.first_mut().advance(1);
///
/// let full = buf.copy_to_bytes(9);
/// assert_eq!(full, b"elloworld"[..]);
/// ```
pub fn first_mut(&mut self) -> &mut T {
&mut self.a
}
/// Gets a reference to the last underlying `Buf`.
///
/// # Examples
///
/// ```
/// use bytes::Buf;
///
/// let buf = (&b"hello"[..])
/// .chain(&b"world"[..]);
///
/// assert_eq!(buf.last_ref()[..], b"world"[..]);
/// ```
pub fn last_ref(&self) -> &U {
&self.b
}
/// Gets a mutable reference to the last underlying `Buf`.
///
/// # Examples
///
/// ```
/// use bytes::Buf;
///
/// let mut buf = (&b"hello "[..])
/// .chain(&b"world"[..]);
///
/// buf.last_mut().advance(1);
///
/// let full = buf.copy_to_bytes(10);
/// assert_eq!(full, b"hello orld"[..]);
/// ```
pub fn last_mut(&mut self) -> &mut U {
&mut self.b
}
/// Consumes this `Chain`, returning the underlying values.
///
/// # Examples
///
/// ```
/// use bytes::Buf;
///
/// let chain = (&b"hello"[..])
/// .chain(&b"world"[..]);
///
/// let (first, last) = chain.into_inner();
/// assert_eq!(first[..], b"hello"[..]);
/// assert_eq!(last[..], b"world"[..]);
/// ```
pub fn into_inner(self) -> (T, U) {
(self.a, self.b)
}
}
impl<T, U> Buf for Chain<T, U>
where
T: Buf,
U: Buf,
{
fn remaining(&self) -> usize {
self.a.remaining().checked_add(self.b.remaining()).unwrap()
}
fn chunk(&self) -> &[u8] {
if self.a.has_remaining() {
self.a.chunk()
} else {
self.b.chunk()
}
}
fn advance(&mut self, mut cnt: usize) {
let a_rem = self.a.remaining();
if a_rem != 0 {
if a_rem >= cnt {
self.a.advance(cnt);
return;
}
// Consume what is left of a
self.a.advance(a_rem);
cnt -= a_rem;
}
self.b.advance(cnt);
}
#[cfg(feature = "std")]
fn chunks_vectored<'a>(&'a self, dst: &mut [IoSlice<'a>]) -> usize {
let mut n = self.a.chunks_vectored(dst);
n += self.b.chunks_vectored(&mut dst[n..]);
n
}
fn copy_to_bytes(&mut self, len: usize) -> Bytes {
let a_rem = self.a.remaining();
if a_rem >= len {
self.a.copy_to_bytes(len)
} else if a_rem == 0 {
self.b.copy_to_bytes(len)
} else {
assert!(
len - a_rem <= self.b.remaining(),
"`len` greater than remaining"
);
let mut ret = crate::BytesMut::with_capacity(len);
ret.put(&mut self.a);
ret.put((&mut self.b).take(len - a_rem));
ret.freeze()
}
}
}
unsafe impl<T, U> BufMut for Chain<T, U>
where
T: BufMut,
U: BufMut,
{
fn remaining_mut(&self) -> usize {
self.a
.remaining_mut()
.checked_add(self.b.remaining_mut())
.unwrap()
}
fn chunk_mut(&mut self) -> &mut UninitSlice {
if self.a.has_remaining_mut() {
self.a.chunk_mut()
} else {
self.b.chunk_mut()
}
}
unsafe fn advance_mut(&mut self, mut cnt: usize) {
let a_rem = self.a.remaining_mut();
if a_rem != 0 {
if a_rem >= cnt {
self.a.advance_mut(cnt);
return;
}
// Consume what is left of a
self.a.advance_mut(a_rem);
cnt -= a_rem;
}
self.b.advance_mut(cnt);
}
}
impl<T, U> IntoIterator for Chain<T, U>
where
T: Buf,
U: Buf,
{
type Item = u8;
type IntoIter = IntoIter<Chain<T, U>>;
fn into_iter(self) -> Self::IntoIter {
IntoIter::new(self)
}
}
+132
View File
@@ -0,0 +1,132 @@
use crate::Buf;
/// Iterator over the bytes contained by the buffer.
///
/// This struct is created by the [`iter`] method on [`Buf`].
///
/// # Examples
///
/// Basic usage:
///
/// ```
/// use bytes::Bytes;
///
/// let buf = Bytes::from(&b"abc"[..]);
/// let mut iter = buf.into_iter();
///
/// assert_eq!(iter.next(), Some(b'a'));
/// assert_eq!(iter.next(), Some(b'b'));
/// assert_eq!(iter.next(), Some(b'c'));
/// assert_eq!(iter.next(), None);
/// ```
///
/// [`iter`]: trait.Buf.html#method.iter
/// [`Buf`]: trait.Buf.html
#[derive(Debug)]
pub struct IntoIter<T> {
inner: T,
}
impl<T> IntoIter<T> {
/// Creates an iterator over the bytes contained by the buffer.
///
/// # Examples
///
/// ```
/// use bytes::Bytes;
///
/// let buf = Bytes::from_static(b"abc");
/// let mut iter = buf.into_iter();
///
/// assert_eq!(iter.next(), Some(b'a'));
/// assert_eq!(iter.next(), Some(b'b'));
/// assert_eq!(iter.next(), Some(b'c'));
/// assert_eq!(iter.next(), None);
/// ```
pub(crate) fn new(inner: T) -> IntoIter<T> {
IntoIter { inner }
}
/// Consumes this `IntoIter`, returning the underlying value.
///
/// # Examples
///
/// ```rust
/// use bytes::{Buf, Bytes};
///
/// let buf = Bytes::from(&b"abc"[..]);
/// let mut iter = buf.into_iter();
///
/// assert_eq!(iter.next(), Some(b'a'));
///
/// let buf = iter.into_inner();
/// assert_eq!(2, buf.remaining());
/// ```
pub fn into_inner(self) -> T {
self.inner
}
/// Gets a reference to the underlying `Buf`.
///
/// It is inadvisable to directly read from the underlying `Buf`.
///
/// # Examples
///
/// ```rust
/// use bytes::{Buf, Bytes};
///
/// let buf = Bytes::from(&b"abc"[..]);
/// let mut iter = buf.into_iter();
///
/// assert_eq!(iter.next(), Some(b'a'));
///
/// assert_eq!(2, iter.get_ref().remaining());
/// ```
pub fn get_ref(&self) -> &T {
&self.inner
}
/// Gets a mutable reference to the underlying `Buf`.
///
/// It is inadvisable to directly read from the underlying `Buf`.
///
/// # Examples
///
/// ```rust
/// use bytes::{Buf, BytesMut};
///
/// let buf = BytesMut::from(&b"abc"[..]);
/// let mut iter = buf.into_iter();
///
/// assert_eq!(iter.next(), Some(b'a'));
///
/// iter.get_mut().advance(1);
///
/// assert_eq!(iter.next(), Some(b'c'));
/// ```
pub fn get_mut(&mut self) -> &mut T {
&mut self.inner
}
}
impl<T: Buf> Iterator for IntoIter<T> {
type Item = u8;
fn next(&mut self) -> Option<u8> {
if !self.inner.has_remaining() {
return None;
}
let b = self.inner.chunk()[0];
self.inner.advance(1);
Some(b)
}
fn size_hint(&self) -> (usize, Option<usize>) {
let rem = self.inner.remaining();
(rem, Some(rem))
}
}
impl<T: Buf> ExactSizeIterator for IntoIter<T> {}
+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;
}
}
+37 -426
View File
@@ -1,430 +1,41 @@
mod byte;
mod ring;
mod sink;
mod slice;
mod source;
//! Utilities for working with buffers.
//!
//! A buffer is any structure that contains a sequence of bytes. The bytes may
//! or may not be stored in contiguous memory. This module contains traits used
//! to abstract over buffers as well as utilities for working with buffer types.
//!
//! # `Buf`, `BufMut`
//!
//! These are the two foundational traits for abstractly working with buffers.
//! They can be thought as iterators for byte structures. They offer additional
//! performance over `Iterator` by providing an API optimized for byte slices.
//!
//! See [`Buf`] and [`BufMut`] for more details.
//!
//! [rope]: https://en.wikipedia.org/wiki/Rope_(data_structure)
//! [`Buf`]: trait.Buf.html
//! [`BufMut`]: trait.BufMut.html
mod buf_impl;
mod buf_mut;
mod chain;
mod iter;
mod limit;
#[cfg(feature = "std")]
mod reader;
mod take;
mod uninit_slice;
mod vec_deque;
#[cfg(feature = "std")]
mod writer;
pub use self::byte::{ByteBuf, MutByteBuf, ROByteBuf};
pub use self::ring::RingBuf;
pub use self::slice::{SliceBuf, MutSliceBuf};
pub use self::buf_impl::Buf;
pub use self::buf_mut::BufMut;
pub use self::chain::Chain;
pub use self::iter::IntoIter;
pub use self::limit::Limit;
pub use self::take::Take;
pub use self::uninit_slice::UninitSlice;
use {BufError, RopeBuf};
use std::{cmp, fmt, io, ptr, usize};
/// A trait for values that provide sequential read access to bytes.
pub trait Buf {
/// Returns the number of bytes that can be accessed from the Buf
fn remaining(&self) -> usize;
/// Returns a slice starting at the current Buf position and of length
/// between 0 and `Buf::remaining()`.
fn bytes<'a>(&'a self) -> &'a [u8];
/// Advance the internal cursor of the Buf
fn advance(&mut self, cnt: usize);
/// Returns true if there are any more bytes to consume
fn has_remaining(&self) -> bool {
self.remaining() > 0
}
/// Read bytes from the `Buf` into the given slice and advance the cursor by
/// the number of bytes read.
/// Returns the number of bytes read.
///
/// ```
/// use bytes::{SliceBuf, Buf};
///
/// let mut buf = SliceBuf::wrap(b"hello world");
/// let mut dst = [0; 5];
///
/// buf.read_slice(&mut dst);
/// assert_eq!(b"hello", &dst);
/// assert_eq!(6, buf.remaining());
/// ```
fn read_slice(&mut self, dst: &mut [u8]) -> usize {
let mut off = 0;
let len = cmp::min(dst.len(), self.remaining());
while off < len {
let cnt;
unsafe {
let src = self.bytes();
cnt = cmp::min(src.len(), len - off);
ptr::copy_nonoverlapping(
src.as_ptr(), dst[off..].as_mut_ptr(), cnt);
off += src.len();
}
self.advance(cnt);
}
len
}
/// Read a single byte from the `Buf`
fn read_byte(&mut self) -> Option<u8> {
let mut dst = [0];
if self.read_slice(&mut dst) == 0 {
return None;
}
Some(dst[0])
}
}
/// An extension trait providing extra functions applicable to all `Buf` values.
pub trait BufExt {
/// Read bytes from this Buf into the given sink and advance the cursor by
/// the number of bytes read.
fn read<S: Sink>(&mut self, dst: S) -> Result<usize, S::Error>;
}
/// A trait for values that provide sequential write access to bytes.
pub trait MutBuf : Sized {
/// Returns the number of bytes that can be written to the MutBuf
fn remaining(&self) -> usize;
/// Advance the internal cursor of the MutBuf
unsafe fn advance(&mut self, cnt: usize);
/// Returns true iff there is any more space for bytes to be written
fn has_remaining(&self) -> bool {
self.remaining() > 0
}
/// Returns a mutable slice starting at the current MutBuf position and of
/// length between 0 and `MutBuf::remaining()`.
///
/// The returned byte slice may represent uninitialized memory.
unsafe fn mut_bytes<'a>(&'a mut self) -> &'a mut [u8];
/// Write bytes from the given slice into the `MutBuf` and advance the
/// cursor by the number of bytes written.
/// Returns the number of bytes written.
///
/// ```
/// use bytes::{MutSliceBuf, Buf, MutBuf};
///
/// let mut dst = [0; 6];
///
/// {
/// let mut buf = MutSliceBuf::wrap(&mut dst);
/// buf.write_slice(b"hello");
///
/// assert_eq!(1, buf.remaining());
/// }
///
/// assert_eq!(b"hello\0", &dst);
/// ```
fn write_slice(&mut self, src: &[u8]) -> usize {
let mut off = 0;
let len = cmp::min(src.len(), self.remaining());
while off < len {
let cnt;
unsafe {
let dst = self.mut_bytes();
cnt = cmp::min(dst.len(), len - off);
ptr::copy_nonoverlapping(
src[off..].as_ptr(),
dst.as_mut_ptr(),
cnt);
off += cnt;
}
unsafe { self.advance(cnt); }
}
len
}
/// Write a single byte to the `MuBuf`
fn write_byte(&mut self, byte: u8) -> bool {
let src = [byte];
if self.write_slice(&src) == 0 {
return false;
}
true
}
}
/// An extension trait providing extra functions applicable to all `MutBuf` values.
pub trait MutBufExt {
/// Write bytes from the given source into the current `MutBuf` and advance
/// the cursor by the number of bytes written.
fn write<S: Source>(&mut self, src: S) -> Result<usize, S::Error>;
}
/*
*
* ===== *Ext impls =====
*
*/
impl<B: Buf> BufExt for B {
fn read<S: Sink>(&mut self, dst: S) -> Result<usize, S::Error> {
dst.sink(self)
}
}
impl<B: MutBuf> MutBufExt for B {
fn write<S: Source>(&mut self, src: S) -> Result<usize, S::Error> {
src.fill(self)
}
}
/*
*
* ===== Sink / Source =====
*
*/
/// A value that reads bytes from a Buf into itself
pub trait Sink {
type Error;
fn sink<B: Buf>(self, buf: &mut B) -> Result<usize, Self::Error>;
}
/// A value that writes bytes from itself into a `MutBuf`.
pub trait Source {
type Error;
fn fill<B: MutBuf>(self, buf: &mut B) -> Result<usize, Self::Error>;
}
impl<'a> Sink for &'a mut [u8] {
type Error = BufError;
fn sink<B: Buf>(self, buf: &mut B) -> Result<usize, BufError> {
Ok(buf.read_slice(self))
}
}
impl<'a> Sink for &'a mut Vec<u8> {
type Error = BufError;
fn sink<B: Buf>(self, buf: &mut B) -> Result<usize, BufError> {
use std::slice;
self.clear();
let rem = buf.remaining();
let cap = self.capacity();
// Ensure that the vec is big enough
if rem > self.capacity() {
self.reserve(rem - cap);
}
unsafe {
{
let dst = &mut self[..];
let cnt = buf.read_slice(slice::from_raw_parts_mut(dst.as_mut_ptr(), rem));
debug_assert!(cnt == rem);
}
self.set_len(rem);
}
Ok(rem)
}
}
impl<'a> Source for &'a [u8] {
type Error = BufError;
fn fill<B: MutBuf>(self, buf: &mut B) -> Result<usize, BufError> {
Ok(buf.write_slice(self))
}
}
impl<'a> Source for &'a Vec<u8> {
type Error = BufError;
fn fill<B: MutBuf>(self, buf: &mut B) -> Result<usize, BufError> {
Ok(buf.write_slice(self.as_ref()))
}
}
impl<'a, R: io::Read+'a> Source for &'a mut R {
type Error = io::Error;
fn fill<B: MutBuf>(self, buf: &mut B) -> Result<usize, io::Error> {
let mut cnt = 0;
while buf.has_remaining() {
let i = try!(self.read(unsafe { buf.mut_bytes() }));
if i == 0 {
break;
}
unsafe { buf.advance(i); }
cnt += i;
}
Ok(cnt)
}
}
/*
*
* ===== Buf impls =====
*
*/
impl Buf for Box<Buf+'static> {
fn remaining(&self) -> usize {
(**self).remaining()
}
fn bytes(&self) -> &[u8] {
(**self).bytes()
}
fn advance(&mut self, cnt: usize) {
(**self).advance(cnt);
}
fn read_slice(&mut self, dst: &mut [u8]) -> usize {
(**self).read_slice(dst)
}
}
impl fmt::Debug for Box<Buf+'static> {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
write!(fmt, "Box<Buf> {{ remaining: {} }}", self.remaining())
}
}
impl Buf for io::Cursor<Vec<u8>> {
fn remaining(&self) -> usize {
self.get_ref().len() - self.position() as usize
}
fn bytes(&self) -> &[u8] {
let pos = self.position() as usize;
&(&self.get_ref())[pos..]
}
fn advance(&mut self, cnt: usize) {
let pos = self.position() as usize;
let pos = cmp::min(self.get_ref().len(), pos + cnt);
self.set_position(pos as u64);
}
}
impl MutBuf for Vec<u8> {
fn remaining(&self) -> usize {
usize::MAX - self.len()
}
unsafe fn advance(&mut self, cnt: usize) {
let len = self.len() + cnt;
if len > self.capacity() {
// Reserve additional
// TODO: Should this case panic?
let cap = self.capacity();
self.reserve(cap - len);
}
self.set_len(len);
}
unsafe fn mut_bytes(&mut self) -> &mut [u8] {
use std::slice;
if self.capacity() == self.len() {
self.reserve(64); // Grow the vec
}
let cap = self.capacity();
let len = self.len();
let ptr = self.as_mut_ptr();
&mut slice::from_raw_parts_mut(ptr, cap)[len..]
}
}
impl<'a> Buf for io::Cursor<&'a [u8]> {
fn remaining(&self) -> usize {
self.get_ref().len() - self.position() as usize
}
fn bytes(&self) -> &[u8] {
let pos = self.position() as usize;
&(&self.get_ref())[pos..]
}
fn advance(&mut self, cnt: usize) {
let pos = self.position() as usize;
let pos = cmp::min(self.get_ref().len(), pos + cnt);
self.set_position(pos as u64);
}
}
/*
*
* ===== Read impls =====
*
*/
macro_rules! impl_read {
($ty:ty) => {
impl io::Read for $ty {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
if !self.has_remaining() {
return Ok(0);
}
Ok(self.read_slice(buf))
}
}
}
}
impl_read!(ByteBuf);
impl_read!(ROByteBuf);
impl_read!(RopeBuf);
impl_read!(Box<Buf+'static>);
macro_rules! impl_write {
($ty:ty) => {
impl io::Write for $ty {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
if !self.has_remaining() {
return Ok(0);
}
Ok(self.write_slice(buf))
}
fn flush(&mut self) -> io::Result<()> {
Ok(())
}
}
}
}
impl_write!(MutByteBuf);
#[cfg(feature = "std")]
pub use self::{reader::Reader, writer::Writer};
+81
View File
@@ -0,0 +1,81 @@
use crate::Buf;
use std::{cmp, io};
/// A `Buf` adapter which implements `io::Read` for the inner value.
///
/// This struct is generally created by calling `reader()` on `Buf`. See
/// documentation of [`reader()`](trait.Buf.html#method.reader) for more
/// details.
#[derive(Debug)]
pub struct Reader<B> {
buf: B,
}
pub fn new<B>(buf: B) -> Reader<B> {
Reader { buf }
}
impl<B: Buf> Reader<B> {
/// Gets a reference to the underlying `Buf`.
///
/// It is inadvisable to directly read from the underlying `Buf`.
///
/// # Examples
///
/// ```rust
/// use bytes::Buf;
///
/// let buf = b"hello world".reader();
///
/// assert_eq!(b"hello world", buf.get_ref());
/// ```
pub fn get_ref(&self) -> &B {
&self.buf
}
/// Gets a mutable reference to the underlying `Buf`.
///
/// It is inadvisable to directly read from the underlying `Buf`.
pub fn get_mut(&mut self) -> &mut B {
&mut self.buf
}
/// Consumes this `Reader`, returning the underlying value.
///
/// # Examples
///
/// ```rust
/// use bytes::Buf;
/// use std::io;
///
/// let mut buf = b"hello world".reader();
/// let mut dst = vec![];
///
/// io::copy(&mut buf, &mut dst).unwrap();
///
/// let buf = buf.into_inner();
/// assert_eq!(0, buf.remaining());
/// ```
pub fn into_inner(self) -> B {
self.buf
}
}
impl<B: Buf + Sized> io::Read for Reader<B> {
fn read(&mut self, dst: &mut [u8]) -> io::Result<usize> {
let len = cmp::min(self.buf.remaining(), dst.len());
Buf::copy_to_slice(&mut self.buf, &mut dst[0..len]);
Ok(len)
}
}
impl<B: Buf + Sized> io::BufRead for Reader<B> {
fn fill_buf(&mut self) -> io::Result<&[u8]> {
Ok(self.buf.chunk())
}
fn consume(&mut self, amt: usize) {
self.buf.advance(amt)
}
}
-250
View File
@@ -1,250 +0,0 @@
use {alloc, Buf, MutBuf};
use std::{cmp, fmt, io, ptr};
enum Mark {
NoMark,
At { pos: usize, len: usize },
}
/// Buf backed by a continous chunk of memory. Maintains a read cursor and a
/// write cursor. When reads and writes reach the end of the allocated buffer,
/// wraps around to the start.
///
/// This type is suited for use cases where reads and writes are intermixed.
pub struct RingBuf {
ptr: alloc::MemRef, // Pointer to the memory
cap: usize, // Capacity of the buffer
pos: usize, // Offset of read cursor
len: usize, // Number of bytes to read
mark: Mark, // Marked read position
}
// TODO: There are most likely many optimizations that can be made
impl RingBuf {
/// Allocates a new `RingBuf` with the specified capacity.
pub fn new(mut capacity: usize) -> RingBuf {
// Handle the 0 length buffer case
if capacity == 0 {
return RingBuf {
ptr: alloc::MemRef::none(),
cap: 0,
pos: 0,
len: 0,
mark: Mark::NoMark,
}
}
// Round to the next power of 2 for better alignment
capacity = capacity.next_power_of_two();
let mem = alloc::heap(capacity as usize);
RingBuf {
ptr: mem,
cap: capacity,
pos: 0,
len: 0,
mark: Mark::NoMark,
}
}
/// Returns `true` if the buf cannot accept any further writes.
pub fn is_full(&self) -> bool {
self.cap == self.len
}
/// Returns `true` if the buf cannot accept any further reads.
pub fn is_empty(&self) -> bool {
self.len == 0
}
/// Returns the number of bytes that the buf can hold.
pub fn capacity(&self) -> usize {
self.cap
}
/// Marks the current read location.
///
/// Together with `reset`, this can be used to read from a section of the
/// buffer multiple times. The mark will be cleared if it is overwritten
/// during a write.
pub fn mark(&mut self) {
self.mark = Mark::At { pos: self.pos, len: self.len };
}
/// Resets the read position to the previously marked position.
///
/// Together with `mark`, this can be used to read from a section of the
/// buffer multiple times.
///
/// # Panics
///
/// This method will panic if no mark has been set,
pub fn reset(&mut self){
match self.mark {
Mark::NoMark => panic!("no mark set"),
Mark::At {pos, len} => {
self.pos = pos;
self.len = len;
self.mark = Mark::NoMark;
}
}
}
/// Resets all internal state to the initial state.
pub fn clear(&mut self) {
self.pos = 0;
self.len = 0;
self.mark = Mark::NoMark;
}
/// Returns the number of bytes remaining to read.
fn read_remaining(&self) -> usize {
self.len
}
/// Returns the remaining write capacity until which the buf becomes full.
fn write_remaining(&self) -> usize {
self.cap - self.len
}
fn advance_reader(&mut self, mut cnt: usize) {
if self.cap == 0 {
return;
}
cnt = cmp::min(cnt, self.read_remaining());
self.pos += cnt;
self.pos %= self.cap;
self.len -= cnt;
}
fn advance_writer(&mut self, mut cnt: usize) {
cnt = cmp::min(cnt, self.write_remaining());
self.len += cnt;
// Adjust the mark to account for bytes written.
if let Mark::At { ref mut len, .. } = self.mark {
*len += cnt;
}
// Clear the mark if we've written past it.
if let Mark::At { len, .. } = self.mark {
if len > self.cap {
self.mark = Mark::NoMark;
}
}
}
}
impl Clone for RingBuf {
fn clone(&self) -> RingBuf {
use std::cmp;
let mut ret = RingBuf::new(self.cap);
ret.pos = self.pos;
ret.len = self.len;
unsafe {
let to = self.pos + self.len;
if to > self.cap {
ptr::copy(self.ptr.ptr() as *const u8, ret.ptr.ptr(), to % self.cap);
}
ptr::copy(
self.ptr.ptr().offset(self.pos as isize) as *const u8,
ret.ptr.ptr().offset(self.pos as isize),
cmp::min(self.len, self.cap - self.pos));
}
ret
}
// TODO: an improved version of clone_from is possible that potentially
// re-uses the buffer
}
impl fmt::Debug for RingBuf {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
write!(fmt, "RingBuf[.. {}]", self.len)
}
}
impl Buf for RingBuf {
fn remaining(&self) -> usize {
self.read_remaining()
}
fn bytes(&self) -> &[u8] {
let mut to = self.pos + self.len;
if to > self.cap {
to = self.cap
}
&self.ptr.bytes()[self.pos .. to]
}
fn advance(&mut self, cnt: usize) {
self.advance_reader(cnt)
}
}
impl MutBuf for RingBuf {
fn remaining(&self) -> usize {
self.write_remaining()
}
unsafe fn advance(&mut self, cnt: usize) {
self.advance_writer(cnt)
}
unsafe fn mut_bytes(&mut self) -> &mut [u8] {
if self.cap == 0 {
return self.ptr.bytes_mut();
}
let mut from;
let mut to;
from = self.pos + self.len;
from %= self.cap;
to = from + <Self as MutBuf>::remaining(&self);
if to >= self.cap {
to = self.cap;
}
&mut self.ptr.bytes_mut()[from..to]
}
}
impl io::Read for RingBuf {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
if !Buf::has_remaining(self) {
return Ok(0);
}
Ok(self.read_slice(buf))
}
}
impl io::Write for RingBuf {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
if !MutBuf::has_remaining(self) {
return Ok(0);
}
Ok(self.write_slice(buf))
}
fn flush(&mut self) -> io::Result<()> {
Ok(())
}
}
unsafe impl Send for RingBuf { }
View File
-59
View File
@@ -1,59 +0,0 @@
use std::cmp;
use {Buf, MutBuf};
// TODO: Rename -> Cursor. Use as buf for various byte strings
pub struct SliceBuf<'a> {
bytes: &'a [u8],
pos: usize
}
impl<'a> SliceBuf<'a> {
pub fn wrap(bytes: &'a [u8]) -> SliceBuf<'a> {
SliceBuf { bytes: bytes, pos: 0 }
}
}
impl<'a> Buf for SliceBuf<'a> {
fn remaining(&self) -> usize {
self.bytes.len() - self.pos
}
fn bytes<'b>(&'b self) -> &'b [u8] {
&self.bytes[self.pos..]
}
fn advance(&mut self, mut cnt: usize) {
cnt = cmp::min(cnt, self.remaining());
self.pos += cnt;
}
}
pub struct MutSliceBuf<'a> {
bytes: &'a mut [u8],
pos: usize
}
impl<'a> MutSliceBuf<'a> {
pub fn wrap(bytes: &'a mut [u8]) -> MutSliceBuf<'a> {
MutSliceBuf {
bytes: bytes,
pos: 0
}
}
}
impl<'a> MutBuf for MutSliceBuf<'a> {
fn remaining(&self) -> usize {
self.bytes.len() - self.pos
}
unsafe fn advance(&mut self, mut cnt: usize) {
cnt = cmp::min(cnt, self.remaining());
self.pos += cnt;
}
unsafe fn mut_bytes<'b>(&'b mut self) -> &'b mut [u8] {
&mut self.bytes[self.pos..]
}
}
View File
+114 -38
View File
@@ -1,36 +1,129 @@
use buf::{Buf, MutBuf};
use std::{cmp, io};
use crate::{Buf, Bytes};
use core::cmp;
/// A `Buf` adapter which limits the bytes read from an underlying buffer.
///
/// This struct is generally created by calling `take()` on `Buf`. See
/// documentation of [`take()`](trait.Buf.html#method.take) for more details.
#[derive(Debug)]
pub struct Take<T> {
inner: T,
limit: usize,
}
impl<T> Take<T> {
pub fn new(inner: T, limit: usize) -> Take<T> {
Take {
inner: inner,
limit: limit,
}
}
pub fn new<T>(inner: T, limit: usize) -> Take<T> {
Take { inner, limit }
}
impl<T> Take<T> {
/// Consumes this `Take`, returning the underlying value.
///
/// # Examples
///
/// ```rust
/// use bytes::{Buf, BufMut};
///
/// let mut buf = b"hello world".take(2);
/// let mut dst = vec![];
///
/// dst.put(&mut buf);
/// assert_eq!(*dst, b"he"[..]);
///
/// let mut buf = buf.into_inner();
///
/// dst.clear();
/// dst.put(&mut buf);
/// assert_eq!(*dst, b"llo world"[..]);
/// ```
pub fn into_inner(self) -> T {
self.inner
}
/// Gets a reference to the underlying `Buf`.
///
/// It is inadvisable to directly read from the underlying `Buf`.
///
/// # Examples
///
/// ```rust
/// use bytes::Buf;
///
/// let buf = b"hello world".take(2);
///
/// assert_eq!(11, buf.get_ref().remaining());
/// ```
pub fn get_ref(&self) -> &T {
&self.inner
}
/// Gets a mutable reference to the underlying `Buf`.
///
/// It is inadvisable to directly read from the underlying `Buf`.
///
/// # Examples
///
/// ```rust
/// use bytes::{Buf, BufMut};
///
/// let mut buf = b"hello world".take(2);
/// let mut dst = vec![];
///
/// buf.get_mut().advance(2);
///
/// dst.put(&mut buf);
/// assert_eq!(*dst, b"ll"[..]);
/// ```
pub fn get_mut(&mut self) -> &mut T {
&mut self.inner
}
/// Returns the maximum number of bytes that can be read.
///
/// # Note
///
/// If the inner `Buf` has fewer bytes than indicated by this method then
/// that is the actual number of available bytes.
///
/// # Examples
///
/// ```rust
/// use bytes::Buf;
///
/// let mut buf = b"hello world".take(2);
///
/// assert_eq!(2, buf.limit());
/// assert_eq!(b'h', buf.get_u8());
/// assert_eq!(1, buf.limit());
/// ```
pub fn limit(&self) -> usize {
self.limit
}
/// Sets the maximum number of bytes that can be read.
///
/// # Note
///
/// If the inner `Buf` has fewer bytes than `lim` then that is the actual
/// number of available bytes.
///
/// # Examples
///
/// ```rust
/// use bytes::{Buf, BufMut};
///
/// let mut buf = b"hello world".take(2);
/// let mut dst = vec![];
///
/// dst.put(&mut buf);
/// assert_eq!(*dst, b"he"[..]);
///
/// dst.clear();
///
/// buf.set_limit(3);
/// dst.put(&mut buf);
/// assert_eq!(*dst, b"llo"[..]);
/// ```
pub fn set_limit(&mut self, lim: usize) {
self.limit = lim
}
@@ -41,39 +134,22 @@ impl<T: Buf> Buf for Take<T> {
cmp::min(self.inner.remaining(), self.limit)
}
fn bytes<'a>(&'a self) -> &'a [u8] {
&self.inner.bytes()[..self.limit]
fn chunk(&self) -> &[u8] {
let bytes = self.inner.chunk();
&bytes[..cmp::min(bytes.len(), self.limit)]
}
fn advance(&mut self, cnt: usize) {
let cnt = cmp::min(cnt, self.limit);
self.limit -= cnt;
assert!(cnt <= self.limit);
self.inner.advance(cnt);
}
}
impl<T: Buf> io::Read for Take<T> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
if !self.has_remaining() {
return Ok(0);
}
Ok(self.read_slice(buf))
}
}
impl<T: MutBuf> MutBuf for Take<T> {
fn remaining(&self) -> usize {
cmp::min(self.inner.remaining(), self.limit)
}
unsafe fn mut_bytes<'a>(&'a mut self) -> &'a mut [u8] {
&mut self.inner.mut_bytes()[..self.limit]
}
unsafe fn advance(&mut self, cnt: usize) {
let cnt = cmp::min(cnt, self.limit);
self.limit -= cnt;
self.inner.advance(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
}
}
+183
View File
@@ -0,0 +1,183 @@
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 _
}
/// 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);
}
}
+88
View File
@@ -0,0 +1,88 @@
use crate::BufMut;
use std::{cmp, io};
/// A `BufMut` adapter which implements `io::Write` for the inner value.
///
/// This struct is generally created by calling `writer()` on `BufMut`. See
/// documentation of [`writer()`](trait.BufMut.html#method.writer) for more
/// details.
#[derive(Debug)]
pub struct Writer<B> {
buf: B,
}
pub fn new<B>(buf: B) -> Writer<B> {
Writer { buf }
}
impl<B: BufMut> Writer<B> {
/// Gets a reference to the underlying `BufMut`.
///
/// It is inadvisable to directly write to the underlying `BufMut`.
///
/// # Examples
///
/// ```rust
/// use bytes::BufMut;
///
/// let buf = Vec::with_capacity(1024).writer();
///
/// assert_eq!(1024, buf.get_ref().capacity());
/// ```
pub fn get_ref(&self) -> &B {
&self.buf
}
/// Gets a mutable reference to the underlying `BufMut`.
///
/// It is inadvisable to directly write to the underlying `BufMut`.
///
/// # Examples
///
/// ```rust
/// use bytes::BufMut;
///
/// let mut buf = vec![].writer();
///
/// buf.get_mut().reserve(1024);
///
/// assert_eq!(1024, buf.get_ref().capacity());
/// ```
pub fn get_mut(&mut self) -> &mut B {
&mut self.buf
}
/// Consumes this `Writer`, returning the underlying value.
///
/// # Examples
///
/// ```rust
/// use bytes::BufMut;
/// use std::io;
///
/// let mut buf = vec![].writer();
/// let mut src = &b"hello world"[..];
///
/// io::copy(&mut src, &mut buf).unwrap();
///
/// let buf = buf.into_inner();
/// assert_eq!(*buf, b"hello world"[..]);
/// ```
pub fn into_inner(self) -> B {
self.buf
}
}
impl<B: BufMut + Sized> io::Write for Writer<B> {
fn write(&mut self, src: &[u8]) -> io::Result<usize> {
let n = cmp::min(self.buf.remaining_mut(), src.len());
self.buf.put(&src[0..n]);
Ok(n)
}
fn flush(&mut self) -> io::Result<()> {
Ok(())
}
}
+1144
View File
File diff suppressed because it is too large Load Diff
+1598
View File
File diff suppressed because it is too large Load Diff
+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 b >= 0x20 && b < 0x7f {
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]);
+110 -48
View File
@@ -1,54 +1,116 @@
#![crate_name = "bytes"]
#![deny(warnings)]
#![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
//! ([`Bytes`](struct.Bytes.html)) and traits for working with buffer
//! implementations ([`Buf`], [`BufMut`]).
//!
//! [`Buf`]: trait.Buf.html
//! [`BufMut`]: trait.BufMut.html
//!
//! # `Bytes`
//!
//! `Bytes` is an efficient container for storing and operating on contiguous
//! slices of memory. It is intended for use primarily in networking code, but
//! could have applications elsewhere as well.
//!
//! `Bytes` values facilitate zero-copy network programming by allowing multiple
//! `Bytes` objects to point to the same underlying memory. This is managed by
//! using a reference count to track when the memory is no longer needed and can
//! be freed.
//!
//! A `Bytes` handle can be created directly from an existing byte store (such as `&[u8]`
//! or `Vec<u8>`), but usually a `BytesMut` is used first and written to. For
//! example:
//!
//! ```rust
//! use bytes::{BytesMut, BufMut};
//!
//! let mut buf = BytesMut::with_capacity(1024);
//! buf.put(&b"hello world"[..]);
//! buf.put_u16(1234);
//!
//! let a = buf.split();
//! assert_eq!(a, b"hello world\x04\xD2"[..]);
//!
//! buf.put(&b"goodbye world"[..]);
//!
//! let b = buf.split();
//! assert_eq!(b, b"goodbye world"[..]);
//!
//! assert_eq!(buf.capacity(), 998);
//! ```
//!
//! In the above example, only a single buffer of 1024 is allocated. The handles
//! `a` and `b` will share the underlying buffer and maintain indices tracking
//! the view into the buffer represented by the handle.
//!
//! See the [struct docs] for more details.
//!
//! [struct docs]: struct.Bytes.html
//!
//! # `Buf`, `BufMut`
//!
//! These two traits provide read and write access to buffers. The underlying
//! storage may or may not be in contiguous memory. For example, `Bytes` is a
//! buffer that guarantees contiguous memory, but a [rope] stores the bytes in
//! disjoint chunks. `Buf` and `BufMut` maintain cursors tracking the current
//! position in the underlying byte storage. When bytes are read or written, the
//! cursor is advanced.
//!
//! [rope]: https://en.wikipedia.org/wiki/Rope_(data_structure)
//!
//! ## Relation with `Read` and `Write`
//!
//! At first glance, it may seem that `Buf` and `BufMut` overlap in
//! functionality with `std::io::Read` and `std::io::Write`. However, they
//! serve different purposes. A buffer is the value that is provided as an
//! argument to `Read::read` and `Write::write`. `Read` and `Write` may then
//! perform a syscall, which has the potential of failing. Operations on `Buf`
//! and `BufMut` are infallible.
extern crate alloc;
#[cfg(feature = "std")]
extern crate std;
pub mod alloc;
pub mod buf;
pub mod str;
pub use crate::buf::{Buf, BufMut};
pub use buf::{
Buf,
BufExt,
MutBuf,
MutBufExt,
ByteBuf,
MutByteBuf,
RingBuf,
ROByteBuf,
SliceBuf,
MutSliceBuf,
Source,
Sink,
Take,
};
pub use str::{
ByteStr,
Bytes,
Rope,
RopeBuf,
SeqByteStr,
SmallByteStr,
SmallByteStrBuf,
ToBytes,
};
mod bytes;
mod bytes_mut;
mod fmt;
mod loom;
pub use crate::bytes::Bytes;
pub use crate::bytes_mut::BytesMut;
use std::u32;
// Optional Serde support
#[cfg(feature = "serde")]
mod serde;
pub mod traits {
//! All traits are re-exported here to allow glob imports.
pub use {Buf, BufExt, MutBuf, MutBufExt, ByteStr, ToBytes};
}
const MAX_CAPACITY: usize = u32::MAX as usize;
/*
*
* ===== BufError =====
*
*/
#[derive(Copy, Clone, Debug)]
pub enum BufError {
Underflow,
Overflow,
#[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::{fence, 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::{fence, AtomicPtr, AtomicUsize, Ordering};
pub(crate) trait AtomicMut<T> {}
}
}
+89
View File
@@ -0,0 +1,89 @@
use super::{Bytes, BytesMut};
use alloc::string::String;
use alloc::vec::Vec;
use core::{cmp, fmt};
use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
macro_rules! serde_impl {
($ty:ident, $visitor_ty:ident, $from_slice:ident, $from_vec:ident) => {
impl Serialize for $ty {
#[inline]
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_bytes(&self)
}
}
struct $visitor_ty;
impl<'de> de::Visitor<'de> for $visitor_ty {
type Value = $ty;
fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.write_str("byte array")
}
#[inline]
fn visit_seq<V>(self, mut seq: V) -> Result<Self::Value, V::Error>
where
V: de::SeqAccess<'de>,
{
let len = cmp::min(seq.size_hint().unwrap_or(0), 4096);
let mut values: Vec<u8> = Vec::with_capacity(len);
while let Some(value) = seq.next_element()? {
values.push(value);
}
Ok($ty::$from_vec(values))
}
#[inline]
fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E>
where
E: de::Error,
{
Ok($ty::$from_slice(v))
}
#[inline]
fn visit_byte_buf<E>(self, v: Vec<u8>) -> Result<Self::Value, E>
where
E: de::Error,
{
Ok($ty::$from_vec(v))
}
#[inline]
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
where
E: de::Error,
{
Ok($ty::$from_slice(v.as_bytes()))
}
#[inline]
fn visit_string<E>(self, v: String) -> Result<Self::Value, E>
where
E: de::Error,
{
Ok($ty::$from_vec(v.into_bytes()))
}
}
impl<'de> Deserialize<'de> for $ty {
#[inline]
fn deserialize<D>(deserializer: D) -> Result<$ty, D::Error>
where
D: Deserializer<'de>,
{
deserializer.deserialize_byte_buf($visitor_ty)
}
}
};
}
serde_impl!(Bytes, BytesVisitor, copy_from_slice, from);
serde_impl!(BytesMut, BytesMutVisitor, from, from_vec);
-310
View File
@@ -1,310 +0,0 @@
use {ByteBuf, MutBuf, SmallByteStr, Source, BufError};
use traits::{Buf, ByteStr, ToBytes};
use std::{cmp, fmt, mem, ops, ptr};
use std::any::{Any, TypeId};
const INLINE: usize = 1;
/// A specialized `ByteStr` box.
pub struct Bytes {
vtable: usize,
data: *mut (),
}
impl Bytes {
pub fn from_slice(bytes: &[u8]) -> Bytes {
SmallByteStr::from_slice(bytes)
.map(|small| Bytes::of(small))
.unwrap_or_else(|| ByteBuf::from_slice(bytes).to_bytes())
}
pub fn of<B: ByteStr>(bytes: B) -> Bytes {
unsafe {
if inline::<B>() {
let vtable;
let data;
{
let obj: &ByteStrPriv = &bytes;
let obj: TraitObject = mem::transmute(obj);
let ptr: *const *mut () = mem::transmute(obj.data);
data = *ptr;
vtable = obj.vtable;
}
// Prevent drop from being called
mem::forget(bytes);
Bytes {
vtable: vtable as usize | INLINE,
data: data,
}
} else {
let obj: Box<ByteStrPriv> = Box::new(bytes);
let obj: TraitObject = mem::transmute(obj);
Bytes {
vtable: obj.vtable as usize,
data: obj.data,
}
}
}
}
pub fn empty() -> Bytes {
Bytes::of(SmallByteStr::zero())
}
/// If the underlying `ByteStr` is of type `B`, returns a reference to it
/// otherwise None.
pub fn downcast_ref<'a, B: ByteStr>(&'a self) -> Option<&'a B> {
if TypeId::of::<B>() == self.obj().get_type_id() {
unsafe {
if inline::<B>() {
return Some(mem::transmute(&self.data));
} else {
return Some(mem::transmute(self.data));
}
}
}
None
}
/// If the underlying `ByteStr` is of type `B`, returns the unwraped value,
/// otherwise, returns the original `Bytes` as `Err`.
pub fn try_unwrap<B: ByteStr>(self) -> Result<B, Bytes> {
if TypeId::of::<B>() == self.obj().get_type_id() {
unsafe {
// Underlying ByteStr value is of the correct type. Unwrap it
let ret;
if inline::<B>() {
// The value is inline, read directly from the pointer
ret = ptr::read(mem::transmute(&self.data));
} else {
ret = ptr::read(mem::transmute(self.data));
}
mem::forget(self);
Ok(ret)
}
} else {
Err(self)
}
}
fn obj(&self) -> &ByteStrPriv {
unsafe {
mem::transmute(self.to_trait_object())
}
}
fn obj_mut(&mut self) -> &mut ByteStrPriv {
unsafe {
mem::transmute(self.to_trait_object())
}
}
unsafe fn to_trait_object(&self) -> TraitObject {
if self.is_inline() {
TraitObject {
data: mem::transmute(&self.data),
vtable: mem::transmute(self.vtable - 1),
}
} else {
TraitObject {
data: self.data,
vtable: mem::transmute(self.vtable),
}
}
}
fn is_inline(&self) -> bool {
(self.vtable & INLINE) == INLINE
}
}
fn inline<B: ByteStr>() -> bool {
mem::size_of::<B>() <= 2 * mem::size_of::<usize>()
}
impl ByteStr for Bytes {
type Buf = Box<Buf+'static>;
fn buf(&self) -> Box<Buf+'static> {
self.obj().buf()
}
fn concat<B: ByteStr>(&self, other: &B) -> Bytes {
self.obj().concat(&Bytes::of(other.clone()))
}
fn len(&self) -> usize {
self.obj().len()
}
fn slice(&self, begin: usize, end: usize) -> Bytes {
self.obj().slice(begin, end)
}
fn split_at(&self, mid: usize) -> (Bytes, Bytes) {
self.obj().split_at(mid)
}
}
impl ToBytes for Bytes {
fn to_bytes(self) -> Bytes {
self
}
}
impl ops::Index<usize> for Bytes {
type Output = u8;
fn index(&self, index: usize) -> &u8 {
self.obj().index(index)
}
}
impl fmt::Debug for Bytes {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
super::debug(self, "Bytes", fmt)
}
}
impl Clone for Bytes {
fn clone(&self) -> Bytes {
self.obj().clone()
}
}
impl Drop for Bytes {
fn drop(&mut self) {
unsafe {
if self.is_inline() {
let obj = self.obj_mut();
obj.drop();
} else {
let _: Box<ByteStrPriv> =
mem::transmute(self.obj());
}
}
}
}
unsafe impl Send for Bytes { }
unsafe impl Sync for Bytes { }
impl<'a> Source for &'a Bytes {
type Error = BufError;
fn fill<B: MutBuf>(self, dst: &mut B) -> Result<usize, BufError> {
let mut src = ByteStr::buf(self);
let mut res = 0;
while src.has_remaining() && dst.has_remaining() {
let l;
unsafe {
let s = src.bytes();
let d = dst.mut_bytes();
l = cmp::min(s.len(), d.len());
ptr::copy_nonoverlapping(
s.as_ptr(),
d.as_mut_ptr(),
l);
}
src.advance(l);
unsafe { dst.advance(l); }
res += l;
}
Ok(res)
}
}
trait ByteStrPriv {
fn buf(&self) -> Box<Buf+'static>;
fn clone(&self) -> Bytes;
fn concat(&self, other: &Bytes) -> Bytes;
fn drop(&mut self);
fn get_type_id(&self) -> TypeId;
fn index(&self, index: usize) -> &u8;
fn len(&self) -> usize;
fn slice(&self, begin: usize, end: usize) -> Bytes;
fn split_at(&self, mid: usize) -> (Bytes, Bytes);
}
impl<B: ByteStr> ByteStrPriv for B {
fn buf(&self) -> Box<Buf+'static> {
Box::new(self.buf())
}
fn clone(&self) -> Bytes {
Bytes::of(self.clone())
}
fn concat(&self, other: &Bytes) -> Bytes {
self.concat(other)
}
fn drop(&mut self) {
unsafe {
ptr::read(mem::transmute(self))
}
}
fn get_type_id(&self) -> TypeId {
TypeId::of::<B>()
}
fn index(&self, index: usize) -> &u8 {
ops::Index::index(self, index)
}
fn len(&self) -> usize {
self.len()
}
fn slice(&self, begin: usize, end: usize) -> Bytes {
self.slice(begin, end)
}
fn split_at(&self, mid: usize) -> (Bytes, Bytes) {
self.split_at(mid)
}
}
// TODO: Figure out how to not depend on the memory layout of trait objects
// Blocked: rust-lang/rust#24050
#[repr(C)]
struct TraitObject {
data: *mut (),
vtable: *mut (),
}
#[test]
pub fn test_size_of() {
// TODO: One day, there shouldn't be a drop flag
let ptr_size = mem::size_of::<usize>();
let expect = ptr_size * 3;
assert_eq!(expect, mem::size_of::<Bytes>());
assert_eq!(expect + ptr_size, mem::size_of::<Option<Bytes>>());
}
-187
View File
@@ -1,187 +0,0 @@
mod bytes;
mod rope;
mod seq;
mod small;
pub use self::bytes::Bytes;
pub use self::rope::{Rope, RopeBuf};
pub use self::seq::SeqByteStr;
pub use self::small::{SmallByteStr, SmallByteStrBuf};
use {Buf};
use std::{cmp, fmt, ops};
use std::any::Any;
/// An immutable sequence of bytes. Operations will not mutate the original
/// value. Since only immutable access is permitted, operations do not require
/// copying (though, sometimes copying will happen as an optimization).
pub trait ByteStr : Clone + Sized + Send + Sync + Any + ToBytes + ops::Index<usize, Output=u8> + 'static {
// Until HKT lands, the buf must be bound by 'static
type Buf: Buf+'static;
/// Returns a read-only `Buf` for accessing the byte contents of the
/// `ByteStr`.
fn buf(&self) -> Self::Buf;
/// Returns a new `Bytes` value representing the concatenation of `self`
/// with the given `Bytes`.
fn concat<B: ByteStr+'static>(&self, other: &B) -> Bytes;
/// Returns the number of bytes in the ByteStr
fn len(&self) -> usize;
/// Returns true if the length of the `ByteStr` is 0
fn is_empty(&self) -> bool {
self.len() == 0
}
/// Returns a new ByteStr value containing the byte range between `begin`
/// (inclusive) and `end` (exclusive)
fn slice(&self, begin: usize, end: usize) -> Bytes;
/// Returns a new ByteStr value containing the byte range starting from
/// `begin` (inclusive) to the end of the byte str.
///
/// Equivalent to `bytes.slice(begin, bytes.len())`
fn slice_from(&self, begin: usize) -> Bytes {
self.slice(begin, self.len())
}
/// Returns a new ByteStr value containing the byte range from the start up
/// to `end` (exclusive).
///
/// Equivalent to `bytes.slice(0, end)`
fn slice_to(&self, end: usize) -> Bytes {
self.slice(0, end)
}
/// Divides the value into two `Bytes` at the given index.
///
/// The first will contain all bytes from `[0, mid]` (excluding the index
/// `mid` itself) and the second will contain all indices from `[mid, len)`
/// (excluding the index `len` itself).
///
/// Panics if `mid > len`.
fn split_at(&self, mid: usize) -> (Bytes, Bytes) {
(self.slice_to(mid), self.slice_from(mid))
}
}
macro_rules! impl_parteq {
($ty:ty) => {
impl<B: ByteStr> cmp::PartialEq<B> for $ty {
fn eq(&self, other: &B) -> bool {
if self.len() != other.len() {
return false;
}
let mut buf1 = self.buf();
let mut buf2 = self.buf();
while buf1.has_remaining() {
let len;
{
let b1 = buf1.bytes();
let b2 = buf2.bytes();
len = cmp::min(b1.len(), b2.len());
if b1[..len] != b2[..len] {
return false;
}
}
buf1.advance(len);
buf2.advance(len);
}
true
}
fn ne(&self, other: &B) -> bool {
return !self.eq(other)
}
}
}
}
impl_parteq!(SeqByteStr);
impl_parteq!(SmallByteStr);
impl_parteq!(Bytes);
impl_parteq!(Rope);
macro_rules! impl_eq {
($ty:ty) => {
impl cmp::Eq for $ty {}
}
}
impl_eq!(Bytes);
/*
*
* ===== ToBytes =====
*
*/
pub trait ToBytes {
/// Consumes the value and returns a `Bytes` instance containing
/// identical bytes
fn to_bytes(self) -> Bytes;
}
impl<'a> ToBytes for &'a [u8] {
fn to_bytes(self) -> Bytes {
Bytes::from_slice(self)
}
}
impl<'a> ToBytes for &'a Vec<u8> {
fn to_bytes(self) -> Bytes {
(&self[..]).to_bytes()
}
}
/*
*
* ===== Internal utilities =====
*
*/
fn debug<B: ByteStr>(bytes: &B, name: &str, fmt: &mut fmt::Formatter) -> fmt::Result {
let mut buf = bytes.buf();
try!(write!(fmt, "{}[len={}; ", name, bytes.len()));
let mut rem = 128;
while let Some(byte) = buf.read_byte() {
if rem > 0 {
if is_ascii(byte) {
try!(write!(fmt, "{}", byte as char));
} else {
try!(write!(fmt, "\\x{:02X}", byte));
}
rem -= 1;
} else {
try!(write!(fmt, " ... "));
break;
}
}
try!(write!(fmt, "]"));
Ok(())
}
fn is_ascii(byte: u8) -> bool {
match byte {
10 | 13 | 32...126 => true,
_ => false,
}
}
-585
View File
@@ -1,585 +0,0 @@
use {Bytes, ByteBuf, Source, BufError};
use traits::{Buf, ByteStr, MutBuf, MutBufExt, ToBytes};
use std::{cmp, mem, ops};
use std::sync::Arc;
// The implementation is mostly a port of the implementation found in the Java
// protobuf lib.
const CONCAT_BY_COPY_LEN: usize = 128;
const MAX_DEPTH: usize = 47;
// Used to decide when to rebalance the tree.
static MIN_LENGTH_BY_DEPTH: [usize; MAX_DEPTH] = [
1, 2, 3, 5, 8,
13, 21, 34, 55, 89,
144, 233, 377, 610, 987,
1_597, 2_584, 4_181, 6_765, 10_946,
17_711, 28_657, 46_368, 75_025, 121_393,
196_418, 317_811, 514_229, 832_040, 1_346_269,
2_178_309, 3_524_578, 5_702_887, 9_227_465, 14_930_352,
24_157_817, 39_088_169, 63_245_986, 102_334_155, 165_580_141,
267_914_296, 433_494_437, 701_408_733, 1_134_903_170, 1_836_311_903,
2_971_215_073, 4_294_967_295];
/// An immutable sequence of bytes formed by concatenation of other `ByteStr`
/// values, without copying the data in the pieces. The concatenation is
/// represented as a tree whose leaf nodes are each a `Bytes` value.
///
/// Most of the operation here is inspired by the now-famous paper [Ropes: an
/// Alternative to Strings. hans-j. boehm, russ atkinson and michael
/// plass](http://www.cs.rit.edu/usr/local/pub/jeh/courses/QUARTERS/FP/Labs/CedarRope/rope-paper.pdf).
///
/// Fundamentally the Rope algorithm represents the collection of pieces as a
/// binary tree. BAP95 uses a Fibonacci bound relating depth to a minimum
/// sequence length, sequences that are too short relative to their depth cause
/// a tree rebalance. More precisely, a tree of depth d is "balanced" in the
/// terminology of BAP95 if its length is at least F(d+2), where F(n) is the
/// n-the Fibonacci number. Thus for depths 0, 1, 2, 3, 4, 5,... we have
/// minimum lengths 1, 2, 3, 5, 8, 13,...
pub struct Rope {
inner: Arc<RopeInner>,
}
impl Rope {
pub fn from_slice(bytes: &[u8]) -> Rope {
Rope::new(Bytes::from_slice(bytes), Bytes::empty())
}
/// Returns a Rope consisting of the supplied Bytes as a single segment.
pub fn of<B: ByteStr + 'static>(bytes: B) -> Rope {
let bytes = Bytes::of(bytes);
match bytes.try_unwrap() {
Ok(rope) => rope,
Err(bytes) => Rope::new(bytes, Bytes::empty()),
}
}
fn new(left: Bytes, right: Bytes) -> Rope {
Rope { inner: Arc::new(RopeInner::new(left, right)) }
}
pub fn len(&self) -> usize {
self.inner.len as usize
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
/*
*
* ===== Priv fns =====
*
*/
fn depth(&self) -> u16 {
self.inner.depth
}
fn left(&self) -> &Bytes {
&self.inner.left
}
fn right(&self) -> &Bytes {
&self.inner.right
}
fn pieces<'a>(&'a self) -> PieceIter<'a> {
PieceIter::new(&self.inner)
}
}
impl ByteStr for Rope {
type Buf = RopeBuf;
fn buf(&self) -> RopeBuf {
RopeBuf::new(self.clone())
}
fn concat<B: ByteStr+'static>(&self, other: &B) -> Bytes {
let left = Bytes::of(self.clone());
let right = Bytes::of(other.clone());
Bytes::of(concat(left, right))
}
fn len(&self) -> usize {
Rope::len(self)
}
fn slice(&self, begin: usize, end: usize) -> Bytes {
if begin >= end || begin >= self.len() {
return Bytes::empty()
}
let end = cmp::min(end, self.len());
let len = end - begin;
// Empty slice
if len == 0 {
return Bytes::empty();
}
// Full rope
if len == self.len() {
return Bytes::of(self.clone());
}
// == Proper substring ==
let left_len = self.inner.left.len();
if end <= left_len {
// Slice on the left
return self.inner.left.slice(begin, end);
}
if begin >= left_len {
// Slice on the right
return self.inner.right.slice(begin - left_len, end - left_len);
}
// Split slice
let left_slice = self.inner.left.slice_from(begin);
let right_slice = self.inner.right.slice_to(end - left_len);
Bytes::of(Rope::new(left_slice, right_slice))
}
}
impl ToBytes for Rope {
fn to_bytes(self) -> Bytes {
Bytes::of(self)
}
}
impl ops::Index<usize> for Rope {
type Output = u8;
fn index(&self, index: usize) -> &u8 {
assert!(index < self.len());
let left_len = self.inner.left.len();
if index < left_len {
self.inner.left.index(index)
} else {
self.inner.right.index(index - left_len)
}
}
}
impl Clone for Rope {
fn clone(&self) -> Rope {
Rope { inner: self.inner.clone() }
}
}
impl<'a> Source for &'a Rope {
type Error = BufError;
fn fill<B: MutBuf>(self, _buf: &mut B) -> Result<usize, BufError> {
unimplemented!();
}
}
/*
*
* ===== Helper Fns =====
*
*/
fn depth(bytes: &Bytes) -> u16 {
match bytes.downcast_ref::<Rope>() {
Some(rope) => rope.inner.depth,
None => 0,
}
}
fn is_balanced(bytes: &Bytes) -> bool {
if let Some(rope) = bytes.downcast_ref::<Rope>() {
return rope.len() >= MIN_LENGTH_BY_DEPTH[rope.depth() as usize];
}
true
}
fn concat(left: Bytes, right: Bytes) -> Rope {
if right.is_empty() {
return Rope::of(left);
}
if left.is_empty() {
return Rope::of(right);
}
let len = left.len() + right.len();
if len < CONCAT_BY_COPY_LEN {
return concat_bytes(&left, &right, len);
}
if let Some(left) = left.downcast_ref::<Rope>() {
let len = left.inner.right.len() + right.len();
if len < CONCAT_BY_COPY_LEN {
// Optimization from BAP95: As an optimization of the case
// where the ByteString is constructed by repeated concatenate,
// recognize the case where a short string is concatenated to a
// left-hand node whose right-hand branch is short. In the
// paper this applies to leaves, but we just look at the length
// here. This has the advantage of shedding references to
// unneeded data when substrings have been taken.
//
// When we recognize this case, we do a copy of the data and
// create a new parent node so that the depth of the result is
// the same as the given left tree.
let new_right = concat_bytes(&left.inner.right, &right, len);
return Rope::new(left.inner.left.clone(), Bytes::of(new_right));
}
if depth(left.left()) > depth(left.right()) && left.depth() > depth(&right) {
// Typically for concatenate-built strings the left-side is
// deeper than the right. This is our final attempt to
// concatenate without increasing the tree depth. We'll redo
// the the node on the RHS. This is yet another optimization
// for building the string by repeatedly concatenating on the
// right.
let new_right = Rope::new(left.right().clone(), right);
return Rope::new(left.left().clone(), Bytes::of(new_right));
}
}
// Fine, we'll add a node and increase the tree depth -- unless we
// rebalance ;^)
let depth = cmp::max(depth(&left), depth(&right)) + 1;
if len >= MIN_LENGTH_BY_DEPTH[depth as usize] {
// No need to rebalance
return Rope::new(left, right);
}
Balance::new().balance(left, right)
}
fn concat_bytes(left: &Bytes, right: &Bytes, len: usize) -> Rope {
let mut buf = ByteBuf::mut_with_capacity(len);
buf.write(left).ok().expect("unexpected error");
buf.write(right).ok().expect("unexpected error");
return Rope::of(buf.flip().to_bytes());
}
fn depth_for_len(len: usize) -> u16 {
match MIN_LENGTH_BY_DEPTH.binary_search(&len) {
Ok(idx) => idx as u16,
Err(idx) => {
// It wasn't an exact match, so convert to the index of the
// containing fragment, which is one less even than the insertion
// point.
idx as u16 - 1
}
}
}
/*
*
* ===== RopeBuf =====
*
*/
pub struct RopeBuf {
rem: usize,
// Only here for the ref count
#[allow(dead_code)]
rope: Rope,
// This must be done with unsafe code to avoid having a lifetime bound on
// RopeBuf but is safe due to Rope being held. As long as data doesn't
// escape (which it shouldn't) it is safe. Doing this properly would
// require HKT.
pieces: PieceIter<'static>,
leaf_buf: Option<Box<Buf+'static>>,
}
impl RopeBuf {
fn new(rope: Rope) -> RopeBuf {
// In order to get the lifetimes to work out, transmute to a 'static
// lifetime. Never allow the iter to escape the internals of RopeBuf.
let mut pieces: PieceIter<'static> =
unsafe { mem::transmute(rope.pieces()) };
// Get the next buf
let leaf_buf = pieces.next()
.map(|bytes| bytes.buf());
let len = rope.len();
RopeBuf {
rope: rope,
rem: len,
pieces: pieces,
leaf_buf: leaf_buf,
}
}
}
impl Buf for RopeBuf {
fn remaining(&self) -> usize {
self.rem
}
fn bytes(&self) -> &[u8] {
self.leaf_buf.as_ref()
.map(|b| b.bytes())
.unwrap_or(&[])
}
fn advance(&mut self, mut cnt: usize) {
cnt = cmp::min(cnt, self.rem);
// Advance the internal cursor
self.rem -= cnt;
// Advance the leaf buffer
while cnt > 0 {
{
let curr = self.leaf_buf.as_mut()
.expect("expected a value");
if curr.remaining() > cnt {
curr.advance(cnt);
break;
}
cnt -= curr.remaining();
}
self.leaf_buf = self.pieces.next()
.map(|bytes| bytes.buf());
}
}
}
/*
*
* ===== PieceIter =====
*
*/
// TODO: store stack inline if possible
struct PieceIter<'a> {
stack: Vec<&'a RopeInner>,
next: Option<&'a Bytes>,
}
impl<'a> PieceIter<'a> {
fn new(root: &'a RopeInner) -> PieceIter<'a> {
let mut iter = PieceIter {
stack: vec![],
next: None,
};
iter.next = iter.get_leaf_by_left(root);
iter
}
fn get_leaf_by_left(&mut self, mut root: &'a RopeInner) -> Option<&'a Bytes> {
loop {
self.stack.push(root);
let left = &root.left;
if left.is_empty() {
return None;
}
if let Some(rope) = left.downcast_ref::<Rope>() {
root = &*rope.inner;
continue;
}
return Some(left);
}
}
fn next_non_empty_leaf(&mut self) -> Option<&'a Bytes>{
loop {
if let Some(node) = self.stack.pop() {
if let Some(rope) = node.right.downcast_ref::<Rope>() {
let res = self.get_leaf_by_left(&rope.inner);
if res.is_none() {
continue;
}
return res;
}
if node.right.is_empty() {
continue;
}
return Some(&node.right);
}
return None;
}
}
}
impl<'a> Iterator for PieceIter<'a> {
type Item = &'a Bytes;
fn next(&mut self) -> Option<&'a Bytes> {
let ret = self.next.take();
if ret.is_some() {
self.next = self.next_non_empty_leaf();
}
ret
}
}
/*
*
* ===== Balance =====
*
*/
struct Balance {
stack: Vec<Bytes>,
}
impl Balance {
fn new() -> Balance {
Balance { stack: vec![] }
}
fn balance(&mut self, left: Bytes, right: Bytes) -> Rope {
self.do_balance(left);
self.do_balance(right);
let mut partial = self.stack.pop()
.expect("expected a value");
while !partial.is_empty() {
let new_left = self.stack.pop()
.expect("expected a value");
partial = Bytes::of(Rope::new(new_left, partial));
}
Rope::of(partial)
}
fn do_balance(&mut self, root: Bytes) {
// BAP95: Insert balanced subtrees whole. This means the result might not
// be balanced, leading to repeated rebalancings on concatenate. However,
// these rebalancings are shallow due to ignoring balanced subtrees, and
// relatively few calls to insert() result.
if is_balanced(&root) {
self.insert(root);
} else {
let rope = root.try_unwrap::<Rope>()
.ok().expect("expected a value");
self.do_balance(rope.left().clone());
self.do_balance(rope.right().clone());
}
}
// Push a string on the balance stack (BAP95). BAP95 uses an array and
// calls the elements in the array 'bins'. We instead use a stack, so the
// 'bins' of lengths are represented by differences between the elements of
// minLengthByDepth.
//
// If the length bin for our string, and all shorter length bins, are
// empty, we just push it on the stack. Otherwise, we need to start
// concatenating, putting the given string in the "middle" and continuing
// until we land in an empty length bin that matches the length of our
// concatenation.
fn insert(&mut self, bytes: Bytes) {
let depth_bin = depth_for_len(bytes.len());
let bin_end = MIN_LENGTH_BY_DEPTH[depth_bin as usize + 1];
// BAP95: Concatenate all trees occupying bins representing the length
// of our new piece or of shorter pieces, to the extent that is
// possible. The goal is to clear the bin which our piece belongs in,
// but that may not be entirely possible if there aren't enough longer
// bins occupied.
if let Some(len) = self.peek().map(|r| r.len()) {
if len >= bin_end {
self.stack.push(bytes);
return;
}
}
let bin_start = MIN_LENGTH_BY_DEPTH[depth_bin as usize];
// Concatenate the subtrees of shorter length
let mut new_tree = self.stack.pop()
.expect("expected a value");
while let Some(len) = self.peek().map(|r| r.len()) {
// If the head is big enough, break the loop
if len >= bin_start { break; }
let left = self.stack.pop()
.expect("expected a value");
new_tree = Bytes::of(Rope::new(left, new_tree));
}
// Concatenate the given string
new_tree = Bytes::of(Rope::new(new_tree, bytes));
// Continue concatenating until we land in an empty bin
while let Some(len) = self.peek().map(|r| r.len()) {
let depth_bin = depth_for_len(new_tree.len());
let bin_end = MIN_LENGTH_BY_DEPTH[depth_bin as usize + 1];
if len < bin_end {
let left = self.stack.pop()
.expect("expected a value");
new_tree = Bytes::of(Rope::new(left, new_tree));
} else {
break;
}
}
self.stack.push(new_tree);
}
fn peek(&self) -> Option<&Bytes> {
self.stack.last()
}
}
struct RopeInner {
left: Bytes,
right: Bytes,
depth: u16,
len: u32,
}
impl RopeInner {
fn new(left: Bytes, right: Bytes) -> RopeInner {
// If left is 0 then right must be zero
debug_assert!(!left.is_empty() || right.is_empty());
let len = left.len() + right.len();
let depth = cmp::max(depth(&left), depth(&right)) + 1;
RopeInner {
left: left,
right: right,
depth: depth,
len: len as u32,
}
}
}
-100
View File
@@ -1,100 +0,0 @@
use {alloc, ByteBuf, MutBufExt, ByteStr, ROByteBuf, Rope, Bytes, ToBytes};
use std::ops;
pub struct SeqByteStr {
mem: alloc::MemRef,
pos: u32,
len: u32,
}
impl SeqByteStr {
/// Create a new `SeqByteStr` from a byte slice.
///
/// The contents of the byte slice will be copied.
pub fn from_slice(bytes: &[u8]) -> SeqByteStr {
let mut buf = ByteBuf::mut_with_capacity(bytes.len());
if let Err(e) = buf.write(bytes) {
panic!("failed to copy bytes from slice; err={:?}", e);
}
buf.flip().to_seq_byte_str()
}
/// Creates a new `SeqByteStr` from a `MemRef`, an offset, and a length.
///
/// This function is unsafe as there are no guarantees that the given
/// arguments are valid.
pub unsafe fn from_mem_ref(mem: alloc::MemRef, pos: u32, len: u32) -> SeqByteStr {
SeqByteStr {
mem: mem,
pos: pos,
len: len,
}
}
}
impl ByteStr for SeqByteStr {
type Buf = ROByteBuf;
fn buf(&self) -> ROByteBuf {
unsafe {
let pos = self.pos;
let lim = pos + self.len;
ROByteBuf::from_mem_ref(self.mem.clone(), lim, pos, lim)
}
}
fn concat<B: ByteStr+'static>(&self, other: &B) -> Bytes {
Rope::of(self.clone()).concat(other)
}
fn len(&self) -> usize {
self.len as usize
}
fn slice(&self, begin: usize, end: usize) -> Bytes {
if begin >= end || begin >= self.len() {
return Bytes::empty()
}
let bytes = unsafe {
SeqByteStr::from_mem_ref(
self.mem.clone(),
self.pos + begin as u32,
(end - begin) as u32)
};
Bytes::of(bytes)
}
}
impl ToBytes for SeqByteStr {
fn to_bytes(self) -> Bytes {
Bytes::of(self)
}
}
impl ops::Index<usize> for SeqByteStr {
type Output = u8;
fn index(&self, index: usize) -> &u8 {
assert!(index < self.len());
unsafe {
&*self.mem.ptr()
.offset(index as isize + self.pos as isize)
}
}
}
impl Clone for SeqByteStr {
fn clone(&self) -> SeqByteStr {
SeqByteStr {
mem: self.mem.clone(),
pos: self.pos,
len: self.len,
}
}
}
-131
View File
@@ -1,131 +0,0 @@
use {Bytes, Rope};
use traits::{Buf, MutBuf, ByteStr, ToBytes};
use std::{cmp, ops};
/*
*
* ===== SmallByteStr =====
*
*/
#[cfg(target_pointer_width = "64")]
const MAX_LEN: usize = 7;
#[cfg(target_pointer_width = "32")]
const MAX_LEN: usize = 3;
#[derive(Clone, Copy)]
pub struct SmallByteStr {
len: u8,
bytes: [u8; MAX_LEN],
}
impl SmallByteStr {
pub fn zero() -> SmallByteStr {
use std::mem;
SmallByteStr {
len: 0,
bytes: unsafe { mem::zeroed() }
}
}
pub fn from_slice(bytes: &[u8]) -> Option<SmallByteStr> {
use std::{mem, ptr};
if bytes.len() > MAX_LEN {
return None;
}
let mut ret = SmallByteStr {
len: bytes.len() as u8,
bytes: unsafe { mem::zeroed() },
};
// Copy the memory
unsafe {
ptr::copy_nonoverlapping(
bytes.as_ptr(),
ret.bytes.as_mut_ptr(),
bytes.len());
}
Some(ret)
}
pub fn as_slice(&self) -> &[u8] {
&self.bytes[..self.len as usize]
}
}
impl ByteStr for SmallByteStr {
type Buf = SmallByteStrBuf;
fn buf(&self) -> SmallByteStrBuf {
SmallByteStrBuf { small: self.clone() }
}
fn concat<B: ByteStr+'static>(&self, other: &B) -> Bytes {
Rope::of(self.clone()).concat(other)
}
fn len(&self) -> usize {
self.len as usize
}
fn slice(&self, begin: usize, end: usize) -> Bytes {
Bytes::from_slice(&self.as_slice()[begin..end])
}
}
impl ToBytes for SmallByteStr {
fn to_bytes(self) -> Bytes {
Bytes::of(self)
}
}
impl ops::Index<usize> for SmallByteStr {
type Output = u8;
fn index(&self, index: usize) -> &u8 {
assert!(index < self.len());
&self.bytes[index]
}
}
#[derive(Clone)]
#[allow(missing_copy_implementations)]
pub struct SmallByteStrBuf {
small: SmallByteStr,
}
impl SmallByteStrBuf {
fn len(&self) -> usize {
(self.small.len & 0x0F) as usize
}
fn pos(&self) -> usize {
(self.small.len >> 4) as usize
}
}
impl Buf for SmallByteStrBuf {
fn remaining(&self) -> usize {
self.len() - self.pos()
}
fn bytes(&self) -> &[u8] {
&self.small.bytes[self.pos()..self.len()]
}
fn advance(&mut self, mut cnt: usize) {
cnt = cmp::min(cnt, self.remaining());
self.small.len += (cnt as u8) << 4;
}
}
#[test]
pub fn test_size_of() {
use std::mem;
assert_eq!(mem::size_of::<SmallByteStr>(), mem::size_of::<usize>());
}
-18
View File
@@ -1,18 +0,0 @@
use rand::random;
extern crate bytes;
extern crate rand;
mod test_buf;
mod test_buf_fill;
mod test_buf_take;
mod test_byte_buf;
mod test_bytes;
mod test_ring;
mod test_rope;
mod test_seq_byte_str;
mod test_small_byte_str;
fn gen_bytes(n: usize) -> Vec<u8> {
(0..n).map(|_| random()).collect()
}
-50
View File
@@ -1,50 +0,0 @@
use bytes::{Buf, MutBuf, MutBufExt};
use std::usize;
use std::io::{Cursor};
#[test]
pub fn test_fresh_cursor_vec() {
let mut buf = Cursor::new(b"hello".to_vec());
assert_eq!(buf.remaining(), 5);
assert_eq!(buf.bytes(), b"hello");
buf.advance(2);
assert_eq!(buf.remaining(), 3);
assert_eq!(buf.bytes(), b"llo");
buf.advance(3);
assert_eq!(buf.remaining(), 0);
assert_eq!(buf.bytes(), b"");
buf.advance(1);
assert_eq!(buf.remaining(), 0);
assert_eq!(buf.bytes(), b"");
}
#[test]
pub fn test_vec_as_mut_buf() {
let mut buf = Vec::with_capacity(64);
assert_eq!(buf.remaining(), usize::MAX);
unsafe {
assert!(buf.mut_bytes().len() >= 64);
}
buf.write(&b"zomg"[..]).unwrap();
assert_eq!(&buf, b"zomg");
assert_eq!(buf.remaining(), usize::MAX - 4);
assert_eq!(buf.capacity(), 64);
for _ in 0..16 {
buf.write(&b"zomg"[..]).unwrap();
}
assert_eq!(buf.len(), 68);
}
-47
View File
@@ -1,47 +0,0 @@
use bytes::*;
use std::io;
#[test]
pub fn test_filling_buf_from_reader() {
let mut reader = chunks(vec![b"foo", b"bar", b"baz"]);
let mut buf = ByteBuf::mut_with_capacity(1024);
assert_eq!(9, buf.write(&mut reader).unwrap());
assert_eq!(b"foobarbaz".to_bytes(), buf.flip().to_bytes());
}
fn chunks(chunks: Vec<&'static [u8]>) -> Chunked {
Chunked { chunks: chunks }
}
struct Chunked {
chunks: Vec<&'static [u8]>,
}
impl io::Read for Chunked {
fn read(&mut self, dst: &mut [u8]) -> io::Result<usize> {
use std::{cmp, ptr};
if self.chunks.is_empty() {
return Ok(0);
}
let src = self.chunks[0];
let len = cmp::min(src.len(), dst.len());
unsafe {
ptr::copy_nonoverlapping(
src[..len].as_ptr(),
dst[..len].as_mut_ptr(),
len);
}
if len < src.len() {
self.chunks[0] = &src[len..];
} else {
self.chunks.remove(0);
}
Ok(len)
}
}
-12
View File
@@ -1,12 +0,0 @@
use bytes::*;
use std::io::{Cursor, Read};
#[test]
pub fn test_take_from_buf() {
let mut buf = Take::new(Cursor::new(b"hello world".to_vec()), 5);
let mut res = vec![];
buf.read_to_end(&mut res);
assert_eq!(&res, b"hello");
}
-71
View File
@@ -1,71 +0,0 @@
use bytes::ByteBuf;
use bytes::traits::*;
#[test]
pub fn test_initial_buf_empty() {
let buf = ByteBuf::mut_with_capacity(100);
assert!(buf.capacity() == 128);
assert!(buf.remaining() == 128);
let buf = buf.flip();
assert!(buf.remaining() == 0);
let buf = buf.flip();
assert!(buf.remaining() == 128);
}
#[test]
pub fn test_byte_buf_bytes() {
let mut buf = ByteBuf::mut_with_capacity(32);
buf.write(&b"hello "[..]).unwrap();
assert_eq!(&b"hello "[..], buf.bytes());
buf.write(&b"world"[..]).unwrap();
assert_eq!(&b"hello world"[..], buf.bytes());
let buf = buf.flip();
assert_eq!(&b"hello world"[..], buf.bytes());
}
#[test]
pub fn test_byte_buf_read_write() {
let mut buf = ByteBuf::mut_with_capacity(32);
buf.write(&b"hello world"[..]).unwrap();
assert_eq!(21, buf.remaining());
buf.write(&b" goodbye"[..]).unwrap();
assert_eq!(13, buf.remaining());
let mut buf = buf.flip();
let mut dst = [0; 5];
buf.mark();
assert_eq!(5, buf.read(&mut dst[..]).unwrap());
assert_eq!(b"hello", &dst);
buf.reset();
assert_eq!(5, buf.read(&mut dst[..]).unwrap());
assert_eq!(b"hello", &dst);
assert_eq!(5, buf.read(&mut dst[..]).unwrap());
assert_eq!(b" worl", &dst);
let mut dst = [0; 2];
assert_eq!(2, buf.read(&mut dst[..]).unwrap());
assert_eq!(b"d ", &dst);
let mut dst = [0; 7];
assert_eq!(7, buf.read(&mut dst[..]).unwrap());
assert_eq!(b"goodbye", &dst);
let mut buf = buf.resume();
assert_eq!(13, buf.remaining());
buf.write(&b" have fun"[..]).unwrap();
assert_eq!(4, buf.remaining());
let buf = buf.flip();
assert_eq!(buf.bytes(), b"hello world goodbye have fun");
}
-42
View File
@@ -1,42 +0,0 @@
use bytes::*;
#[test]
pub fn test_debug_short_str_valid_ascii() {
let b = Bytes::from_slice(b"abcdefghij234");
let d = format!("{:?}", b);
assert_eq!(d, "Bytes[len=13; abcdefghij234]");
}
#[test]
pub fn test_debug_long_str_valid_ascii() {
let s = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. \
Duis volutpat eros in gravida malesuada. Phasellus lobortis \
maximus cursus. Praesent tristique orci non purus porta \
dapibus. Ut ut commodo risus, sed semper felis. Phasellus \
bibendum dui nunc, ac pharetra dui viverra a. Nunc imperdiet \
sed nulla ut condimentum. In hac habitasse platea dictumst. \
Interdum et malesuada fames ac ante ipsum primis in faucibus. \
Sed facilisis dictum malesuada. Sed tempor odio ullamcorper mi \
iaculis, eu tempus diam semper. Vivamus pulvinar metus ac erat \
aliquet aliquam.";
let b = Bytes::from_slice(s.as_bytes());
let d = format!("{:?}", b);
assert_eq!(d, "Bytes[len=556; Lorem ipsum dolor sit amet, \
consectetur adipiscing elit. Duis volutpat \
eros in gravida malesuada. Phasellus \
lobortis maximus cur ... ]");
}
#[test]
pub fn test_short_string_invalid_ascii() {
let b = Bytes::from_slice(b"foo\x00bar\xFFbaz");
let d = format!("{:?}", b);
println!("{:?}", b);
assert_eq!(d, "Bytes[len=11; foo\\x00bar\\xFFbaz]");
}
-138
View File
@@ -1,138 +0,0 @@
use bytes::RingBuf;
#[test]
pub fn test_initial_buf_empty() {
use bytes::traits::{Buf, BufExt, MutBuf, MutBufExt};
let mut buf = RingBuf::new(16);
assert_eq!(MutBuf::remaining(&buf), 16);
assert_eq!(Buf::remaining(&buf), 0);
let bytes_written = buf.write(&[1, 2, 3][..]).unwrap();
assert_eq!(bytes_written, 3);
let bytes_written = buf.write(&[][..]).unwrap();
assert_eq!(bytes_written, 0);
assert_eq!(MutBuf::remaining(&buf), 13);
assert_eq!(Buf::remaining(&buf), 3);
assert_eq!(buf.bytes(), [1, 2, 3]);
let mut out = [0u8; 3];
buf.mark();
let bytes_read = buf.read(&mut out[..]).unwrap();;
assert_eq!(bytes_read, 3);
assert_eq!(out, [1, 2, 3]);
buf.reset();
let bytes_read = buf.read(&mut out[..]).unwrap();;
assert_eq!(bytes_read, 3);
assert_eq!(out, [1, 2, 3]);
assert_eq!(MutBuf::remaining(&buf), 16);
assert_eq!(Buf::remaining(&buf), 0);
}
#[test]
fn test_wrapping_write() {
use bytes::traits::{BufExt, MutBufExt};
let mut buf = RingBuf::new(16);
let mut out = [0;10];
buf.write(&[42;12][..]).unwrap();
let bytes_read = buf.read(&mut out[..]).unwrap();
assert_eq!(bytes_read, 10);
let bytes_written = buf.write(&[23;8][..]).unwrap();
assert_eq!(bytes_written, 8);
buf.mark();
let bytes_read = buf.read(&mut out[..]).unwrap();
assert_eq!(bytes_read, 10);
assert_eq!(out, [42, 42, 23, 23, 23, 23, 23, 23, 23, 23]);
buf.reset();
let bytes_read = buf.read(&mut out[..]).unwrap();
assert_eq!(bytes_read, 10);
assert_eq!(out, [42, 42, 23, 23, 23, 23, 23, 23, 23, 23]);
}
#[test]
fn test_io_write_and_read() {
use std::io::{Read, Write};
let mut buf = RingBuf::new(16);
let mut out = [0;8];
let written = buf.write(&[1;8][..]).unwrap();
assert_eq!(written, 8);
buf.read(&mut out).unwrap();
assert_eq!(out, [1;8]);
let written = buf.write(&[2;8][..]).unwrap();
assert_eq!(written, 8);
let bytes_read = buf.read(&mut out).unwrap();
assert_eq!(bytes_read, 8);
assert_eq!(out, [2;8]);
}
#[test]
#[should_panic]
fn test_wrap_reset() {
use std::io::{Read, Write};
let mut buf = RingBuf::new(8);
buf.write(&[1, 2, 3, 4, 5, 6, 7]).unwrap();
buf.mark();
buf.read(&mut [0; 4]).unwrap();
buf.write(&[1, 2, 3, 4]).unwrap();
buf.reset();
}
#[test]
// Test that writes across a mark/reset are preserved.
fn test_mark_write() {
use std::io::{Read, Write};
let mut buf = RingBuf::new(8);
buf.write(&[1, 2, 3, 4, 5, 6, 7]).unwrap();
buf.mark();
buf.write(&[8]).unwrap();
buf.reset();
let mut buf2 = [0; 8];
buf.read(&mut buf2).unwrap();
assert_eq!(buf2, [1, 2, 3, 4, 5, 6, 7, 8]);
}
#[test]
// Test that "RingBuf::reset" does not reset the length of a
// full buffer to zero.
fn test_reset_full() {
use bytes::traits::MutBuf;
use std::io::Write;
let mut buf = RingBuf::new(8);
buf.write(&[1, 2, 3, 4, 5, 6, 7, 8]).unwrap();
assert_eq!(MutBuf::remaining(&buf), 0);
buf.mark();
buf.reset();
assert_eq!(MutBuf::remaining(&buf), 0);
}
#[test]
// Test that "RingBuf::clear" does the full reset
fn test_clear() {
use bytes::traits::{Buf, MutBuf};
use std::io::Write;
let mut buf = RingBuf::new(8);
buf.write(&[0; 8]).unwrap();
assert_eq!(MutBuf::remaining(&buf), 0);
assert_eq!(Buf::remaining(&buf), 8);
buf.clear();
assert_eq!(MutBuf::remaining(&buf), 8);
assert_eq!(Buf::remaining(&buf), 0);
}
-107
View File
@@ -1,107 +0,0 @@
use bytes::Rope;
use bytes::traits::*;
use super::gen_bytes;
const TEST_BYTES_1: &'static [u8] =
b"dblm4ng7jp4v9rdn1w6hhssmluoqrrrqj59rccl9
nkv2tm1t2da4jyku51ge7f8hv581gkki8lekmf5f
1l44whp4aiwbvhkziw02292on4noyvuwjzsloqyc
5n0iyn4l6o6tgjhlek00mynfzb1wgcwj4mqp6zdr
3625yy7rj7xuisal7b1a7xgq271abvt5ssxuj39v
njtetokxxrgxzp7ik9adnypkmmcn4270yv9l46m7
9mu2zmqmkxdmgia210vkdytb7ywfcyt2bvcsg9eq
5yqizxl6888zrksvaxhzs2v355jxu8gr21m33t83
qvoian1ra7c6pvxabshgngldxa408p18l1fdet2h";
const TEST_BYTES_2: &'static [u8] =
b"jmh14t79mllzj1ohxfj6fun7idwbks8oh35f83g6
ryaowe86mmou5t1xa91uyg8e95wcu5mje1mswien
tt4clgj029cw0pyuvfbvsgzdg1x7sr9qsjkf2b1t
h43smgp1ea22lph17f78cel0cc2kjoht5281xuy8
0ex9uaqwj4330jrp30stsk15j9bpqezu3w78ktit
ev5g6xsngr35q7pemdm9hihf0ebrw5fbwhm530lo
e0zyj1bm7yfyk7f2i45jhr3wu3bvb4hj8jve6db0
iewmr9weecaon9vdnqo5hen9iaiox5vsaxuo461m
8336ugp20u4sfky3kfawr0ome1tiqyx8chkerrjh
a95s0gypcsgo9jqxasqkoj08t4uq5moxmay5plg5
tlh6f9omhn0ezvi0w2n8hx7n6qk7rn1s3mjpnpl6
hvilp8awaa4tvsis66q4e5b3xwy2z1h2klpa87h7";
#[test]
pub fn test_rope_round_trip() {
let rope = Rope::from_slice(b"zomg");
assert_eq!(4, rope.len());
let mut dst = vec![];
rope.buf().read(&mut dst).unwrap();
assert_eq!(b"zomg", &dst[..]);
}
#[test]
pub fn test_rope_slice() {
let mut dst = vec![];
let bytes = Rope::from_slice(TEST_BYTES_1);
assert_eq!(TEST_BYTES_1.len(), bytes.len());
bytes.buf().read(&mut dst).unwrap();
assert_eq!(dst, TEST_BYTES_1);
let left = bytes.slice_to(250);
assert_eq!(250, left.len());
left.buf().read(&mut dst).unwrap();
assert_eq!(dst, &TEST_BYTES_1[..250]);
let right = bytes.slice_from(250);
assert_eq!(TEST_BYTES_1.len() - 250, right.len());
right.buf().read(&mut dst).unwrap();
assert_eq!(dst, &TEST_BYTES_1[250..]);
}
#[test]
pub fn test_rope_concat_two_byte_str() {
let mut dst = vec![];
let left = Rope::from_slice(TEST_BYTES_1);
let right = Rope::from_slice(TEST_BYTES_2);
let both = left.concat(&right);
assert_eq!(both.len(), TEST_BYTES_1.len() + TEST_BYTES_2.len());
both.buf().read(&mut dst).unwrap();
let mut expected = Vec::new();
expected.extend(TEST_BYTES_1.iter().cloned());
expected.extend(TEST_BYTES_2.iter().cloned());
assert_eq!(dst, expected);
}
#[test]
#[ignore]
pub fn test_slice_parity() {
let bytes = gen_bytes(2048 * 1024);
let start = 512 * 1024 - 3333;
let end = 512 * 1024 + 7777;
let _ = Rope::from_slice(&bytes).slice(start, end);
// stuff
}
#[test]
pub fn test_rope_equality() {
let a = &b"Mary had a little lamb, its fleece was white as snow; ".to_bytes()
.concat(&b"And everywhere that Mary went, the lamb was sure to go.".to_bytes());
let b = &b"Mary had a little lamb, ".to_bytes()
.concat(&b"its fleece was white as snow; ".to_bytes())
.concat(
&b"And everywhere that Mary went, ".to_bytes()
.concat(&b"the lamb was sure to go.".to_bytes()));
assert_eq!(a, b);
}
-33
View File
@@ -1,33 +0,0 @@
use bytes::SeqByteStr;
use bytes::traits::*;
use super::gen_bytes;
#[test]
pub fn test_slice_round_trip() {
let mut dst = vec![];
let src = gen_bytes(2000);
let s = SeqByteStr::from_slice(&src);
assert_eq!(2000, s.len());
s.buf().read(&mut dst).unwrap();
assert_eq!(dst, src);
}
#[test]
pub fn test_index() {
let src = gen_bytes(2000);
let s = SeqByteStr::from_slice(&src);
for i in 0..2000 {
assert_eq!(src[i], s[i]);
}
}
#[test]
#[should_panic]
pub fn test_index_out_of_range() {
let s = SeqByteStr::from_slice(&gen_bytes(2000));
let _ = s[2001];
}
-33
View File
@@ -1,33 +0,0 @@
use bytes::SmallByteStr;
use bytes::traits::*;
use super::gen_bytes;
#[test]
pub fn test_slice_round_trip() {
let mut dst = vec![];
let src = gen_bytes(3);
let s = SmallByteStr::from_slice(&src).unwrap();
assert_eq!(3, s.len());
s.buf().read(&mut dst).unwrap();
assert_eq!(dst, src);
}
#[test]
pub fn test_index() {
let src = gen_bytes(3);
let s = SmallByteStr::from_slice(&src).unwrap();
for i in 0..3 {
assert_eq!(src[i], s[i]);
}
}
#[test]
#[should_panic]
pub fn test_index_out_of_range() {
let s = SmallByteStr::from_slice(&gen_bytes(3)).unwrap();
let _ = s[2001];
}
+120
View File
@@ -0,0 +1,120 @@
#![warn(rust_2018_idioms)]
use bytes::Buf;
#[cfg(feature = "std")]
use std::io::IoSlice;
#[test]
fn test_fresh_cursor_vec() {
let mut buf = &b"hello"[..];
assert_eq!(buf.remaining(), 5);
assert_eq!(buf.chunk(), b"hello");
buf.advance(2);
assert_eq!(buf.remaining(), 3);
assert_eq!(buf.chunk(), b"llo");
buf.advance(3);
assert_eq!(buf.remaining(), 0);
assert_eq!(buf.chunk(), b"");
}
#[test]
fn test_get_u8() {
let mut buf = &b"\x21zomg"[..];
assert_eq!(0x21, buf.get_u8());
}
#[test]
fn test_get_u16() {
let mut buf = &b"\x21\x54zomg"[..];
assert_eq!(0x2154, buf.get_u16());
let mut buf = &b"\x21\x54zomg"[..];
assert_eq!(0x5421, buf.get_u16_le());
}
#[test]
#[should_panic]
fn test_get_u16_buffer_underflow() {
let mut buf = &b"\x21"[..];
buf.get_u16();
}
#[cfg(feature = "std")]
#[test]
fn test_bufs_vec() {
let buf = &b"hello world"[..];
let b1: &[u8] = &mut [];
let b2: &[u8] = &mut [];
let mut dst = [IoSlice::new(b1), IoSlice::new(b2)];
assert_eq!(1, buf.chunks_vectored(&mut dst[..]));
}
#[test]
fn test_vec_deque() {
use std::collections::VecDeque;
let mut buffer: VecDeque<u8> = VecDeque::new();
buffer.extend(b"hello world");
assert_eq!(11, buffer.remaining());
assert_eq!(b"hello world", buffer.chunk());
buffer.advance(6);
assert_eq!(b"world", buffer.chunk());
buffer.extend(b" piece");
let mut out = [0; 11];
buffer.copy_to_slice(&mut out);
assert_eq!(b"world piece", &out[..]);
}
#[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);
}
+178
View File
@@ -0,0 +1,178 @@
#![warn(rust_2018_idioms)]
use bytes::buf::UninitSlice;
use bytes::{BufMut, BytesMut};
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(), isize::MAX as usize);
assert!(buf.chunk_mut().len() >= 64);
buf.put(&b"zomg"[..]);
assert_eq!(&buf, b"zomg");
assert_eq!(buf.remaining_mut(), isize::MAX as usize - 4);
assert_eq!(buf.capacity(), 64);
for _ in 0..16 {
buf.put(&b"zomg"[..]);
}
assert_eq!(buf.len(), 68);
}
#[test]
fn test_vec_put_bytes() {
let mut buf = Vec::new();
buf.push(17);
buf.put_bytes(19, 2);
assert_eq!([17, 19, 19], &buf[..]);
}
#[test]
fn test_put_u8() {
let mut buf = Vec::with_capacity(8);
buf.put_u8(33);
assert_eq!(b"\x21", &buf[..]);
}
#[test]
fn test_put_u16() {
let mut buf = Vec::with_capacity(8);
buf.put_u16(8532);
assert_eq!(b"\x21\x54", &buf[..]);
buf.clear();
buf.put_u16_le(8532);
assert_eq!(b"\x54\x21", &buf[..]);
}
#[test]
fn test_put_int() {
let mut buf = Vec::with_capacity(8);
buf.put_int(0x1020304050607080, 3);
assert_eq!(b"\x60\x70\x80", &buf[..]);
}
#[test]
#[should_panic]
fn test_put_int_nbytes_overflow() {
let mut buf = Vec::with_capacity(8);
buf.put_int(0x1020304050607080, 9);
}
#[test]
fn test_put_int_le() {
let mut buf = Vec::with_capacity(8);
buf.put_int_le(0x1020304050607080, 3);
assert_eq!(b"\x80\x70\x60", &buf[..]);
}
#[test]
#[should_panic]
fn test_put_int_le_nbytes_overflow() {
let mut buf = Vec::with_capacity(8);
buf.put_int_le(0x1020304050607080, 9);
}
#[test]
#[should_panic(expected = "cannot advance")]
fn test_vec_advance_mut() {
// Verify fix for #354
let mut buf = Vec::with_capacity(8);
unsafe {
buf.advance_mut(12);
}
}
#[test]
fn test_clone() {
let mut buf = BytesMut::with_capacity(100);
buf.write_str("this is a test").unwrap();
let buf2 = buf.clone();
buf.write_str(" of our emergency broadcast system").unwrap();
assert!(buf != buf2);
}
#[test]
fn test_mut_slice() {
let mut v = vec![0, 0, 0, 0];
let mut s = &mut v[..];
s.put_u32(42);
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");
}
+1004
View File
File diff suppressed because it is too large Load Diff
+69
View File
@@ -0,0 +1,69 @@
//! 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() {
let ptr = ptr.offset(1);
ptr
} 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();
}
+79
View File
@@ -0,0 +1,79 @@
use std::alloc::{GlobalAlloc, Layout, System};
use std::{mem, ptr};
use bytes::{Buf, Bytes};
#[global_allocator]
static LEDGER: Ledger = Ledger;
struct Ledger;
const USIZE_SIZE: usize = mem::size_of::<usize>();
unsafe impl GlobalAlloc for Ledger {
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
if layout.align() == 1 && layout.size() > 0 {
// Allocate extra space to stash a record of
// how much space there was.
let orig_size = layout.size();
let size = orig_size + USIZE_SIZE;
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 as *mut usize).write(orig_size);
let ptr = ptr.offset(USIZE_SIZE as isize);
ptr
} else {
ptr
}
} else {
System.alloc(layout)
}
}
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
if layout.align() == 1 && layout.size() > 0 {
let off_ptr = (ptr as *mut usize).offset(-1);
let orig_size = off_ptr.read();
if orig_size != layout.size() {
panic!(
"bad dealloc: alloc size was {}, dealloc size is {}",
orig_size,
layout.size()
);
}
let new_layout = match Layout::from_size_align(layout.size() + USIZE_SIZE, 1) {
Ok(layout) => layout,
Err(_err) => std::process::abort(),
};
System.dealloc(off_ptr as *mut u8, new_layout);
} 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);
}
+155
View File
@@ -0,0 +1,155 @@
#![warn(rust_2018_idioms)]
use bytes::{Buf, BufMut, Bytes};
#[cfg(feature = "std")]
use std::io::IoSlice;
#[test]
fn collect_two_bufs() {
let a = Bytes::from(&b"hello"[..]);
let b = Bytes::from(&b"world"[..]);
let res = a.chain(b).copy_to_bytes(10);
assert_eq!(res, &b"helloworld"[..]);
}
#[test]
fn writing_chained() {
let mut a = [0u8; 64];
let mut b = [0u8; 64];
{
let mut buf = (&mut a[..]).chain_mut(&mut b[..]);
for i in 0u8..128 {
buf.put_u8(i);
}
}
for i in 0..64 {
let expect = i as u8;
assert_eq!(expect, a[i]);
assert_eq!(expect + 64, b[i]);
}
}
#[test]
fn iterating_two_bufs() {
let a = Bytes::from(&b"hello"[..]);
let b = Bytes::from(&b"world"[..]);
let res: Vec<u8> = a.chain(b).into_iter().collect();
assert_eq!(res, &b"helloworld"[..]);
}
#[cfg(feature = "std")]
#[test]
fn vectored_read() {
let a = Bytes::from(&b"hello"[..]);
let b = Bytes::from(&b"world"[..]);
let mut buf = a.chain(b);
{
let b1: &[u8] = &mut [];
let b2: &[u8] = &mut [];
let b3: &[u8] = &mut [];
let b4: &[u8] = &mut [];
let mut iovecs = [
IoSlice::new(b1),
IoSlice::new(b2),
IoSlice::new(b3),
IoSlice::new(b4),
];
assert_eq!(2, buf.chunks_vectored(&mut iovecs));
assert_eq!(iovecs[0][..], b"hello"[..]);
assert_eq!(iovecs[1][..], b"world"[..]);
assert_eq!(iovecs[2][..], b""[..]);
assert_eq!(iovecs[3][..], b""[..]);
}
buf.advance(2);
{
let b1: &[u8] = &mut [];
let b2: &[u8] = &mut [];
let b3: &[u8] = &mut [];
let b4: &[u8] = &mut [];
let mut iovecs = [
IoSlice::new(b1),
IoSlice::new(b2),
IoSlice::new(b3),
IoSlice::new(b4),
];
assert_eq!(2, buf.chunks_vectored(&mut iovecs));
assert_eq!(iovecs[0][..], b"llo"[..]);
assert_eq!(iovecs[1][..], b"world"[..]);
assert_eq!(iovecs[2][..], b""[..]);
assert_eq!(iovecs[3][..], b""[..]);
}
buf.advance(3);
{
let b1: &[u8] = &mut [];
let b2: &[u8] = &mut [];
let b3: &[u8] = &mut [];
let b4: &[u8] = &mut [];
let mut iovecs = [
IoSlice::new(b1),
IoSlice::new(b2),
IoSlice::new(b3),
IoSlice::new(b4),
];
assert_eq!(1, buf.chunks_vectored(&mut iovecs));
assert_eq!(iovecs[0][..], b"world"[..]);
assert_eq!(iovecs[1][..], b""[..]);
assert_eq!(iovecs[2][..], b""[..]);
assert_eq!(iovecs[3][..], b""[..]);
}
buf.advance(3);
{
let b1: &[u8] = &mut [];
let b2: &[u8] = &mut [];
let b3: &[u8] = &mut [];
let b4: &[u8] = &mut [];
let mut iovecs = [
IoSlice::new(b1),
IoSlice::new(b2),
IoSlice::new(b3),
IoSlice::new(b4),
];
assert_eq!(1, buf.chunks_vectored(&mut iovecs));
assert_eq!(iovecs[0][..], b"ld"[..]);
assert_eq!(iovecs[1][..], b""[..]);
assert_eq!(iovecs[2][..], b""[..]);
assert_eq!(iovecs[3][..], b""[..]);
}
}
#[test]
fn chain_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());
}
+35
View File
@@ -0,0 +1,35 @@
#![warn(rust_2018_idioms)]
use bytes::Bytes;
#[test]
fn fmt() {
let vec: Vec<_> = (0..0x100).map(|b| b as u8).collect();
let expected = "b\"\
\\0\\x01\\x02\\x03\\x04\\x05\\x06\\x07\
\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\
\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\
\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f\
\x20!\\\"#$%&'()*+,-./0123456789:;<=>?\
@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\\\]^_\
`abcdefghijklmnopqrstuvwxyz{|}~\\x7f\
\\x80\\x81\\x82\\x83\\x84\\x85\\x86\\x87\
\\x88\\x89\\x8a\\x8b\\x8c\\x8d\\x8e\\x8f\
\\x90\\x91\\x92\\x93\\x94\\x95\\x96\\x97\
\\x98\\x99\\x9a\\x9b\\x9c\\x9d\\x9e\\x9f\
\\xa0\\xa1\\xa2\\xa3\\xa4\\xa5\\xa6\\xa7\
\\xa8\\xa9\\xaa\\xab\\xac\\xad\\xae\\xaf\
\\xb0\\xb1\\xb2\\xb3\\xb4\\xb5\\xb6\\xb7\
\\xb8\\xb9\\xba\\xbb\\xbc\\xbd\\xbe\\xbf\
\\xc0\\xc1\\xc2\\xc3\\xc4\\xc5\\xc6\\xc7\
\\xc8\\xc9\\xca\\xcb\\xcc\\xcd\\xce\\xcf\
\\xd0\\xd1\\xd2\\xd3\\xd4\\xd5\\xd6\\xd7\
\\xd8\\xd9\\xda\\xdb\\xdc\\xdd\\xde\\xdf\
\\xe0\\xe1\\xe2\\xe3\\xe4\\xe5\\xe6\\xe7\
\\xe8\\xe9\\xea\\xeb\\xec\\xed\\xee\\xef\
\\xf0\\xf1\\xf2\\xf3\\xf4\\xf5\\xf6\\xf7\
\\xf8\\xf9\\xfa\\xfb\\xfc\\xfd\\xfe\\xff\"";
assert_eq!(expected, format!("{:?}", Bytes::from(vec)));
}
+21
View File
@@ -0,0 +1,21 @@
#![warn(rust_2018_idioms)]
use bytes::Bytes;
#[test]
fn iter_len() {
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_static(b"");
let iter = buf.iter();
assert_eq!(iter.size_hint(), (0, Some(0)));
assert_eq!(iter.len(), 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);
}
+20
View File
@@ -0,0 +1,20 @@
#![cfg(feature = "serde")]
#![warn(rust_2018_idioms)]
use serde_test::{assert_tokens, Token};
#[test]
fn test_ser_de_empty() {
let b = bytes::Bytes::new();
assert_tokens(&b, &[Token::Bytes(b"")]);
let b = bytes::BytesMut::with_capacity(0);
assert_tokens(&b, &[Token::Bytes(b"")]);
}
#[test]
fn test_ser_de() {
let b = bytes::Bytes::from(&b"bytes"[..]);
assert_tokens(&b, &[Token::Bytes(b"bytes")]);
let b = bytes::BytesMut::from(&b"bytes"[..]);
assert_tokens(&b, &[Token::Bytes(b"bytes")]);
}
+32
View File
@@ -0,0 +1,32 @@
#![warn(rust_2018_idioms)]
use bytes::buf::Buf;
use bytes::Bytes;
#[test]
fn long_take() {
// Tests that get a take with a size greater than the buffer length will not
// overrun the buffer. Regression test for #138.
let buf = b"hello world".take(100);
assert_eq!(11, buf.remaining());
assert_eq!(b"hello world", buf.chunk());
}
#[test]
fn take_copy_to_bytes() {
let mut abcd = Bytes::copy_from_slice(b"abcd");
let abcd_ptr = abcd.as_ptr();
let mut take = (&mut abcd).take(2);
let a = take.copy_to_bytes(1);
assert_eq!(Bytes::copy_from_slice(b"a"), a);
// assert `to_bytes` did not allocate
assert_eq!(abcd_ptr, a.as_ptr());
assert_eq!(Bytes::copy_from_slice(b"bcd"), abcd);
}
#[test]
#[should_panic]
fn take_copy_to_bytes_panics() {
let abcd = Bytes::copy_from_slice(b"abcd");
abcd.take(2).copy_to_bytes(3);
}