mirror of
https://github.com/tokio-rs/bytes.git
synced 2026-08-08 00:00:26 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9eb5bd50b8 | ||
|
|
b46d3fd32e | ||
|
|
8c11456185 | ||
|
|
128c56ddc4 | ||
|
|
5c6eadfcb0 | ||
|
|
c6fe5a1e4f | ||
|
|
99aafb0a22 | ||
|
|
cf5a1bc4f1 | ||
|
|
0360f191f8 | ||
|
|
aa06b6dd6a | ||
|
|
5048eec143 | ||
|
|
268226051d | ||
|
|
646624c130 | ||
|
|
bababa8797 | ||
|
|
0e0066e8a0 | ||
|
|
53d1c788e0 | ||
|
|
4c6ebeba87 | ||
|
|
8da9e81469 | ||
|
|
36c9a8c287 | ||
|
|
44d40d34d7 | ||
|
|
70fed562eb | ||
|
|
accc8a460d | ||
|
|
8b01298806 | ||
|
|
a8320da0f8 | ||
|
|
93c08064bb | ||
|
|
2b796d40e9 | ||
|
|
12d0804f17 | ||
|
|
4886b44516 | ||
|
|
a367a723d8 | ||
|
|
11fe277c0d | ||
|
|
57e84f267b | ||
|
|
d717fde5ca | ||
|
|
b42d94c33b | ||
|
|
8d2508bfeb | ||
|
|
ec7d7f27fe | ||
|
|
d7306d949b | ||
|
|
a4bfc63de7 | ||
|
|
6f97d04077 | ||
|
|
e00c08c6c7 | ||
|
|
e1c7f183ca | ||
|
|
4ca7e0fabf | ||
|
|
b10992a5e8 | ||
|
|
b1dc10e907 | ||
|
|
c16ad2bc9d | ||
|
|
a7d38e29e5 | ||
|
|
98e0d954b5 | ||
|
|
d05bfb6346 | ||
|
|
3c58b0c75c | ||
|
|
4105901244 | ||
|
|
1f188b5628 | ||
|
|
f693e038d9 | ||
|
|
d0d27bd540 | ||
|
|
046c864543 | ||
|
|
38abb8074b | ||
|
|
be23af6bb7 | ||
|
|
fbebb19a02 | ||
|
|
04e0ac75e2 | ||
|
|
b2efe63c70 | ||
|
|
16b4266c3c | ||
|
|
b6a424d892 | ||
|
|
6529f6392a | ||
|
|
3f68c4bd27 | ||
|
|
eec203c118 | ||
|
|
41b722dee8 | ||
|
|
d650404bb8 | ||
|
|
1c2234f7fe | ||
|
|
dc25c7564e | ||
|
|
b10b1cd2e2 | ||
|
|
3ca009577b | ||
|
|
270d2e2844 |
+52
-12
@@ -1,17 +1,57 @@
|
||||
---
|
||||
dist: trusty
|
||||
language: rust
|
||||
sudo: false
|
||||
rust:
|
||||
- nightly
|
||||
- 1.1.0
|
||||
|
||||
script:
|
||||
- cargo test
|
||||
- cargo doc --no-deps
|
||||
|
||||
after_success:
|
||||
- test $TRAVIS_PULL_REQUEST == "false" && test $TRAVIS_BRANCH == "master" && bash deploy.sh
|
||||
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: TARGET=powerpc-unknown-linux-gnu
|
||||
- env: 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
|
||||
|
||||
+7
-13
@@ -1,7 +1,7 @@
|
||||
[package]
|
||||
|
||||
name = "bytes"
|
||||
version = "0.3.0"
|
||||
version = "0.4.0"
|
||||
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,16 +17,10 @@ exclude = [
|
||||
"bench/**/*",
|
||||
"test/**/*"
|
||||
]
|
||||
categories = ["network-programming", "data-structures"]
|
||||
|
||||
[dependencies]
|
||||
byteorder = "1.0.0"
|
||||
|
||||
[dev-dependencies]
|
||||
rand = "0.3.5"
|
||||
|
||||
[[bench]]
|
||||
|
||||
name = "bench"
|
||||
path = "bench/bench.rs"
|
||||
|
||||
[[test]]
|
||||
|
||||
name = "test"
|
||||
path = "test/test.rs"
|
||||
tokio-core = "0.1.0"
|
||||
|
||||
@@ -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
@@ -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
@@ -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.
|
||||
@@ -2,16 +2,32 @@
|
||||
|
||||
A utility library for working with bytes.
|
||||
|
||||
[](https://crates.io/crates/bytes)
|
||||
[](https://crates.io/crates/bytes)
|
||||
[](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.
|
||||
|
||||
@@ -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]);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -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);
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -1,52 +0,0 @@
|
||||
use alloc::{Allocator, Mem, MemRef};
|
||||
use std::{mem, ptr, usize};
|
||||
use std::ops::DerefMut;
|
||||
|
||||
const MAX_ALLOC_SIZE: usize = usize::MAX;
|
||||
|
||||
pub struct Heap;
|
||||
|
||||
impl Heap {
|
||||
pub fn allocate(&self, len: usize) -> MemRef {
|
||||
// Make sure that the allocation is within the permitted range
|
||||
if len > MAX_ALLOC_SIZE {
|
||||
return MemRef::none();
|
||||
}
|
||||
|
||||
let alloc_len = len +
|
||||
mem::size_of::<Mem>() +
|
||||
mem::size_of::<Vec<u8>>();
|
||||
|
||||
unsafe {
|
||||
let mut vec: Vec<u8> = Vec::with_capacity(alloc_len);
|
||||
vec.set_len(alloc_len);
|
||||
|
||||
let ptr = vec.deref_mut().as_mut_ptr();
|
||||
|
||||
ptr::write(ptr as *mut Vec<u8>, vec);
|
||||
|
||||
let ptr = ptr.offset(mem::size_of::<Vec<u8>>() as isize);
|
||||
ptr::write(ptr as *mut Mem, Mem::new(len, mem::transmute(self as &Allocator)));
|
||||
|
||||
// Return the info
|
||||
MemRef::new(ptr as *mut Mem)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn deallocate(&self, mem: *mut Mem) {
|
||||
unsafe {
|
||||
let ptr = mem as *mut u8;
|
||||
let _ = ptr::read(ptr.offset(-(mem::size_of::<Vec<u8>>() as isize)) as *const Vec<u8>);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Allocator for Heap {
|
||||
fn allocate(&self, len: usize) -> MemRef {
|
||||
Heap::allocate(self, len)
|
||||
}
|
||||
|
||||
fn deallocate(&self, mem: *mut Mem) {
|
||||
Heap::deallocate(self, mem)
|
||||
}
|
||||
}
|
||||
@@ -1,131 +0,0 @@
|
||||
mod heap;
|
||||
|
||||
pub use self::heap::{Heap};
|
||||
|
||||
use std::{mem, ptr};
|
||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||
|
||||
pub fn heap(len: usize) -> MemRef {
|
||||
Heap.allocate(len)
|
||||
}
|
||||
|
||||
/// Allocates memory to be used by Bufs or Bytes. Allows allocating memory
|
||||
/// using alternate stratgies than the default Rust heap allocator. Also does
|
||||
/// not require that allocations are continuous in memory.
|
||||
///
|
||||
/// For example, an alternate allocator could use a slab of 4kb chunks of
|
||||
/// memory and return as many chunks as needed to satisfy the length
|
||||
/// requirement.
|
||||
pub trait Allocator: Sync + Send {
|
||||
|
||||
/// Allocate memory. May or may not be contiguous.
|
||||
fn allocate(&self, len: usize) -> MemRef;
|
||||
|
||||
/// Deallocate a chunk of memory
|
||||
fn deallocate(&self, mem: *mut Mem);
|
||||
}
|
||||
|
||||
pub struct MemRef {
|
||||
ptr: *mut u8,
|
||||
}
|
||||
|
||||
impl MemRef {
|
||||
pub fn new(mem: *mut Mem) -> MemRef {
|
||||
let ptr = mem as *mut u8;
|
||||
|
||||
unsafe {
|
||||
MemRef {
|
||||
ptr: ptr.offset(mem::size_of::<Mem>() as isize),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn none() -> MemRef {
|
||||
MemRef { ptr: ptr::null_mut() }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_none(&self) -> bool {
|
||||
self.ptr.is_null()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn ptr(&self) -> *mut u8 {
|
||||
self.ptr
|
||||
}
|
||||
|
||||
pub fn bytes(&self) -> &[u8] {
|
||||
use std::slice;
|
||||
unsafe {
|
||||
slice::from_raw_parts(self.ptr(), self.mem().len)
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn bytes_mut(&mut self) -> &mut [u8] {
|
||||
use std::slice;
|
||||
unsafe {
|
||||
slice::from_raw_parts_mut(self.ptr(), self.mem().len)
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn mem_ptr(&self) -> *mut Mem {
|
||||
unsafe {
|
||||
self.ptr.offset(-(mem::size_of::<Mem>() as isize)) as *mut Mem
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn mem(&self) -> &Mem {
|
||||
unsafe {
|
||||
mem::transmute(self.mem_ptr())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for MemRef {
|
||||
#[inline]
|
||||
fn clone(&self) -> MemRef {
|
||||
self.mem().refs.fetch_add(1, Ordering::Relaxed);
|
||||
MemRef { ptr: self.ptr }
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for MemRef {
|
||||
fn drop(&mut self) {
|
||||
// Guard against the ref having already been dropped
|
||||
if self.ptr.is_null() { return; }
|
||||
|
||||
// Decrement the ref count
|
||||
if 1 == self.mem().refs.fetch_sub(1, Ordering::Relaxed) {
|
||||
// Last ref dropped, free the memory
|
||||
unsafe {
|
||||
let alloc: &Allocator = mem::transmute(self.mem().allocator);
|
||||
alloc.deallocate(self.mem_ptr());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl Send for MemRef { }
|
||||
unsafe impl Sync for MemRef { }
|
||||
|
||||
/// Memory allocated by an Allocator must be prefixed with Mem
|
||||
pub struct Mem {
|
||||
// TODO: It should be possible to reduce the size of this struct
|
||||
allocator: *const Allocator,
|
||||
refs: AtomicUsize,
|
||||
len: usize,
|
||||
}
|
||||
|
||||
impl Mem {
|
||||
pub fn new(len: usize, allocator: *const Allocator) -> Mem {
|
||||
Mem {
|
||||
allocator: allocator,
|
||||
refs: AtomicUsize::new(1),
|
||||
len: len,
|
||||
}
|
||||
}
|
||||
}
|
||||
+1733
File diff suppressed because it is too large
Load Diff
-347
@@ -1,347 +0,0 @@
|
||||
use {alloc, Bytes, SeqByteStr, MAX_CAPACITY};
|
||||
use traits::{Buf, MutBuf, MutBufExt, ByteStr};
|
||||
use std::{cmp, fmt, ptr};
|
||||
|
||||
/*
|
||||
*
|
||||
* ===== ByteBuf =====
|
||||
*
|
||||
*/
|
||||
|
||||
/// A `Buf` backed by a contiguous region of memory.
|
||||
///
|
||||
/// This `Buf` is better suited for cases where there is a clear delineation
|
||||
/// between reading and writing.
|
||||
pub struct ByteBuf {
|
||||
mem: alloc::MemRef,
|
||||
cap: u32,
|
||||
pos: u32,
|
||||
lim: u32,
|
||||
mark: Option<u32>,
|
||||
}
|
||||
|
||||
impl ByteBuf {
|
||||
/// Create a new `ByteBuf` by copying the contents of the given slice.
|
||||
pub fn from_slice(bytes: &[u8]) -> ByteBuf {
|
||||
let mut buf = ByteBuf::mut_with_capacity(bytes.len());
|
||||
buf.write(bytes).ok().expect("unexpected failure");
|
||||
buf.flip()
|
||||
}
|
||||
|
||||
pub fn mut_with_capacity(capacity: usize) -> MutByteBuf {
|
||||
assert!(capacity <= MAX_CAPACITY);
|
||||
MutByteBuf { buf: ByteBuf::new(capacity as u32) }
|
||||
}
|
||||
|
||||
pub fn none() -> ByteBuf {
|
||||
ByteBuf {
|
||||
mem: alloc::MemRef::none(),
|
||||
cap: 0,
|
||||
pos: 0,
|
||||
lim: 0,
|
||||
mark: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn from_mem_ref(mem: alloc::MemRef, cap: u32, pos: u32, lim: u32) -> ByteBuf {
|
||||
debug_assert!(pos <= lim && lim <= cap, "invalid arguments; cap={}; pos={}; lim={}", cap, pos, lim);
|
||||
|
||||
ByteBuf {
|
||||
mem: mem,
|
||||
cap: cap,
|
||||
pos: pos,
|
||||
lim: lim,
|
||||
mark: None,
|
||||
}
|
||||
}
|
||||
|
||||
fn new(mut capacity: u32) -> ByteBuf {
|
||||
// Handle 0 capacity case
|
||||
if capacity == 0 {
|
||||
return ByteBuf::none();
|
||||
}
|
||||
|
||||
// Round the capacity to the closest power of 2
|
||||
capacity = capacity.next_power_of_two();
|
||||
|
||||
// Allocate the memory
|
||||
let mem = alloc::heap(capacity as usize);
|
||||
|
||||
// If the allocation failed, return a blank buf
|
||||
if mem.is_none() {
|
||||
return ByteBuf::none();
|
||||
}
|
||||
|
||||
ByteBuf {
|
||||
mem: mem,
|
||||
cap: capacity,
|
||||
pos: 0,
|
||||
lim: capacity,
|
||||
mark: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn capacity(&self) -> usize {
|
||||
self.cap as usize
|
||||
}
|
||||
|
||||
pub fn flip(self) -> MutByteBuf {
|
||||
let mut buf = MutByteBuf { buf: self };
|
||||
buf.clear();
|
||||
buf
|
||||
}
|
||||
|
||||
/// Flips the buffer back to mutable, resetting the write position
|
||||
/// to the byte after the previous write.
|
||||
pub fn resume(mut self) -> MutByteBuf {
|
||||
self.pos = self.lim;
|
||||
self.lim = self.cap;
|
||||
MutByteBuf { buf: self }
|
||||
}
|
||||
|
||||
pub fn read_slice(&mut self, dst: &mut [u8]) -> usize {
|
||||
let len = cmp::min(dst.len(), self.remaining());
|
||||
let cnt = len as u32;
|
||||
|
||||
unsafe {
|
||||
ptr::copy_nonoverlapping(
|
||||
self.mem.ptr().offset(self.pos as isize),
|
||||
dst.as_mut_ptr(),
|
||||
len);
|
||||
}
|
||||
|
||||
self.pos += cnt;
|
||||
len
|
||||
}
|
||||
|
||||
pub fn to_seq_byte_str(self) -> SeqByteStr {
|
||||
unsafe {
|
||||
let ByteBuf { mem, pos, lim, .. } = self;
|
||||
SeqByteStr::from_mem_ref(
|
||||
mem, pos, lim - pos)
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn to_bytes(self) -> Bytes {
|
||||
Bytes::of(self.to_seq_byte_str())
|
||||
}
|
||||
|
||||
/// Marks the current read location.
|
||||
///
|
||||
/// Together with `reset`, this can be used to read from a section of the
|
||||
/// buffer multiple times. The marked location will be cleared when the
|
||||
/// buffer is flipped.
|
||||
pub fn mark(&mut self) {
|
||||
self.mark = Some(self.pos);
|
||||
}
|
||||
|
||||
/// Resets the read position to the previously marked position.
|
||||
///
|
||||
/// Together with `mark`, this can be used to read from a section of the
|
||||
/// buffer multiple times.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// This method will panic if no mark has been set.
|
||||
pub fn reset(&mut self) {
|
||||
self.pos = self.mark.take().expect("no mark set");
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn pos(&self) -> usize {
|
||||
self.pos as usize
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn lim(&self) -> usize {
|
||||
self.lim as usize
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn remaining_u32(&self) -> u32 {
|
||||
self.lim - self.pos
|
||||
}
|
||||
}
|
||||
|
||||
impl Buf for ByteBuf {
|
||||
|
||||
#[inline]
|
||||
fn remaining(&self) -> usize {
|
||||
self.remaining_u32() as usize
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn bytes<'a>(&'a self) -> &'a [u8] {
|
||||
&self.mem.bytes()[self.pos()..self.lim()]
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn advance(&mut self, mut cnt: usize) {
|
||||
cnt = cmp::min(cnt, self.remaining());
|
||||
self.pos += cnt as u32;
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn read_slice(&mut self, dst: &mut [u8]) -> usize {
|
||||
ByteBuf::read_slice(self, dst)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for ByteBuf {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||
self.bytes().fmt(fmt)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
* ===== ROByteBuf =====
|
||||
*
|
||||
*/
|
||||
|
||||
/// Same as `ByteBuf` but cannot be flipped to a `MutByteBuf`.
|
||||
pub struct ROByteBuf {
|
||||
buf: ByteBuf,
|
||||
}
|
||||
|
||||
impl ROByteBuf {
|
||||
pub unsafe fn from_mem_ref(mem: alloc::MemRef, cap: u32, pos: u32, lim: u32) -> ROByteBuf {
|
||||
ROByteBuf {
|
||||
buf: ByteBuf::from_mem_ref(mem, cap, pos, lim)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_seq_byte_str(self) -> SeqByteStr {
|
||||
self.buf.to_seq_byte_str()
|
||||
}
|
||||
|
||||
pub fn to_bytes(self) -> Bytes {
|
||||
self.buf.to_bytes()
|
||||
}
|
||||
|
||||
/// Marks the current read location.
|
||||
///
|
||||
/// Together with `reset`, this can be used to read from a section of the
|
||||
/// buffer multiple times.
|
||||
pub fn mark(&mut self) {
|
||||
self.buf.mark = Some(self.buf.pos);
|
||||
}
|
||||
|
||||
/// Resets the read position to the previously marked position.
|
||||
///
|
||||
/// Together with `mark`, this can be used to read from a section of the
|
||||
/// buffer multiple times.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// This method will panic if no mark has been set.
|
||||
pub fn reset(&mut self) {
|
||||
self.buf.pos = self.buf.mark.take().expect("no mark set");
|
||||
}
|
||||
}
|
||||
|
||||
impl Buf for ROByteBuf {
|
||||
|
||||
fn remaining(&self) -> usize {
|
||||
self.buf.remaining()
|
||||
}
|
||||
|
||||
fn bytes<'a>(&'a self) -> &'a [u8] {
|
||||
self.buf.bytes()
|
||||
}
|
||||
|
||||
fn advance(&mut self, cnt: usize) {
|
||||
self.buf.advance(cnt)
|
||||
}
|
||||
|
||||
fn read_slice(&mut self, dst: &mut [u8]) -> usize {
|
||||
self.buf.read_slice(dst)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for ROByteBuf {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||
self.bytes().fmt(fmt)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
* ===== MutByteBuf =====
|
||||
*
|
||||
*/
|
||||
|
||||
pub struct MutByteBuf {
|
||||
buf: ByteBuf,
|
||||
}
|
||||
|
||||
impl MutByteBuf {
|
||||
pub fn capacity(&self) -> usize {
|
||||
self.buf.capacity() as usize
|
||||
}
|
||||
|
||||
pub fn flip(self) -> ByteBuf {
|
||||
let mut buf = self.buf;
|
||||
|
||||
buf.lim = buf.pos;
|
||||
buf.pos = 0;
|
||||
buf
|
||||
}
|
||||
|
||||
pub fn clear(&mut self) {
|
||||
self.buf.pos = 0;
|
||||
self.buf.lim = self.buf.cap;
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn write_slice(&mut self, src: &[u8]) -> usize {
|
||||
let cnt = src.len() as u32;
|
||||
let rem = self.buf.remaining_u32();
|
||||
|
||||
if rem < cnt {
|
||||
self.write_ptr(src.as_ptr(), rem)
|
||||
} else {
|
||||
self.write_ptr(src.as_ptr(), cnt)
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn write_ptr(&mut self, src: *const u8, len: u32) -> usize {
|
||||
unsafe {
|
||||
ptr::copy_nonoverlapping(
|
||||
src,
|
||||
self.buf.mem.ptr().offset(self.buf.pos as isize),
|
||||
len as usize);
|
||||
|
||||
self.buf.pos += len;
|
||||
len as usize
|
||||
}
|
||||
}
|
||||
|
||||
pub fn bytes<'a>(&'a self) -> &'a [u8] {
|
||||
&self.buf.mem.bytes()[..self.buf.pos()]
|
||||
}
|
||||
}
|
||||
|
||||
impl MutBuf for MutByteBuf {
|
||||
fn remaining(&self) -> usize {
|
||||
self.buf.remaining()
|
||||
}
|
||||
|
||||
unsafe fn advance(&mut self, cnt: usize) {
|
||||
self.buf.advance(cnt)
|
||||
}
|
||||
|
||||
unsafe fn mut_bytes<'a>(&'a mut self) -> &'a mut [u8] {
|
||||
let pos = self.buf.pos();
|
||||
let lim = self.buf.lim();
|
||||
&mut self.buf.mem.bytes_mut()[pos..lim]
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for MutByteBuf {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||
self.bytes().fmt(fmt)
|
||||
}
|
||||
}
|
||||
-430
@@ -1,430 +0,0 @@
|
||||
mod byte;
|
||||
mod ring;
|
||||
mod sink;
|
||||
mod slice;
|
||||
mod source;
|
||||
mod take;
|
||||
|
||||
pub use self::byte::{ByteBuf, MutByteBuf, ROByteBuf};
|
||||
pub use self::ring::RingBuf;
|
||||
pub use self::slice::{SliceBuf, MutSliceBuf};
|
||||
pub use self::take::Take;
|
||||
|
||||
use {BufError, RopeBuf};
|
||||
use std::{cmp, fmt, io, ptr, usize};
|
||||
|
||||
/// A trait for values that provide sequential read access to bytes.
|
||||
pub trait Buf {
|
||||
|
||||
/// Returns the number of bytes that can be accessed from the Buf
|
||||
fn remaining(&self) -> usize;
|
||||
|
||||
/// Returns a slice starting at the current Buf position and of length
|
||||
/// between 0 and `Buf::remaining()`.
|
||||
fn bytes<'a>(&'a self) -> &'a [u8];
|
||||
|
||||
/// Advance the internal cursor of the Buf
|
||||
fn advance(&mut self, cnt: usize);
|
||||
|
||||
/// Returns true if there are any more bytes to consume
|
||||
fn has_remaining(&self) -> bool {
|
||||
self.remaining() > 0
|
||||
}
|
||||
|
||||
/// Read bytes from the `Buf` into the given slice and advance the cursor by
|
||||
/// the number of bytes read.
|
||||
/// Returns the number of bytes read.
|
||||
///
|
||||
/// ```
|
||||
/// use bytes::{SliceBuf, Buf};
|
||||
///
|
||||
/// let mut buf = SliceBuf::wrap(b"hello world");
|
||||
/// let mut dst = [0; 5];
|
||||
///
|
||||
/// buf.read_slice(&mut dst);
|
||||
/// assert_eq!(b"hello", &dst);
|
||||
/// assert_eq!(6, buf.remaining());
|
||||
/// ```
|
||||
fn read_slice(&mut self, dst: &mut [u8]) -> usize {
|
||||
let mut off = 0;
|
||||
let len = cmp::min(dst.len(), self.remaining());
|
||||
|
||||
while off < len {
|
||||
let cnt;
|
||||
|
||||
unsafe {
|
||||
let src = self.bytes();
|
||||
cnt = cmp::min(src.len(), len - off);
|
||||
|
||||
ptr::copy_nonoverlapping(
|
||||
src.as_ptr(), dst[off..].as_mut_ptr(), cnt);
|
||||
|
||||
off += src.len();
|
||||
}
|
||||
|
||||
self.advance(cnt);
|
||||
}
|
||||
|
||||
len
|
||||
}
|
||||
|
||||
/// Read a single byte from the `Buf`
|
||||
fn read_byte(&mut self) -> Option<u8> {
|
||||
let mut dst = [0];
|
||||
|
||||
if self.read_slice(&mut dst) == 0 {
|
||||
return None;
|
||||
}
|
||||
|
||||
Some(dst[0])
|
||||
}
|
||||
}
|
||||
|
||||
/// An extension trait providing extra functions applicable to all `Buf` values.
|
||||
pub trait BufExt {
|
||||
|
||||
/// Read bytes from this Buf into the given sink and advance the cursor by
|
||||
/// the number of bytes read.
|
||||
fn read<S: Sink>(&mut self, dst: S) -> Result<usize, S::Error>;
|
||||
}
|
||||
|
||||
/// A trait for values that provide sequential write access to bytes.
|
||||
pub trait MutBuf : Sized {
|
||||
|
||||
/// Returns the number of bytes that can be written to the MutBuf
|
||||
fn remaining(&self) -> usize;
|
||||
|
||||
/// Advance the internal cursor of the MutBuf
|
||||
unsafe fn advance(&mut self, cnt: usize);
|
||||
|
||||
/// Returns true iff there is any more space for bytes to be written
|
||||
fn has_remaining(&self) -> bool {
|
||||
self.remaining() > 0
|
||||
}
|
||||
|
||||
/// Returns a mutable slice starting at the current MutBuf position and of
|
||||
/// length between 0 and `MutBuf::remaining()`.
|
||||
///
|
||||
/// The returned byte slice may represent uninitialized memory.
|
||||
unsafe fn mut_bytes<'a>(&'a mut self) -> &'a mut [u8];
|
||||
|
||||
/// Write bytes from the given slice into the `MutBuf` and advance the
|
||||
/// cursor by the number of bytes written.
|
||||
/// Returns the number of bytes written.
|
||||
///
|
||||
/// ```
|
||||
/// use bytes::{MutSliceBuf, Buf, MutBuf};
|
||||
///
|
||||
/// let mut dst = [0; 6];
|
||||
///
|
||||
/// {
|
||||
/// let mut buf = MutSliceBuf::wrap(&mut dst);
|
||||
/// buf.write_slice(b"hello");
|
||||
///
|
||||
/// assert_eq!(1, buf.remaining());
|
||||
/// }
|
||||
///
|
||||
/// assert_eq!(b"hello\0", &dst);
|
||||
/// ```
|
||||
fn write_slice(&mut self, src: &[u8]) -> usize {
|
||||
let mut off = 0;
|
||||
let len = cmp::min(src.len(), self.remaining());
|
||||
|
||||
while off < len {
|
||||
let cnt;
|
||||
|
||||
unsafe {
|
||||
let dst = self.mut_bytes();
|
||||
cnt = cmp::min(dst.len(), len - off);
|
||||
|
||||
ptr::copy_nonoverlapping(
|
||||
src[off..].as_ptr(),
|
||||
dst.as_mut_ptr(),
|
||||
cnt);
|
||||
|
||||
off += cnt;
|
||||
|
||||
}
|
||||
|
||||
unsafe { self.advance(cnt); }
|
||||
}
|
||||
|
||||
len
|
||||
}
|
||||
|
||||
/// Write a single byte to the `MuBuf`
|
||||
fn write_byte(&mut self, byte: u8) -> bool {
|
||||
let src = [byte];
|
||||
|
||||
if self.write_slice(&src) == 0 {
|
||||
return false;
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
/// An extension trait providing extra functions applicable to all `MutBuf` values.
|
||||
pub trait MutBufExt {
|
||||
|
||||
/// Write bytes from the given source into the current `MutBuf` and advance
|
||||
/// the cursor by the number of bytes written.
|
||||
fn write<S: Source>(&mut self, src: S) -> Result<usize, S::Error>;
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
* ===== *Ext impls =====
|
||||
*
|
||||
*/
|
||||
|
||||
impl<B: Buf> BufExt for B {
|
||||
fn read<S: Sink>(&mut self, dst: S) -> Result<usize, S::Error> {
|
||||
dst.sink(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: MutBuf> MutBufExt for B {
|
||||
fn write<S: Source>(&mut self, src: S) -> Result<usize, S::Error> {
|
||||
src.fill(self)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
* ===== Sink / Source =====
|
||||
*
|
||||
*/
|
||||
|
||||
/// A value that reads bytes from a Buf into itself
|
||||
pub trait Sink {
|
||||
type Error;
|
||||
|
||||
fn sink<B: Buf>(self, buf: &mut B) -> Result<usize, Self::Error>;
|
||||
}
|
||||
|
||||
/// A value that writes bytes from itself into a `MutBuf`.
|
||||
pub trait Source {
|
||||
type Error;
|
||||
|
||||
fn fill<B: MutBuf>(self, buf: &mut B) -> Result<usize, Self::Error>;
|
||||
}
|
||||
|
||||
impl<'a> Sink for &'a mut [u8] {
|
||||
type Error = BufError;
|
||||
|
||||
fn sink<B: Buf>(self, buf: &mut B) -> Result<usize, BufError> {
|
||||
Ok(buf.read_slice(self))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Sink for &'a mut Vec<u8> {
|
||||
type Error = BufError;
|
||||
|
||||
fn sink<B: Buf>(self, buf: &mut B) -> Result<usize, BufError> {
|
||||
use std::slice;
|
||||
|
||||
self.clear();
|
||||
|
||||
let rem = buf.remaining();
|
||||
let cap = self.capacity();
|
||||
|
||||
// Ensure that the vec is big enough
|
||||
if rem > self.capacity() {
|
||||
self.reserve(rem - cap);
|
||||
}
|
||||
|
||||
unsafe {
|
||||
{
|
||||
let dst = &mut self[..];
|
||||
let cnt = buf.read_slice(slice::from_raw_parts_mut(dst.as_mut_ptr(), rem));
|
||||
|
||||
debug_assert!(cnt == rem);
|
||||
}
|
||||
|
||||
self.set_len(rem);
|
||||
}
|
||||
|
||||
Ok(rem)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Source for &'a [u8] {
|
||||
type Error = BufError;
|
||||
|
||||
fn fill<B: MutBuf>(self, buf: &mut B) -> Result<usize, BufError> {
|
||||
Ok(buf.write_slice(self))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Source for &'a Vec<u8> {
|
||||
type Error = BufError;
|
||||
|
||||
fn fill<B: MutBuf>(self, buf: &mut B) -> Result<usize, BufError> {
|
||||
Ok(buf.write_slice(self.as_ref()))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl<'a, R: io::Read+'a> Source for &'a mut R {
|
||||
type Error = io::Error;
|
||||
|
||||
fn fill<B: MutBuf>(self, buf: &mut B) -> Result<usize, io::Error> {
|
||||
let mut cnt = 0;
|
||||
|
||||
while buf.has_remaining() {
|
||||
let i = try!(self.read(unsafe { buf.mut_bytes() }));
|
||||
|
||||
if i == 0 {
|
||||
break;
|
||||
}
|
||||
|
||||
unsafe { buf.advance(i); }
|
||||
cnt += i;
|
||||
}
|
||||
|
||||
Ok(cnt)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
* ===== Buf impls =====
|
||||
*
|
||||
*/
|
||||
|
||||
impl Buf for Box<Buf+'static> {
|
||||
fn remaining(&self) -> usize {
|
||||
(**self).remaining()
|
||||
}
|
||||
|
||||
fn bytes(&self) -> &[u8] {
|
||||
(**self).bytes()
|
||||
}
|
||||
|
||||
fn advance(&mut self, cnt: usize) {
|
||||
(**self).advance(cnt);
|
||||
}
|
||||
|
||||
fn read_slice(&mut self, dst: &mut [u8]) -> usize {
|
||||
(**self).read_slice(dst)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Box<Buf+'static> {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(fmt, "Box<Buf> {{ remaining: {} }}", self.remaining())
|
||||
}
|
||||
}
|
||||
|
||||
impl Buf for io::Cursor<Vec<u8>> {
|
||||
fn remaining(&self) -> usize {
|
||||
self.get_ref().len() - self.position() as usize
|
||||
}
|
||||
|
||||
fn bytes(&self) -> &[u8] {
|
||||
let pos = self.position() as usize;
|
||||
&(&self.get_ref())[pos..]
|
||||
}
|
||||
|
||||
fn advance(&mut self, cnt: usize) {
|
||||
let pos = self.position() as usize;
|
||||
let pos = cmp::min(self.get_ref().len(), pos + cnt);
|
||||
self.set_position(pos as u64);
|
||||
}
|
||||
}
|
||||
|
||||
impl MutBuf for Vec<u8> {
|
||||
fn remaining(&self) -> usize {
|
||||
usize::MAX - self.len()
|
||||
}
|
||||
|
||||
unsafe fn advance(&mut self, cnt: usize) {
|
||||
let len = self.len() + cnt;
|
||||
|
||||
if len > self.capacity() {
|
||||
// Reserve additional
|
||||
// TODO: Should this case panic?
|
||||
let cap = self.capacity();
|
||||
self.reserve(cap - len);
|
||||
}
|
||||
|
||||
self.set_len(len);
|
||||
}
|
||||
|
||||
unsafe fn mut_bytes(&mut self) -> &mut [u8] {
|
||||
use std::slice;
|
||||
|
||||
if self.capacity() == self.len() {
|
||||
self.reserve(64); // Grow the vec
|
||||
}
|
||||
|
||||
let cap = self.capacity();
|
||||
let len = self.len();
|
||||
|
||||
let ptr = self.as_mut_ptr();
|
||||
&mut slice::from_raw_parts_mut(ptr, cap)[len..]
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Buf for io::Cursor<&'a [u8]> {
|
||||
fn remaining(&self) -> usize {
|
||||
self.get_ref().len() - self.position() as usize
|
||||
}
|
||||
|
||||
fn bytes(&self) -> &[u8] {
|
||||
let pos = self.position() as usize;
|
||||
&(&self.get_ref())[pos..]
|
||||
}
|
||||
|
||||
fn advance(&mut self, cnt: usize) {
|
||||
let pos = self.position() as usize;
|
||||
let pos = cmp::min(self.get_ref().len(), pos + cnt);
|
||||
self.set_position(pos as u64);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
* ===== Read impls =====
|
||||
*
|
||||
*/
|
||||
|
||||
macro_rules! impl_read {
|
||||
($ty:ty) => {
|
||||
impl io::Read for $ty {
|
||||
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
||||
if !self.has_remaining() {
|
||||
return Ok(0);
|
||||
}
|
||||
|
||||
Ok(self.read_slice(buf))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl_read!(ByteBuf);
|
||||
impl_read!(ROByteBuf);
|
||||
impl_read!(RopeBuf);
|
||||
impl_read!(Box<Buf+'static>);
|
||||
|
||||
macro_rules! impl_write {
|
||||
($ty:ty) => {
|
||||
impl io::Write for $ty {
|
||||
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
||||
if !self.has_remaining() {
|
||||
return Ok(0);
|
||||
}
|
||||
|
||||
Ok(self.write_slice(buf))
|
||||
}
|
||||
|
||||
fn flush(&mut self) -> io::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl_write!(MutByteBuf);
|
||||
-250
@@ -1,250 +0,0 @@
|
||||
use {alloc, Buf, MutBuf};
|
||||
use std::{cmp, fmt, io, ptr};
|
||||
|
||||
enum Mark {
|
||||
NoMark,
|
||||
At { pos: usize, len: usize },
|
||||
}
|
||||
|
||||
/// Buf backed by a continous chunk of memory. Maintains a read cursor and a
|
||||
/// write cursor. When reads and writes reach the end of the allocated buffer,
|
||||
/// wraps around to the start.
|
||||
///
|
||||
/// This type is suited for use cases where reads and writes are intermixed.
|
||||
pub struct RingBuf {
|
||||
ptr: alloc::MemRef, // Pointer to the memory
|
||||
cap: usize, // Capacity of the buffer
|
||||
pos: usize, // Offset of read cursor
|
||||
len: usize, // Number of bytes to read
|
||||
mark: Mark, // Marked read position
|
||||
}
|
||||
|
||||
// TODO: There are most likely many optimizations that can be made
|
||||
impl RingBuf {
|
||||
/// Allocates a new `RingBuf` with the specified capacity.
|
||||
pub fn new(mut capacity: usize) -> RingBuf {
|
||||
// Handle the 0 length buffer case
|
||||
if capacity == 0 {
|
||||
return RingBuf {
|
||||
ptr: alloc::MemRef::none(),
|
||||
cap: 0,
|
||||
pos: 0,
|
||||
len: 0,
|
||||
mark: Mark::NoMark,
|
||||
}
|
||||
}
|
||||
|
||||
// Round to the next power of 2 for better alignment
|
||||
capacity = capacity.next_power_of_two();
|
||||
|
||||
let mem = alloc::heap(capacity as usize);
|
||||
|
||||
RingBuf {
|
||||
ptr: mem,
|
||||
cap: capacity,
|
||||
pos: 0,
|
||||
len: 0,
|
||||
mark: Mark::NoMark,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `true` if the buf cannot accept any further writes.
|
||||
pub fn is_full(&self) -> bool {
|
||||
self.cap == self.len
|
||||
}
|
||||
|
||||
/// Returns `true` if the buf cannot accept any further reads.
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.len == 0
|
||||
}
|
||||
|
||||
/// Returns the number of bytes that the buf can hold.
|
||||
pub fn capacity(&self) -> usize {
|
||||
self.cap
|
||||
}
|
||||
|
||||
/// Marks the current read location.
|
||||
///
|
||||
/// Together with `reset`, this can be used to read from a section of the
|
||||
/// buffer multiple times. The mark will be cleared if it is overwritten
|
||||
/// during a write.
|
||||
pub fn mark(&mut self) {
|
||||
self.mark = Mark::At { pos: self.pos, len: self.len };
|
||||
}
|
||||
|
||||
/// Resets the read position to the previously marked position.
|
||||
///
|
||||
/// Together with `mark`, this can be used to read from a section of the
|
||||
/// buffer multiple times.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// This method will panic if no mark has been set,
|
||||
pub fn reset(&mut self){
|
||||
match self.mark {
|
||||
Mark::NoMark => panic!("no mark set"),
|
||||
Mark::At {pos, len} => {
|
||||
self.pos = pos;
|
||||
self.len = len;
|
||||
self.mark = Mark::NoMark;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Resets all internal state to the initial state.
|
||||
pub fn clear(&mut self) {
|
||||
self.pos = 0;
|
||||
self.len = 0;
|
||||
self.mark = Mark::NoMark;
|
||||
}
|
||||
|
||||
/// Returns the number of bytes remaining to read.
|
||||
fn read_remaining(&self) -> usize {
|
||||
self.len
|
||||
}
|
||||
|
||||
/// Returns the remaining write capacity until which the buf becomes full.
|
||||
fn write_remaining(&self) -> usize {
|
||||
self.cap - self.len
|
||||
}
|
||||
|
||||
fn advance_reader(&mut self, mut cnt: usize) {
|
||||
if self.cap == 0 {
|
||||
return;
|
||||
}
|
||||
cnt = cmp::min(cnt, self.read_remaining());
|
||||
|
||||
self.pos += cnt;
|
||||
self.pos %= self.cap;
|
||||
self.len -= cnt;
|
||||
}
|
||||
|
||||
fn advance_writer(&mut self, mut cnt: usize) {
|
||||
cnt = cmp::min(cnt, self.write_remaining());
|
||||
self.len += cnt;
|
||||
|
||||
// Adjust the mark to account for bytes written.
|
||||
if let Mark::At { ref mut len, .. } = self.mark {
|
||||
*len += cnt;
|
||||
}
|
||||
|
||||
// Clear the mark if we've written past it.
|
||||
if let Mark::At { len, .. } = self.mark {
|
||||
if len > self.cap {
|
||||
self.mark = Mark::NoMark;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for RingBuf {
|
||||
fn clone(&self) -> RingBuf {
|
||||
use std::cmp;
|
||||
|
||||
let mut ret = RingBuf::new(self.cap);
|
||||
|
||||
ret.pos = self.pos;
|
||||
ret.len = self.len;
|
||||
|
||||
unsafe {
|
||||
let to = self.pos + self.len;
|
||||
|
||||
if to > self.cap {
|
||||
ptr::copy(self.ptr.ptr() as *const u8, ret.ptr.ptr(), to % self.cap);
|
||||
}
|
||||
|
||||
ptr::copy(
|
||||
self.ptr.ptr().offset(self.pos as isize) as *const u8,
|
||||
ret.ptr.ptr().offset(self.pos as isize),
|
||||
cmp::min(self.len, self.cap - self.pos));
|
||||
}
|
||||
|
||||
ret
|
||||
}
|
||||
|
||||
// TODO: an improved version of clone_from is possible that potentially
|
||||
// re-uses the buffer
|
||||
}
|
||||
|
||||
impl fmt::Debug for RingBuf {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(fmt, "RingBuf[.. {}]", self.len)
|
||||
}
|
||||
}
|
||||
|
||||
impl Buf for RingBuf {
|
||||
|
||||
fn remaining(&self) -> usize {
|
||||
self.read_remaining()
|
||||
}
|
||||
|
||||
fn bytes(&self) -> &[u8] {
|
||||
let mut to = self.pos + self.len;
|
||||
|
||||
if to > self.cap {
|
||||
to = self.cap
|
||||
}
|
||||
|
||||
&self.ptr.bytes()[self.pos .. to]
|
||||
}
|
||||
|
||||
fn advance(&mut self, cnt: usize) {
|
||||
self.advance_reader(cnt)
|
||||
}
|
||||
}
|
||||
|
||||
impl MutBuf for RingBuf {
|
||||
|
||||
fn remaining(&self) -> usize {
|
||||
self.write_remaining()
|
||||
}
|
||||
|
||||
unsafe fn advance(&mut self, cnt: usize) {
|
||||
self.advance_writer(cnt)
|
||||
}
|
||||
|
||||
unsafe fn mut_bytes(&mut self) -> &mut [u8] {
|
||||
if self.cap == 0 {
|
||||
return self.ptr.bytes_mut();
|
||||
}
|
||||
let mut from;
|
||||
let mut to;
|
||||
|
||||
from = self.pos + self.len;
|
||||
from %= self.cap;
|
||||
|
||||
to = from + <Self as MutBuf>::remaining(&self);
|
||||
|
||||
if to >= self.cap {
|
||||
to = self.cap;
|
||||
}
|
||||
|
||||
&mut self.ptr.bytes_mut()[from..to]
|
||||
}
|
||||
}
|
||||
|
||||
impl io::Read for RingBuf {
|
||||
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
||||
if !Buf::has_remaining(self) {
|
||||
return Ok(0);
|
||||
}
|
||||
|
||||
Ok(self.read_slice(buf))
|
||||
}
|
||||
}
|
||||
|
||||
impl io::Write for RingBuf {
|
||||
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
||||
if !MutBuf::has_remaining(self) {
|
||||
return Ok(0);
|
||||
}
|
||||
|
||||
Ok(self.write_slice(buf))
|
||||
}
|
||||
|
||||
fn flush(&mut self) -> io::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl Send for RingBuf { }
|
||||
@@ -1,59 +0,0 @@
|
||||
use std::cmp;
|
||||
use {Buf, MutBuf};
|
||||
|
||||
// TODO: Rename -> Cursor. Use as buf for various byte strings
|
||||
|
||||
pub struct SliceBuf<'a> {
|
||||
bytes: &'a [u8],
|
||||
pos: usize
|
||||
}
|
||||
|
||||
impl<'a> SliceBuf<'a> {
|
||||
pub fn wrap(bytes: &'a [u8]) -> SliceBuf<'a> {
|
||||
SliceBuf { bytes: bytes, pos: 0 }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Buf for SliceBuf<'a> {
|
||||
fn remaining(&self) -> usize {
|
||||
self.bytes.len() - self.pos
|
||||
}
|
||||
|
||||
fn bytes<'b>(&'b self) -> &'b [u8] {
|
||||
&self.bytes[self.pos..]
|
||||
}
|
||||
|
||||
fn advance(&mut self, mut cnt: usize) {
|
||||
cnt = cmp::min(cnt, self.remaining());
|
||||
self.pos += cnt;
|
||||
}
|
||||
}
|
||||
|
||||
pub struct MutSliceBuf<'a> {
|
||||
bytes: &'a mut [u8],
|
||||
pos: usize
|
||||
}
|
||||
|
||||
impl<'a> MutSliceBuf<'a> {
|
||||
pub fn wrap(bytes: &'a mut [u8]) -> MutSliceBuf<'a> {
|
||||
MutSliceBuf {
|
||||
bytes: bytes,
|
||||
pos: 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> MutBuf for MutSliceBuf<'a> {
|
||||
fn remaining(&self) -> usize {
|
||||
self.bytes.len() - self.pos
|
||||
}
|
||||
|
||||
unsafe fn advance(&mut self, mut cnt: usize) {
|
||||
cnt = cmp::min(cnt, self.remaining());
|
||||
self.pos += cnt;
|
||||
}
|
||||
|
||||
unsafe fn mut_bytes<'b>(&'b mut self) -> &'b mut [u8] {
|
||||
&mut self.bytes[self.pos..]
|
||||
}
|
||||
}
|
||||
@@ -1,79 +0,0 @@
|
||||
use buf::{Buf, MutBuf};
|
||||
use std::{cmp, io};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Take<T> {
|
||||
inner: T,
|
||||
limit: usize,
|
||||
}
|
||||
|
||||
impl<T> Take<T> {
|
||||
pub fn new(inner: T, limit: usize) -> Take<T> {
|
||||
Take {
|
||||
inner: inner,
|
||||
limit: limit,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn into_inner(self) -> T {
|
||||
self.inner
|
||||
}
|
||||
|
||||
pub fn get_ref(&self) -> &T {
|
||||
&self.inner
|
||||
}
|
||||
|
||||
pub fn get_mut(&mut self) -> &mut T {
|
||||
&mut self.inner
|
||||
}
|
||||
|
||||
pub fn limit(&self) -> usize {
|
||||
self.limit
|
||||
}
|
||||
|
||||
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<'a>(&'a self) -> &'a [u8] {
|
||||
&self.inner.bytes()[..self.limit]
|
||||
}
|
||||
|
||||
fn advance(&mut self, cnt: usize) {
|
||||
let cnt = cmp::min(cnt, self.limit);
|
||||
self.limit -= cnt;
|
||||
self.inner.advance(cnt);
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Buf> io::Read for Take<T> {
|
||||
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
||||
if !self.has_remaining() {
|
||||
return Ok(0);
|
||||
}
|
||||
|
||||
Ok(self.read_slice(buf))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: MutBuf> MutBuf for Take<T> {
|
||||
fn remaining(&self) -> usize {
|
||||
cmp::min(self.inner.remaining(), self.limit)
|
||||
}
|
||||
|
||||
unsafe fn mut_bytes<'a>(&'a mut self) -> &'a mut [u8] {
|
||||
&mut self.inner.mut_bytes()[..self.limit]
|
||||
}
|
||||
|
||||
unsafe fn advance(&mut self, cnt: usize) {
|
||||
let cnt = cmp::min(cnt, self.limit);
|
||||
self.limit -= cnt;
|
||||
self.inner.advance(cnt);
|
||||
}
|
||||
}
|
||||
+2155
File diff suppressed because it is too large
Load Diff
+81
-47
@@ -1,54 +1,88 @@
|
||||
#![crate_name = "bytes"]
|
||||
#![deny(warnings)]
|
||||
//! 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.
|
||||
|
||||
pub mod alloc;
|
||||
pub mod buf;
|
||||
pub mod str;
|
||||
#![deny(warnings, missing_docs)]
|
||||
|
||||
extern crate byteorder;
|
||||
|
||||
mod buf;
|
||||
mod bytes;
|
||||
|
||||
pub use buf::{
|
||||
Buf,
|
||||
BufExt,
|
||||
MutBuf,
|
||||
MutBufExt,
|
||||
ByteBuf,
|
||||
MutByteBuf,
|
||||
RingBuf,
|
||||
ROByteBuf,
|
||||
SliceBuf,
|
||||
MutSliceBuf,
|
||||
BufMut,
|
||||
IntoBuf,
|
||||
Source,
|
||||
Sink,
|
||||
Reader,
|
||||
Writer,
|
||||
Take,
|
||||
};
|
||||
pub use str::{
|
||||
ByteStr,
|
||||
Bytes,
|
||||
Rope,
|
||||
RopeBuf,
|
||||
SeqByteStr,
|
||||
SmallByteStr,
|
||||
SmallByteStrBuf,
|
||||
ToBytes,
|
||||
};
|
||||
|
||||
use std::u32;
|
||||
|
||||
pub mod traits {
|
||||
//! All traits are re-exported here to allow glob imports.
|
||||
pub use {Buf, BufExt, MutBuf, MutBufExt, ByteStr, ToBytes};
|
||||
}
|
||||
|
||||
const MAX_CAPACITY: usize = u32::MAX as usize;
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* ===== BufError =====
|
||||
*
|
||||
*/
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub enum BufError {
|
||||
Underflow,
|
||||
Overflow,
|
||||
}
|
||||
pub use bytes::{Bytes, BytesMut};
|
||||
pub use byteorder::{ByteOrder, BigEndian, LittleEndian};
|
||||
|
||||
@@ -1,310 +0,0 @@
|
||||
use {ByteBuf, MutBuf, SmallByteStr, Source, BufError};
|
||||
use traits::{Buf, ByteStr, ToBytes};
|
||||
use std::{cmp, fmt, mem, ops, ptr};
|
||||
use std::any::{Any, TypeId};
|
||||
|
||||
const INLINE: usize = 1;
|
||||
|
||||
/// A specialized `ByteStr` box.
|
||||
pub struct Bytes {
|
||||
vtable: usize,
|
||||
data: *mut (),
|
||||
}
|
||||
|
||||
impl Bytes {
|
||||
pub fn from_slice(bytes: &[u8]) -> Bytes {
|
||||
SmallByteStr::from_slice(bytes)
|
||||
.map(|small| Bytes::of(small))
|
||||
.unwrap_or_else(|| ByteBuf::from_slice(bytes).to_bytes())
|
||||
}
|
||||
|
||||
pub fn of<B: ByteStr>(bytes: B) -> Bytes {
|
||||
unsafe {
|
||||
if inline::<B>() {
|
||||
let vtable;
|
||||
let data;
|
||||
|
||||
{
|
||||
let obj: &ByteStrPriv = &bytes;
|
||||
let obj: TraitObject = mem::transmute(obj);
|
||||
let ptr: *const *mut () = mem::transmute(obj.data);
|
||||
|
||||
data = *ptr;
|
||||
vtable = obj.vtable;
|
||||
}
|
||||
|
||||
// Prevent drop from being called
|
||||
mem::forget(bytes);
|
||||
|
||||
Bytes {
|
||||
vtable: vtable as usize | INLINE,
|
||||
data: data,
|
||||
}
|
||||
} else {
|
||||
let obj: Box<ByteStrPriv> = Box::new(bytes);
|
||||
let obj: TraitObject = mem::transmute(obj);
|
||||
|
||||
Bytes {
|
||||
vtable: obj.vtable as usize,
|
||||
data: obj.data,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn empty() -> Bytes {
|
||||
Bytes::of(SmallByteStr::zero())
|
||||
}
|
||||
|
||||
/// If the underlying `ByteStr` is of type `B`, returns a reference to it
|
||||
/// otherwise None.
|
||||
pub fn downcast_ref<'a, B: ByteStr>(&'a self) -> Option<&'a B> {
|
||||
if TypeId::of::<B>() == self.obj().get_type_id() {
|
||||
unsafe {
|
||||
if inline::<B>() {
|
||||
return Some(mem::transmute(&self.data));
|
||||
} else {
|
||||
return Some(mem::transmute(self.data));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
/// If the underlying `ByteStr` is of type `B`, returns the unwraped value,
|
||||
/// otherwise, returns the original `Bytes` as `Err`.
|
||||
pub fn try_unwrap<B: ByteStr>(self) -> Result<B, Bytes> {
|
||||
if TypeId::of::<B>() == self.obj().get_type_id() {
|
||||
unsafe {
|
||||
// Underlying ByteStr value is of the correct type. Unwrap it
|
||||
let ret;
|
||||
|
||||
if inline::<B>() {
|
||||
// The value is inline, read directly from the pointer
|
||||
ret = ptr::read(mem::transmute(&self.data));
|
||||
} else {
|
||||
ret = ptr::read(mem::transmute(self.data));
|
||||
}
|
||||
|
||||
mem::forget(self);
|
||||
Ok(ret)
|
||||
}
|
||||
} else {
|
||||
Err(self)
|
||||
}
|
||||
}
|
||||
|
||||
fn obj(&self) -> &ByteStrPriv {
|
||||
unsafe {
|
||||
mem::transmute(self.to_trait_object())
|
||||
}
|
||||
}
|
||||
|
||||
fn obj_mut(&mut self) -> &mut ByteStrPriv {
|
||||
unsafe {
|
||||
mem::transmute(self.to_trait_object())
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn to_trait_object(&self) -> TraitObject {
|
||||
if self.is_inline() {
|
||||
TraitObject {
|
||||
data: mem::transmute(&self.data),
|
||||
vtable: mem::transmute(self.vtable - 1),
|
||||
}
|
||||
} else {
|
||||
TraitObject {
|
||||
data: self.data,
|
||||
vtable: mem::transmute(self.vtable),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn is_inline(&self) -> bool {
|
||||
(self.vtable & INLINE) == INLINE
|
||||
}
|
||||
}
|
||||
|
||||
fn inline<B: ByteStr>() -> bool {
|
||||
mem::size_of::<B>() <= 2 * mem::size_of::<usize>()
|
||||
}
|
||||
|
||||
impl ByteStr for Bytes {
|
||||
|
||||
type Buf = Box<Buf+'static>;
|
||||
|
||||
fn buf(&self) -> Box<Buf+'static> {
|
||||
self.obj().buf()
|
||||
}
|
||||
|
||||
fn concat<B: ByteStr>(&self, other: &B) -> Bytes {
|
||||
self.obj().concat(&Bytes::of(other.clone()))
|
||||
}
|
||||
|
||||
fn len(&self) -> usize {
|
||||
self.obj().len()
|
||||
}
|
||||
|
||||
fn slice(&self, begin: usize, end: usize) -> Bytes {
|
||||
self.obj().slice(begin, end)
|
||||
}
|
||||
|
||||
fn split_at(&self, mid: usize) -> (Bytes, Bytes) {
|
||||
self.obj().split_at(mid)
|
||||
}
|
||||
}
|
||||
|
||||
impl ToBytes for Bytes {
|
||||
fn to_bytes(self) -> Bytes {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl ops::Index<usize> for Bytes {
|
||||
type Output = u8;
|
||||
|
||||
fn index(&self, index: usize) -> &u8 {
|
||||
self.obj().index(index)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Bytes {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||
super::debug(self, "Bytes", fmt)
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for Bytes {
|
||||
fn clone(&self) -> Bytes {
|
||||
self.obj().clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Bytes {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
if self.is_inline() {
|
||||
let obj = self.obj_mut();
|
||||
obj.drop();
|
||||
} else {
|
||||
let _: Box<ByteStrPriv> =
|
||||
mem::transmute(self.obj());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl Send for Bytes { }
|
||||
unsafe impl Sync for Bytes { }
|
||||
|
||||
impl<'a> Source for &'a Bytes {
|
||||
type Error = BufError;
|
||||
|
||||
fn fill<B: MutBuf>(self, dst: &mut B) -> Result<usize, BufError> {
|
||||
let mut src = ByteStr::buf(self);
|
||||
let mut res = 0;
|
||||
|
||||
while src.has_remaining() && dst.has_remaining() {
|
||||
let l;
|
||||
|
||||
unsafe {
|
||||
let s = src.bytes();
|
||||
let d = dst.mut_bytes();
|
||||
l = cmp::min(s.len(), d.len());
|
||||
|
||||
ptr::copy_nonoverlapping(
|
||||
s.as_ptr(),
|
||||
d.as_mut_ptr(),
|
||||
l);
|
||||
}
|
||||
|
||||
src.advance(l);
|
||||
unsafe { dst.advance(l); }
|
||||
|
||||
res += l;
|
||||
}
|
||||
|
||||
Ok(res)
|
||||
}
|
||||
}
|
||||
|
||||
trait ByteStrPriv {
|
||||
|
||||
fn buf(&self) -> Box<Buf+'static>;
|
||||
|
||||
fn clone(&self) -> Bytes;
|
||||
|
||||
fn concat(&self, other: &Bytes) -> Bytes;
|
||||
|
||||
fn drop(&mut self);
|
||||
|
||||
fn get_type_id(&self) -> TypeId;
|
||||
|
||||
fn index(&self, index: usize) -> &u8;
|
||||
|
||||
fn len(&self) -> usize;
|
||||
|
||||
fn slice(&self, begin: usize, end: usize) -> Bytes;
|
||||
|
||||
fn split_at(&self, mid: usize) -> (Bytes, Bytes);
|
||||
}
|
||||
|
||||
impl<B: ByteStr> ByteStrPriv for B {
|
||||
|
||||
fn buf(&self) -> Box<Buf+'static> {
|
||||
Box::new(self.buf())
|
||||
}
|
||||
|
||||
fn clone(&self) -> Bytes {
|
||||
Bytes::of(self.clone())
|
||||
}
|
||||
|
||||
fn concat(&self, other: &Bytes) -> Bytes {
|
||||
self.concat(other)
|
||||
}
|
||||
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
ptr::read(mem::transmute(self))
|
||||
}
|
||||
}
|
||||
|
||||
fn get_type_id(&self) -> TypeId {
|
||||
TypeId::of::<B>()
|
||||
}
|
||||
|
||||
fn index(&self, index: usize) -> &u8 {
|
||||
ops::Index::index(self, index)
|
||||
}
|
||||
|
||||
fn len(&self) -> usize {
|
||||
self.len()
|
||||
}
|
||||
|
||||
fn slice(&self, begin: usize, end: usize) -> Bytes {
|
||||
self.slice(begin, end)
|
||||
}
|
||||
|
||||
fn split_at(&self, mid: usize) -> (Bytes, Bytes) {
|
||||
self.split_at(mid)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Figure out how to not depend on the memory layout of trait objects
|
||||
// Blocked: rust-lang/rust#24050
|
||||
#[repr(C)]
|
||||
struct TraitObject {
|
||||
data: *mut (),
|
||||
vtable: *mut (),
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_size_of() {
|
||||
// TODO: One day, there shouldn't be a drop flag
|
||||
let ptr_size = mem::size_of::<usize>();
|
||||
let expect = ptr_size * 3;
|
||||
|
||||
assert_eq!(expect, mem::size_of::<Bytes>());
|
||||
assert_eq!(expect + ptr_size, mem::size_of::<Option<Bytes>>());
|
||||
}
|
||||
-187
@@ -1,187 +0,0 @@
|
||||
mod bytes;
|
||||
mod rope;
|
||||
mod seq;
|
||||
mod small;
|
||||
|
||||
pub use self::bytes::Bytes;
|
||||
pub use self::rope::{Rope, RopeBuf};
|
||||
pub use self::seq::SeqByteStr;
|
||||
pub use self::small::{SmallByteStr, SmallByteStrBuf};
|
||||
|
||||
use {Buf};
|
||||
use std::{cmp, fmt, ops};
|
||||
use std::any::Any;
|
||||
|
||||
/// An immutable sequence of bytes. Operations will not mutate the original
|
||||
/// value. Since only immutable access is permitted, operations do not require
|
||||
/// copying (though, sometimes copying will happen as an optimization).
|
||||
pub trait ByteStr : Clone + Sized + Send + Sync + Any + ToBytes + ops::Index<usize, Output=u8> + 'static {
|
||||
|
||||
// Until HKT lands, the buf must be bound by 'static
|
||||
type Buf: Buf+'static;
|
||||
|
||||
/// Returns a read-only `Buf` for accessing the byte contents of the
|
||||
/// `ByteStr`.
|
||||
fn buf(&self) -> Self::Buf;
|
||||
|
||||
/// Returns a new `Bytes` value representing the concatenation of `self`
|
||||
/// with the given `Bytes`.
|
||||
fn concat<B: ByteStr+'static>(&self, other: &B) -> Bytes;
|
||||
|
||||
/// Returns the number of bytes in the ByteStr
|
||||
fn len(&self) -> usize;
|
||||
|
||||
/// Returns true if the length of the `ByteStr` is 0
|
||||
fn is_empty(&self) -> bool {
|
||||
self.len() == 0
|
||||
}
|
||||
|
||||
/// Returns a new ByteStr value containing the byte range between `begin`
|
||||
/// (inclusive) and `end` (exclusive)
|
||||
fn slice(&self, begin: usize, end: usize) -> Bytes;
|
||||
|
||||
/// Returns a new ByteStr value containing the byte range starting from
|
||||
/// `begin` (inclusive) to the end of the byte str.
|
||||
///
|
||||
/// Equivalent to `bytes.slice(begin, bytes.len())`
|
||||
fn slice_from(&self, begin: usize) -> Bytes {
|
||||
self.slice(begin, self.len())
|
||||
}
|
||||
|
||||
/// Returns a new ByteStr value containing the byte range from the start up
|
||||
/// to `end` (exclusive).
|
||||
///
|
||||
/// Equivalent to `bytes.slice(0, end)`
|
||||
fn slice_to(&self, end: usize) -> Bytes {
|
||||
self.slice(0, end)
|
||||
}
|
||||
|
||||
/// Divides the value into two `Bytes` at the given index.
|
||||
///
|
||||
/// The first will contain all bytes from `[0, mid]` (excluding the index
|
||||
/// `mid` itself) and the second will contain all indices from `[mid, len)`
|
||||
/// (excluding the index `len` itself).
|
||||
///
|
||||
/// Panics if `mid > len`.
|
||||
fn split_at(&self, mid: usize) -> (Bytes, Bytes) {
|
||||
(self.slice_to(mid), self.slice_from(mid))
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! impl_parteq {
|
||||
($ty:ty) => {
|
||||
impl<B: ByteStr> cmp::PartialEq<B> for $ty {
|
||||
fn eq(&self, other: &B) -> bool {
|
||||
if self.len() != other.len() {
|
||||
return false;
|
||||
}
|
||||
|
||||
let mut buf1 = self.buf();
|
||||
let mut buf2 = self.buf();
|
||||
|
||||
while buf1.has_remaining() {
|
||||
let len;
|
||||
|
||||
{
|
||||
let b1 = buf1.bytes();
|
||||
let b2 = buf2.bytes();
|
||||
|
||||
len = cmp::min(b1.len(), b2.len());
|
||||
|
||||
if b1[..len] != b2[..len] {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
buf1.advance(len);
|
||||
buf2.advance(len);
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
fn ne(&self, other: &B) -> bool {
|
||||
return !self.eq(other)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl_parteq!(SeqByteStr);
|
||||
impl_parteq!(SmallByteStr);
|
||||
impl_parteq!(Bytes);
|
||||
impl_parteq!(Rope);
|
||||
|
||||
macro_rules! impl_eq {
|
||||
($ty:ty) => {
|
||||
impl cmp::Eq for $ty {}
|
||||
}
|
||||
}
|
||||
|
||||
impl_eq!(Bytes);
|
||||
|
||||
/*
|
||||
*
|
||||
* ===== ToBytes =====
|
||||
*
|
||||
*/
|
||||
|
||||
pub trait ToBytes {
|
||||
/// Consumes the value and returns a `Bytes` instance containing
|
||||
/// identical bytes
|
||||
fn to_bytes(self) -> Bytes;
|
||||
}
|
||||
|
||||
impl<'a> ToBytes for &'a [u8] {
|
||||
fn to_bytes(self) -> Bytes {
|
||||
Bytes::from_slice(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ToBytes for &'a Vec<u8> {
|
||||
fn to_bytes(self) -> Bytes {
|
||||
(&self[..]).to_bytes()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* ===== Internal utilities =====
|
||||
*
|
||||
*/
|
||||
|
||||
fn debug<B: ByteStr>(bytes: &B, name: &str, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||
let mut buf = bytes.buf();
|
||||
|
||||
try!(write!(fmt, "{}[len={}; ", name, bytes.len()));
|
||||
|
||||
let mut rem = 128;
|
||||
|
||||
while let Some(byte) = buf.read_byte() {
|
||||
if rem > 0 {
|
||||
if is_ascii(byte) {
|
||||
try!(write!(fmt, "{}", byte as char));
|
||||
} else {
|
||||
try!(write!(fmt, "\\x{:02X}", byte));
|
||||
}
|
||||
|
||||
rem -= 1;
|
||||
} else {
|
||||
try!(write!(fmt, " ... "));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
try!(write!(fmt, "]"));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn is_ascii(byte: u8) -> bool {
|
||||
match byte {
|
||||
10 | 13 | 32...126 => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
-585
@@ -1,585 +0,0 @@
|
||||
use {Bytes, ByteBuf, Source, BufError};
|
||||
use traits::{Buf, ByteStr, MutBuf, MutBufExt, ToBytes};
|
||||
use std::{cmp, mem, ops};
|
||||
use std::sync::Arc;
|
||||
|
||||
// The implementation is mostly a port of the implementation found in the Java
|
||||
// protobuf lib.
|
||||
|
||||
const CONCAT_BY_COPY_LEN: usize = 128;
|
||||
const MAX_DEPTH: usize = 47;
|
||||
|
||||
// Used to decide when to rebalance the tree.
|
||||
static MIN_LENGTH_BY_DEPTH: [usize; MAX_DEPTH] = [
|
||||
1, 2, 3, 5, 8,
|
||||
13, 21, 34, 55, 89,
|
||||
144, 233, 377, 610, 987,
|
||||
1_597, 2_584, 4_181, 6_765, 10_946,
|
||||
17_711, 28_657, 46_368, 75_025, 121_393,
|
||||
196_418, 317_811, 514_229, 832_040, 1_346_269,
|
||||
2_178_309, 3_524_578, 5_702_887, 9_227_465, 14_930_352,
|
||||
24_157_817, 39_088_169, 63_245_986, 102_334_155, 165_580_141,
|
||||
267_914_296, 433_494_437, 701_408_733, 1_134_903_170, 1_836_311_903,
|
||||
2_971_215_073, 4_294_967_295];
|
||||
|
||||
/// An immutable sequence of bytes formed by concatenation of other `ByteStr`
|
||||
/// values, without copying the data in the pieces. The concatenation is
|
||||
/// represented as a tree whose leaf nodes are each a `Bytes` value.
|
||||
///
|
||||
/// Most of the operation here is inspired by the now-famous paper [Ropes: an
|
||||
/// Alternative to Strings. hans-j. boehm, russ atkinson and michael
|
||||
/// plass](http://www.cs.rit.edu/usr/local/pub/jeh/courses/QUARTERS/FP/Labs/CedarRope/rope-paper.pdf).
|
||||
///
|
||||
/// Fundamentally the Rope algorithm represents the collection of pieces as a
|
||||
/// binary tree. BAP95 uses a Fibonacci bound relating depth to a minimum
|
||||
/// sequence length, sequences that are too short relative to their depth cause
|
||||
/// a tree rebalance. More precisely, a tree of depth d is "balanced" in the
|
||||
/// terminology of BAP95 if its length is at least F(d+2), where F(n) is the
|
||||
/// n-the Fibonacci number. Thus for depths 0, 1, 2, 3, 4, 5,... we have
|
||||
/// minimum lengths 1, 2, 3, 5, 8, 13,...
|
||||
pub struct Rope {
|
||||
inner: Arc<RopeInner>,
|
||||
}
|
||||
|
||||
impl Rope {
|
||||
pub fn from_slice(bytes: &[u8]) -> Rope {
|
||||
Rope::new(Bytes::from_slice(bytes), Bytes::empty())
|
||||
}
|
||||
|
||||
/// Returns a Rope consisting of the supplied Bytes as a single segment.
|
||||
pub fn of<B: ByteStr + 'static>(bytes: B) -> Rope {
|
||||
let bytes = Bytes::of(bytes);
|
||||
|
||||
match bytes.try_unwrap() {
|
||||
Ok(rope) => rope,
|
||||
Err(bytes) => Rope::new(bytes, Bytes::empty()),
|
||||
}
|
||||
}
|
||||
|
||||
fn new(left: Bytes, right: Bytes) -> Rope {
|
||||
Rope { inner: Arc::new(RopeInner::new(left, right)) }
|
||||
}
|
||||
|
||||
pub fn len(&self) -> usize {
|
||||
self.inner.len as usize
|
||||
}
|
||||
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.len() == 0
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
* ===== Priv fns =====
|
||||
*
|
||||
*/
|
||||
|
||||
fn depth(&self) -> u16 {
|
||||
self.inner.depth
|
||||
}
|
||||
|
||||
fn left(&self) -> &Bytes {
|
||||
&self.inner.left
|
||||
}
|
||||
|
||||
fn right(&self) -> &Bytes {
|
||||
&self.inner.right
|
||||
}
|
||||
|
||||
fn pieces<'a>(&'a self) -> PieceIter<'a> {
|
||||
PieceIter::new(&self.inner)
|
||||
}
|
||||
}
|
||||
|
||||
impl ByteStr for Rope {
|
||||
type Buf = RopeBuf;
|
||||
|
||||
fn buf(&self) -> RopeBuf {
|
||||
RopeBuf::new(self.clone())
|
||||
}
|
||||
|
||||
fn concat<B: ByteStr+'static>(&self, other: &B) -> Bytes {
|
||||
let left = Bytes::of(self.clone());
|
||||
let right = Bytes::of(other.clone());
|
||||
Bytes::of(concat(left, right))
|
||||
}
|
||||
|
||||
fn len(&self) -> usize {
|
||||
Rope::len(self)
|
||||
}
|
||||
|
||||
fn slice(&self, begin: usize, end: usize) -> Bytes {
|
||||
if begin >= end || begin >= self.len() {
|
||||
return Bytes::empty()
|
||||
}
|
||||
|
||||
let end = cmp::min(end, self.len());
|
||||
let len = end - begin;
|
||||
|
||||
// Empty slice
|
||||
if len == 0 {
|
||||
return Bytes::empty();
|
||||
}
|
||||
|
||||
// Full rope
|
||||
if len == self.len() {
|
||||
return Bytes::of(self.clone());
|
||||
}
|
||||
|
||||
// == Proper substring ==
|
||||
|
||||
let left_len = self.inner.left.len();
|
||||
|
||||
if end <= left_len {
|
||||
// Slice on the left
|
||||
return self.inner.left.slice(begin, end);
|
||||
}
|
||||
|
||||
if begin >= left_len {
|
||||
// Slice on the right
|
||||
return self.inner.right.slice(begin - left_len, end - left_len);
|
||||
}
|
||||
|
||||
// Split slice
|
||||
let left_slice = self.inner.left.slice_from(begin);
|
||||
let right_slice = self.inner.right.slice_to(end - left_len);
|
||||
|
||||
Bytes::of(Rope::new(left_slice, right_slice))
|
||||
}
|
||||
}
|
||||
|
||||
impl ToBytes for Rope {
|
||||
fn to_bytes(self) -> Bytes {
|
||||
Bytes::of(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl ops::Index<usize> for Rope {
|
||||
type Output = u8;
|
||||
|
||||
fn index(&self, index: usize) -> &u8 {
|
||||
assert!(index < self.len());
|
||||
|
||||
let left_len = self.inner.left.len();
|
||||
|
||||
if index < left_len {
|
||||
self.inner.left.index(index)
|
||||
} else {
|
||||
self.inner.right.index(index - left_len)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for Rope {
|
||||
fn clone(&self) -> Rope {
|
||||
Rope { inner: self.inner.clone() }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Source for &'a Rope {
|
||||
type Error = BufError;
|
||||
|
||||
fn fill<B: MutBuf>(self, _buf: &mut B) -> Result<usize, BufError> {
|
||||
unimplemented!();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
* ===== Helper Fns =====
|
||||
*
|
||||
*/
|
||||
|
||||
fn depth(bytes: &Bytes) -> u16 {
|
||||
match bytes.downcast_ref::<Rope>() {
|
||||
Some(rope) => rope.inner.depth,
|
||||
None => 0,
|
||||
}
|
||||
}
|
||||
|
||||
fn is_balanced(bytes: &Bytes) -> bool {
|
||||
if let Some(rope) = bytes.downcast_ref::<Rope>() {
|
||||
return rope.len() >= MIN_LENGTH_BY_DEPTH[rope.depth() as usize];
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
fn concat(left: Bytes, right: Bytes) -> Rope {
|
||||
if right.is_empty() {
|
||||
return Rope::of(left);
|
||||
}
|
||||
|
||||
if left.is_empty() {
|
||||
return Rope::of(right);
|
||||
}
|
||||
|
||||
let len = left.len() + right.len();
|
||||
|
||||
if len < CONCAT_BY_COPY_LEN {
|
||||
return concat_bytes(&left, &right, len);
|
||||
}
|
||||
|
||||
if let Some(left) = left.downcast_ref::<Rope>() {
|
||||
let len = left.inner.right.len() + right.len();
|
||||
|
||||
if len < CONCAT_BY_COPY_LEN {
|
||||
// Optimization from BAP95: As an optimization of the case
|
||||
// where the ByteString is constructed by repeated concatenate,
|
||||
// recognize the case where a short string is concatenated to a
|
||||
// left-hand node whose right-hand branch is short. In the
|
||||
// paper this applies to leaves, but we just look at the length
|
||||
// here. This has the advantage of shedding references to
|
||||
// unneeded data when substrings have been taken.
|
||||
//
|
||||
// When we recognize this case, we do a copy of the data and
|
||||
// create a new parent node so that the depth of the result is
|
||||
// the same as the given left tree.
|
||||
let new_right = concat_bytes(&left.inner.right, &right, len);
|
||||
return Rope::new(left.inner.left.clone(), Bytes::of(new_right));
|
||||
}
|
||||
|
||||
if depth(left.left()) > depth(left.right()) && left.depth() > depth(&right) {
|
||||
// Typically for concatenate-built strings the left-side is
|
||||
// deeper than the right. This is our final attempt to
|
||||
// concatenate without increasing the tree depth. We'll redo
|
||||
// the the node on the RHS. This is yet another optimization
|
||||
// for building the string by repeatedly concatenating on the
|
||||
// right.
|
||||
let new_right = Rope::new(left.right().clone(), right);
|
||||
return Rope::new(left.left().clone(), Bytes::of(new_right));
|
||||
}
|
||||
}
|
||||
|
||||
// Fine, we'll add a node and increase the tree depth -- unless we
|
||||
// rebalance ;^)
|
||||
let depth = cmp::max(depth(&left), depth(&right)) + 1;
|
||||
|
||||
if len >= MIN_LENGTH_BY_DEPTH[depth as usize] {
|
||||
// No need to rebalance
|
||||
return Rope::new(left, right);
|
||||
}
|
||||
|
||||
Balance::new().balance(left, right)
|
||||
}
|
||||
|
||||
fn concat_bytes(left: &Bytes, right: &Bytes, len: usize) -> Rope {
|
||||
let mut buf = ByteBuf::mut_with_capacity(len);
|
||||
|
||||
buf.write(left).ok().expect("unexpected error");
|
||||
buf.write(right).ok().expect("unexpected error");
|
||||
|
||||
return Rope::of(buf.flip().to_bytes());
|
||||
}
|
||||
|
||||
fn depth_for_len(len: usize) -> u16 {
|
||||
match MIN_LENGTH_BY_DEPTH.binary_search(&len) {
|
||||
Ok(idx) => idx as u16,
|
||||
Err(idx) => {
|
||||
// It wasn't an exact match, so convert to the index of the
|
||||
// containing fragment, which is one less even than the insertion
|
||||
// point.
|
||||
idx as u16 - 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
* ===== RopeBuf =====
|
||||
*
|
||||
*/
|
||||
|
||||
pub struct RopeBuf {
|
||||
rem: usize,
|
||||
|
||||
// Only here for the ref count
|
||||
#[allow(dead_code)]
|
||||
rope: Rope,
|
||||
|
||||
// This must be done with unsafe code to avoid having a lifetime bound on
|
||||
// RopeBuf but is safe due to Rope being held. As long as data doesn't
|
||||
// escape (which it shouldn't) it is safe. Doing this properly would
|
||||
// require HKT.
|
||||
pieces: PieceIter<'static>,
|
||||
leaf_buf: Option<Box<Buf+'static>>,
|
||||
}
|
||||
|
||||
impl RopeBuf {
|
||||
fn new(rope: Rope) -> RopeBuf {
|
||||
// In order to get the lifetimes to work out, transmute to a 'static
|
||||
// lifetime. Never allow the iter to escape the internals of RopeBuf.
|
||||
let mut pieces: PieceIter<'static> =
|
||||
unsafe { mem::transmute(rope.pieces()) };
|
||||
|
||||
// Get the next buf
|
||||
let leaf_buf = pieces.next()
|
||||
.map(|bytes| bytes.buf());
|
||||
|
||||
let len = rope.len();
|
||||
|
||||
RopeBuf {
|
||||
rope: rope,
|
||||
rem: len,
|
||||
pieces: pieces,
|
||||
leaf_buf: leaf_buf,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Buf for RopeBuf {
|
||||
fn remaining(&self) -> usize {
|
||||
self.rem
|
||||
}
|
||||
|
||||
fn bytes(&self) -> &[u8] {
|
||||
self.leaf_buf.as_ref()
|
||||
.map(|b| b.bytes())
|
||||
.unwrap_or(&[])
|
||||
}
|
||||
|
||||
fn advance(&mut self, mut cnt: usize) {
|
||||
cnt = cmp::min(cnt, self.rem);
|
||||
|
||||
// Advance the internal cursor
|
||||
self.rem -= cnt;
|
||||
|
||||
// Advance the leaf buffer
|
||||
while cnt > 0 {
|
||||
{
|
||||
let curr = self.leaf_buf.as_mut()
|
||||
.expect("expected a value");
|
||||
|
||||
if curr.remaining() > cnt {
|
||||
curr.advance(cnt);
|
||||
break;
|
||||
}
|
||||
|
||||
cnt -= curr.remaining();
|
||||
}
|
||||
|
||||
self.leaf_buf = self.pieces.next()
|
||||
.map(|bytes| bytes.buf());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
* ===== PieceIter =====
|
||||
*
|
||||
*/
|
||||
|
||||
// TODO: store stack inline if possible
|
||||
struct PieceIter<'a> {
|
||||
stack: Vec<&'a RopeInner>,
|
||||
next: Option<&'a Bytes>,
|
||||
}
|
||||
|
||||
impl<'a> PieceIter<'a> {
|
||||
fn new(root: &'a RopeInner) -> PieceIter<'a> {
|
||||
let mut iter = PieceIter {
|
||||
stack: vec![],
|
||||
next: None,
|
||||
};
|
||||
|
||||
iter.next = iter.get_leaf_by_left(root);
|
||||
iter
|
||||
}
|
||||
|
||||
fn get_leaf_by_left(&mut self, mut root: &'a RopeInner) -> Option<&'a Bytes> {
|
||||
loop {
|
||||
self.stack.push(root);
|
||||
let left = &root.left;
|
||||
|
||||
if left.is_empty() {
|
||||
return None;
|
||||
}
|
||||
|
||||
if let Some(rope) = left.downcast_ref::<Rope>() {
|
||||
root = &*rope.inner;
|
||||
continue;
|
||||
}
|
||||
|
||||
return Some(left);
|
||||
}
|
||||
}
|
||||
|
||||
fn next_non_empty_leaf(&mut self) -> Option<&'a Bytes>{
|
||||
loop {
|
||||
if let Some(node) = self.stack.pop() {
|
||||
if let Some(rope) = node.right.downcast_ref::<Rope>() {
|
||||
let res = self.get_leaf_by_left(&rope.inner);
|
||||
|
||||
if res.is_none() {
|
||||
continue;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
if node.right.is_empty() {
|
||||
continue;
|
||||
}
|
||||
|
||||
return Some(&node.right);
|
||||
}
|
||||
|
||||
return None;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Iterator for PieceIter<'a> {
|
||||
type Item = &'a Bytes;
|
||||
|
||||
fn next(&mut self) -> Option<&'a Bytes> {
|
||||
let ret = self.next.take();
|
||||
|
||||
if ret.is_some() {
|
||||
self.next = self.next_non_empty_leaf();
|
||||
}
|
||||
|
||||
ret
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
* ===== Balance =====
|
||||
*
|
||||
*/
|
||||
|
||||
struct Balance {
|
||||
stack: Vec<Bytes>,
|
||||
}
|
||||
|
||||
impl Balance {
|
||||
fn new() -> Balance {
|
||||
Balance { stack: vec![] }
|
||||
}
|
||||
|
||||
fn balance(&mut self, left: Bytes, right: Bytes) -> Rope {
|
||||
self.do_balance(left);
|
||||
self.do_balance(right);
|
||||
|
||||
let mut partial = self.stack.pop()
|
||||
.expect("expected a value");
|
||||
|
||||
while !partial.is_empty() {
|
||||
let new_left = self.stack.pop()
|
||||
.expect("expected a value");
|
||||
|
||||
partial = Bytes::of(Rope::new(new_left, partial));
|
||||
}
|
||||
|
||||
Rope::of(partial)
|
||||
}
|
||||
|
||||
fn do_balance(&mut self, root: Bytes) {
|
||||
// BAP95: Insert balanced subtrees whole. This means the result might not
|
||||
// be balanced, leading to repeated rebalancings on concatenate. However,
|
||||
// these rebalancings are shallow due to ignoring balanced subtrees, and
|
||||
// relatively few calls to insert() result.
|
||||
if is_balanced(&root) {
|
||||
self.insert(root);
|
||||
} else {
|
||||
let rope = root.try_unwrap::<Rope>()
|
||||
.ok().expect("expected a value");
|
||||
|
||||
self.do_balance(rope.left().clone());
|
||||
self.do_balance(rope.right().clone());
|
||||
}
|
||||
}
|
||||
|
||||
// Push a string on the balance stack (BAP95). BAP95 uses an array and
|
||||
// calls the elements in the array 'bins'. We instead use a stack, so the
|
||||
// 'bins' of lengths are represented by differences between the elements of
|
||||
// minLengthByDepth.
|
||||
//
|
||||
// If the length bin for our string, and all shorter length bins, are
|
||||
// empty, we just push it on the stack. Otherwise, we need to start
|
||||
// concatenating, putting the given string in the "middle" and continuing
|
||||
// until we land in an empty length bin that matches the length of our
|
||||
// concatenation.
|
||||
fn insert(&mut self, bytes: Bytes) {
|
||||
let depth_bin = depth_for_len(bytes.len());
|
||||
let bin_end = MIN_LENGTH_BY_DEPTH[depth_bin as usize + 1];
|
||||
|
||||
// BAP95: Concatenate all trees occupying bins representing the length
|
||||
// of our new piece or of shorter pieces, to the extent that is
|
||||
// possible. The goal is to clear the bin which our piece belongs in,
|
||||
// but that may not be entirely possible if there aren't enough longer
|
||||
// bins occupied.
|
||||
if let Some(len) = self.peek().map(|r| r.len()) {
|
||||
if len >= bin_end {
|
||||
self.stack.push(bytes);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
let bin_start = MIN_LENGTH_BY_DEPTH[depth_bin as usize];
|
||||
|
||||
// Concatenate the subtrees of shorter length
|
||||
let mut new_tree = self.stack.pop()
|
||||
.expect("expected a value");
|
||||
|
||||
while let Some(len) = self.peek().map(|r| r.len()) {
|
||||
// If the head is big enough, break the loop
|
||||
if len >= bin_start { break; }
|
||||
|
||||
let left = self.stack.pop()
|
||||
.expect("expected a value");
|
||||
|
||||
new_tree = Bytes::of(Rope::new(left, new_tree));
|
||||
}
|
||||
|
||||
// Concatenate the given string
|
||||
new_tree = Bytes::of(Rope::new(new_tree, bytes));
|
||||
|
||||
// Continue concatenating until we land in an empty bin
|
||||
while let Some(len) = self.peek().map(|r| r.len()) {
|
||||
let depth_bin = depth_for_len(new_tree.len());
|
||||
let bin_end = MIN_LENGTH_BY_DEPTH[depth_bin as usize + 1];
|
||||
|
||||
if len < bin_end {
|
||||
let left = self.stack.pop()
|
||||
.expect("expected a value");
|
||||
|
||||
new_tree = Bytes::of(Rope::new(left, new_tree));
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
self.stack.push(new_tree);
|
||||
}
|
||||
|
||||
fn peek(&self) -> Option<&Bytes> {
|
||||
self.stack.last()
|
||||
}
|
||||
}
|
||||
|
||||
struct RopeInner {
|
||||
left: Bytes,
|
||||
right: Bytes,
|
||||
depth: u16,
|
||||
len: u32,
|
||||
}
|
||||
|
||||
impl RopeInner {
|
||||
fn new(left: Bytes, right: Bytes) -> RopeInner {
|
||||
// If left is 0 then right must be zero
|
||||
debug_assert!(!left.is_empty() || right.is_empty());
|
||||
|
||||
let len = left.len() + right.len();
|
||||
let depth = cmp::max(depth(&left), depth(&right)) + 1;
|
||||
|
||||
RopeInner {
|
||||
left: left,
|
||||
right: right,
|
||||
depth: depth,
|
||||
len: len as u32,
|
||||
}
|
||||
}
|
||||
}
|
||||
-100
@@ -1,100 +0,0 @@
|
||||
use {alloc, ByteBuf, MutBufExt, ByteStr, ROByteBuf, Rope, Bytes, ToBytes};
|
||||
use std::ops;
|
||||
|
||||
pub struct SeqByteStr {
|
||||
mem: alloc::MemRef,
|
||||
pos: u32,
|
||||
len: u32,
|
||||
}
|
||||
|
||||
impl SeqByteStr {
|
||||
/// Create a new `SeqByteStr` from a byte slice.
|
||||
///
|
||||
/// The contents of the byte slice will be copied.
|
||||
pub fn from_slice(bytes: &[u8]) -> SeqByteStr {
|
||||
let mut buf = ByteBuf::mut_with_capacity(bytes.len());
|
||||
|
||||
if let Err(e) = buf.write(bytes) {
|
||||
panic!("failed to copy bytes from slice; err={:?}", e);
|
||||
}
|
||||
|
||||
buf.flip().to_seq_byte_str()
|
||||
}
|
||||
|
||||
/// Creates a new `SeqByteStr` from a `MemRef`, an offset, and a length.
|
||||
///
|
||||
/// This function is unsafe as there are no guarantees that the given
|
||||
/// arguments are valid.
|
||||
pub unsafe fn from_mem_ref(mem: alloc::MemRef, pos: u32, len: u32) -> SeqByteStr {
|
||||
SeqByteStr {
|
||||
mem: mem,
|
||||
pos: pos,
|
||||
len: len,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ByteStr for SeqByteStr {
|
||||
type Buf = ROByteBuf;
|
||||
|
||||
fn buf(&self) -> ROByteBuf {
|
||||
unsafe {
|
||||
let pos = self.pos;
|
||||
let lim = pos + self.len;
|
||||
|
||||
ROByteBuf::from_mem_ref(self.mem.clone(), lim, pos, lim)
|
||||
}
|
||||
}
|
||||
|
||||
fn concat<B: ByteStr+'static>(&self, other: &B) -> Bytes {
|
||||
Rope::of(self.clone()).concat(other)
|
||||
}
|
||||
|
||||
fn len(&self) -> usize {
|
||||
self.len as usize
|
||||
}
|
||||
|
||||
fn slice(&self, begin: usize, end: usize) -> Bytes {
|
||||
if begin >= end || begin >= self.len() {
|
||||
return Bytes::empty()
|
||||
}
|
||||
|
||||
let bytes = unsafe {
|
||||
SeqByteStr::from_mem_ref(
|
||||
self.mem.clone(),
|
||||
self.pos + begin as u32,
|
||||
(end - begin) as u32)
|
||||
};
|
||||
|
||||
Bytes::of(bytes)
|
||||
}
|
||||
}
|
||||
|
||||
impl ToBytes for SeqByteStr {
|
||||
fn to_bytes(self) -> Bytes {
|
||||
Bytes::of(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl ops::Index<usize> for SeqByteStr {
|
||||
type Output = u8;
|
||||
|
||||
fn index(&self, index: usize) -> &u8 {
|
||||
assert!(index < self.len());
|
||||
|
||||
unsafe {
|
||||
&*self.mem.ptr()
|
||||
.offset(index as isize + self.pos as isize)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for SeqByteStr {
|
||||
fn clone(&self) -> SeqByteStr {
|
||||
SeqByteStr {
|
||||
mem: self.mem.clone(),
|
||||
pos: self.pos,
|
||||
len: self.len,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,131 +0,0 @@
|
||||
use {Bytes, Rope};
|
||||
use traits::{Buf, MutBuf, ByteStr, ToBytes};
|
||||
use std::{cmp, ops};
|
||||
|
||||
/*
|
||||
*
|
||||
* ===== SmallByteStr =====
|
||||
*
|
||||
*/
|
||||
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
const MAX_LEN: usize = 7;
|
||||
|
||||
#[cfg(target_pointer_width = "32")]
|
||||
const MAX_LEN: usize = 3;
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct SmallByteStr {
|
||||
len: u8,
|
||||
bytes: [u8; MAX_LEN],
|
||||
}
|
||||
|
||||
impl SmallByteStr {
|
||||
pub fn zero() -> SmallByteStr {
|
||||
use std::mem;
|
||||
|
||||
SmallByteStr {
|
||||
len: 0,
|
||||
bytes: unsafe { mem::zeroed() }
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_slice(bytes: &[u8]) -> Option<SmallByteStr> {
|
||||
use std::{mem, ptr};
|
||||
|
||||
if bytes.len() > MAX_LEN {
|
||||
return None;
|
||||
}
|
||||
|
||||
let mut ret = SmallByteStr {
|
||||
len: bytes.len() as u8,
|
||||
bytes: unsafe { mem::zeroed() },
|
||||
};
|
||||
|
||||
// Copy the memory
|
||||
unsafe {
|
||||
ptr::copy_nonoverlapping(
|
||||
bytes.as_ptr(),
|
||||
ret.bytes.as_mut_ptr(),
|
||||
bytes.len());
|
||||
}
|
||||
|
||||
Some(ret)
|
||||
}
|
||||
|
||||
pub fn as_slice(&self) -> &[u8] {
|
||||
&self.bytes[..self.len as usize]
|
||||
}
|
||||
}
|
||||
|
||||
impl ByteStr for SmallByteStr {
|
||||
type Buf = SmallByteStrBuf;
|
||||
|
||||
fn buf(&self) -> SmallByteStrBuf {
|
||||
SmallByteStrBuf { small: self.clone() }
|
||||
}
|
||||
|
||||
fn concat<B: ByteStr+'static>(&self, other: &B) -> Bytes {
|
||||
Rope::of(self.clone()).concat(other)
|
||||
}
|
||||
|
||||
fn len(&self) -> usize {
|
||||
self.len as usize
|
||||
}
|
||||
|
||||
fn slice(&self, begin: usize, end: usize) -> Bytes {
|
||||
Bytes::from_slice(&self.as_slice()[begin..end])
|
||||
}
|
||||
}
|
||||
|
||||
impl ToBytes for SmallByteStr {
|
||||
fn to_bytes(self) -> Bytes {
|
||||
Bytes::of(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl ops::Index<usize> for SmallByteStr {
|
||||
type Output = u8;
|
||||
|
||||
fn index(&self, index: usize) -> &u8 {
|
||||
assert!(index < self.len());
|
||||
&self.bytes[index]
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
#[allow(missing_copy_implementations)]
|
||||
pub struct SmallByteStrBuf {
|
||||
small: SmallByteStr,
|
||||
}
|
||||
|
||||
impl SmallByteStrBuf {
|
||||
fn len(&self) -> usize {
|
||||
(self.small.len & 0x0F) as usize
|
||||
}
|
||||
|
||||
fn pos(&self) -> usize {
|
||||
(self.small.len >> 4) as usize
|
||||
}
|
||||
}
|
||||
|
||||
impl Buf for SmallByteStrBuf {
|
||||
fn remaining(&self) -> usize {
|
||||
self.len() - self.pos()
|
||||
}
|
||||
|
||||
fn bytes(&self) -> &[u8] {
|
||||
&self.small.bytes[self.pos()..self.len()]
|
||||
}
|
||||
|
||||
fn advance(&mut self, mut cnt: usize) {
|
||||
cnt = cmp::min(cnt, self.remaining());
|
||||
self.small.len += (cnt as u8) << 4;
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_size_of() {
|
||||
use std::mem;
|
||||
assert_eq!(mem::size_of::<SmallByteStr>(), mem::size_of::<usize>());
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
use rand::random;
|
||||
|
||||
extern crate bytes;
|
||||
extern crate rand;
|
||||
|
||||
mod test_buf;
|
||||
mod test_buf_fill;
|
||||
mod test_buf_take;
|
||||
mod test_byte_buf;
|
||||
mod test_bytes;
|
||||
mod test_ring;
|
||||
mod test_rope;
|
||||
mod test_seq_byte_str;
|
||||
mod test_small_byte_str;
|
||||
|
||||
fn gen_bytes(n: usize) -> Vec<u8> {
|
||||
(0..n).map(|_| random()).collect()
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
use bytes::{Buf, MutBuf, MutBufExt};
|
||||
use std::usize;
|
||||
use std::io::{Cursor};
|
||||
|
||||
#[test]
|
||||
pub fn test_fresh_cursor_vec() {
|
||||
let mut buf = Cursor::new(b"hello".to_vec());
|
||||
|
||||
assert_eq!(buf.remaining(), 5);
|
||||
assert_eq!(buf.bytes(), b"hello");
|
||||
|
||||
buf.advance(2);
|
||||
|
||||
assert_eq!(buf.remaining(), 3);
|
||||
assert_eq!(buf.bytes(), b"llo");
|
||||
|
||||
buf.advance(3);
|
||||
|
||||
assert_eq!(buf.remaining(), 0);
|
||||
assert_eq!(buf.bytes(), b"");
|
||||
|
||||
buf.advance(1);
|
||||
|
||||
assert_eq!(buf.remaining(), 0);
|
||||
assert_eq!(buf.bytes(), b"");
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_vec_as_mut_buf() {
|
||||
let mut buf = Vec::with_capacity(64);
|
||||
|
||||
assert_eq!(buf.remaining(), usize::MAX);
|
||||
|
||||
unsafe {
|
||||
assert!(buf.mut_bytes().len() >= 64);
|
||||
}
|
||||
|
||||
buf.write(&b"zomg"[..]).unwrap();
|
||||
|
||||
assert_eq!(&buf, b"zomg");
|
||||
|
||||
assert_eq!(buf.remaining(), usize::MAX - 4);
|
||||
assert_eq!(buf.capacity(), 64);
|
||||
|
||||
for _ in 0..16 {
|
||||
buf.write(&b"zomg"[..]).unwrap();
|
||||
}
|
||||
|
||||
assert_eq!(buf.len(), 68);
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
use bytes::*;
|
||||
use std::io;
|
||||
|
||||
#[test]
|
||||
pub fn test_filling_buf_from_reader() {
|
||||
let mut reader = chunks(vec![b"foo", b"bar", b"baz"]);
|
||||
let mut buf = ByteBuf::mut_with_capacity(1024);
|
||||
|
||||
assert_eq!(9, buf.write(&mut reader).unwrap());
|
||||
assert_eq!(b"foobarbaz".to_bytes(), buf.flip().to_bytes());
|
||||
}
|
||||
|
||||
fn chunks(chunks: Vec<&'static [u8]>) -> Chunked {
|
||||
Chunked { chunks: chunks }
|
||||
}
|
||||
|
||||
struct Chunked {
|
||||
chunks: Vec<&'static [u8]>,
|
||||
}
|
||||
|
||||
impl io::Read for Chunked {
|
||||
fn read(&mut self, dst: &mut [u8]) -> io::Result<usize> {
|
||||
use std::{cmp, ptr};
|
||||
|
||||
if self.chunks.is_empty() {
|
||||
return Ok(0);
|
||||
}
|
||||
|
||||
let src = self.chunks[0];
|
||||
let len = cmp::min(src.len(), dst.len());
|
||||
|
||||
unsafe {
|
||||
ptr::copy_nonoverlapping(
|
||||
src[..len].as_ptr(),
|
||||
dst[..len].as_mut_ptr(),
|
||||
len);
|
||||
}
|
||||
|
||||
if len < src.len() {
|
||||
self.chunks[0] = &src[len..];
|
||||
} else {
|
||||
self.chunks.remove(0);
|
||||
}
|
||||
|
||||
Ok(len)
|
||||
}
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
use bytes::*;
|
||||
use std::io::{Cursor, Read};
|
||||
|
||||
#[test]
|
||||
pub fn test_take_from_buf() {
|
||||
let mut buf = Take::new(Cursor::new(b"hello world".to_vec()), 5);
|
||||
let mut res = vec![];
|
||||
|
||||
buf.read_to_end(&mut res);
|
||||
|
||||
assert_eq!(&res, b"hello");
|
||||
}
|
||||
@@ -1,71 +0,0 @@
|
||||
use bytes::ByteBuf;
|
||||
use bytes::traits::*;
|
||||
|
||||
#[test]
|
||||
pub fn test_initial_buf_empty() {
|
||||
let buf = ByteBuf::mut_with_capacity(100);
|
||||
|
||||
assert!(buf.capacity() == 128);
|
||||
assert!(buf.remaining() == 128);
|
||||
|
||||
let buf = buf.flip();
|
||||
|
||||
assert!(buf.remaining() == 0);
|
||||
|
||||
let buf = buf.flip();
|
||||
|
||||
assert!(buf.remaining() == 128);
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_byte_buf_bytes() {
|
||||
let mut buf = ByteBuf::mut_with_capacity(32);
|
||||
buf.write(&b"hello "[..]).unwrap();
|
||||
assert_eq!(&b"hello "[..], buf.bytes());
|
||||
|
||||
buf.write(&b"world"[..]).unwrap();
|
||||
assert_eq!(&b"hello world"[..], buf.bytes());
|
||||
let buf = buf.flip();
|
||||
assert_eq!(&b"hello world"[..], buf.bytes());
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_byte_buf_read_write() {
|
||||
let mut buf = ByteBuf::mut_with_capacity(32);
|
||||
|
||||
buf.write(&b"hello world"[..]).unwrap();
|
||||
assert_eq!(21, buf.remaining());
|
||||
|
||||
buf.write(&b" goodbye"[..]).unwrap();
|
||||
assert_eq!(13, buf.remaining());
|
||||
|
||||
let mut buf = buf.flip();
|
||||
let mut dst = [0; 5];
|
||||
|
||||
buf.mark();
|
||||
assert_eq!(5, buf.read(&mut dst[..]).unwrap());
|
||||
assert_eq!(b"hello", &dst);
|
||||
buf.reset();
|
||||
assert_eq!(5, buf.read(&mut dst[..]).unwrap());
|
||||
assert_eq!(b"hello", &dst);
|
||||
|
||||
assert_eq!(5, buf.read(&mut dst[..]).unwrap());
|
||||
assert_eq!(b" worl", &dst);
|
||||
|
||||
let mut dst = [0; 2];
|
||||
assert_eq!(2, buf.read(&mut dst[..]).unwrap());
|
||||
assert_eq!(b"d ", &dst);
|
||||
|
||||
let mut dst = [0; 7];
|
||||
assert_eq!(7, buf.read(&mut dst[..]).unwrap());
|
||||
assert_eq!(b"goodbye", &dst);
|
||||
|
||||
let mut buf = buf.resume();
|
||||
assert_eq!(13, buf.remaining());
|
||||
|
||||
buf.write(&b" have fun"[..]).unwrap();
|
||||
assert_eq!(4, buf.remaining());
|
||||
|
||||
let buf = buf.flip();
|
||||
assert_eq!(buf.bytes(), b"hello world goodbye have fun");
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
use bytes::*;
|
||||
|
||||
#[test]
|
||||
pub fn test_debug_short_str_valid_ascii() {
|
||||
let b = Bytes::from_slice(b"abcdefghij234");
|
||||
let d = format!("{:?}", b);
|
||||
|
||||
assert_eq!(d, "Bytes[len=13; abcdefghij234]");
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_debug_long_str_valid_ascii() {
|
||||
let s = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. \
|
||||
Duis volutpat eros in gravida malesuada. Phasellus lobortis \
|
||||
maximus cursus. Praesent tristique orci non purus porta \
|
||||
dapibus. Ut ut commodo risus, sed semper felis. Phasellus \
|
||||
bibendum dui nunc, ac pharetra dui viverra a. Nunc imperdiet \
|
||||
sed nulla ut condimentum. In hac habitasse platea dictumst. \
|
||||
Interdum et malesuada fames ac ante ipsum primis in faucibus. \
|
||||
Sed facilisis dictum malesuada. Sed tempor odio ullamcorper mi \
|
||||
iaculis, eu tempus diam semper. Vivamus pulvinar metus ac erat \
|
||||
aliquet aliquam.";
|
||||
|
||||
let b = Bytes::from_slice(s.as_bytes());
|
||||
|
||||
let d = format!("{:?}", b);
|
||||
|
||||
assert_eq!(d, "Bytes[len=556; Lorem ipsum dolor sit amet, \
|
||||
consectetur adipiscing elit. Duis volutpat \
|
||||
eros in gravida malesuada. Phasellus \
|
||||
lobortis maximus cur ... ]");
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_short_string_invalid_ascii() {
|
||||
let b = Bytes::from_slice(b"foo\x00bar\xFFbaz");
|
||||
let d = format!("{:?}", b);
|
||||
|
||||
println!("{:?}", b);
|
||||
|
||||
assert_eq!(d, "Bytes[len=11; foo\\x00bar\\xFFbaz]");
|
||||
}
|
||||
@@ -1,138 +0,0 @@
|
||||
use bytes::RingBuf;
|
||||
|
||||
|
||||
#[test]
|
||||
pub fn test_initial_buf_empty() {
|
||||
use bytes::traits::{Buf, BufExt, MutBuf, MutBufExt};
|
||||
|
||||
let mut buf = RingBuf::new(16);
|
||||
assert_eq!(MutBuf::remaining(&buf), 16);
|
||||
assert_eq!(Buf::remaining(&buf), 0);
|
||||
|
||||
let bytes_written = buf.write(&[1, 2, 3][..]).unwrap();
|
||||
assert_eq!(bytes_written, 3);
|
||||
|
||||
let bytes_written = buf.write(&[][..]).unwrap();
|
||||
assert_eq!(bytes_written, 0);
|
||||
assert_eq!(MutBuf::remaining(&buf), 13);
|
||||
assert_eq!(Buf::remaining(&buf), 3);
|
||||
assert_eq!(buf.bytes(), [1, 2, 3]);
|
||||
|
||||
let mut out = [0u8; 3];
|
||||
|
||||
buf.mark();
|
||||
let bytes_read = buf.read(&mut out[..]).unwrap();;
|
||||
assert_eq!(bytes_read, 3);
|
||||
assert_eq!(out, [1, 2, 3]);
|
||||
buf.reset();
|
||||
let bytes_read = buf.read(&mut out[..]).unwrap();;
|
||||
assert_eq!(bytes_read, 3);
|
||||
assert_eq!(out, [1, 2, 3]);
|
||||
|
||||
assert_eq!(MutBuf::remaining(&buf), 16);
|
||||
assert_eq!(Buf::remaining(&buf), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_wrapping_write() {
|
||||
use bytes::traits::{BufExt, MutBufExt};
|
||||
let mut buf = RingBuf::new(16);
|
||||
let mut out = [0;10];
|
||||
|
||||
buf.write(&[42;12][..]).unwrap();
|
||||
let bytes_read = buf.read(&mut out[..]).unwrap();
|
||||
assert_eq!(bytes_read, 10);
|
||||
|
||||
let bytes_written = buf.write(&[23;8][..]).unwrap();
|
||||
assert_eq!(bytes_written, 8);
|
||||
|
||||
buf.mark();
|
||||
let bytes_read = buf.read(&mut out[..]).unwrap();
|
||||
assert_eq!(bytes_read, 10);
|
||||
assert_eq!(out, [42, 42, 23, 23, 23, 23, 23, 23, 23, 23]);
|
||||
buf.reset();
|
||||
let bytes_read = buf.read(&mut out[..]).unwrap();
|
||||
assert_eq!(bytes_read, 10);
|
||||
assert_eq!(out, [42, 42, 23, 23, 23, 23, 23, 23, 23, 23]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_io_write_and_read() {
|
||||
use std::io::{Read, Write};
|
||||
|
||||
let mut buf = RingBuf::new(16);
|
||||
let mut out = [0;8];
|
||||
|
||||
let written = buf.write(&[1;8][..]).unwrap();
|
||||
assert_eq!(written, 8);
|
||||
|
||||
buf.read(&mut out).unwrap();
|
||||
assert_eq!(out, [1;8]);
|
||||
|
||||
let written = buf.write(&[2;8][..]).unwrap();
|
||||
assert_eq!(written, 8);
|
||||
|
||||
let bytes_read = buf.read(&mut out).unwrap();
|
||||
assert_eq!(bytes_read, 8);
|
||||
assert_eq!(out, [2;8]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn test_wrap_reset() {
|
||||
use std::io::{Read, Write};
|
||||
|
||||
let mut buf = RingBuf::new(8);
|
||||
buf.write(&[1, 2, 3, 4, 5, 6, 7]).unwrap();
|
||||
buf.mark();
|
||||
buf.read(&mut [0; 4]).unwrap();
|
||||
buf.write(&[1, 2, 3, 4]).unwrap();
|
||||
buf.reset();
|
||||
}
|
||||
|
||||
#[test]
|
||||
// Test that writes across a mark/reset are preserved.
|
||||
fn test_mark_write() {
|
||||
use std::io::{Read, Write};
|
||||
|
||||
let mut buf = RingBuf::new(8);
|
||||
buf.write(&[1, 2, 3, 4, 5, 6, 7]).unwrap();
|
||||
buf.mark();
|
||||
buf.write(&[8]).unwrap();
|
||||
buf.reset();
|
||||
|
||||
let mut buf2 = [0; 8];
|
||||
buf.read(&mut buf2).unwrap();
|
||||
assert_eq!(buf2, [1, 2, 3, 4, 5, 6, 7, 8]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
// Test that "RingBuf::reset" does not reset the length of a
|
||||
// full buffer to zero.
|
||||
fn test_reset_full() {
|
||||
use bytes::traits::MutBuf;
|
||||
use std::io::Write;
|
||||
|
||||
let mut buf = RingBuf::new(8);
|
||||
buf.write(&[1, 2, 3, 4, 5, 6, 7, 8]).unwrap();
|
||||
assert_eq!(MutBuf::remaining(&buf), 0);
|
||||
buf.mark();
|
||||
buf.reset();
|
||||
assert_eq!(MutBuf::remaining(&buf), 0);
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
// Test that "RingBuf::clear" does the full reset
|
||||
fn test_clear() {
|
||||
use bytes::traits::{Buf, MutBuf};
|
||||
use std::io::Write;
|
||||
|
||||
let mut buf = RingBuf::new(8);
|
||||
buf.write(&[0; 8]).unwrap();
|
||||
assert_eq!(MutBuf::remaining(&buf), 0);
|
||||
assert_eq!(Buf::remaining(&buf), 8);
|
||||
buf.clear();
|
||||
assert_eq!(MutBuf::remaining(&buf), 8);
|
||||
assert_eq!(Buf::remaining(&buf), 0);
|
||||
}
|
||||
@@ -1,107 +0,0 @@
|
||||
use bytes::Rope;
|
||||
use bytes::traits::*;
|
||||
use super::gen_bytes;
|
||||
|
||||
const TEST_BYTES_1: &'static [u8] =
|
||||
b"dblm4ng7jp4v9rdn1w6hhssmluoqrrrqj59rccl9
|
||||
nkv2tm1t2da4jyku51ge7f8hv581gkki8lekmf5f
|
||||
1l44whp4aiwbvhkziw02292on4noyvuwjzsloqyc
|
||||
5n0iyn4l6o6tgjhlek00mynfzb1wgcwj4mqp6zdr
|
||||
3625yy7rj7xuisal7b1a7xgq271abvt5ssxuj39v
|
||||
njtetokxxrgxzp7ik9adnypkmmcn4270yv9l46m7
|
||||
9mu2zmqmkxdmgia210vkdytb7ywfcyt2bvcsg9eq
|
||||
5yqizxl6888zrksvaxhzs2v355jxu8gr21m33t83
|
||||
qvoian1ra7c6pvxabshgngldxa408p18l1fdet2h";
|
||||
|
||||
const TEST_BYTES_2: &'static [u8] =
|
||||
b"jmh14t79mllzj1ohxfj6fun7idwbks8oh35f83g6
|
||||
ryaowe86mmou5t1xa91uyg8e95wcu5mje1mswien
|
||||
tt4clgj029cw0pyuvfbvsgzdg1x7sr9qsjkf2b1t
|
||||
h43smgp1ea22lph17f78cel0cc2kjoht5281xuy8
|
||||
0ex9uaqwj4330jrp30stsk15j9bpqezu3w78ktit
|
||||
ev5g6xsngr35q7pemdm9hihf0ebrw5fbwhm530lo
|
||||
e0zyj1bm7yfyk7f2i45jhr3wu3bvb4hj8jve6db0
|
||||
iewmr9weecaon9vdnqo5hen9iaiox5vsaxuo461m
|
||||
8336ugp20u4sfky3kfawr0ome1tiqyx8chkerrjh
|
||||
a95s0gypcsgo9jqxasqkoj08t4uq5moxmay5plg5
|
||||
tlh6f9omhn0ezvi0w2n8hx7n6qk7rn1s3mjpnpl6
|
||||
hvilp8awaa4tvsis66q4e5b3xwy2z1h2klpa87h7";
|
||||
|
||||
#[test]
|
||||
pub fn test_rope_round_trip() {
|
||||
let rope = Rope::from_slice(b"zomg");
|
||||
|
||||
assert_eq!(4, rope.len());
|
||||
|
||||
let mut dst = vec![];
|
||||
rope.buf().read(&mut dst).unwrap();
|
||||
|
||||
assert_eq!(b"zomg", &dst[..]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_rope_slice() {
|
||||
let mut dst = vec![];
|
||||
|
||||
let bytes = Rope::from_slice(TEST_BYTES_1);
|
||||
assert_eq!(TEST_BYTES_1.len(), bytes.len());
|
||||
|
||||
bytes.buf().read(&mut dst).unwrap();
|
||||
assert_eq!(dst, TEST_BYTES_1);
|
||||
|
||||
let left = bytes.slice_to(250);
|
||||
assert_eq!(250, left.len());
|
||||
|
||||
left.buf().read(&mut dst).unwrap();
|
||||
assert_eq!(dst, &TEST_BYTES_1[..250]);
|
||||
|
||||
let right = bytes.slice_from(250);
|
||||
assert_eq!(TEST_BYTES_1.len() - 250, right.len());
|
||||
|
||||
right.buf().read(&mut dst).unwrap();
|
||||
assert_eq!(dst, &TEST_BYTES_1[250..]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_rope_concat_two_byte_str() {
|
||||
let mut dst = vec![];
|
||||
|
||||
let left = Rope::from_slice(TEST_BYTES_1);
|
||||
let right = Rope::from_slice(TEST_BYTES_2);
|
||||
|
||||
let both = left.concat(&right);
|
||||
|
||||
assert_eq!(both.len(), TEST_BYTES_1.len() + TEST_BYTES_2.len());
|
||||
|
||||
both.buf().read(&mut dst).unwrap();
|
||||
let mut expected = Vec::new();
|
||||
expected.extend(TEST_BYTES_1.iter().cloned());
|
||||
expected.extend(TEST_BYTES_2.iter().cloned());
|
||||
assert_eq!(dst, expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore]
|
||||
pub fn test_slice_parity() {
|
||||
let bytes = gen_bytes(2048 * 1024);
|
||||
let start = 512 * 1024 - 3333;
|
||||
let end = 512 * 1024 + 7777;
|
||||
|
||||
let _ = Rope::from_slice(&bytes).slice(start, end);
|
||||
|
||||
// stuff
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_rope_equality() {
|
||||
let a = &b"Mary had a little lamb, its fleece was white as snow; ".to_bytes()
|
||||
.concat(&b"And everywhere that Mary went, the lamb was sure to go.".to_bytes());
|
||||
|
||||
let b = &b"Mary had a little lamb, ".to_bytes()
|
||||
.concat(&b"its fleece was white as snow; ".to_bytes())
|
||||
.concat(
|
||||
&b"And everywhere that Mary went, ".to_bytes()
|
||||
.concat(&b"the lamb was sure to go.".to_bytes()));
|
||||
|
||||
assert_eq!(a, b);
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
use bytes::SeqByteStr;
|
||||
use bytes::traits::*;
|
||||
use super::gen_bytes;
|
||||
|
||||
#[test]
|
||||
pub fn test_slice_round_trip() {
|
||||
let mut dst = vec![];
|
||||
let src = gen_bytes(2000);
|
||||
|
||||
let s = SeqByteStr::from_slice(&src);
|
||||
assert_eq!(2000, s.len());
|
||||
|
||||
s.buf().read(&mut dst).unwrap();
|
||||
assert_eq!(dst, src);
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_index() {
|
||||
let src = gen_bytes(2000);
|
||||
|
||||
let s = SeqByteStr::from_slice(&src);
|
||||
|
||||
for i in 0..2000 {
|
||||
assert_eq!(src[i], s[i]);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
pub fn test_index_out_of_range() {
|
||||
let s = SeqByteStr::from_slice(&gen_bytes(2000));
|
||||
let _ = s[2001];
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
use bytes::SmallByteStr;
|
||||
use bytes::traits::*;
|
||||
use super::gen_bytes;
|
||||
|
||||
#[test]
|
||||
pub fn test_slice_round_trip() {
|
||||
let mut dst = vec![];
|
||||
let src = gen_bytes(3);
|
||||
|
||||
let s = SmallByteStr::from_slice(&src).unwrap();
|
||||
assert_eq!(3, s.len());
|
||||
|
||||
s.buf().read(&mut dst).unwrap();
|
||||
assert_eq!(dst, src);
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_index() {
|
||||
let src = gen_bytes(3);
|
||||
|
||||
let s = SmallByteStr::from_slice(&src).unwrap();
|
||||
|
||||
for i in 0..3 {
|
||||
assert_eq!(src[i], s[i]);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
pub fn test_index_out_of_range() {
|
||||
let s = SmallByteStr::from_slice(&gen_bytes(3)).unwrap();
|
||||
let _ = s[2001];
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
extern crate bytes;
|
||||
extern crate byteorder;
|
||||
|
||||
use bytes::Buf;
|
||||
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"");
|
||||
|
||||
buf.advance(1);
|
||||
|
||||
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>();
|
||||
}
|
||||
@@ -0,0 +1,295 @@
|
||||
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 = format!("{:?}", 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 drain_to_1() {
|
||||
// Inline
|
||||
let mut a = Bytes::from(SHORT);
|
||||
let b = a.drain_to(4);
|
||||
|
||||
assert_eq!(SHORT[4..], a);
|
||||
assert_eq!(SHORT[..4], b);
|
||||
|
||||
// Allocated
|
||||
let mut a = Bytes::from(LONG);
|
||||
let b = a.drain_to(4);
|
||||
|
||||
assert_eq!(LONG[4..], a);
|
||||
assert_eq!(LONG[..4], b);
|
||||
|
||||
let mut a = Bytes::from(LONG);
|
||||
let b = a.drain_to(30);
|
||||
|
||||
assert_eq!(LONG[30..], a);
|
||||
assert_eq!(LONG[..30], b);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn drain_to_2() {
|
||||
let mut a = Bytes::from(LONG);
|
||||
assert_eq!(LONG, a);
|
||||
|
||||
let b = a.drain_to(1);
|
||||
|
||||
assert_eq!(LONG[1..], a);
|
||||
drop(b);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn drain_to_oob() {
|
||||
let mut hello = Bytes::from(&b"helloworld"[..]);
|
||||
hello.drain_to(inline_cap() + 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn drain_to_oob_mut() {
|
||||
let mut hello = BytesMut::from(&b"helloworld"[..]);
|
||||
hello.drain_to(inline_cap() + 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn drain_to_uninitialized() {
|
||||
let mut bytes = BytesMut::with_capacity(1024);
|
||||
let other = bytes.drain_to(128);
|
||||
|
||||
assert_eq!(bytes.len(), 0);
|
||||
assert_eq!(bytes.capacity(), 896);
|
||||
|
||||
assert_eq!(other.len(), 0);
|
||||
assert_eq!(other.capacity(), 128);
|
||||
}
|
||||
|
||||
#[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.drain_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.drain_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.drain();
|
||||
|
||||
bytes.reserve(65);
|
||||
assert_eq!(bytes.capacity(), 128);
|
||||
}
|
||||
|
||||
#[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 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(BytesMut::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 = buf.clone();
|
||||
}));
|
||||
}
|
||||
|
||||
for th in joins {
|
||||
th.join().unwrap();
|
||||
}
|
||||
|
||||
assert_eq!(*buf, data[..]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
extern crate bytes;
|
||||
extern crate byteorder;
|
||||
|
||||
use bytes::{BufMut, BytesMut};
|
||||
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);
|
||||
}
|
||||
Reference in New Issue
Block a user