Compare commits

..
174 Commits
Author SHA1 Message Date
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
Carl Lerche 12dfc417ce Bump version to v0.3.0 2015-12-03 20:40:52 -08:00
Carl Lerche 6b624b849a Make MutBuf::advance unsafe
Closes #38
2015-12-03 19:57:08 -08:00
Florian HartwigandCarl Lerche 01c1e05a91 Implement Debug for the various ByteBuf types 2015-09-25 09:47:46 -07:00
Nandor KracserandCarl Lerche a76dd8ed0e Add clear method to RingBuf 2015-09-25 09:45:55 -07:00
Carl Lerche 4ce8b1c2c8 Make sub mods public to help docgen 2015-09-25 09:43:58 -07:00
Carl Lerche 3d0a4adc30 Fix tests 2015-09-25 09:36:32 -07:00
Carl Lerche ef82792adf Specify Rust versions in travis.yml 2015-09-25 09:12:47 -07:00
Carl Lerche 3fae2b0bbf Remove Windows build status 2015-09-25 09:06:07 -07:00
Carl Lerche 846aec9d2b Remove Appveyor builds 2015-09-25 09:05:03 -07:00
Dawid Ciężarkiewicz 7edb577d0a Fix for latest rustc. 2015-08-10 21:53:14 -07:00
Carl Lerche 531c77654c Merge branch 'v0.2.x' 2015-08-10 10:14:32 -07:00
Carl Lerche ed087be853 Provide Take decorator that limits Buf size 2015-07-28 12:51:24 -07:00
Carl Lerche b4abd1431a Mark MutBuf::mut_buf as unsafe
`MutBuf::mut_buf` allows access to uninitialized memory.
2015-07-26 11:02:46 -07:00
Carl Lerche 296cac263c Implement buffer traits on Vec<u8>, &[u8], Cursor 2015-07-24 16:52:19 -07:00
Paul Cavallaro 23ad12f842 Add bytes() method to MutByteBuf to allow reading of data already written
without necessitating flipping to ByteBuf.
2015-07-17 22:22:58 -04:00
Carl Lerche d20661676f Bump version to v0.2.10 2015-07-08 13:07:14 -07:00
Felix Kronlage c17f16fdf2 no need to be marked mutable
allows code to compile with nightly again.
2015-07-07 17:38:12 +02:00
Jamie Turner 7b63fa034f Add resume() method to ByteBuf that restores prior write position. 2015-07-02 17:19:43 -07:00
James Bielman d2b4cc3870 RingBuf: Fix edge cases with mark/reset.
- This fixes #25 and fixes #26.

- Move the mark state into a 'Mark' enum.

- Store both 'pos' and 'len' inside the mark because both
  are needed to distinguish between full/empty states. This
  fixes 'reset' setting 'len' to zero when the buffer was
  full when marked.

- Clear the mark when the length of the marked input range
  exceeds the capacity. Fixes bugs with the mark not being
  cleared correctly on writes.

- Add test cases.
2015-06-02 23:51:57 -07:00
Carl Lerche 2d3b4b9002 More badges! 2015-05-19 17:13:21 -07:00
Carl Lerche 0d7d120733 Run Windows CI on multiple platforms 2015-05-19 16:39:49 -07:00
Carl Lerche 5584fa84dc Use Appveyor for Windows CI 2015-05-13 10:41:34 -07:00
Carl Lerche 64f8a0c6f6 Bump version to v0.2.9 2015-05-12 22:26:53 -07:00
Florian Hartwig d25958970e + isn't implemented on Vec any more 2015-05-09 17:58:23 +02:00
Florian Hartwig c5452b8cce Don't transmute & to &mut 2015-05-09 17:34:00 +02:00
Carl Lerche a91ee81bda Bump version to v0.2.8 2015-04-22 09:27:57 -07:00
Carl Lerche e39f2ba917 Remove unstable attribute 2015-04-22 08:25:53 -07:00
Carl Lerche e62bd07b77 Bump version to v0.2.7 2015-04-12 15:29:37 -07:00
Dan Burkert 4d645c7f53 add mark/reset feature to ByteBuf and RingBuf 2015-04-11 15:18:32 -07:00
Florian Hartwig 40f1d1aa77 Add some basic tests for RingBuf 2015-04-09 23:18:16 +02:00
Florian HartwigandCarl Lerche c4546493ea Fix bugs in RingBuf's io::Read and io::Write instance 2015-04-08 13:44:53 -07:00
Florian HartwigandCarl Lerche e22415b416 Fix Buf and MutBuf documentation 2015-04-08 13:43:02 -07:00
Carl Lerche c9d3427fd5 Move various ByteStr impls into separate files 2015-04-08 10:51:52 -07:00
Carl Lerche ac42766535 Group files as buf or byte str related 2015-04-07 23:40:00 -07:00
Carl Lerche c4f2e20eb1 Move heap allocator into a module 2015-04-07 21:06:38 -07:00
Carl Lerche dfe4cec871 Remove unnecessary #[allow(..)] 2015-04-07 19:11:38 -07:00
Carl Lerche 1ead637f69 Bump version to v0.2.6 2015-04-07 16:15:55 -07:00
Carl Lerche c8f0bbd513 Fix TraitObject 2015-04-07 16:15:11 -07:00
Carl Lerche 8af74ae40e Bump version to v0.2.5 2015-04-07 14:53:12 -07:00
Carl Lerche 29e5dc72bb Get compiling on Rust 1.0 beta 2015-04-03 23:45:34 -07:00
Victor Berger 635274752b Update for new blanket impl rules. 2015-04-03 22:46:10 +02:00
Carl Lerche fb67281e72 Bump version to v0.2.4 2015-04-01 20:09:45 -07:00
Carl Lerche f0ce42d9c3 Track Rust nightlies 2015-04-01 20:09:20 -07:00
Carl Lerche 7a12abb6e6 Bump version to v0.2.3 2015-03-30 15:15:03 -07:00
Andrew Hobden e4fd392458 Add Read and Write to RingBuf 2015-03-30 14:42:59 -07:00
Carl Lerche 74a59c66b4 Bump version to v0.2.2 2015-03-28 17:00:59 -07:00
Carl Lerche 805b15e517 Track Rust nightlies 2015-03-28 16:56:53 -07:00
Carl Lerche 54f98821f3 Bump version to 0.2.1 2015-03-25 12:55:36 -07:00
Carl Lerche 8f526231d8 Track Rust nightlies 2015-03-25 12:44:38 -07:00
Carl Lerche 53624038ad Bump version to 0.2.0 2015-03-24 22:28:09 -07:00
Carl Lerche 83680dda27 Implement Source for std::io::Read 2015-03-24 22:10:29 -07:00
Florian Hartwig bb1227116b Fix panics on operations on 0-capacity RingBuf 2015-03-25 01:11:25 +01:00
Carl Lerche 68a0abf687 Implement slice for small ByteStr 2015-03-23 23:38:53 -07:00
Carl Lerche bd2c643e17 Flesh out ToBytes, ByteStr::concat, and ByteStr eq 2015-03-23 23:22:21 -07:00
Carl Lerche a87dea0bd4 Track Rust master 2015-03-23 17:12:39 -07:00
Florian Hartwig 3f9b7f6d46 Fix errors and warnings with current rust nightly 2015-03-19 16:23:29 +01:00
Carl Lerche e806a59b4a Fix deprecation warnings 2015-03-09 22:30:41 -07:00
Florian HartwigandCarl Lerche 6f00c6117b Remove RingBufReader and RingBufWriter types 2015-03-09 22:24:42 -07:00
Carl Lerche 113bff22c6 Fix a couple of bugs 2015-03-09 22:21:10 -07:00
Carl Lerche b7c7ff5ab6 Bump version to 0.1.3 2015-02-17 15:04:04 -08:00
Florian HartwigandCarl Lerche 7e02c29e85 Remove unnecessary Send impl 2015-02-17 14:10:07 -08:00
Carl Lerche 7444721d98 Implement Debug for Bytes 2015-02-17 12:40:15 -08:00
Carl Lerche e39ba25a95 Implement Read / Write for Buf types 2015-02-16 20:30:04 -08:00
Carl Lerche 1f1aa36547 Bump version to 0.1.2 2015-02-15 14:54:38 -08:00
Carl Lerche a3fea6b1e2 Add io feature 2015-02-14 19:47:31 -08:00
Carl Lerche d7a9e9ffc9 Temporarily remove iobuf from deps 2015-02-14 19:46:18 -08:00
Valerii Hiora 1442ad219c Fixed error on Rust master - no drop flag requires feature 2015-02-13 09:50:53 +02:00
Carl Lerche 4ebffd0103 Add more documentation 2015-02-11 10:04:31 -08:00
Carl Lerche 66c00aaf72 Bump version 2015-02-10 19:35:37 -08:00
Carl Lerche 974043bd13 Add read_byte and write_byte 2015-02-10 19:29:39 -08:00
45 changed files with 6144 additions and 2488 deletions
+52 -9
View File
@@ -1,14 +1,57 @@
---
dist: trusty
language: rust
sudo: false
script:
- cargo test
- cargo doc --no-deps
after_success:
- test $TRAVIS_PULL_REQUEST == "false" && test $TRAVIS_BRANCH == "master" && bash deploy.sh
services: docker
sudo: required
rust: stable
env:
global:
secure: "mBLJANLvtmyWCXw4zMquptqHQnws0pF+C/u4zL1Jfwz8T4UnUjmBUMxSOgSEIzrOM3qb+CTCjY2/j6BM21+/Zfdl8k8CvFWtkqQUPwIfrtwddCgI+P8Hlrk8G43drz/8XAbZ7dOl+Ovwhr0xnSD9ImfyXJec1kDWhubmgyt47Fs="
- CRATE_NAME=bytes
# Default job
- TARGET=x86_64-unknown-linux-gnu
- secure: "f17G5kb6uAQlAG9+GknFFYAmngGBqy9h+3FtNbp3mXTI0FOLltz00Ul5kGPysE4eagypm/dWOuvBkNjN01jhE6fCbekmInEsobIuanatrk6TvXT6caJqykxhPJC2cUoq8pKnMqEOuucEqPPUH6Qy6Hz4/2cRu5JV22Uv9dtS29Q="
matrix:
include:
# Run build on oldest supported rust version. Do not change the rust
# version without a Github issue first.
#
# This job will also build and deploy the docs to gh-pages.
- env: TARGET=x86_64-unknown-linux-gnu
rust: 1.10.0
after_success:
- |
pip install 'travis-cargo<0.2' --user &&
export PATH=$HOME/.local/bin:$PATH
- travis-cargo doc
- travis-cargo doc-upload
# Run tests on some extra platforms
- env: TARGET=i686-unknown-linux-gnu
- env: TARGET=armv7-unknown-linux-gnueabihf
- env: RUST_TEST_THREADS=1 TARGET=powerpc-unknown-linux-gnu
- env: RUST_TEST_THREADS=1 TARGET=powerpc64-unknown-linux-gnu
before_install: set -e
install:
- sh ci/install.sh
- source ~/.cargo/env || true
script:
- bash ci/script.sh
after_script: set +e
before_deploy:
- sh ci/before_deploy.sh
cache: cargo
before_cache:
# Travis can't cache files that are not readable by "others"
- chmod -R a+r $HOME/.cargo
notifications:
email:
on_success: never
+23
View File
@@ -0,0 +1,23 @@
# 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
+8 -16
View File
@@ -1,7 +1,7 @@
[package]
name = "bytes"
version = "0.1.0"
version = "0.4.2"
license = "MIT"
authors = ["Carl Lerche <[email protected]>"]
description = "Types and traits for working with bytes"
@@ -9,7 +9,7 @@ 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"]
keywords = ["buffers", "zero-copy", "io"]
exclude = [
".gitignore",
".travis.yml",
@@ -17,19 +17,11 @@ exclude = [
"bench/**/*",
"test/**/*"
]
categories = ["network-programming", "data-structures"]
[dependencies]
byteorder = "1.0.0"
iovec = "0.1"
[dev-dependencies]
rand = "0.1.2"
iobuf = "*"
[[bench]]
name = "bench"
path = "bench/bench.rs"
[[test]]
name = "test"
path = "test/test.rs"
tokio-core = "0.1.0"
-52
View File
@@ -1,52 +0,0 @@
Copyright (c) 2015 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:
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.
+201
View File
@@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright 2017 Carl Lerche
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
+25
View File
@@ -0,0 +1,25 @@
Copyright (c) 2017 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:
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.
+20 -3
View File
@@ -2,15 +2,32 @@
A utility library for working with bytes.
[![Crates.io](https://img.shields.io/crates/v/bytes.svg?maxAge=2592000)](https://crates.io/crates/bytes)
[![Build Status](https://travis-ci.org/carllerche/bytes.svg?branch=master)](https://travis-ci.org/carllerche/bytes)
- [API documentation](http://carllerche.github.io/bytes/bytes/index.html)
[Documentation](https://carllerche.github.io/bytes/bytes/index.html)
## Usage
To use `bytes`, first add this to your `Cargo.toml`:
```toml
[dependencies.bytes]
git = "https://github.com/carllerche/bytes"
[dependencies]
bytes = "0.4"
```
Next, add this to your crate:
```rust
extern crate bytes;
use bytes::{Bytes, BytesMut, Buf, BufMut};
```
# License
`bytes` is primarily distributed under the terms of both the MIT license and the
Apache License (Version 2.0), with portions covered by various BSD-like
licenses.
See LICENSE-APACHE, and LICENSE-MIT for details.
-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]);
}
});
}
+210
View File
@@ -0,0 +1,210 @@
#![feature(test)]
extern crate tokio_core;
extern crate bytes;
extern crate test;
mod bench_easy_buf {
use test::{self, Bencher};
use tokio_core::io::EasyBuf;
#[bench]
fn alloc_small(b: &mut Bencher) {
b.iter(|| {
for _ in 0..1024 {
test::black_box(EasyBuf::with_capacity(12));
}
})
}
#[bench]
fn alloc_mid(b: &mut Bencher) {
b.iter(|| {
test::black_box(EasyBuf::with_capacity(128));
})
}
#[bench]
fn alloc_big(b: &mut Bencher) {
b.iter(|| {
test::black_box(EasyBuf::with_capacity(4096));
})
}
#[bench]
fn deref_front(b: &mut Bencher) {
let mut buf = EasyBuf::with_capacity(4096);
buf.get_mut().extend_from_slice(&[0; 1024][..]);
b.iter(|| {
for _ in 0..1024 {
test::black_box(buf.as_slice());
}
})
}
#[bench]
fn deref_mid(b: &mut Bencher) {
let mut buf = EasyBuf::with_capacity(4096);
buf.get_mut().extend_from_slice(&[0; 1024][..]);
let _a = buf.drain_to(512);
b.iter(|| {
for _ in 0..1024 {
test::black_box(buf.as_slice());
}
})
}
#[bench]
fn alloc_write_drain_to_mid(b: &mut Bencher) {
b.iter(|| {
let mut buf = EasyBuf::with_capacity(128);
buf.get_mut().extend_from_slice(&[0u8; 64]);
test::black_box(buf.drain_to(64));
})
}
#[bench]
fn drain_write_drain(b: &mut Bencher) {
let data = [0u8; 128];
b.iter(|| {
let mut buf = EasyBuf::with_capacity(1024);
let mut parts = Vec::with_capacity(8);
for _ in 0..8 {
buf.get_mut().extend_from_slice(&data[..]);
parts.push(buf.drain_to(128));
}
test::black_box(parts);
})
}
}
mod bench_bytes {
use test::{self, Bencher};
use bytes::{BytesMut, BufMut};
#[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_inline(b: &mut Bencher) {
let mut buf = BytesMut::with_capacity(8);
buf.put(&[0u8; 8][..]);
b.iter(|| {
for _ in 0..1024 {
test::black_box(&buf[..]);
}
})
}
#[bench]
fn deref_two(b: &mut Bencher) {
let mut buf1 = BytesMut::with_capacity(8);
buf1.put(&[0u8; 8][..]);
let mut buf2 = BytesMut::with_capacity(4096);
buf2.put(&[0u8; 1024][..]);
b.iter(|| {
for _ in 0..512 {
test::black_box(&buf1[..]);
test::black_box(&buf2[..]);
}
})
}
#[bench]
fn alloc_write_drain_to_mid(b: &mut Bencher) {
b.iter(|| {
let mut buf = BytesMut::with_capacity(128);
buf.put_slice(&[0u8; 64]);
test::black_box(buf.drain_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.drain_to(128));
}
test::black_box(parts);
})
}
}
+23
View File
@@ -0,0 +1,23 @@
# This script takes care of packaging the build artifacts that will go in the
# release zipfile
$SRC_DIR = $PWD.Path
$STAGE = [System.Guid]::NewGuid().ToString()
Set-Location $ENV:Temp
New-Item -Type Directory -Name $STAGE
Set-Location $STAGE
$ZIP = "$SRC_DIR\$($Env:CRATE_NAME)-$($Env:APPVEYOR_REPO_TAG_NAME)-$($Env:TARGET).zip"
# TODO Update this to package the right artifacts
Copy-Item "$SRC_DIR\target\$($Env:TARGET)\release\hello.exe" '.\'
7z a "$ZIP" *
Push-AppveyorArtifact "$ZIP"
Remove-Item *.* -Force
Set-Location ..
Remove-Item $STAGE
Set-Location $SRC_DIR
+33
View File
@@ -0,0 +1,33 @@
# This script takes care of building your crate and packaging it for release
set -ex
main() {
local src=$(pwd) \
stage=
case $TRAVIS_OS_NAME in
linux)
stage=$(mktemp -d)
;;
osx)
stage=$(mktemp -d -t tmp)
;;
esac
test -f Cargo.lock || cargo generate-lockfile
# TODO Update this to build the artifacts that matter to you
cross rustc --bin hello --target $TARGET --release -- -C lto
# TODO Update this to package the right artifacts
cp target/$TARGET/release/hello $stage/
cd $stage
tar czf $src/$CRATE_NAME-$TRAVIS_TAG-$TARGET.tar.gz *
cd $src
rm -rf $stage
}
main
+31
View File
@@ -0,0 +1,31 @@
set -ex
main() {
curl https://sh.rustup.rs -sSf | \
sh -s -- -y --default-toolchain $TRAVIS_RUST_VERSION
local target=
if [ $TRAVIS_OS_NAME = linux ]; then
target=x86_64-unknown-linux-gnu
sort=sort
else
target=x86_64-apple-darwin
sort=gsort # for `sort --sort-version`, from brew's coreutils.
fi
# This fetches latest stable release
local tag=$(git ls-remote --tags --refs --exit-code https://github.com/japaric/cross \
| cut -d/ -f3 \
| grep -E '^v[0-9.]+$' \
| $sort --version-sort \
| tail -n1)
echo cross version: $tag
curl -LSfs https://japaric.github.io/trust/install.sh | \
sh -s -- \
--force \
--git japaric/cross \
--tag $tag \
--target $target
}
main
+18
View File
@@ -0,0 +1,18 @@
# This script takes care of testing your crate
set -ex
main() {
cross build --target $TARGET
if [ ! -z $DISABLE_TESTS ]; then
return
fi
cross test --target $TARGET
}
# we don't run the "test phase" when doing deploys
if [ -z $TRAVIS_TAG ]; then
main
fi
-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
-180
View File
@@ -1,180 +0,0 @@
use std::{mem, ptr};
use std::rt::heap;
use std::sync::atomic::{AtomicUsize, Ordering};
const MAX_ALLOC_SIZE: usize = (1 << 32) - 1;
/// Allocates memory to be used by Bufs or Bytes. Allows allocating memory
/// using alternate stratgies than the default Rust heap allocator. Also does
/// not require that allocations are continuous in memory.
///
/// For example, an alternate allocator could use a slab of 4kb chunks of
/// memory and return as many chunks as needed to satisfy the length
/// requirement.
pub trait Allocator: Sync + Send {
/// Allocate memory. May or may not be contiguous.
fn allocate(&self, len: usize) -> MemRef;
/// Deallocate a chunk of memory
fn deallocate(&self, mem: *mut Mem);
}
pub struct MemRef {
ptr: *mut u8,
}
impl MemRef {
pub fn new(mem: *mut Mem) -> MemRef {
let ptr = mem as *mut u8;
unsafe {
MemRef {
ptr: ptr.offset(mem::size_of::<Mem>() as isize),
}
}
}
#[inline]
pub fn none() -> MemRef {
MemRef { ptr: ptr::null_mut() }
}
#[inline]
pub fn is_none(&self) -> bool {
self.ptr.is_null()
}
#[inline]
pub fn ptr(&self) -> *mut u8 {
self.ptr
}
pub fn bytes(&self) -> &[u8] {
use std::raw::Slice;
unsafe {
mem::transmute(Slice {
data: self.ptr(),
len: self.mem().len,
})
}
}
#[inline]
pub fn bytes_mut(&mut self) -> &mut [u8] {
unsafe { mem::transmute(self.bytes()) }
}
#[inline]
fn mem_ptr(&self) -> *mut Mem {
unsafe {
self.ptr.offset(-(mem::size_of::<Mem>() as isize)) as *mut Mem
}
}
#[inline]
fn mem(&self) -> &Mem {
unsafe {
mem::transmute(self.mem_ptr())
}
}
}
impl Clone for MemRef {
#[inline]
fn clone(&self) -> MemRef {
self.mem().refs.fetch_add(1, Ordering::Relaxed);
MemRef { ptr: self.ptr }
}
}
impl Drop for MemRef {
fn drop(&mut self) {
// Guard against the ref having already been dropped
if self.ptr.is_null() { return; }
// Decrement the ref count
if 1 == self.mem().refs.fetch_sub(1, Ordering::Relaxed) {
// Last ref dropped, free the memory
unsafe {
let alloc: &Allocator = mem::transmute(self.mem().allocator);
alloc.deallocate(self.mem_ptr());
}
}
}
}
unsafe impl Send for MemRef { }
unsafe impl Sync for MemRef { }
/// Memory allocated by an Allocator must be prefixed with Mem
pub struct Mem {
// TODO: It should be possible to reduce the size of this struct
allocator: *const Allocator,
refs: AtomicUsize,
len: usize,
}
impl Mem {
fn new(len: usize, allocator: *const Allocator) -> Mem {
Mem {
allocator: allocator,
refs: AtomicUsize::new(1),
len: len,
}
}
}
pub static HEAP: Heap = Heap;
#[allow(missing_copy_implementations)]
pub struct Heap;
impl Heap {
pub fn allocate(&self, len: usize) -> MemRef {
// Make sure that the allocation is within the permitted range
if len > MAX_ALLOC_SIZE {
return MemRef::none();
}
let alloc_len = len + mem::size_of::<Mem>();
unsafe {
// Attempt to allocate the memory
let ptr: *mut Mem = mem::transmute(
heap::allocate(alloc_len, mem::min_align_of::<u8>()));
// If failed, return None
if ptr.is_null() {
return MemRef::none();
}
// Write the mem header
ptr::write(ptr, Mem::new(len, mem::transmute(self as &Allocator)));
// Return the info
MemRef::new(ptr)
}
}
pub fn deallocate(&self, mem: *mut Mem) {
unsafe {
let m: &Mem = mem::transmute(mem);
heap::deallocate(
mem as *mut u8, m.len + mem::size_of::<Mem>(),
mem::min_align_of::<u8>())
}
}
}
impl Allocator for Heap {
fn allocate(&self, len: usize) -> MemRef {
Heap::allocate(self, len)
}
fn deallocate(&self, mem: *mut Mem) {
Heap::deallocate(self, mem)
}
}
+751
View File
@@ -0,0 +1,751 @@
use super::{IntoBuf, Take, Reader, Iter, FromBuf, Chain};
use byteorder::ByteOrder;
use iovec::IoVec;
use std::{cmp, io, ptr};
/// Read bytes from a buffer.
///
/// A buffer stores bytes in memory such that read operations are infallible.
/// The underlying storage may or may not be in contiguous memory. A `Buf` value
/// is a cursor into the buffer. Reading from `Buf` advances the cursor
/// position. It can be thought of as an efficient `Iterator` for collections of
/// bytes.
///
/// The simplest `Buf` is a `Cursor` wrapping a `[u8]`.
///
/// ```
/// use bytes::Buf;
/// use std::io::Cursor;
///
/// let mut buf = Cursor::new(b"hello world");
///
/// assert_eq!(b'h', buf.get_u8());
/// assert_eq!(b'e', buf.get_u8());
/// assert_eq!(b'l', buf.get_u8());
///
/// let mut rest = [0; 8];
/// buf.copy_to_slice(&mut rest);
///
/// assert_eq!(&rest[..], b"lo world");
/// ```
pub trait Buf {
/// Returns the number of bytes between the current position and the end of
/// the buffer.
///
/// This value is greater than or equal to the length of the slice returned
/// by `bytes`.
///
/// # Examples
///
/// ```
/// use bytes::Buf;
/// use std::io::Cursor;
///
/// let mut buf = Cursor::new(b"hello world");
///
/// assert_eq!(buf.remaining(), 11);
///
/// buf.get_u8();
///
/// assert_eq!(buf.remaining(), 10);
/// ```
///
/// # Implementer notes
///
/// Implementations of `remaining` should ensure that the return value does
/// not change unless a call is made to `advance` or any other function that
/// is documented to change the `Buf`'s current position.
fn remaining(&self) -> usize;
/// Returns a slice starting at the current position and of length between 0
/// and `Buf::remaining()`.
///
/// This is a lower level function. Most operations are done with other
/// functions.
///
/// # Examples
///
/// ```
/// use bytes::Buf;
/// use std::io::Cursor;
///
/// let mut buf = Cursor::new(b"hello world");
///
/// assert_eq!(buf.bytes(), b"hello world");
///
/// buf.advance(6);
///
/// assert_eq!(buf.bytes(), b"world");
/// ```
///
/// # Implementer notes
///
/// This function should never panic. Once the end of the buffer is reached,
/// i.e., `Buf::remaining` returns 0, calls to `bytes` should return an
/// empty slice.
fn bytes(&self) -> &[u8];
/// Fills `dst` with potentially multiple slices starting at `self`'s
/// current position.
///
/// If the `Buf` is backed by disjoint slices of bytes, `bytes_vec` enables
/// fetching more than one slice at once. `dst` is a slice of `IoVec`
/// references, enabling the slice to be directly used with [`writev`]
/// without any further conversion. The sum of the lengths of all the
/// buffers in `dst` will be less than or equal to `Buf::remaining()`.
///
/// The entries in `dst` will be overwritten, but the data **contained** by
/// the slices **will not** be modified. If `bytes_vec` does not fill every
/// entry in `dst`, then `dst` is guaranteed to contain all remaining slices
/// in `self.
///
/// This is a lower level function. Most operations are done with other
/// functions.
///
/// # Implementer notes
///
/// This function should never panic. Once the end of the buffer is reached,
/// i.e., `Buf::remaining` returns 0, calls to `bytes_vec` must return 0
/// without mutating `dst`.
///
/// Implementations should also take care to properly handle being called
/// with `dst` being a zero length slice.
///
/// [`writev`]: http://man7.org/linux/man-pages/man2/readv.2.html
fn bytes_vec<'a>(&'a self, dst: &mut [&'a IoVec]) -> usize {
if dst.is_empty() {
return 0;
}
if self.has_remaining() {
dst[0] = self.bytes().into();
1
} else {
0
}
}
/// Advance the internal cursor of the Buf
///
/// The next call to `bytes` will return a slice starting `cnt` bytes
/// further into the underlying buffer.
///
/// # Examples
///
/// ```
/// use bytes::Buf;
/// use std::io::Cursor;
///
/// let mut buf = Cursor::new(b"hello world");
///
/// assert_eq!(buf.bytes(), b"hello world");
///
/// buf.advance(6);
///
/// assert_eq!(buf.bytes(), b"world");
/// ```
///
/// # Panics
///
/// This function **may** panic if `cnt > self.remaining()`.
///
/// # Implementer notes
///
/// It is recommended for implementations of `advance` to panic if `cnt >
/// self.remaining()`. If the implementation does not panic, the call must
/// behave as if `cnt == self.remaining()`.
///
/// A call with `cnt == 0` should never panic and be a no-op.
fn advance(&mut self, cnt: usize);
/// Returns true if there are any more bytes to consume
///
/// This is equivalent to `self.remaining() != 0`.
///
/// # Examples
///
/// ```
/// use bytes::Buf;
/// use std::io::Cursor;
///
/// let mut buf = Cursor::new(b"a");
///
/// assert!(buf.has_remaining());
///
/// buf.get_u8();
///
/// assert!(!buf.has_remaining());
/// ```
fn has_remaining(&self) -> bool {
self.remaining() > 0
}
/// Copies bytes from `self` into `dst`.
///
/// The cursor is advanced by the number of bytes copied. `self` must have
/// enough remaining bytes to fill `dst`.
///
/// # Examples
///
/// ```
/// use bytes::Buf;
/// use std::io::Cursor;
///
/// let mut buf = Cursor::new(b"hello world");
/// let mut dst = [0; 5];
///
/// buf.copy_to_slice(&mut dst);
/// assert_eq!(b"hello", &dst);
/// assert_eq!(6, buf.remaining());
/// ```
///
/// # Panics
///
/// This function panics if `self.remaining() < dst.len()`
fn copy_to_slice(&mut self, dst: &mut [u8]) {
let mut off = 0;
assert!(self.remaining() >= dst.len());
while off < dst.len() {
let cnt;
unsafe {
let src = self.bytes();
cnt = cmp::min(src.len(), dst.len() - off);
ptr::copy_nonoverlapping(
src.as_ptr(), dst[off..].as_mut_ptr(), cnt);
off += src.len();
}
self.advance(cnt);
}
}
/// Gets an unsigned 8 bit integer from `self`.
///
/// The current position is advanced by 1.
///
/// # Examples
///
/// ```
/// use bytes::Buf;
/// use std::io::Cursor;
///
/// let mut buf = Cursor::new(b"\x08 hello");
/// assert_eq!(8, buf.get_u8());
/// ```
///
/// # Panics
///
/// This function panics if there is no more remaining data in `self`.
fn get_u8(&mut self) -> u8 {
let mut buf = [0; 1];
self.copy_to_slice(&mut buf);
buf[0]
}
/// Gets a signed 8 bit integer from `self`.
///
/// The current position is advanced by 1.
///
/// # Examples
///
/// ```
/// use bytes::Buf;
/// use std::io::Cursor;
///
/// let mut buf = Cursor::new(b"\x08 hello");
/// assert_eq!(8, buf.get_i8());
/// ```
///
/// # Panics
///
/// This function panics if there is no more remaining data in `self`.
fn get_i8(&mut self) -> i8 {
let mut buf = [0; 1];
self.copy_to_slice(&mut buf);
buf[0] as i8
}
/// Gets an unsigned 16 bit integer from `self` in the specified byte order.
///
/// The current position is advanced by 2.
///
/// # Examples
///
/// ```
/// use bytes::{Buf, BigEndian};
/// use std::io::Cursor;
///
/// let mut buf = Cursor::new(b"\x08\x09 hello");
/// assert_eq!(0x0809, buf.get_u16::<BigEndian>());
/// ```
///
/// # Panics
///
/// This function panics if there is not enough remaining data in `self`.
fn get_u16<T: ByteOrder>(&mut self) -> u16 {
let mut buf = [0; 2];
self.copy_to_slice(&mut buf);
T::read_u16(&buf)
}
/// Gets a signed 16 bit integer from `self` in the specified byte order.
///
/// The current position is advanced by 2.
///
/// # Examples
///
/// ```
/// use bytes::{Buf, BigEndian};
/// use std::io::Cursor;
///
/// let mut buf = Cursor::new(b"\x08\x09 hello");
/// assert_eq!(0x0809, buf.get_i16::<BigEndian>());
/// ```
///
/// # Panics
///
/// This function panics if there is not enough remaining data in `self`.
fn get_i16<T: ByteOrder>(&mut self) -> i16 {
let mut buf = [0; 2];
self.copy_to_slice(&mut buf);
T::read_i16(&buf)
}
/// Gets an unsigned 32 bit integer from `self` in the specified byte order.
///
/// The current position is advanced by 4.
///
/// # Examples
///
/// ```
/// use bytes::{Buf, BigEndian};
/// use std::io::Cursor;
///
/// let mut buf = Cursor::new(b"\x08\x09\xA0\xA1 hello");
/// assert_eq!(0x0809A0A1, buf.get_u32::<BigEndian>());
/// ```
///
/// # Panics
///
/// This function panics if there is not enough remaining data in `self`.
fn get_u32<T: ByteOrder>(&mut self) -> u32 {
let mut buf = [0; 4];
self.copy_to_slice(&mut buf);
T::read_u32(&buf)
}
/// Gets a signed 32 bit integer from `self` in the specified byte order.
///
/// The current position is advanced by 4.
///
/// # Examples
///
/// ```
/// use bytes::{Buf, BigEndian};
/// use std::io::Cursor;
///
/// let mut buf = Cursor::new(b"\x08\x09\xA0\xA1 hello");
/// assert_eq!(0x0809A0A1, buf.get_i32::<BigEndian>());
/// ```
///
/// # Panics
///
/// This function panics if there is not enough remaining data in `self`.
fn get_i32<T: ByteOrder>(&mut self) -> i32 {
let mut buf = [0; 4];
self.copy_to_slice(&mut buf);
T::read_i32(&buf)
}
/// Gets an unsigned 64 bit integer from `self` in the specified byte order.
///
/// The current position is advanced by 8.
///
/// # Examples
///
/// ```
/// use bytes::{Buf, BigEndian};
/// use std::io::Cursor;
///
/// let mut buf = Cursor::new(b"\x01\x02\x03\x04\x05\x06\x07\x08 hello");
/// assert_eq!(0x0102030405060708, buf.get_u64::<BigEndian>());
/// ```
///
/// # Panics
///
/// This function panics if there is not enough remaining data in `self`.
fn get_u64<T: ByteOrder>(&mut self) -> u64 {
let mut buf = [0; 8];
self.copy_to_slice(&mut buf);
T::read_u64(&buf)
}
/// Gets a signed 64 bit integer from `self` in the specified byte order.
///
/// The current position is advanced by 8.
///
/// # Examples
///
/// ```
/// use bytes::{Buf, BigEndian};
/// use std::io::Cursor;
///
/// let mut buf = Cursor::new(b"\x01\x02\x03\x04\x05\x06\x07\x08 hello");
/// assert_eq!(0x0102030405060708, buf.get_i64::<BigEndian>());
/// ```
///
/// # Panics
///
/// This function panics if there is not enough remaining data in `self`.
fn get_i64<T: ByteOrder>(&mut self) -> i64 {
let mut buf = [0; 8];
self.copy_to_slice(&mut buf);
T::read_i64(&buf)
}
/// Gets an unsigned n-byte integer from `self` in the specified byte order.
///
/// The current position is advanced by `nbytes`.
///
/// # Examples
///
/// ```
/// use bytes::{Buf, BigEndian};
/// use std::io::Cursor;
///
/// let mut buf = Cursor::new(b"\x01\x02\x03 hello");
/// assert_eq!(0x010203, buf.get_uint::<BigEndian>(3));
/// ```
///
/// # Panics
///
/// This function panics if there is not enough remaining data in `self`.
fn get_uint<T: ByteOrder>(&mut self, nbytes: usize) -> u64 {
let mut buf = [0; 8];
self.copy_to_slice(&mut buf[..nbytes]);
T::read_uint(&buf[..nbytes], nbytes)
}
/// Gets a signed n-byte integer from `self` in the specified byte order.
///
/// The current position is advanced by `nbytes`.
///
/// # Examples
///
/// ```
/// use bytes::{Buf, BigEndian};
/// use std::io::Cursor;
///
/// let mut buf = Cursor::new(b"\x01\x02\x03 hello");
/// assert_eq!(0x010203, buf.get_int::<BigEndian>(3));
/// ```
///
/// # Panics
///
/// This function panics if there is not enough remaining data in `self`.
fn get_int<T: ByteOrder>(&mut self, nbytes: usize) -> i64 {
let mut buf = [0; 8];
self.copy_to_slice(&mut buf[..nbytes]);
T::read_int(&buf[..nbytes], nbytes)
}
/// Gets an IEEE754 single-precision (4 bytes) floating point number from
/// `self` in the specified byte order.
///
/// The current position is advanced by 4.
///
/// # Examples
///
/// ```
/// use bytes::{Buf, BigEndian};
/// use std::io::Cursor;
///
/// let mut buf = Cursor::new(b"\x3F\x99\x99\x9A hello");
/// assert_eq!(1.2f32, buf.get_f32::<BigEndian>());
/// ```
///
/// # Panics
///
/// This function panics if there is not enough remaining data in `self`.
fn get_f32<T: ByteOrder>(&mut self) -> f32 {
let mut buf = [0; 4];
self.copy_to_slice(&mut buf);
T::read_f32(&buf)
}
/// Gets an IEEE754 double-precision (8 bytes) floating point number from
/// `self` in the specified byte order.
///
/// The current position is advanced by 8.
///
/// # Examples
///
/// ```
/// use bytes::{Buf, BigEndian};
/// use std::io::Cursor;
///
/// let mut buf = Cursor::new(b"\x3F\xF3\x33\x33\x33\x33\x33\x33 hello");
/// assert_eq!(1.2f64, buf.get_f64::<BigEndian>());
/// ```
///
/// # Panics
///
/// This function panics if there is not enough remaining data in `self`.
fn get_f64<T: ByteOrder>(&mut self) -> f64 {
let mut buf = [0; 8];
self.copy_to_slice(&mut buf);
T::read_f64(&buf)
}
/// Transforms a `Buf` into a concrete buffer.
///
/// `collect()` can operate on any value that implements `Buf`, and turn it
/// into the relevent concrete buffer type.
///
/// # Examples
///
/// Collecting a buffer and loading the contents into a `Vec<u8>`.
///
/// ```
/// use bytes::{Buf, Bytes, IntoBuf};
///
/// let buf = Bytes::from(&b"hello world"[..]).into_buf();
/// let vec: Vec<u8> = buf.collect();
///
/// assert_eq!(vec, &b"hello world"[..]);
/// ```
fn collect<B>(self) -> B
where Self: Sized,
B: FromBuf,
{
B::from_buf(self)
}
/// Creates an adaptor which will read at most `limit` bytes from `self`.
///
/// This function returns a new instance of `Buf` which will read at most
/// `limit` bytes.
///
/// # Examples
///
/// ```
/// use bytes::{Buf, BufMut};
/// use std::io::Cursor;
///
/// let mut buf = Cursor::new("hello world").take(5);
/// let mut dst = vec![];
///
/// dst.put(&mut buf);
/// assert_eq!(dst, b"hello");
///
/// let mut buf = buf.into_inner();
/// dst.clear();
/// dst.put(&mut buf);
/// assert_eq!(dst, b" world");
/// ```
fn take(self, limit: usize) -> Take<Self>
where Self: Sized
{
super::take::new(self, limit)
}
/// Creates an adaptor which will chain this buffer with another.
///
/// The returned `Buf` instance will first consume all bytes from `self`.
/// Afterwards the output is equivalent to the output of next.
///
/// # Examples
///
/// ```
/// use bytes::{Bytes, Buf, IntoBuf};
/// use bytes::buf::Chain;
///
/// let buf = Bytes::from(&b"hello "[..]).into_buf()
/// .chain(Bytes::from(&b"world"[..]));
///
/// let full: Bytes = buf.collect();
/// assert_eq!(full[..], b"hello world"[..]);
/// ```
fn chain<U>(self, next: U) -> Chain<Self, U::Buf>
where U: IntoBuf,
Self: Sized,
{
Chain::new(self, next.into_buf())
}
/// Creates a "by reference" adaptor for this instance of `Buf`.
///
/// The returned adaptor also implements `Buf` and will simply borrow `self`.
///
/// # Examples
///
/// ```
/// use bytes::{Buf, BufMut};
/// use std::io::Cursor;
///
/// let mut buf = Cursor::new("hello world");
/// let mut dst = vec![];
///
/// {
/// let mut reference = buf.by_ref();
/// dst.put(&mut reference.take(5));
/// assert_eq!(dst, b"hello");
/// } // drop our &mut reference so we can use `buf` again
///
/// dst.clear();
/// dst.put(&mut buf);
/// assert_eq!(dst, b" world");
/// ```
fn by_ref(&mut self) -> &mut Self where Self: Sized {
self
}
/// Creates an adaptor which implements the `Read` trait for `self`.
///
/// This function returns a new value which implements `Read` by adapting
/// the `Read` trait functions to the `Buf` trait functions. Given that
/// `Buf` operations are infallible, none of the `Read` functions will
/// return with `Err`.
///
/// # Examples
///
/// ```
/// use bytes::{Buf, IntoBuf, Bytes};
/// use std::io::Read;
///
/// let buf = Bytes::from("hello world").into_buf();
///
/// let mut reader = buf.reader();
/// let mut dst = [0; 1024];
///
/// let num = reader.read(&mut dst).unwrap();
///
/// assert_eq!(11, num);
/// assert_eq!(&dst[..11], b"hello world");
/// ```
fn reader(self) -> Reader<Self> where Self: Sized {
super::reader::new(self)
}
/// Returns an iterator over the bytes contained by the buffer.
///
/// # Examples
///
/// ```
/// use bytes::{Buf, IntoBuf, Bytes};
///
/// let buf = Bytes::from(&b"abc"[..]).into_buf();
/// let mut iter = buf.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);
/// ```
fn iter(self) -> Iter<Self> where Self: Sized {
super::iter::new(self)
}
}
impl<'a, T: Buf + ?Sized> Buf for &'a mut T {
fn remaining(&self) -> usize {
(**self).remaining()
}
fn bytes(&self) -> &[u8] {
(**self).bytes()
}
fn bytes_vec<'b>(&'b self, dst: &mut [&'b IoVec]) -> usize {
(**self).bytes_vec(dst)
}
fn advance(&mut self, cnt: usize) {
(**self).advance(cnt)
}
}
impl<T: Buf + ?Sized> Buf for Box<T> {
fn remaining(&self) -> usize {
(**self).remaining()
}
fn bytes(&self) -> &[u8] {
(**self).bytes()
}
fn bytes_vec<'b>(&'b self, dst: &mut [&'b IoVec]) -> usize {
(**self).bytes_vec(dst)
}
fn advance(&mut self, cnt: usize) {
(**self).advance(cnt)
}
}
impl<T: AsRef<[u8]>> Buf for io::Cursor<T> {
fn remaining(&self) -> usize {
let len = self.get_ref().as_ref().len();
let pos = self.position();
if pos >= len as u64 {
return 0;
}
len - pos as usize
}
fn bytes(&self) -> &[u8] {
let len = self.get_ref().as_ref().len();
let pos = self.position() as usize;
if pos >= len {
return Default::default();
}
&(self.get_ref().as_ref())[pos..]
}
fn advance(&mut self, cnt: usize) {
let pos = (self.position() as usize)
.checked_add(cnt).expect("overflow");
assert!(pos <= self.get_ref().as_ref().len());
self.set_position(pos as u64);
}
}
impl Buf for Option<[u8; 1]> {
fn remaining(&self) -> usize {
if self.is_some() {
1
} else {
0
}
}
fn bytes(&self) -> &[u8] {
self.as_ref().map(AsRef::as_ref)
.unwrap_or(Default::default())
}
fn advance(&mut self, cnt: usize) {
if cnt == 0 {
return;
}
if self.is_none() {
panic!("overflow");
} else {
assert_eq!(1, cnt);
*self = None;
}
}
}
+736
View File
@@ -0,0 +1,736 @@
use super::{IntoBuf, Writer};
use byteorder::ByteOrder;
use iovec::IoVec;
use std::{cmp, io, ptr, usize};
/// A trait for values that provide sequential write access to bytes.
///
/// Write bytes to a buffer
///
/// A buffer stores bytes in memory such that write operations are infallible.
/// The underlying storage may or may not be in contiguous memory. A `BufMut`
/// value is a cursor into the buffer. Writing to `BufMut` advances the cursor
/// position.
///
/// The simplest `BufMut` is a `Vec<u8>`.
///
/// ```
/// use bytes::BufMut;
///
/// let mut buf = vec![];
///
/// buf.put("hello world");
///
/// assert_eq!(buf, b"hello world");
/// ```
pub trait BufMut {
/// Returns the number of bytes that can be written from the current
/// position until the end of the buffer is reached.
///
/// This value is greater than or equal to the length of the slice returned
/// by `bytes_mut`.
///
/// # Examples
///
/// ```
/// use bytes::BufMut;
/// use std::io::Cursor;
///
/// let mut dst = [0; 10];
/// let mut buf = Cursor::new(&mut dst[..]);
///
/// assert_eq!(10, buf.remaining_mut());
/// buf.put("hello");
///
/// assert_eq!(5, buf.remaining_mut());
/// ```
///
/// # Implementer notes
///
/// Implementations of `remaining_mut` should ensure that the return value
/// does not change unless a call is made to `advance_mut` or any other
/// function that is documented to change the `BufMut`'s current position.
fn remaining_mut(&self) -> usize;
/// Advance the internal cursor of the BufMut
///
/// The next call to `bytes_mut` will return a slice starting `cnt` bytes
/// further into the underlying buffer.
///
/// This function is unsafe because there is no guarantee that the bytes
/// being advanced past have been initialized.
///
/// # Examples
///
/// ```
/// use bytes::BufMut;
///
/// let mut buf = Vec::with_capacity(16);
///
/// unsafe {
/// buf.bytes_mut()[0] = b'h';
/// buf.bytes_mut()[1] = b'e';
///
/// buf.advance_mut(2);
///
/// buf.bytes_mut()[0] = b'l';
/// buf.bytes_mut()[1..3].copy_from_slice(b"lo");
///
/// buf.advance_mut(3);
/// }
///
/// assert_eq!(5, buf.len());
/// assert_eq!(buf, b"hello");
/// ```
///
/// # Panics
///
/// This function **may** panic if `cnt > self.remaining_mut()`.
///
/// # Implementer notes
///
/// It is recommended for implementations of `advance_mut` to panic if
/// `cnt > self.remaining_mut()`. If the implementation does not panic,
/// the call must behave as if `cnt == self.remaining_mut()`.
///
/// A call with `cnt == 0` should never panic and be a no-op.
unsafe fn advance_mut(&mut self, cnt: usize);
/// Returns true if there is space in `self` for more bytes.
///
/// This is equivalent to `self.remaining_mut() != 0`.
///
/// # Examples
///
/// ```
/// use bytes::BufMut;
/// use std::io::Cursor;
///
/// let mut dst = [0; 5];
/// let mut buf = Cursor::new(&mut dst);
///
/// assert!(buf.has_remaining_mut());
///
/// buf.put("hello");
///
/// assert!(!buf.has_remaining_mut());
/// ```
fn has_remaining_mut(&self) -> bool {
self.remaining_mut() > 0
}
/// Returns a mutable slice starting at the current BufMut position and of
/// length between 0 and `BufMut::remaining_mut()`.
///
/// This is a lower level function. Most operations are done with other
/// functions.
///
/// The returned byte slice may represent uninitialized memory.
///
/// # Examples
///
/// ```
/// use bytes::BufMut;
///
/// let mut buf = Vec::with_capacity(16);
///
/// unsafe {
/// buf.bytes_mut()[0] = b'h';
/// buf.bytes_mut()[1] = b'e';
///
/// buf.advance_mut(2);
///
/// buf.bytes_mut()[0] = b'l';
/// buf.bytes_mut()[1..3].copy_from_slice(b"lo");
///
/// buf.advance_mut(3);
/// }
///
/// assert_eq!(5, buf.len());
/// assert_eq!(buf, b"hello");
/// ```
///
/// # Implementer notes
///
/// This function should never panic. `bytes_mut` should return an empty
/// slice **if and only if** `remaining_mut` returns 0. In other words,
/// `bytes_mut` returning an empty slice implies that `remaining_mut` will
/// return 0 and `remaining_mut` returning 0 implies that `bytes_mut` will
/// return an empty slice.
unsafe fn bytes_mut(&mut self) -> &mut [u8];
/// Fills `dst` with potentially multiple mutable slices starting at `self`'s
/// current position.
///
/// If the `BufMut` is backed by disjoint slices of bytes, `bytes_vec_mut`
/// enables fetching more than one slice at once. `dst` is a slice of
/// mutable `IoVec` references, enabling the slice to be directly used with
/// [`readv`] without any further conversion. The sum of the lengths of all
/// the buffers in `dst` will be less than or equal to
/// `Buf::remaining_mut()`.
///
/// The entries in `dst` will be overwritten, but the data **contained** by
/// the slices **will not** be modified. If `bytes_vec_mut` does not fill every
/// entry in `dst`, then `dst` is guaranteed to contain all remaining slices
/// in `self.
///
/// This is a lower level function. Most operations are done with other
/// functions.
///
/// # Implementer notes
///
/// This function should never panic. Once the end of the buffer is reached,
/// i.e., `BufMut::remaining_mut` returns 0, calls to `bytes_vec_mut` must
/// return 0 without mutating `dst`.
///
/// Implementations should also take care to properly handle being called
/// with `dst` being a zero length slice.
///
/// [`readv`]: http://man7.org/linux/man-pages/man2/readv.2.html
unsafe fn bytes_vec_mut<'a>(&'a mut self, dst: &mut [&'a mut IoVec]) -> usize {
if dst.is_empty() {
return 0;
}
if self.has_remaining_mut() {
dst[0] = self.bytes_mut().into();
1
} else {
0
}
}
/// Transfer bytes into `self` from `src` and advance the cursor by the
/// number of bytes written.
///
/// # Examples
///
/// ```
/// use bytes::BufMut;
///
/// let mut buf = vec![];
///
/// buf.put(b'h');
/// buf.put(&b"ello"[..]);
/// buf.put(" world");
///
/// assert_eq!(buf, b"hello world");
/// ```
///
/// # Panics
///
/// Panics if `self` does not have enough capacity to contain `src`.
fn put<T: IntoBuf>(&mut self, src: T) where Self: Sized {
use super::Buf;
let mut src = src.into_buf();
assert!(self.remaining_mut() >= src.remaining());
while src.has_remaining() {
let l;
unsafe {
let s = src.bytes();
let d = self.bytes_mut();
l = cmp::min(s.len(), d.len());
ptr::copy_nonoverlapping(
s.as_ptr(),
d.as_mut_ptr(),
l);
}
src.advance(l);
unsafe { self.advance_mut(l); }
}
}
/// Transfer bytes into `self` from `src` and advance the cursor by the
/// number of bytes written.
///
/// `self` must have enough remaining capacity to contain all of `src`.
///
/// ```
/// use bytes::BufMut;
/// use std::io::Cursor;
///
/// let mut dst = [0; 6];
///
/// {
/// let mut buf = Cursor::new(&mut dst);
/// buf.put_slice(b"hello");
///
/// assert_eq!(1, buf.remaining_mut());
/// }
///
/// assert_eq!(b"hello\0", &dst);
/// ```
fn put_slice(&mut self, src: &[u8]) {
let mut off = 0;
assert!(self.remaining_mut() >= src.len(), "buffer overflow");
while off < src.len() {
let cnt;
unsafe {
let dst = self.bytes_mut();
cnt = cmp::min(dst.len(), src.len() - off);
ptr::copy_nonoverlapping(
src[off..].as_ptr(),
dst.as_mut_ptr(),
cnt);
off += cnt;
}
unsafe { self.advance_mut(cnt); }
}
}
/// Writes an unsigned 8 bit integer to `self`.
///
/// The current position is advanced by 1.
///
/// # Examples
///
/// ```
/// use bytes::BufMut;
///
/// let mut buf = vec![];
/// buf.put_u8(0x01);
/// assert_eq!(buf, b"\x01");
/// ```
///
/// # Panics
///
/// This function panics if there is not enough remaining capacity in
/// `self`.
fn put_u8(&mut self, n: u8) {
let src = [n];
self.put_slice(&src);
}
/// Writes a signed 8 bit integer to `self`.
///
/// The current position is advanced by 1.
///
/// # Examples
///
/// ```
/// use bytes::BufMut;
///
/// let mut buf = vec![];
/// buf.put_i8(0x01);
/// assert_eq!(buf, b"\x01");
/// ```
///
/// # Panics
///
/// This function panics if there is not enough remaining capacity in
/// `self`.
fn put_i8(&mut self, n: i8) {
let src = [n as u8];
self.put_slice(&src)
}
/// Writes an unsigned 16 bit integer to `self` in the specified byte order.
///
/// The current position is advanced by 2.
///
/// # Examples
///
/// ```
/// use bytes::{BufMut, BigEndian};
///
/// let mut buf = vec![];
/// buf.put_u16::<BigEndian>(0x0809);
/// assert_eq!(buf, b"\x08\x09");
/// ```
///
/// # Panics
///
/// This function panics if there is not enough remaining capacity in
/// `self`.
fn put_u16<T: ByteOrder>(&mut self, n: u16) {
let mut buf = [0; 2];
T::write_u16(&mut buf, n);
self.put_slice(&buf)
}
/// Writes a signed 16 bit integer to `self` in the specified byte order.
///
/// The current position is advanced by 2.
///
/// # Examples
///
/// ```
/// use bytes::{BufMut, BigEndian};
///
/// let mut buf = vec![];
/// buf.put_i16::<BigEndian>(0x0809);
/// assert_eq!(buf, b"\x08\x09");
/// ```
///
/// # Panics
///
/// This function panics if there is not enough remaining capacity in
/// `self`.
fn put_i16<T: ByteOrder>(&mut self, n: i16) {
let mut buf = [0; 2];
T::write_i16(&mut buf, n);
self.put_slice(&buf)
}
/// Writes an unsigned 32 bit integer to `self` in the specified byte order.
///
/// The current position is advanced by 4.
///
/// # Examples
///
/// ```
/// use bytes::{BufMut, BigEndian};
///
/// let mut buf = vec![];
/// buf.put_u32::<BigEndian>(0x0809A0A1);
/// assert_eq!(buf, b"\x08\x09\xA0\xA1");
/// ```
///
/// # Panics
///
/// This function panics if there is not enough remaining capacity in
/// `self`.
fn put_u32<T: ByteOrder>(&mut self, n: u32) {
let mut buf = [0; 4];
T::write_u32(&mut buf, n);
self.put_slice(&buf)
}
/// Writes a signed 32 bit integer to `self` in the specified byte order.
///
/// The current position is advanced by 4.
///
/// # Examples
///
/// ```
/// use bytes::{BufMut, BigEndian};
///
/// let mut buf = vec![];
/// buf.put_i32::<BigEndian>(0x0809A0A1);
/// assert_eq!(buf, b"\x08\x09\xA0\xA1");
/// ```
///
/// # Panics
///
/// This function panics if there is not enough remaining capacity in
/// `self`.
fn put_i32<T: ByteOrder>(&mut self, n: i32) {
let mut buf = [0; 4];
T::write_i32(&mut buf, n);
self.put_slice(&buf)
}
/// Writes an unsigned 64 bit integer to `self` in the specified byte order.
///
/// The current position is advanced by 8.
///
/// # Examples
///
/// ```
/// use bytes::{BufMut, BigEndian};
///
/// let mut buf = vec![];
/// buf.put_u64::<BigEndian>(0x0102030405060708);
/// assert_eq!(buf, b"\x01\x02\x03\x04\x05\x06\x07\x08");
/// ```
///
/// # Panics
///
/// This function panics if there is not enough remaining capacity in
/// `self`.
fn put_u64<T: ByteOrder>(&mut self, n: u64) {
let mut buf = [0; 8];
T::write_u64(&mut buf, n);
self.put_slice(&buf)
}
/// Writes a signed 64 bit integer to `self` in the specified byte order.
///
/// The current position is advanced by 8.
///
/// # Examples
///
/// ```
/// use bytes::{BufMut, BigEndian};
///
/// let mut buf = vec![];
/// buf.put_i64::<BigEndian>(0x0102030405060708);
/// assert_eq!(buf, b"\x01\x02\x03\x04\x05\x06\x07\x08");
/// ```
///
/// # Panics
///
/// This function panics if there is not enough remaining capacity in
/// `self`.
fn put_i64<T: ByteOrder>(&mut self, n: i64) {
let mut buf = [0; 8];
T::write_i64(&mut buf, n);
self.put_slice(&buf)
}
/// Writes an unsigned n-byte integer to `self` in the specified byte order.
///
/// The current position is advanced by `nbytes`.
///
/// # Examples
///
/// ```
/// use bytes::{BufMut, BigEndian};
///
/// let mut buf = vec![];
/// buf.put_uint::<BigEndian>(0x010203, 3);
/// assert_eq!(buf, b"\x01\x02\x03");
/// ```
///
/// # Panics
///
/// This function panics if there is not enough remaining capacity in
/// `self`.
fn put_uint<T: ByteOrder>(&mut self, n: u64, nbytes: usize) {
let mut buf = [0; 8];
T::write_uint(&mut buf, n, nbytes);
self.put_slice(&buf[0..nbytes])
}
/// Writes a signed n-byte integer to `self` in the specified byte order.
///
/// The current position is advanced by `nbytes`.
///
/// # Examples
///
/// ```
/// use bytes::{BufMut, BigEndian};
///
/// let mut buf = vec![];
/// buf.put_int::<BigEndian>(0x010203, 3);
/// assert_eq!(buf, b"\x01\x02\x03");
/// ```
///
/// # Panics
///
/// This function panics if there is not enough remaining capacity in
/// `self`.
fn put_int<T: ByteOrder>(&mut self, n: i64, nbytes: usize) {
let mut buf = [0; 8];
T::write_int(&mut buf, n, nbytes);
self.put_slice(&buf[0..nbytes])
}
/// Writes an IEEE754 single-precision (4 bytes) floating point number to
/// `self` in the specified byte order.
///
/// The current position is advanced by 4.
///
/// # Examples
///
/// ```
/// use bytes::{BufMut, BigEndian};
///
/// let mut buf = vec![];
/// buf.put_f32::<BigEndian>(1.2f32);
/// assert_eq!(buf, b"\x3F\x99\x99\x9A");
/// ```
///
/// # Panics
///
/// This function panics if there is not enough remaining capacity in
/// `self`.
fn put_f32<T: ByteOrder>(&mut self, n: f32) {
let mut buf = [0; 4];
T::write_f32(&mut buf, n);
self.put_slice(&buf)
}
/// Writes an IEEE754 double-precision (8 bytes) floating point number to
/// `self` in the specified byte order.
///
/// The current position is advanced by 8.
///
/// # Examples
///
/// ```
/// use bytes::{BufMut, BigEndian};
///
/// let mut buf = vec![];
/// buf.put_f64::<BigEndian>(1.2f64);
/// assert_eq!(buf, b"\x3F\xF3\x33\x33\x33\x33\x33\x33");
/// ```
///
/// # Panics
///
/// This function panics if there is not enough remaining capacity in
/// `self`.
fn put_f64<T: ByteOrder>(&mut self, n: f64) {
let mut buf = [0; 8];
T::write_f64(&mut buf, n);
self.put_slice(&buf)
}
/// Creates a "by reference" adaptor for this instance of `BufMut`.
///
/// The returned adapter also implements `BufMut` and will simply borrow
/// `self`.
///
/// # Examples
///
/// ```
/// use bytes::BufMut;
/// use std::io;
///
/// let mut buf = vec![];
///
/// {
/// let mut reference = buf.by_ref();
///
/// // Adapt reference to `std::io::Write`.
/// let mut writer = reference.writer();
///
/// // Use the buffer as a writter
/// io::Write::write(&mut writer, &b"hello world"[..]).unwrap();
/// } // drop our &mut reference so that we can use `buf` again
///
/// assert_eq!(buf, &b"hello world"[..]);
/// ```
fn by_ref(&mut self) -> &mut Self where Self: Sized {
self
}
/// Creates an adaptor which implements the `Write` trait for `self`.
///
/// This function returns a new value which implements `Write` by adapting
/// the `Write` trait functions to the `BufMut` trait functions. Given that
/// `BufMut` operations are infallible, none of the `Write` functions will
/// return with `Err`.
///
/// # Examples
///
/// ```
/// use bytes::BufMut;
/// use std::io::Write;
///
/// let mut buf = vec![].writer();
///
/// let num = buf.write(&b"hello world"[..]).unwrap();
/// assert_eq!(11, num);
///
/// let buf = buf.into_inner();
///
/// assert_eq!(*buf, b"hello world"[..]);
/// ```
fn writer(self) -> Writer<Self> where Self: Sized {
super::writer::new(self)
}
}
impl<'a, T: BufMut + ?Sized> BufMut for &'a mut T {
fn remaining_mut(&self) -> usize {
(**self).remaining_mut()
}
unsafe fn bytes_mut(&mut self) -> &mut [u8] {
(**self).bytes_mut()
}
unsafe fn bytes_vec_mut<'b>(&'b mut self, dst: &mut [&'b mut IoVec]) -> usize {
(**self).bytes_vec_mut(dst)
}
unsafe fn advance_mut(&mut self, cnt: usize) {
(**self).advance_mut(cnt)
}
}
impl<T: BufMut + ?Sized> BufMut for Box<T> {
fn remaining_mut(&self) -> usize {
(**self).remaining_mut()
}
unsafe fn bytes_mut(&mut self) -> &mut [u8] {
(**self).bytes_mut()
}
unsafe fn bytes_vec_mut<'b>(&'b mut self, dst: &mut [&'b mut IoVec]) -> usize {
(**self).bytes_vec_mut(dst)
}
unsafe fn advance_mut(&mut self, cnt: usize) {
(**self).advance_mut(cnt)
}
}
impl<T: AsMut<[u8]> + AsRef<[u8]>> BufMut for io::Cursor<T> {
fn remaining_mut(&self) -> usize {
use Buf;
self.remaining()
}
/// Advance the internal cursor of the BufMut
unsafe fn advance_mut(&mut self, cnt: usize) {
use Buf;
self.advance(cnt);
}
/// Returns a mutable slice starting at the current BufMut position and of
/// length between 0 and `BufMut::remaining()`.
///
/// The returned byte slice may represent uninitialized memory.
unsafe fn bytes_mut(&mut self) -> &mut [u8] {
let len = self.get_ref().as_ref().len();
let pos = self.position() as usize;
if pos >= len {
return Default::default();
}
&mut (self.get_mut().as_mut())[pos..]
}
}
impl BufMut for Vec<u8> {
#[inline]
fn remaining_mut(&self) -> usize {
usize::MAX - self.len()
}
#[inline]
unsafe fn advance_mut(&mut self, cnt: usize) {
let len = self.len();
let remaining = self.capacity() - len;
if cnt > remaining {
// Reserve additional capacity, and ensure that the total length
// will not overflow usize.
self.reserve(cnt - remaining);
}
self.set_len(len + cnt);
}
#[inline]
unsafe fn bytes_mut(&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..]
}
}
+226
View File
@@ -0,0 +1,226 @@
use {Buf, BufMut};
use iovec::IoVec;
/// A `Chain` sequences two buffers.
///
/// `Chain` is an adapter that links two underlying buffers and provides a
/// continous view across both buffers. It is able to sequence either immutable
/// 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, IntoBuf};
/// use bytes::buf::Chain;
///
/// let buf = Bytes::from(&b"hello "[..]).into_buf()
/// .chain(Bytes::from(&b"world"[..]));
///
/// let full: Bytes = buf.collect();
/// 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.
///
/// # Examples
///
/// ```
/// use bytes::BytesMut;
/// use bytes::buf::Chain;
///
/// let buf = Chain::new(
/// BytesMut::with_capacity(1024),
/// BytesMut::with_capacity(1024));
///
/// // Use the chained buffer
/// ```
pub fn new(a: T, b: U) -> Chain<T, U> {
Chain {
a: a,
b: b,
}
}
/// Gets a reference to the first underlying `Buf`.
///
/// # Examples
///
/// ```
/// use bytes::{Bytes, Buf, IntoBuf};
///
/// let buf = Bytes::from(&b"hello"[..]).into_buf()
/// .chain(Bytes::from(&b"world"[..]));
///
/// assert_eq!(buf.first_ref().get_ref()[..], b"hello"[..]);
/// ```
pub fn first_ref(&self) -> &T {
&self.a
}
/// Gets a mutable reference to the first underlying `Buf`.
///
/// # Examples
///
/// ```
/// use bytes::{Bytes, Buf, IntoBuf};
///
/// let mut buf = Bytes::from(&b"hello "[..]).into_buf()
/// .chain(Bytes::from(&b"world"[..]));
///
/// buf.first_mut().set_position(1);
///
/// let full: Bytes = buf.collect();
/// assert_eq!(full[..], b"ello world"[..]);
/// ```
pub fn first_mut(&mut self) -> &mut T {
&mut self.a
}
/// Gets a reference to the last underlying `Buf`.
///
/// # Examples
///
/// ```
/// use bytes::{Bytes, Buf, IntoBuf};
///
/// let buf = Bytes::from(&b"hello"[..]).into_buf()
/// .chain(Bytes::from(&b"world"[..]));
///
/// assert_eq!(buf.last_ref().get_ref()[..], b"world"[..]);
/// ```
pub fn last_ref(&self) -> &U {
&self.b
}
/// Gets a mutable reference to the last underlying `Buf`.
///
/// # Examples
///
/// ```
/// use bytes::{Bytes, Buf, IntoBuf};
///
/// let mut buf = Bytes::from(&b"hello "[..]).into_buf()
/// .chain(Bytes::from(&b"world"[..]));
///
/// buf.last_mut().set_position(1);
///
/// let full: Bytes = buf.collect();
/// 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::{Bytes, Buf, IntoBuf};
///
/// let buf = Bytes::from(&b"hello"[..]).into_buf()
/// .chain(Bytes::from(&b"world"[..]));
///
/// let (first, last) = buf.into_inner();
/// assert_eq!(first.get_ref()[..], b"hello"[..]);
/// assert_eq!(last.get_ref()[..], 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() + self.b.remaining()
}
fn bytes(&self) -> &[u8] {
if self.a.has_remaining() {
self.a.bytes()
} else {
self.b.bytes()
}
}
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);
}
fn bytes_vec<'a>(&'a self, dst: &mut [&'a IoVec]) -> usize {
let mut n = self.a.bytes_vec(dst);
n += self.b.bytes_vec(&mut dst[n..]);
n
}
}
impl<T, U> BufMut for Chain<T, U>
where T: BufMut,
U: BufMut,
{
fn remaining_mut(&self) -> usize {
self.a.remaining_mut() + self.b.remaining_mut()
}
unsafe fn bytes_mut(&mut self) -> &mut [u8] {
if self.a.has_remaining_mut() {
self.a.bytes_mut()
} else {
self.b.bytes_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);
}
unsafe fn bytes_vec_mut<'a>(&'a mut self, dst: &mut [&'a mut IoVec]) -> usize {
let mut n = self.a.bytes_vec_mut(dst);
n += self.b.bytes_vec_mut(&mut dst[n..]);
n
}
}
+117
View File
@@ -0,0 +1,117 @@
use {Buf, BufMut, IntoBuf, Bytes, BytesMut};
/// Conversion from a [`Buf`]
///
/// Implementing `FromBuf` for a type defines how it is created from a buffer.
/// This is common for types which represent byte storage of some kind.
///
/// [`FromBuf::from_buf`] is rarely called explicitly, and it is instead used
/// through [`Buf::collect`]. See [`Buf::collect`] documentation for more examples.
///
/// See also [`IntoBuf`].
///
/// # Examples
///
/// Basic usage:
///
/// ```
/// use bytes::{Bytes, IntoBuf};
/// use bytes::buf::FromBuf;
///
/// let buf = Bytes::from(&b"hello world"[..]).into_buf();
/// let vec = Vec::from_buf(buf);
///
/// assert_eq!(vec, &b"hello world"[..]);
/// ```
///
/// Using [`Buf::collect`] to implicitly use `FromBuf`:
///
/// ```
/// use bytes::{Buf, Bytes, IntoBuf};
///
/// let buf = Bytes::from(&b"hello world"[..]).into_buf();
/// let vec: Vec<u8> = buf.collect();
///
/// assert_eq!(vec, &b"hello world"[..]);
/// ```
///
/// Implementing `FromBuf` for your type:
///
/// ```
/// use bytes::{BufMut, Bytes};
/// use bytes::buf::{IntoBuf, FromBuf};
///
/// // A sample buffer, that's just a wrapper over Vec<u8>
/// struct MyBuffer(Vec<u8>);
///
/// impl FromBuf for MyBuffer {
/// fn from_buf<B>(buf: B) -> Self where B: IntoBuf {
/// let mut v = Vec::new();
/// v.put(buf.into_buf());
/// MyBuffer(v)
/// }
/// }
///
/// // Now we can make a new buf
/// let buf = Bytes::from(&b"hello world"[..]);
///
/// // And make a MyBuffer out of it
/// let my_buf = MyBuffer::from_buf(buf);
///
/// assert_eq!(my_buf.0, &b"hello world"[..]);
/// ```
///
/// [`Buf`]: trait.Buf.html
/// [`FromBuf::from_buf`]: #method.from_buf
/// [`Buf::collect`]: trait.Buf.html#method.collect
/// [`IntoBuf`]: trait.IntoBuf.html
pub trait FromBuf {
/// Creates a value from a buffer.
///
/// See the [type-level documentation](#) for more details.
///
/// # Examples
///
/// Basic usage:
///
/// ```
/// use bytes::{Bytes, IntoBuf};
/// use bytes::buf::FromBuf;
///
/// let buf = Bytes::from(&b"hello world"[..]).into_buf();
/// let vec = Vec::from_buf(buf);
///
/// assert_eq!(vec, &b"hello world"[..]);
/// ```
fn from_buf<T>(buf: T) -> Self where T: IntoBuf;
}
impl FromBuf for Vec<u8> {
fn from_buf<T>(buf: T) -> Self
where T: IntoBuf
{
let buf = buf.into_buf();
let mut ret = Vec::with_capacity(buf.remaining());
ret.put(buf);
ret
}
}
impl FromBuf for Bytes {
fn from_buf<T>(buf: T) -> Self
where T: IntoBuf
{
BytesMut::from_buf(buf).freeze()
}
}
impl FromBuf for BytesMut {
fn from_buf<T>(buf: T) -> Self
where T: IntoBuf
{
let buf = buf.into_buf();
let mut ret = BytesMut::with_capacity(buf.remaining());
ret.put(buf);
ret
}
}
+138
View File
@@ -0,0 +1,138 @@
use super::{Buf};
use std::io;
/// Conversion into a `Buf`
///
/// An `IntoBuf` implementation defines how to convert a value into a `Buf`.
/// This is common for types that represent byte storage of some kind. `IntoBuf`
/// may be implemented directly for types or on references for those types.
///
/// # Examples
///
/// ```
/// use bytes::{Buf, IntoBuf, BigEndian};
///
/// let bytes = b"\x00\x01hello world";
/// let mut buf = bytes.into_buf();
///
/// assert_eq!(1, buf.get_u16::<BigEndian>());
///
/// let mut rest = [0; 11];
/// buf.copy_to_slice(&mut rest);
///
/// assert_eq!(b"hello world", &rest);
/// ```
pub trait IntoBuf {
/// The `Buf` type that `self` is being converted into
type Buf: Buf;
/// Creates a `Buf` from a value.
///
/// # Examples
///
/// ```
/// use bytes::{Buf, IntoBuf, BigEndian};
///
/// let bytes = b"\x00\x01hello world";
/// let mut buf = bytes.into_buf();
///
/// assert_eq!(1, buf.get_u16::<BigEndian>());
///
/// let mut rest = [0; 11];
/// buf.copy_to_slice(&mut rest);
///
/// assert_eq!(b"hello world", &rest);
/// ```
fn into_buf(self) -> Self::Buf;
}
impl<T: Buf> IntoBuf for T {
type Buf = Self;
fn into_buf(self) -> Self {
self
}
}
impl<'a> IntoBuf for &'a [u8] {
type Buf = io::Cursor<&'a [u8]>;
fn into_buf(self) -> Self::Buf {
io::Cursor::new(self)
}
}
impl<'a> IntoBuf for &'a str {
type Buf = io::Cursor<&'a [u8]>;
fn into_buf(self) -> Self::Buf {
self.as_bytes().into_buf()
}
}
impl IntoBuf for Vec<u8> {
type Buf = io::Cursor<Vec<u8>>;
fn into_buf(self) -> Self::Buf {
io::Cursor::new(self)
}
}
impl<'a> IntoBuf for &'a Vec<u8> {
type Buf = io::Cursor<&'a [u8]>;
fn into_buf(self) -> Self::Buf {
io::Cursor::new(&self[..])
}
}
// Kind of annoying... but this impl is required to allow passing `&'static
// [u8]` where for<'a> &'a T: IntoBuf is required.
impl<'a> IntoBuf for &'a &'static [u8] {
type Buf = io::Cursor<&'static [u8]>;
fn into_buf(self) -> Self::Buf {
io::Cursor::new(self)
}
}
impl<'a> IntoBuf for &'a &'static str {
type Buf = io::Cursor<&'static [u8]>;
fn into_buf(self) -> Self::Buf {
self.as_bytes().into_buf()
}
}
impl IntoBuf for String {
type Buf = io::Cursor<Vec<u8>>;
fn into_buf(self) -> Self::Buf {
self.into_bytes().into_buf()
}
}
impl<'a> IntoBuf for &'a String {
type Buf = io::Cursor<&'a [u8]>;
fn into_buf(self) -> Self::Buf {
self.as_bytes().into_buf()
}
}
impl IntoBuf for u8 {
type Buf = Option<[u8; 1]>;
fn into_buf(self) -> Self::Buf {
Some([self])
}
}
impl IntoBuf for i8 {
type Buf = Option<[u8; 1]>;
fn into_buf(self) -> Self::Buf {
Some([self as u8; 1])
}
}
+114
View File
@@ -0,0 +1,114 @@
use Buf;
/// Iterator over the bytes contained by the buffer.
///
/// This struct is created by the [`iter`] method on [`Buf`].
///
/// # Examples
///
/// Basic usage:
///
/// ```
/// use bytes::{Buf, IntoBuf, Bytes};
///
/// let buf = Bytes::from(&b"abc"[..]).into_buf();
/// let mut iter = buf.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 Iter<T> {
inner: T,
}
impl<T> Iter<T> {
/// Consumes this `Iter`, returning the underlying value.
///
/// # Examples
///
/// ```rust
/// use bytes::{Buf, IntoBuf, Bytes};
///
/// let buf = Bytes::from(&b"abc"[..]).into_buf();
/// let mut iter = buf.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, IntoBuf, Bytes};
///
/// let buf = Bytes::from(&b"abc"[..]).into_buf();
/// let mut iter = buf.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, IntoBuf, BytesMut};
///
/// let buf = BytesMut::from(&b"abc"[..]).into_buf();
/// let mut iter = buf.iter();
///
/// assert_eq!(iter.next(), Some(b'a'));
///
/// iter.get_mut().set_position(0);
///
/// assert_eq!(iter.next(), Some(b'a'));
/// ```
pub fn get_mut(&mut self) -> &mut T {
&mut self.inner
}
}
pub fn new<T>(inner: T) -> Iter<T> {
Iter { inner: inner }
}
impl<T: Buf> Iterator for Iter<T> {
type Item = u8;
fn next(&mut self) -> Option<u8> {
if !self.inner.has_remaining() {
return None;
}
let b = self.inner.bytes()[0];
self.inner.advance(1);
Some(b)
}
fn size_hint(&self) -> (usize, Option<usize>) {
let rem = self.inner.remaining();
(rem, Some(rem))
}
}
+37
View File
@@ -0,0 +1,37 @@
//! 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;
mod buf_mut;
mod from_buf;
mod chain;
mod into_buf;
mod iter;
mod reader;
mod take;
mod writer;
pub use self::buf::Buf;
pub use self::buf_mut::BufMut;
pub use self::from_buf::FromBuf;
pub use self::chain::Chain;
pub use self::into_buf::IntoBuf;
pub use self::iter::Iter;
pub use self::reader::Reader;
pub use self::take::Take;
pub use self::writer::Writer;
+88
View File
@@ -0,0 +1,88 @@
use {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: 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;
/// use std::io::{self, Cursor};
///
/// let mut buf = Cursor::new(b"hello world").reader();
///
/// assert_eq!(0, buf.get_ref().position());
/// ```
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`.
///
/// # Examples
///
/// ```rust
/// use bytes::Buf;
/// use std::io::{self, Cursor};
///
/// let mut buf = Cursor::new(b"hello world").reader();
/// let mut dst = vec![];
///
/// buf.get_mut().set_position(2);
/// io::copy(&mut buf, &mut dst).unwrap();
///
/// assert_eq!(*dst, b"llo world"[..]);
/// ```
pub fn get_mut(&mut self) -> &mut B {
&mut self.buf
}
/// Consumes this `Reader`, returning the underlying value.
///
/// # Examples
///
/// ```rust
/// use bytes::Buf;
/// use std::io::{self, Cursor};
///
/// let mut buf = Cursor::new(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)
}
}
+154
View File
@@ -0,0 +1,154 @@
use {Buf};
use std::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,
}
pub fn new<T>(inner: T, limit: usize) -> Take<T> {
Take {
inner: inner,
limit: limit,
}
}
impl<T> Take<T> {
/// Consumes this `Take`, returning the underlying value.
///
/// # Examples
///
/// ```rust
/// use bytes::{Buf, BufMut};
/// use std::io::Cursor;
///
/// let mut buf = Cursor::new(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, BufMut};
/// use std::io::Cursor;
///
/// let mut buf = Cursor::new(b"hello world").take(2);
///
/// assert_eq!(0, buf.get_ref().position());
/// ```
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};
/// use std::io::Cursor;
///
/// let mut buf = Cursor::new(b"hello world").take(2);
/// let mut dst = vec![];
///
/// buf.get_mut().set_position(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;
/// use std::io::Cursor;
///
/// let mut buf = Cursor::new(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};
/// use std::io::Cursor;
///
/// let mut buf = Cursor::new(b"hello world").take(2);
/// let mut dst = vec![];
///
/// dst.put(&mut buf);
/// assert_eq!(*dst, b"he"[..]);
///
/// dst.clear();
///
/// buf.set_limit(3);
/// dst.put(&mut buf);
/// assert_eq!(*dst, b"llo"[..]);
/// ```
pub fn set_limit(&mut self, lim: usize) {
self.limit = lim
}
}
impl<T: Buf> Buf for Take<T> {
fn remaining(&self) -> usize {
cmp::min(self.inner.remaining(), self.limit)
}
fn bytes(&self) -> &[u8] {
&self.inner.bytes()[..self.limit]
}
fn advance(&mut self, cnt: usize) {
assert!(cnt <= self.limit);
self.inner.advance(cnt);
self.limit -= cnt;
}
}
+88
View File
@@ -0,0 +1,88 @@
use 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: 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 mut 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::{self, Cursor};
///
/// let mut buf = vec![].writer();
/// let mut src = Cursor::new(b"hello world");
///
/// io::copy(&mut src, &mut buf).unwrap();
///
/// let buf = buf.into_inner();
/// assert_eq!(*buf, b"hello world"[..]);
/// ```
pub fn into_inner(self) -> B {
self.buf
}
}
impl<B: BufMut + Sized> io::Write for Writer<B> {
fn write(&mut self, src: &[u8]) -> io::Result<usize> {
let n = cmp::min(self.buf.remaining_mut(), src.len());
self.buf.put(&src[0..n]);
Ok(n)
}
fn flush(&mut self) -> io::Result<()> {
Ok(())
}
}
-270
View File
@@ -1,270 +0,0 @@
use {alloc, Bytes, SeqByteStr, MAX_CAPACITY};
use traits::{Buf, MutBuf, MutBufExt, ByteStr};
use std::{cmp, ptr};
use std::num::UnsignedInt;
/*
*
* ===== ByteBuf =====
*
*/
/// A `Buf` backed by a contiguous region of memory.
pub struct ByteBuf {
mem: alloc::MemRef,
cap: u32,
pos: u32,
lim: u32
}
impl ByteBuf {
/// Create a new `ByteBuf` by copying the contents of the given slice.
pub fn from_slice(bytes: &[u8]) -> ByteBuf {
let mut buf = ByteBuf::mut_with_capacity(bytes.len());
buf.write(bytes).ok().expect("unexpected failure");
buf.flip()
}
pub fn mut_with_capacity(capacity: usize) -> MutByteBuf {
assert!(capacity <= MAX_CAPACITY);
MutByteBuf { buf: ByteBuf::new(capacity as u32) }
}
pub fn none() -> ByteBuf {
ByteBuf {
mem: alloc::MemRef::none(),
cap: 0,
pos: 0,
lim: 0,
}
}
pub unsafe fn from_mem_ref(mem: alloc::MemRef, cap: u32, pos: u32, lim: u32) -> ByteBuf {
debug_assert!(pos <= lim && lim <= cap, "invalid arguments; cap={}; pos={}; lim={}", cap, pos, lim);
ByteBuf {
mem: mem,
cap: cap,
pos: pos,
lim: lim,
}
}
fn new(mut capacity: u32) -> ByteBuf {
// Handle 0 capacity case
if capacity == 0 {
return ByteBuf::none();
}
// Round the capacity to the closest power of 2
capacity = UnsignedInt::next_power_of_two(capacity);
// Allocate the memory
let mem = alloc::HEAP.allocate(capacity as usize);
// If the allocation failed, return a blank buf
if mem.is_none() {
return ByteBuf::none();
}
ByteBuf {
mem: mem,
cap: capacity,
pos: 0,
lim: capacity
}
}
pub fn capacity(&self) -> usize {
self.cap as usize
}
pub fn flip(self) -> MutByteBuf {
let mut buf = MutByteBuf { buf: self };
buf.clear();
buf
}
pub fn read_slice(&mut self, dst: &mut [u8]) -> usize {
let len = cmp::min(dst.len(), self.remaining());
let cnt = len as u32;
unsafe {
ptr::copy_nonoverlapping_memory(
dst.as_mut_ptr(),
self.mem.ptr().offset(self.pos as isize), len);
}
self.pos += cnt;
len
}
pub fn to_seq_byte_str(self) -> SeqByteStr {
unsafe {
let ByteBuf { mem, pos, lim, .. } = self;
SeqByteStr::from_mem_ref(
mem, pos, lim - pos)
}
}
#[inline]
pub fn to_bytes(self) -> Bytes {
Bytes::of(self.to_seq_byte_str())
}
#[inline]
fn pos(&self) -> usize {
self.pos as usize
}
#[inline]
fn lim(&self) -> usize {
self.lim as usize
}
#[inline]
fn remaining_u32(&self) -> u32 {
self.lim - self.pos
}
}
impl Buf for ByteBuf {
#[inline]
fn remaining(&self) -> usize {
self.remaining_u32() as usize
}
#[inline]
fn bytes<'a>(&'a self) -> &'a [u8] {
&self.mem.bytes()[self.pos()..self.lim()]
}
#[inline]
fn advance(&mut self, mut cnt: usize) {
cnt = cmp::min(cnt, self.remaining());
self.pos += cnt as u32;
}
#[inline]
fn read_slice(&mut self, dst: &mut [u8]) -> usize {
ByteBuf::read_slice(self, dst)
}
}
unsafe impl Send for ByteBuf { }
/*
*
* ===== ROByteBuf =====
*
*/
/// Same as `ByteBuf` but cannot be flipped to a `MutByteBuf`.
pub struct ROByteBuf {
buf: ByteBuf,
}
impl ROByteBuf {
pub unsafe fn from_mem_ref(mem: alloc::MemRef, cap: u32, pos: u32, lim: u32) -> ROByteBuf {
ROByteBuf {
buf: ByteBuf::from_mem_ref(mem, cap, pos, lim)
}
}
pub fn to_seq_byte_str(self) -> SeqByteStr {
self.buf.to_seq_byte_str()
}
pub fn to_bytes(self) -> Bytes {
self.buf.to_bytes()
}
}
impl Buf for ROByteBuf {
fn remaining(&self) -> usize {
self.buf.remaining()
}
fn bytes<'a>(&'a self) -> &'a [u8] {
self.buf.bytes()
}
fn advance(&mut self, cnt: usize) {
self.buf.advance(cnt)
}
fn read_slice(&mut self, dst: &mut [u8]) -> usize {
self.buf.read_slice(dst)
}
}
/*
*
* ===== MutByteBuf =====
*
*/
pub struct MutByteBuf {
buf: ByteBuf,
}
impl MutByteBuf {
pub fn capacity(&self) -> usize {
self.buf.capacity() as usize
}
pub fn flip(self) -> ByteBuf {
let mut buf = self.buf;
buf.lim = buf.pos;
buf.pos = 0;
buf
}
pub fn clear(&mut self) {
self.buf.pos = 0;
self.buf.lim = self.buf.cap;
}
#[inline]
pub fn write_slice(&mut self, src: &[u8]) -> usize {
let cnt = src.len() as u32;
let rem = self.buf.remaining_u32();
if rem < cnt {
self.write_ptr(src.as_ptr(), rem)
} else {
self.write_ptr(src.as_ptr(), cnt)
}
}
#[inline]
fn write_ptr(&mut self, src: *const u8, len: u32) -> usize {
unsafe {
ptr::copy_nonoverlapping_memory(
self.buf.mem.ptr().offset(self.buf.pos as isize),
src, len as usize);
self.buf.pos += len;
len as usize
}
}
}
impl MutBuf for MutByteBuf {
fn remaining(&self) -> usize {
self.buf.remaining()
}
fn advance(&mut self, cnt: usize) {
self.buf.advance(cnt)
}
fn mut_bytes<'a>(&'a mut self) -> &'a mut [u8] {
let pos = self.buf.pos();
let lim = self.buf.lim();
&mut self.buf.mem.bytes_mut()[pos..lim]
}
}
-227
View File
@@ -1,227 +0,0 @@
use {alloc, Bytes, ByteBuf, ROByteBuf};
use traits::{Buf, MutBuf, MutBufExt, ByteStr};
use std::{cmp, ops};
/*
*
* ===== SeqByteStr =====
*
*/
pub struct SeqByteStr {
mem: alloc::MemRef,
pos: u32,
len: u32,
}
impl SeqByteStr {
/// Create a new `SeqByteStr` from a byte slice.
///
/// The contents of the byte slice will be copied.
pub fn from_slice(bytes: &[u8]) -> SeqByteStr {
let mut buf = ByteBuf::mut_with_capacity(bytes.len());
if let Err(e) = buf.write(bytes) {
panic!("failed to copy bytes from slice; err={:?}", e);
}
buf.flip().to_seq_byte_str()
}
/// Creates a new `SeqByteStr` from a `MemRef`, an offset, and a length.
///
/// This function is unsafe as there are no guarantees that the given
/// arguments are valid.
pub unsafe fn from_mem_ref(mem: alloc::MemRef, pos: u32, len: u32) -> SeqByteStr {
SeqByteStr {
mem: mem,
pos: pos,
len: len,
}
}
}
impl ByteStr for SeqByteStr {
type Buf = ROByteBuf;
fn buf(&self) -> ROByteBuf {
unsafe {
let pos = self.pos;
let lim = pos + self.len;
ROByteBuf::from_mem_ref(self.mem.clone(), lim, pos, lim)
}
}
fn concat<B: ByteStr>(&self, _other: B) -> Bytes {
unimplemented!();
}
fn len(&self) -> usize {
self.len as usize
}
fn slice(&self, begin: usize, end: usize) -> Bytes {
if begin >= end || begin >= self.len() {
return Bytes::empty()
}
let bytes = unsafe {
SeqByteStr::from_mem_ref(
self.mem.clone(),
self.pos + begin as u32,
(end - begin) as u32)
};
Bytes::of(bytes)
}
fn to_bytes(self) -> Bytes {
Bytes::of(self)
}
}
impl ops::Index<usize> for SeqByteStr {
type Output = u8;
fn index(&self, index: &usize) -> &u8 {
assert!(*index < self.len());
unsafe {
&*self.mem.ptr()
.offset(*index as isize + self.pos as isize)
}
}
}
impl Clone for SeqByteStr {
fn clone(&self) -> SeqByteStr {
SeqByteStr {
mem: self.mem.clone(),
pos: self.pos,
len: self.len,
}
}
}
/*
*
* ===== SmallByteStr =====
*
*/
#[cfg(target_pointer_width = "64")]
const MAX_LEN: usize = 7;
#[cfg(target_pointer_width = "32")]
const MAX_LEN: usize = 3;
#[derive(Clone, Copy)]
pub struct SmallByteStr {
len: u8,
bytes: [u8; MAX_LEN],
}
impl SmallByteStr {
pub fn zero() -> SmallByteStr {
use std::mem;
SmallByteStr {
len: 0,
bytes: unsafe { mem::zeroed() }
}
}
pub fn from_slice(bytes: &[u8]) -> Option<SmallByteStr> {
use std::mem;
use std::slice::bytes;
if bytes.len() > MAX_LEN {
return None;
}
let mut ret = SmallByteStr {
len: bytes.len() as u8,
bytes: unsafe { mem::zeroed() },
};
// Copy the memory
bytes::copy_memory(&mut ret.bytes, bytes);
Some(ret)
}
}
impl ByteStr for SmallByteStr {
type Buf = SmallByteStrBuf;
fn buf(&self) -> SmallByteStrBuf {
SmallByteStrBuf { small: self.clone() }
}
fn concat<B: ByteStr>(&self, _other: B) -> Bytes {
unimplemented!();
}
fn len(&self) -> usize {
self.len as usize
}
fn slice(&self, _begin: usize, _end: usize) -> Bytes {
unimplemented!();
}
fn split_at(&self, _mid: usize) -> (Bytes, Bytes) {
unimplemented!();
}
fn to_bytes(self) -> Bytes {
Bytes::of(self)
}
}
impl ops::Index<usize> for SmallByteStr {
type Output = u8;
fn index(&self, index: &usize) -> &u8 {
assert!(*index < self.len());
&self.bytes[*index]
}
}
#[derive(Clone)]
#[allow(missing_copy_implementations)]
pub struct SmallByteStrBuf {
small: SmallByteStr,
}
impl SmallByteStrBuf {
fn len(&self) -> usize {
(self.small.len & 0x0F) as usize
}
fn pos(&self) -> usize {
(self.small.len >> 4) as usize
}
}
impl Buf for SmallByteStrBuf {
fn remaining(&self) -> usize {
self.len() - self.pos()
}
fn bytes(&self) -> &[u8] {
&self.small.bytes[self.pos()..self.len()]
}
fn advance(&mut self, mut cnt: usize) {
cnt = cmp::min(cnt, self.remaining());
self.small.len += (cnt as u8) << 4;
}
}
#[test]
pub fn test_size_of() {
use std::mem;
assert_eq!(mem::size_of::<SmallByteStr>(), mem::size_of::<usize>());
}
+2215 -248
View File
File diff suppressed because it is too large Load Diff
+40
View File
@@ -0,0 +1,40 @@
use std::fmt;
/// Alternative implementation of `fmt::Debug` for byte slice.
///
/// Standard `Debug` implementation for `[u8]` is comma separated
/// list of numbers. Since large amount of byte strings are in fact
/// ASCII strings or contain a lot of ASCII strings (e. g. HTTP),
/// it is convenient to print strings as ASCII when possible.
///
/// This struct wraps `&[u8]` just to override `fmt::Debug`.
///
/// `BsDebug` is not a part of public API of bytes crate.
pub struct BsDebug<'a>(pub &'a [u8]);
impl<'a> fmt::Debug for BsDebug<'a> {
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
try!(write!(fmt, "b\""));
for &c in self.0 {
// https://doc.rust-lang.org/reference.html#byte-escapes
if c == b'\n' {
try!(write!(fmt, "\\n"));
} else if c == b'\r' {
try!(write!(fmt, "\\r"));
} else if c == b'\t' {
try!(write!(fmt, "\\t"));
} else if c == b'\\' || c == b'"' {
try!(write!(fmt, "\\{}", c as char));
} else if c == b'\0' {
try!(write!(fmt, "\\0"));
// ASCII printable except space
} else if c > 0x20 && c < 0x7f {
try!(write!(fmt, "{}", c as char));
} else {
try!(write!(fmt, "\\x{:02x}", c));
}
}
try!(write!(fmt, "\""));
Ok(())
}
}
+89 -374
View File
@@ -1,380 +1,95 @@
#![crate_name = "bytes"]
#![unstable]
//! 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 continguous
//! 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, BigEndian};
//!
//! let mut buf = BytesMut::with_capacity(1024);
//! buf.put(&b"hello world"[..]);
//! buf.put_u16::<BigEndian>(1234);
//!
//! let a = buf.drain();
//! assert_eq!(a, b"hello world\x04\xD2"[..]);
//!
//! buf.put(&b"goodbye world"[..]);
//!
//! let b = buf.drain();
//! 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::Ready` 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.
#![feature(core)]
#![feature(alloc)]
#![deny(warnings, missing_docs, missing_debug_implementations)]
#![doc(html_root_url = "https://docs.rs/bytes/0.4")]
pub use byte_buf::{ByteBuf, ROByteBuf, MutByteBuf};
pub use byte_str::{SeqByteStr, SmallByteStr, SmallByteStrBuf};
pub use bytes::Bytes;
pub use ring::{RingBuf, RingBufReader, RingBufWriter};
pub use rope::Rope;
pub use slice::{SliceBuf, MutSliceBuf};
extern crate byteorder;
extern crate iovec;
use std::{cmp, io, ops, ptr, u32};
pub mod buf;
pub use buf::{
Buf,
BufMut,
IntoBuf,
};
#[deprecated(since = "0.4.1", note = "moved to `buf` module")]
#[doc(hidden)]
pub use buf::{
Reader,
Writer,
Take,
};
extern crate core;
mod alloc;
mod byte_buf;
mod byte_str;
mod bytes;
mod ring;
mod rope;
mod slice;
mod debug;
pub use bytes::{Bytes, BytesMut};
pub mod traits {
pub use {Buf, BufExt, MutBuf, MutBufExt, ByteStr};
}
const MAX_CAPACITY: usize = u32::MAX as usize;
/// A trait for values that provide random and sequential access to bytes.
pub trait Buf {
/// Returns the number of bytes that can be accessed from the Buf
fn remaining(&self) -> usize;
/// Returns a slice starting at the current Buf position and of length
/// between 0 and `Buf::remaining()`.
fn bytes<'a>(&'a self) -> &'a [u8];
/// Advance the internal cursor of the Buf
fn advance(&mut self, cnt: usize);
/// Returns true if there are any more bytes to consume
fn has_remaining(&self) -> bool {
self.remaining() > 0
}
/// Read bytes from this Buf into the given slice and advance the cursor by
/// the number of bytes read.
///
/// If there are fewer bytes remaining than is needed to satisfy the
/// request (aka `dst.len()` > self.remaining()`), then
/// `Err(BufError::Overflow)` is returned.
///
/// ```
/// use bytes::{SliceBuf, Buf};
///
/// let mut buf = SliceBuf::wrap(b"hello world");
/// let mut dst = [0; 5];
///
/// buf.read_slice(&mut dst);
/// assert_eq!(b"hello", dst);
/// assert_eq!(6, buf.remaining());
/// ```
fn read_slice(&mut self, dst: &mut [u8]) -> usize {
let mut off = 0;
let len = cmp::min(dst.len(), self.remaining());
while off < len {
let mut cnt;
unsafe {
let src = self.bytes();
cnt = cmp::min(src.len(), len - off);
ptr::copy_nonoverlapping_memory(
dst[off..].as_mut_ptr(), src.as_ptr(), cnt);
off += src.len();
}
self.advance(cnt);
}
len
}
}
pub trait BufExt {
/// Read bytes from this Buf into the given sink and advance the cursor by
/// the number of bytes read.
fn read<S: Sink>(&mut self, dst: S) -> Result<usize, S::Error>;
}
// TODO: Remove Sized
pub trait MutBuf : Sized {
/// Returns the number of bytes that can be accessed from the Buf
fn remaining(&self) -> usize;
/// Advance the internal cursor of the Buf
fn advance(&mut self, cnt: usize);
/// Returns true if there are any more bytes to consume
fn has_remaining(&self) -> bool {
self.remaining() > 0
}
/// Returns a mutable slice starting at the current Buf position and of
/// length between 0 and `Buf::remaining()`.
fn mut_bytes<'a>(&'a mut self) -> &'a mut [u8];
/// Read bytes from this Buf into the given slice and advance the cursor by
/// the number of bytes read.
///
/// If there are fewer bytes remaining than is needed to satisfy the
/// request (aka `dst.len()` > self.remaining()`), then
/// `Err(BufError::Overflow)` is returned.
///
/// ```
/// use bytes::{MutSliceBuf, Buf, MutBuf};
///
/// let mut dst = [0; 6];
///
/// {
/// let mut buf = MutSliceBuf::wrap(&mut dst);
/// buf.write_slice(b"hello");
///
/// assert_eq!(1, buf.remaining());
/// }
///
/// assert_eq!(b"hello\0", dst);
/// ```
fn write_slice(&mut self, src: &[u8]) -> usize {
let mut off = 0;
let len = cmp::min(src.len(), self.remaining());
while off < len {
let mut cnt;
unsafe {
let dst = self.mut_bytes();
cnt = cmp::min(dst.len(), len - off);
ptr::copy_nonoverlapping_memory(
dst.as_mut_ptr(), src[off..].as_ptr(), cnt);
off += cnt;
}
self.advance(cnt);
}
len
}
}
pub trait MutBufExt {
/// Write bytes from the given source into the current `MutBuf` and advance
/// the cursor by the number of bytes written.
fn write<S: Source>(&mut self, src: S) -> Result<usize, S::Error>;
}
/*
*
* ===== ByteStr =====
*
*/
pub trait ByteStr : Clone + Sized + Send + Sync + ops::Index<usize, Output=u8> {
// Until HKT lands, the buf must be bound by 'static
type Buf: Buf+'static;
/// Returns a read-only `Buf` for accessing the byte contents of the
/// `ByteStr`.
fn buf(&self) -> Self::Buf;
/// Returns a new `Bytes` value representing the concatenation of `self`
/// with the given `Bytes`.
fn concat<B: ByteStr+'static>(&self, other: B) -> Bytes;
/// Returns the number of bytes in the ByteStr
fn len(&self) -> usize;
/// Returns true if the length of the `ByteStr` is 0
fn is_empty(&self) -> bool {
self.len() == 0
}
/// Returns a new ByteStr value containing the byte range between `begin`
/// (inclusive) and `end` (exclusive)
fn slice(&self, begin: usize, end: usize) -> Bytes;
/// Returns a new ByteStr value containing the byte range starting from
/// `begin` (inclusive) to the end of the byte str.
///
/// Equivalent to `bytes.slice(begin, bytes.len())`
fn slice_from(&self, begin: usize) -> Bytes {
self.slice(begin, self.len())
}
/// Returns a new ByteStr value containing the byte range from the start up
/// to `end` (exclusive).
///
/// Equivalent to `bytes.slice(0, end)`
fn slice_to(&self, end: usize) -> Bytes {
self.slice(0, end)
}
/// Divides the value into two `Bytes` at the given index.
///
/// The first will contain all bytes from `[0, mid]` (excluding the index
/// `mid` itself) and the second will contain all indices from `[mid, len)`
/// (excluding the index `len` itself).
///
/// Panics if `mid > len`.
fn split_at(&self, mid: usize) -> (Bytes, Bytes) {
(self.slice_to(mid), self.slice_from(mid))
}
/// Consumes the value and returns a `Bytes` instance containing
/// identical bytes
fn to_bytes(self) -> Bytes;
}
/*
*
* ===== *Ext impls =====
*
*/
impl<B: Buf> BufExt for B {
fn read<S: Sink>(&mut self, dst: S) -> Result<usize, S::Error> {
dst.sink(self)
}
}
impl<B: MutBuf> MutBufExt for B {
fn write<S: Source>(&mut self, src: S) -> Result<usize, S::Error> {
src.fill(self)
}
}
/*
*
* ===== Sink / Source =====
*
*/
/// An value that reads bytes from a Buf into itself
pub trait Sink {
type Error;
fn sink<B: Buf>(self, buf: &mut B) -> Result<usize, Self::Error>;
}
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;
let rem = buf.remaining();
let cap = self.capacity();
let len = rem - cap;
// Ensure that the vec is big enough
if cap < rem {
self.reserve(len);
}
unsafe {
{
let dst = self.as_mut_slice();
buf.read_slice(slice::from_raw_parts_mut(dst.as_mut_ptr(), rem));
}
self.set_len(rem);
}
Ok(len)
}
}
impl<'a> Source for &'a [u8] {
type Error = BufError;
fn fill<B: MutBuf>(self, buf: &mut B) -> Result<usize, BufError> {
Ok(buf.write_slice(self))
}
}
impl<'a> Source for &'a Vec<u8> {
type Error = BufError;
fn fill<B: MutBuf>(self, buf: &mut B) -> Result<usize, BufError> {
Ok(buf.write_slice(self.as_slice()))
}
}
impl<'a> Source for &'a Bytes {
type Error = BufError;
fn fill<B: MutBuf>(self, _buf: &mut B) -> Result<usize, BufError> {
unimplemented!();
}
}
impl<'a> Source for &'a mut (io::Read+'a) {
type Error = io::Error;
fn fill<B: MutBuf>(self, _buf: &mut B) -> Result<usize, io::Error> {
unimplemented!();
}
}
impl<'a> Source for &'a mut (Iterator<Item=u8>+'a) {
type Error = BufError;
fn fill<B: MutBuf>(self, _buf: &mut B) -> Result<usize, BufError> {
unimplemented!();
}
}
/*
*
* ===== Buf impls =====
*
*/
impl Buf for Box<Buf+'static> {
fn remaining(&self) -> usize {
(**self).remaining()
}
fn bytes(&self) -> &[u8] {
(**self).bytes()
}
fn advance(&mut self, cnt: usize) {
(**self).advance(cnt);
}
fn read_slice(&mut self, dst: &mut [u8]) -> usize {
(**self).read_slice(dst)
}
}
/*
*
* ===== BufError / BufResult =====
*
*/
#[derive(Copy, Debug)]
pub enum BufError {
Underflow,
Overflow,
}
pub type BufResult<T> = Result<T, BufError>;
pub use byteorder::{ByteOrder, BigEndian, LittleEndian};
-200
View File
@@ -1,200 +0,0 @@
use super::{Buf, MutBuf};
use std::{cmp, fmt, mem, ptr, slice};
use std::num::UnsignedInt;
use std::rt::heap;
/// Buf backed by a continous chunk of memory. Maintains a read cursor and a
/// write cursor. When reads and writes reach the end of the allocated buffer,
/// wraps around to the start.
pub struct RingBuf {
ptr: *mut u8, // Pointer to the memory
cap: usize, // Capacity of the buffer
pos: usize, // Offset of read cursor
len: usize // Number of bytes to read
}
// TODO: There are most likely many optimizations that can be made
impl RingBuf {
pub fn new(mut capacity: usize) -> RingBuf {
// Handle the 0 length buffer case
if capacity == 0 {
return RingBuf {
ptr: ptr::null_mut(),
cap: 0,
pos: 0,
len: 0
}
}
// Round to the next power of 2 for better alignment
capacity = UnsignedInt::next_power_of_two(capacity);
// Allocate the memory
let ptr = unsafe { heap::allocate(capacity, mem::min_align_of::<u8>()) };
RingBuf {
ptr: ptr as *mut u8,
cap: capacity,
pos: 0,
len: 0
}
}
pub fn is_full(&self) -> bool {
self.cap == self.len
}
pub fn is_empty(&self) -> bool {
self.len == 0
}
pub fn capacity(&self) -> usize {
self.cap
}
// Access readable bytes as a Buf
pub fn reader<'a>(&'a mut self) -> RingBufReader<'a> {
RingBufReader { ring: self }
}
// Access writable bytes as a Buf
pub fn writer<'a>(&'a mut self) -> RingBufWriter<'a> {
RingBufWriter { ring: self }
}
fn read_remaining(&self) -> usize {
self.len
}
fn write_remaining(&self) -> usize {
self.cap - self.len
}
fn advance_reader(&mut self, mut cnt: usize) {
cnt = cmp::min(cnt, self.read_remaining());
self.pos += cnt;
self.pos %= self.cap;
self.len -= cnt;
}
fn advance_writer(&mut self, mut cnt: usize) {
cnt = cmp::min(cnt, self.write_remaining());
self.len += cnt;
}
fn as_slice(&self) -> &[u8] {
unsafe {
slice::from_raw_parts(self.ptr as *const u8, self.cap)
}
}
fn as_mut_slice(&mut self) -> &mut [u8] {
unsafe {
slice::from_raw_parts_mut(self.ptr, self.cap)
}
}
}
impl Clone for RingBuf {
fn clone(&self) -> RingBuf {
use std::cmp;
let mut ret = RingBuf::new(self.cap);
ret.pos = self.pos;
ret.len = self.len;
unsafe {
let to = self.pos + self.len;
if to > self.cap {
ptr::copy_memory(ret.ptr, self.ptr as *const u8, to % self.cap);
}
ptr::copy_memory(
ret.ptr.offset(self.pos as isize),
self.ptr.offset(self.pos as isize) as *const u8,
cmp::min(self.len, self.cap - self.pos));
}
ret
}
// TODO: an improved version of clone_from is possible that potentially
// re-uses the buffer
}
impl fmt::Debug for RingBuf {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
write!(fmt, "RingBuf[.. {}]", self.len)
}
}
impl Drop for RingBuf {
fn drop(&mut self) {
if self.cap > 0 {
unsafe {
heap::deallocate(self.ptr, self.cap, mem::min_align_of::<u8>())
}
}
}
}
pub struct RingBufReader<'a> {
ring: &'a mut RingBuf
}
impl<'a> Buf for RingBufReader<'a> {
fn remaining(&self) -> usize {
self.ring.read_remaining()
}
fn bytes<'b>(&'b self) -> &'b [u8] {
let mut to = self.ring.pos + self.ring.len;
if to > self.ring.cap {
to = self.ring.cap
}
&self.ring.as_slice()[self.ring.pos .. to]
}
fn advance(&mut self, cnt: usize) {
self.ring.advance_reader(cnt)
}
}
pub struct RingBufWriter<'a> {
ring: &'a mut RingBuf
}
impl<'a> MutBuf for RingBufWriter<'a> {
fn remaining(&self) -> usize {
self.ring.write_remaining()
}
fn advance(&mut self, cnt: usize) {
self.ring.advance_writer(cnt)
}
fn mut_bytes<'b>(&'b mut self) -> &'b mut [u8] {
let mut from;
let mut to;
from = self.ring.pos + self.ring.len;
from %= self.ring.cap;
to = from + self.remaining();
if to >= self.ring.cap {
to = self.ring.cap;
}
&mut self.ring.as_mut_slice()[from..to]
}
}
unsafe impl Send for RingBuf { }
-583
View File
@@ -1,583 +0,0 @@
use {Bytes, ByteBuf, Source, BufError};
use traits::*;
use std::{cmp, mem, ops};
use std::sync::Arc;
// The implementation is mostly a port of the implementation found in the Java
// protobuf lib.
const CONCAT_BY_COPY_LEN: usize = 128;
const MAX_DEPTH: usize = 47;
// Used to decide when to rebalance the tree.
static MIN_LENGTH_BY_DEPTH: [usize; MAX_DEPTH] = [
1, 2, 3, 5, 8,
13, 21, 34, 55, 89,
144, 233, 377, 610, 987,
1_597, 2_584, 4_181, 6_765, 10_946,
17_711, 28_657, 46_368, 75_025, 121_393,
196_418, 317_811, 514_229, 832_040, 1_346_269,
2_178_309, 3_524_578, 5_702_887, 9_227_465, 14_930_352,
24_157_817, 39_088_169, 63_245_986, 102_334_155, 165_580_141,
267_914_296, 433_494_437, 701_408_733, 1_134_903_170, 1_836_311_903,
2_971_215_073, 4_294_967_295];
/// An immutable sequence of bytes formed by concatenation of other `ByteStr`
/// values, without copying the data in the pieces. The concatenation is
/// represented as a tree whose leaf nodes are each a `Bytes` value.
///
/// Most of the operation here is inspired by the now-famous paper [Ropes: an
/// Alternative to Strings. hans-j. boehm, russ atkinson and michael
/// plass](http://www.cs.rit.edu/usr/local/pub/jeh/courses/QUARTERS/FP/Labs/CedarRope/rope-paper.pdf).
///
/// Fundamentally the Rope algorithm represents the collection of pieces as a
/// binary tree. BAP95 uses a Fibonacci bound relating depth to a minimum
/// sequence length, sequences that are too short relative to their depth cause
/// a tree rebalance. More precisely, a tree of depth d is "balanced" in the
/// terminology of BAP95 if its length is at least F(d+2), where F(n) is the
/// n-the Fibonacci number. Thus for depths 0, 1, 2, 3, 4, 5,... we have
/// minimum lengths 1, 2, 3, 5, 8, 13,...
pub struct Rope {
inner: Arc<RopeInner>,
}
impl Rope {
pub fn from_slice(bytes: &[u8]) -> Rope {
Rope::new(Bytes::from_slice(bytes), Bytes::empty())
}
/// Returns a Rope consisting of the supplied Bytes as a single segment.
pub fn of<B: ByteStr + 'static>(bytes: B) -> Rope {
let bytes = Bytes::of(bytes);
match bytes.try_unwrap() {
Ok(rope) => rope,
Err(bytes) => Rope::new(bytes, Bytes::empty()),
}
}
fn new(left: Bytes, right: Bytes) -> Rope {
Rope { inner: Arc::new(RopeInner::new(left, right)) }
}
pub fn len(&self) -> usize {
self.inner.len as usize
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
/*
*
* ===== Priv fns =====
*
*/
fn depth(&self) -> u16 {
self.inner.depth
}
fn left(&self) -> &Bytes {
&self.inner.left
}
fn right(&self) -> &Bytes {
&self.inner.right
}
fn pieces<'a>(&'a self) -> PieceIter<'a> {
PieceIter::new(&self.inner)
}
}
impl ByteStr for Rope {
type Buf = RopeBuf;
fn buf(&self) -> RopeBuf {
RopeBuf::new(self.clone())
}
fn concat<B: ByteStr+'static>(&self, other: B) -> Bytes {
let left = Bytes::of(self.clone());
let right = Bytes::of(other);
Bytes::of(concat(left, right))
}
fn len(&self) -> usize {
Rope::len(self)
}
fn slice(&self, begin: usize, end: usize) -> Bytes {
if begin >= end || begin >= self.len() {
return Bytes::empty()
}
let end = cmp::min(end, self.len());
let len = end - begin;
// Empty slice
if len == 0 {
return Bytes::empty();
}
// Full rope
if len == self.len() {
return Bytes::of(self.clone());
}
// == Proper substring ==
let left_len = self.inner.left.len();
if end <= left_len {
// Slice on the left
return self.inner.left.slice(begin, end);
}
if begin >= left_len {
// Slice on the right
return self.inner.right.slice(begin - left_len, end - left_len);
}
// Split slice
let left_slice = self.inner.left.slice_from(begin);
let right_slice = self.inner.right.slice_to(end - left_len);
Bytes::of(Rope::new(left_slice, right_slice))
}
fn to_bytes(self) -> Bytes {
Bytes::of(self)
}
}
impl ops::Index<usize> for Rope {
type Output = u8;
fn index(&self, index: &usize) -> &u8 {
assert!(*index < self.len());
let left_len = self.inner.left.len();
if *index < left_len {
self.inner.left.index(index)
} else {
self.inner.right.index(&(*index - left_len))
}
}
}
impl Clone for Rope {
fn clone(&self) -> Rope {
Rope { inner: self.inner.clone() }
}
}
impl<'a> Source for &'a Rope {
type Error = BufError;
fn fill<B: MutBuf>(self, _buf: &mut B) -> Result<usize, BufError> {
unimplemented!();
}
}
/*
*
* ===== Helper Fns =====
*
*/
fn depth(bytes: &Bytes) -> u16 {
match bytes.downcast_ref::<Rope>() {
Some(rope) => rope.inner.depth,
None => 0,
}
}
fn is_balanced(bytes: &Bytes) -> bool {
if let Some(rope) = bytes.downcast_ref::<Rope>() {
return rope.len() >= MIN_LENGTH_BY_DEPTH[rope.depth() as usize];
}
true
}
fn concat(left: Bytes, right: Bytes) -> Rope {
if right.is_empty() {
return Rope::of(left);
}
if left.is_empty() {
return Rope::of(right);
}
let len = left.len() + right.len();
if len < CONCAT_BY_COPY_LEN {
return concat_bytes(&left, &right, len);
}
if let Some(left) = left.downcast_ref::<Rope>() {
let len = left.inner.right.len() + right.len();
if len < CONCAT_BY_COPY_LEN {
// Optimization from BAP95: As an optimization of the case
// where the ByteString is constructed by repeated concatenate,
// recognize the case where a short string is concatenated to a
// left-hand node whose right-hand branch is short. In the
// paper this applies to leaves, but we just look at the length
// here. This has the advantage of shedding references to
// unneeded data when substrings have been taken.
//
// When we recognize this case, we do a copy of the data and
// create a new parent node so that the depth of the result is
// the same as the given left tree.
let new_right = concat_bytes(&left.inner.right, &right, len);
return Rope::new(left.inner.left.clone(), Bytes::of(new_right));
}
if depth(left.left()) > depth(left.right()) && left.depth() > depth(&right) {
// Typically for concatenate-built strings the left-side is
// deeper than the right. This is our final attempt to
// concatenate without increasing the tree depth. We'll redo
// the the node on the RHS. This is yet another optimization
// for building the string by repeatedly concatenating on the
// right.
let new_right = Rope::new(left.right().clone(), right);
return Rope::new(left.left().clone(), Bytes::of(new_right));
}
}
// Fine, we'll add a node and increase the tree depth -- unless we
// rebalance ;^)
let depth = cmp::max(depth(&left), depth(&right)) + 1;
if len >= MIN_LENGTH_BY_DEPTH[depth as usize] {
// No need to rebalance
return Rope::new(left, right);
}
Balance::new().balance(left, right)
}
fn concat_bytes(left: &Bytes, right: &Bytes, len: usize) -> Rope {
let mut buf = ByteBuf::mut_with_capacity(len);
buf.write(left).ok().expect("unexpected error");
buf.write(right).ok().expect("unexpected error");
return Rope::of(buf.flip().to_bytes());
}
fn depth_for_len(len: usize) -> u16 {
match MIN_LENGTH_BY_DEPTH.binary_search(&len) {
Ok(idx) => idx as u16,
Err(idx) => {
// It wasn't an exact match, so convert to the index of the
// containing fragment, which is one less even than the insertion
// point.
idx as u16 - 1
}
}
}
/*
*
* ===== RopeBuf =====
*
*/
pub struct RopeBuf {
rem: usize,
// Only here for the ref count
#[allow(dead_code)]
rope: Rope,
// This must be done with unsafe code to avoid having a lifetime bound on
// RopeBuf but is safe due to Rope being held. As long as data doesn't
// escape (which it shouldn't) it is safe. Doing this properly would
// require HKT.
pieces: PieceIter<'static>,
leaf_buf: Option<Box<Buf+'static>>,
}
impl RopeBuf {
fn new(rope: Rope) -> RopeBuf {
// In order to get the lifetimes to work out, transmute to a 'static
// lifetime. Never allow the iter to escape the internals of RopeBuf.
let mut pieces: PieceIter<'static> =
unsafe { mem::transmute(rope.pieces()) };
// Get the next buf
let leaf_buf = pieces.next()
.map(|bytes| bytes.buf());
let len = rope.len();
RopeBuf {
rope: rope,
rem: len,
pieces: pieces,
leaf_buf: leaf_buf,
}
}
}
impl Buf for RopeBuf {
fn remaining(&self) -> usize {
self.rem
}
fn bytes(&self) -> &[u8] {
self.leaf_buf.as_ref()
.map(|b| b.bytes())
.unwrap_or(&[])
}
fn advance(&mut self, mut cnt: usize) {
cnt = cmp::min(cnt, self.rem);
// Advance the internal cursor
self.rem -= cnt;
// Advance the leaf buffer
while cnt > 0 {
{
let curr = self.leaf_buf.as_mut()
.expect("expected a value");
if curr.remaining() > cnt {
curr.advance(cnt);
break;
}
cnt -= curr.remaining();
}
self.leaf_buf = self.pieces.next()
.map(|bytes| bytes.buf());
}
}
}
/*
*
* ===== PieceIter =====
*
*/
// TODO: store stack inline if possible
struct PieceIter<'a> {
stack: Vec<&'a RopeInner>,
next: Option<&'a Bytes>,
}
impl<'a> PieceIter<'a> {
fn new(root: &'a RopeInner) -> PieceIter<'a> {
let mut iter = PieceIter {
stack: vec![],
next: None,
};
iter.next = iter.get_leaf_by_left(root);
iter
}
fn get_leaf_by_left(&mut self, mut root: &'a RopeInner) -> Option<&'a Bytes> {
loop {
self.stack.push(root);
let left = &root.left;
if left.is_empty() {
return None;
}
if let Some(rope) = left.downcast_ref::<Rope>() {
root = &*rope.inner;
continue;
}
return Some(left);
}
}
fn next_non_empty_leaf(&mut self) -> Option<&'a Bytes>{
loop {
if let Some(node) = self.stack.pop() {
if let Some(rope) = node.right.downcast_ref::<Rope>() {
let res = self.get_leaf_by_left(&rope.inner);
if res.is_none() {
continue;
}
return res;
}
if node.right.is_empty() {
continue;
}
return Some(&node.right);
}
return None;
}
}
}
impl<'a> Iterator for PieceIter<'a> {
type Item = &'a Bytes;
fn next(&mut self) -> Option<&'a Bytes> {
let ret = self.next.take();
if ret.is_some() {
self.next = self.next_non_empty_leaf();
}
ret
}
}
/*
*
* ===== Balance =====
*
*/
struct Balance {
stack: Vec<Bytes>,
}
impl Balance {
fn new() -> Balance {
Balance { stack: vec![] }
}
fn balance(&mut self, left: Bytes, right: Bytes) -> Rope {
self.do_balance(left);
self.do_balance(right);
let mut partial = self.stack.pop()
.expect("expected a value");
while !partial.is_empty() {
let new_left = self.stack.pop()
.expect("expected a value");
partial = Bytes::of(Rope::new(new_left, partial));
}
Rope::of(partial)
}
fn do_balance(&mut self, root: Bytes) {
// BAP95: Insert balanced subtrees whole. This means the result might not
// be balanced, leading to repeated rebalancings on concatenate. However,
// these rebalancings are shallow due to ignoring balanced subtrees, and
// relatively few calls to insert() result.
if is_balanced(&root) {
self.insert(root);
} else {
let rope = root.try_unwrap::<Rope>()
.ok().expect("expected a value");
self.do_balance(rope.left().clone());
self.do_balance(rope.right().clone());
}
}
// Push a string on the balance stack (BAP95). BAP95 uses an array and
// calls the elements in the array 'bins'. We instead use a stack, so the
// 'bins' of lengths are represented by differences between the elements of
// minLengthByDepth.
//
// If the length bin for our string, and all shorter length bins, are
// empty, we just push it on the stack. Otherwise, we need to start
// concatenating, putting the given string in the "middle" and continuing
// until we land in an empty length bin that matches the length of our
// concatenation.
fn insert(&mut self, bytes: Bytes) {
let depth_bin = depth_for_len(bytes.len());
let bin_end = MIN_LENGTH_BY_DEPTH[depth_bin as usize + 1];
// BAP95: Concatenate all trees occupying bins representing the length
// of our new piece or of shorter pieces, to the extent that is
// possible. The goal is to clear the bin which our piece belongs in,
// but that may not be entirely possible if there aren't enough longer
// bins occupied.
if let Some(len) = self.peek().map(|r| r.len()) {
if len >= bin_end {
self.stack.push(bytes);
return;
}
}
let bin_start = MIN_LENGTH_BY_DEPTH[depth_bin as usize];
// Concatenate the subtrees of shorter length
let mut new_tree = self.stack.pop()
.expect("expected a value");
while let Some(len) = self.peek().map(|r| r.len()) {
// If the head is big enough, break the loop
if len >= bin_start { break; }
let left = self.stack.pop()
.expect("expected a value");
new_tree = Bytes::of(Rope::new(left, new_tree));
}
// Concatenate the given string
new_tree = Bytes::of(Rope::new(new_tree, bytes));
// Continue concatenating until we land in an empty bin
while let Some(len) = self.peek().map(|r| r.len()) {
let depth_bin = depth_for_len(new_tree.len());
let bin_end = MIN_LENGTH_BY_DEPTH[depth_bin as usize + 1];
if len < bin_end {
let left = self.stack.pop()
.expect("expected a value");
new_tree = Bytes::of(Rope::new(left, new_tree));
} else {
break;
}
}
self.stack.push(new_tree);
}
fn peek(&self) -> Option<&Bytes> {
self.stack.as_slice().last()
}
}
struct RopeInner {
left: Bytes,
right: Bytes,
depth: u16,
len: u32,
}
impl RopeInner {
fn new(left: Bytes, right: Bytes) -> RopeInner {
// If left is 0 then right must be zero
debug_assert!(!left.is_empty() || right.is_empty());
let len = left.len() + right.len();
let depth = cmp::max(depth(&left), depth(&right)) + 1;
RopeInner {
left: left,
right: right,
depth: depth,
len: len as u32,
}
}
}
-57
View File
@@ -1,57 +0,0 @@
use std::cmp;
use {Buf, MutBuf};
pub struct SliceBuf<'a> {
bytes: &'a [u8],
pos: usize
}
impl<'a> SliceBuf<'a> {
pub fn wrap(bytes: &'a [u8]) -> SliceBuf<'a> {
SliceBuf { bytes: bytes, pos: 0 }
}
}
impl<'a> Buf for SliceBuf<'a> {
fn remaining(&self) -> usize {
self.bytes.len() - self.pos
}
fn bytes<'b>(&'b self) -> &'b [u8] {
&self.bytes[self.pos..]
}
fn advance(&mut self, mut cnt: usize) {
cnt = cmp::min(cnt, self.remaining());
self.pos += cnt;
}
}
pub struct MutSliceBuf<'a> {
bytes: &'a mut [u8],
pos: usize
}
impl<'a> MutSliceBuf<'a> {
pub fn wrap(bytes: &'a mut [u8]) -> MutSliceBuf<'a> {
MutSliceBuf {
bytes: bytes,
pos: 0
}
}
}
impl<'a> MutBuf for MutSliceBuf<'a> {
fn remaining(&self) -> usize {
self.bytes.len() - self.pos
}
fn advance(&mut self, mut cnt: usize) {
cnt = cmp::min(cnt, self.remaining());
self.pos += cnt;
}
fn mut_bytes<'b>(&'b mut self) -> &'b mut [u8] {
&mut self.bytes[self.pos..]
}
}
-15
View File
@@ -1,15 +0,0 @@
#![feature(core)]
use rand::random;
extern crate bytes;
extern crate rand;
mod test_byte_buf;
mod test_rope;
mod test_seq_byte_str;
mod test_small_byte_str;
fn gen_bytes(n: usize) -> Vec<u8> {
(0..n).map(|_| random()).collect()
}
View File
-46
View File
@@ -1,46 +0,0 @@
use bytes::ByteBuf;
use bytes::traits::*;
#[test]
pub fn test_initial_buf_empty() {
let buf = ByteBuf::mut_with_capacity(100);
assert!(buf.capacity() == 128);
assert!(buf.remaining() == 128);
let buf = buf.flip();
assert!(buf.remaining() == 0);
let buf = buf.flip();
assert!(buf.remaining() == 128);
}
#[test]
pub fn test_byte_buf_read_write() {
let mut buf = ByteBuf::mut_with_capacity(32);
buf.write(b"hello world").unwrap();
assert_eq!(21, buf.remaining());
buf.write(b" goodbye").unwrap();
assert_eq!(13, buf.remaining());
let mut buf = buf.flip();
let mut dst = [0; 5];
assert_eq!(5, buf.read(dst.as_mut_slice()).unwrap());
assert_eq!(b"hello", dst);
assert_eq!(5, buf.read(dst.as_mut_slice()).unwrap());
assert_eq!(b" worl", dst);
let mut dst = [0; 2];
assert_eq!(2, buf.read(dst.as_mut_slice()).unwrap());
assert_eq!(b"d ", dst);
let mut dst = [0; 7];
assert_eq!(7, buf.read(dst.as_mut_slice()).unwrap());
assert_eq!(b"goodbye", dst);
}
-90
View File
@@ -1,90 +0,0 @@
use bytes::Rope;
use bytes::traits::*;
use super::gen_bytes;
const TEST_BYTES_1: &'static [u8] =
&b"dblm4ng7jp4v9rdn1w6hhssmluoqrrrqj59rccl9
nkv2tm1t2da4jyku51ge7f8hv581gkki8lekmf5f
1l44whp4aiwbvhkziw02292on4noyvuwjzsloqyc
5n0iyn4l6o6tgjhlek00mynfzb1wgcwj4mqp6zdr
3625yy7rj7xuisal7b1a7xgq271abvt5ssxuj39v
njtetokxxrgxzp7ik9adnypkmmcn4270yv9l46m7
9mu2zmqmkxdmgia210vkdytb7ywfcyt2bvcsg9eq
5yqizxl6888zrksvaxhzs2v355jxu8gr21m33t83
qvoian1ra7c6pvxabshgngldxa408p18l1fdet2h";
const TEST_BYTES_2: &'static [u8] =
&b"jmh14t79mllzj1ohxfj6fun7idwbks8oh35f83g6
ryaowe86mmou5t1xa91uyg8e95wcu5mje1mswien
tt4clgj029cw0pyuvfbvsgzdg1x7sr9qsjkf2b1t
h43smgp1ea22lph17f78cel0cc2kjoht5281xuy8
0ex9uaqwj4330jrp30stsk15j9bpqezu3w78ktit
ev5g6xsngr35q7pemdm9hihf0ebrw5fbwhm530lo
e0zyj1bm7yfyk7f2i45jhr3wu3bvb4hj8jve6db0
iewmr9weecaon9vdnqo5hen9iaiox5vsaxuo461m
8336ugp20u4sfky3kfawr0ome1tiqyx8chkerrjh
a95s0gypcsgo9jqxasqkoj08t4uq5moxmay5plg5
tlh6f9omhn0ezvi0w2n8hx7n6qk7rn1s3mjpnpl6
hvilp8awaa4tvsis66q4e5b3xwy2z1h2klpa87h7";
#[test]
pub fn test_rope_round_trip() {
let rope = Rope::from_slice(b"zomg");
assert_eq!(4, rope.len());
let mut dst = vec![];
rope.buf().read(&mut dst).unwrap();
assert_eq!(b"zomg", dst.as_slice());
}
#[test]
pub fn test_rope_slice() {
let mut dst = vec![];
let bytes = Rope::from_slice(TEST_BYTES_1);
assert_eq!(TEST_BYTES_1.len(), bytes.len());
bytes.buf().read(&mut dst).unwrap();
assert_eq!(dst.as_slice(), TEST_BYTES_1);
let left = bytes.slice_to(250);
assert_eq!(250, left.len());
left.buf().read(&mut dst).unwrap();
assert_eq!(dst.as_slice(), &TEST_BYTES_1[..250]);
let right = bytes.slice_from(250);
assert_eq!(TEST_BYTES_1.len() - 250, right.len());
right.buf().read(&mut dst).unwrap();
assert_eq!(dst.as_slice(), &TEST_BYTES_1[250..]);
}
#[test]
pub fn test_rope_concat_two_byte_str() {
let mut dst = vec![];
let left = Rope::from_slice(TEST_BYTES_1);
let right = Rope::from_slice(TEST_BYTES_2);
let both = left.concat(right);
assert_eq!(both.len(), TEST_BYTES_1.len() + TEST_BYTES_2.len());
both.buf().read(&mut dst).unwrap();
assert_eq!(dst.as_slice(), TEST_BYTES_1.to_vec() + TEST_BYTES_2);
}
#[test]
#[ignore]
pub fn test_slice_parity() {
let bytes = gen_bytes(2048 * 1024);
let start = 512 * 1024 - 3333;
let end = 512 * 1024 + 7777;
let _ = Rope::from_slice(bytes.as_slice()).slice(start, end);
// stuff
}
-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.as_slice());
assert_eq!(2000, s.len());
s.buf().read(&mut dst).unwrap();
assert_eq!(dst, src);
}
#[test]
pub fn test_index() {
let src = gen_bytes(2000);
let s = SeqByteStr::from_slice(src.as_slice());
for i in 0..2000 {
assert_eq!(src[i], s[i]);
}
}
#[test]
#[should_fail]
pub fn test_index_out_of_range() {
let s = SeqByteStr::from_slice(gen_bytes(2000).as_slice());
let _ = s[2001];
}
-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.as_slice()).unwrap();
assert_eq!(3, s.len());
s.buf().read(&mut dst).unwrap();
assert_eq!(dst, src);
}
#[test]
pub fn test_index() {
let src = gen_bytes(3);
let s = SmallByteStr::from_slice(src.as_slice()).unwrap();
for i in 0..3 {
assert_eq!(src[i], s[i]);
}
}
#[test]
#[should_fail]
pub fn test_index_out_of_range() {
let s = SmallByteStr::from_slice(gen_bytes(3).as_slice()).unwrap();
let _ = s[2001];
}
+53
View File
@@ -0,0 +1,53 @@
extern crate bytes;
extern crate byteorder;
extern crate iovec;
use bytes::Buf;
use iovec::IoVec;
use std::io::Cursor;
#[test]
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"");
}
#[test]
fn test_get_u8() {
let mut buf = Cursor::new(b"\x21zomg");
assert_eq!(0x21, buf.get_u8());
}
#[test]
fn test_get_u16() {
let buf = b"\x21\x54zomg";
assert_eq!(0x2154, Cursor::new(buf).get_u16::<byteorder::BigEndian>());
assert_eq!(0x5421, Cursor::new(buf).get_u16::<byteorder::LittleEndian>());
}
#[test]
#[should_panic]
fn test_get_u16_buffer_underflow() {
let mut buf = Cursor::new(b"\x21");
buf.get_u16::<byteorder::BigEndian>();
}
#[test]
fn test_bufs_vec() {
let buf = Cursor::new(b"hello world");
let mut dst: [&IoVec; 2] = Default::default();
assert_eq!(1, buf.bytes_vec(&mut dst[..]));
}
+72
View File
@@ -0,0 +1,72 @@
extern crate bytes;
extern crate byteorder;
extern crate iovec;
use bytes::{BufMut, BytesMut};
use iovec::IoVec;
use std::usize;
use std::fmt::Write;
#[test]
fn test_vec_as_mut_buf() {
let mut buf = Vec::with_capacity(64);
assert_eq!(buf.remaining_mut(), usize::MAX);
unsafe {
assert!(buf.bytes_mut().len() >= 64);
}
buf.put(&b"zomg"[..]);
assert_eq!(&buf, b"zomg");
assert_eq!(buf.remaining_mut(), usize::MAX - 4);
assert_eq!(buf.capacity(), 64);
for _ in 0..16 {
buf.put(&b"zomg"[..]);
}
assert_eq!(buf.len(), 68);
}
#[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::<byteorder::BigEndian>(8532);
assert_eq!(b"\x21\x54", &buf[..]);
buf.clear();
buf.put_u16::<byteorder::LittleEndian>(8532);
assert_eq!(b"\x54\x21", &buf[..]);
}
#[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 emergecy broadcast system").unwrap();
assert!(buf != buf2);
}
#[test]
fn test_bufs_vec_mut() {
use std::mem;
let mut buf = BytesMut::from(&b"hello world"[..]);
unsafe {
let mut dst: [&mut IoVec; 2] = mem::zeroed();
assert_eq!(1, buf.bytes_vec_mut(&mut dst[..]));
}
}
+411
View File
@@ -0,0 +1,411 @@
extern crate bytes;
use bytes::{Bytes, BytesMut, BufMut};
const LONG: &'static [u8] = b"mary had a little lamb, little lamb, little lamb";
const SHORT: &'static [u8] = b"hello world";
fn inline_cap() -> usize {
use std::mem;
4 * mem::size_of::<usize>() - 1
}
fn is_sync<T: Sync>() {}
fn is_send<T: Send>() {}
#[test]
fn test_bounds() {
is_sync::<Bytes>();
is_sync::<BytesMut>();
is_send::<Bytes>();
is_send::<BytesMut>();
}
#[test]
fn from_slice() {
let a = Bytes::from(&b"abcdefgh"[..]);
assert_eq!(a, b"abcdefgh"[..]);
assert_eq!(a, &b"abcdefgh"[..]);
assert_eq!(a, Vec::from(&b"abcdefgh"[..]));
assert_eq!(b"abcdefgh"[..], a);
assert_eq!(&b"abcdefgh"[..], a);
assert_eq!(Vec::from(&b"abcdefgh"[..]), a);
let a = BytesMut::from(&b"abcdefgh"[..]);
assert_eq!(a, b"abcdefgh"[..]);
assert_eq!(a, &b"abcdefgh"[..]);
assert_eq!(a, Vec::from(&b"abcdefgh"[..]));
assert_eq!(b"abcdefgh"[..], a);
assert_eq!(&b"abcdefgh"[..], a);
assert_eq!(Vec::from(&b"abcdefgh"[..]), a);
}
#[test]
fn fmt() {
let a = format!("{:?}", Bytes::from(&b"abcdefg"[..]));
let b = "b\"abcdefg\"";
assert_eq!(a, b);
let a = format!("{:?}", BytesMut::from(&b"abcdefg"[..]));
assert_eq!(a, b);
}
#[test]
fn len() {
let a = Bytes::from(&b"abcdefg"[..]);
assert_eq!(a.len(), 7);
let a = BytesMut::from(&b"abcdefg"[..]);
assert_eq!(a.len(), 7);
let a = Bytes::from(&b""[..]);
assert!(a.is_empty());
let a = BytesMut::from(&b""[..]);
assert!(a.is_empty());
}
#[test]
fn index() {
let a = Bytes::from(&b"hello world"[..]);
assert_eq!(a[0..5], *b"hello");
}
#[test]
fn slice() {
let a = Bytes::from(&b"hello world"[..]);
let b = a.slice(3, 5);
assert_eq!(b, b"lo"[..]);
let b = a.slice_to(5);
assert_eq!(b, b"hello"[..]);
let b = a.slice_from(3);
assert_eq!(b, b"lo world"[..]);
}
#[test]
#[should_panic]
fn slice_oob_1() {
let a = Bytes::from(&b"hello world"[..]);
a.slice(5, inline_cap() + 1);
}
#[test]
#[should_panic]
fn slice_oob_2() {
let a = Bytes::from(&b"hello world"[..]);
a.slice(inline_cap() + 1, inline_cap() + 5);
}
#[test]
fn split_off() {
let mut hello = Bytes::from(&b"helloworld"[..]);
let world = hello.split_off(5);
assert_eq!(hello, &b"hello"[..]);
assert_eq!(world, &b"world"[..]);
let mut hello = BytesMut::from(&b"helloworld"[..]);
let world = hello.split_off(5);
assert_eq!(hello, &b"hello"[..]);
assert_eq!(world, &b"world"[..]);
}
#[test]
#[should_panic]
fn split_off_oob() {
let mut hello = Bytes::from(&b"helloworld"[..]);
hello.split_off(inline_cap() + 1);
}
#[test]
fn split_off_uninitialized() {
let mut bytes = BytesMut::with_capacity(1024);
let other = bytes.split_off(128);
assert_eq!(bytes.len(), 0);
assert_eq!(bytes.capacity(), 128);
assert_eq!(other.len(), 0);
assert_eq!(other.capacity(), 896);
}
#[test]
fn split_off_to_loop() {
let s = b"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
for i in 0..(s.len() + 1) {
{
let mut bytes = Bytes::from(&s[..]);
let off = bytes.split_off(i);
assert_eq!(i, bytes.len());
let mut sum = Vec::new();
sum.extend(&bytes);
sum.extend(&off);
assert_eq!(&s[..], &sum[..]);
}
{
let mut bytes = BytesMut::from(&s[..]);
let off = bytes.split_off(i);
assert_eq!(i, bytes.len());
let mut sum = Vec::new();
sum.extend(&bytes);
sum.extend(&off);
assert_eq!(&s[..], &sum[..]);
}
{
let mut bytes = Bytes::from(&s[..]);
let off = bytes.split_to(i);
assert_eq!(i, off.len());
let mut sum = Vec::new();
sum.extend(&off);
sum.extend(&bytes);
assert_eq!(&s[..], &sum[..]);
}
{
let mut bytes = BytesMut::from(&s[..]);
let off = bytes.split_to(i);
assert_eq!(i, off.len());
let mut sum = Vec::new();
sum.extend(&off);
sum.extend(&bytes);
assert_eq!(&s[..], &sum[..]);
}
}
}
#[test]
fn split_to_1() {
// Inline
let mut a = Bytes::from(SHORT);
let b = a.split_to(4);
assert_eq!(SHORT[4..], a);
assert_eq!(SHORT[..4], b);
// Allocated
let mut a = Bytes::from(LONG);
let b = a.split_to(4);
assert_eq!(LONG[4..], a);
assert_eq!(LONG[..4], b);
let mut a = Bytes::from(LONG);
let b = a.split_to(30);
assert_eq!(LONG[30..], a);
assert_eq!(LONG[..30], b);
}
#[test]
fn split_to_2() {
let mut a = Bytes::from(LONG);
assert_eq!(LONG, a);
let b = a.split_to(1);
assert_eq!(LONG[1..], a);
drop(b);
}
#[test]
#[should_panic]
fn split_to_oob() {
let mut hello = Bytes::from(&b"helloworld"[..]);
hello.split_to(inline_cap() + 1);
}
#[test]
#[should_panic]
fn split_to_oob_mut() {
let mut hello = BytesMut::from(&b"helloworld"[..]);
hello.split_to(inline_cap() + 1);
}
#[test]
fn split_to_uninitialized() {
let mut bytes = BytesMut::with_capacity(1024);
let other = bytes.split_to(128);
assert_eq!(bytes.len(), 0);
assert_eq!(bytes.capacity(), 896);
assert_eq!(other.len(), 0);
assert_eq!(other.capacity(), 128);
}
#[test]
fn split_off_to_at_gt_len() {
fn make_bytes() -> Bytes {
let mut bytes = BytesMut::with_capacity(100);
bytes.put_slice(&[10, 20, 30, 40]);
bytes.freeze()
}
use std::panic;
make_bytes().split_to(4);
make_bytes().split_off(4);
assert!(panic::catch_unwind(move || {
make_bytes().split_to(5);
}).is_err());
assert!(panic::catch_unwind(move || {
make_bytes().split_off(5);
}).is_err());
}
#[test]
fn fns_defined_for_bytes_mut() {
let mut bytes = BytesMut::from(&b"hello world"[..]);
bytes.as_ptr();
bytes.as_mut_ptr();
// Iterator
let v: Vec<u8> = bytes.iter().map(|b| *b).collect();
assert_eq!(&v[..], bytes);
}
#[test]
fn reserve_convert() {
// Inline -> Vec
let mut bytes = BytesMut::with_capacity(8);
bytes.put("hello");
bytes.reserve(40);
assert_eq!(bytes.capacity(), 45);
assert_eq!(bytes, "hello");
// Inline -> Inline
let mut bytes = BytesMut::with_capacity(inline_cap());
bytes.put("abcdefghijkl");
let a = bytes.split_to(10);
bytes.reserve(inline_cap() - 3);
assert_eq!(inline_cap(), bytes.capacity());
assert_eq!(bytes, "kl");
assert_eq!(a, "abcdefghij");
// Vec -> Vec
let mut bytes = BytesMut::from(LONG);
bytes.reserve(64);
assert_eq!(bytes.capacity(), LONG.len() + 64);
// Arc -> Vec
let mut bytes = BytesMut::from(LONG);
let a = bytes.split_to(30);
bytes.reserve(128);
assert_eq!(bytes.capacity(), (bytes.len() + 128).next_power_of_two());
drop(a);
}
#[test]
fn reserve_growth() {
let mut bytes = BytesMut::with_capacity(64);
bytes.put("hello world");
let _ = bytes.take();
bytes.reserve(65);
assert_eq!(bytes.capacity(), 128);
}
#[test]
fn reserve_allocates_at_least_original_capacity() {
let mut bytes = BytesMut::with_capacity(128);
for i in 0..120 {
bytes.put(i as u8);
}
let _other = bytes.take();
bytes.reserve(16);
assert_eq!(bytes.capacity(), 128);
}
#[test]
fn reserve_max_original_capacity_value() {
const SIZE: usize = 128 * 1024;
let mut bytes = BytesMut::with_capacity(SIZE);
for _ in 0..SIZE {
bytes.put(0u8);
}
let _other = bytes.take();
bytes.reserve(16);
assert_eq!(bytes.capacity(), 64 * 1024);
}
#[test]
fn inline_storage() {
let mut bytes = BytesMut::with_capacity(inline_cap());
let zero = [0u8; 64];
bytes.put(&zero[0..inline_cap()]);
assert_eq!(*bytes, zero[0..inline_cap()]);
}
#[test]
fn extend() {
let mut bytes = BytesMut::with_capacity(0);
bytes.extend(LONG);
assert_eq!(*bytes, LONG[..]);
}
#[test]
fn from_static() {
let mut a = Bytes::from_static(b"ab");
let b = a.split_off(1);
assert_eq!(a, b"a"[..]);
assert_eq!(b, b"b"[..]);
}
#[test]
// Only run these tests on little endian systems. CI uses qemu for testing
// little endian... and qemu doesn't really support threading all that well.
#[cfg(target_endian = "little")]
fn stress() {
// Tests promoting a buffer from a vec -> shared in a concurrent situation
use std::sync::{Arc, Barrier};
use std::thread;
const THREADS: usize = 8;
const ITERS: usize = 1_000;
for i in 0..ITERS {
let data = [i as u8; 256];
let buf = Arc::new(Bytes::from(&data[..]));
let barrier = Arc::new(Barrier::new(THREADS));
let mut joins = Vec::with_capacity(THREADS);
for _ in 0..THREADS {
let c = barrier.clone();
let buf = buf.clone();
joins.push(thread::spawn(move || {
c.wait();
let buf: Bytes = (*buf).clone();
drop(buf);
}));
}
for th in joins {
th.join().unwrap();
}
assert_eq!(*buf, data[..]);
}
}
+102
View File
@@ -0,0 +1,102 @@
extern crate bytes;
extern crate iovec;
use bytes::{Buf, BufMut, Bytes, BytesMut};
use bytes::buf::Chain;
use iovec::IoVec;
use std::io::Cursor;
#[test]
fn collect_two_bufs() {
let a = Cursor::new(Bytes::from(&b"hello"[..]));
let b = Cursor::new(Bytes::from(&b"world"[..]));
let res: Vec<u8> = a.chain(b).collect();
assert_eq!(res, &b"helloworld"[..]);
}
#[test]
fn writing_chained() {
let mut a = BytesMut::with_capacity(64);
let mut b = BytesMut::with_capacity(64);
{
let mut buf = Chain::new(&mut a, &mut b);
for i in 0..128 {
buf.put(i as u8);
}
}
assert_eq!(64, a.len());
assert_eq!(64, b.len());
for i in 0..64 {
let expect = i as u8;
assert_eq!(expect, a[i]);
assert_eq!(expect + 64, b[i]);
}
}
#[test]
fn iterating_two_bufs() {
let a = Cursor::new(Bytes::from(&b"hello"[..]));
let b = Cursor::new(Bytes::from(&b"world"[..]));
let res: Vec<u8> = a.chain(b).iter().collect();
assert_eq!(res, &b"helloworld"[..]);
}
#[test]
fn vectored_read() {
let a = Cursor::new(Bytes::from(&b"hello"[..]));
let b = Cursor::new(Bytes::from(&b"world"[..]));
let mut buf = a.chain(b);
{
let mut iovecs: [&IoVec; 4] = Default::default();
assert_eq!(2, buf.bytes_vec(&mut iovecs));
assert_eq!(iovecs[0][..], b"hello"[..]);
assert_eq!(iovecs[1][..], b"world"[..]);
assert!(iovecs[2].is_empty());
assert!(iovecs[3].is_empty());
}
buf.advance(2);
{
let mut iovecs: [&IoVec; 4] = Default::default();
assert_eq!(2, buf.bytes_vec(&mut iovecs));
assert_eq!(iovecs[0][..], b"llo"[..]);
assert_eq!(iovecs[1][..], b"world"[..]);
assert!(iovecs[2].is_empty());
assert!(iovecs[3].is_empty());
}
buf.advance(3);
{
let mut iovecs: [&IoVec; 4] = Default::default();
assert_eq!(1, buf.bytes_vec(&mut iovecs));
assert_eq!(iovecs[0][..], b"world"[..]);
assert!(iovecs[1].is_empty());
assert!(iovecs[2].is_empty());
assert!(iovecs[3].is_empty());
}
buf.advance(3);
{
let mut iovecs: [&IoVec; 4] = Default::default();
assert_eq!(1, buf.bytes_vec(&mut iovecs));
assert_eq!(iovecs[0][..], b"ld"[..]);
assert!(iovecs[1].is_empty());
assert!(iovecs[2].is_empty());
assert!(iovecs[3].is_empty());
}
}
+35
View File
@@ -0,0 +1,35 @@
extern crate bytes;
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)));
}
+34
View File
@@ -0,0 +1,34 @@
extern crate bytes;
use bytes::{Buf, Bytes, BytesMut};
use std::io::Cursor;
const LONG: &'static [u8] = b"mary had a little lamb, little lamb, little lamb";
const SHORT: &'static [u8] = b"hello world";
#[test]
fn collect_to_vec() {
let buf: Vec<u8> = Cursor::new(SHORT).collect();
assert_eq!(buf, SHORT);
let buf: Vec<u8> = Cursor::new(LONG).collect();
assert_eq!(buf, LONG);
}
#[test]
fn collect_to_bytes() {
let buf: Bytes = Cursor::new(SHORT).collect();
assert_eq!(buf, SHORT);
let buf: Bytes = Cursor::new(LONG).collect();
assert_eq!(buf, LONG);
}
#[test]
fn collect_to_bytes_mut() {
let buf: BytesMut = Cursor::new(SHORT).collect();
assert_eq!(buf, SHORT);
let buf: BytesMut = Cursor::new(LONG).collect();
assert_eq!(buf, LONG);
}