mirror of
https://github.com/tokio-rs/bytes.git
synced 2026-08-08 00:00:26 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d43e283e5e | ||
|
|
e0e30f00a1 | ||
|
|
4948b1053b | ||
|
|
0e8b440650 | ||
|
|
e13d2a783e | ||
|
|
55dfea8c18 | ||
|
|
f3b363a385 | ||
|
|
42b669690a | ||
|
|
9504447adc | ||
|
|
b3248c8807 | ||
|
|
c6c5b8fb54 | ||
|
|
7c3085aaec | ||
|
|
e64a123d00 | ||
|
|
e5304410a4 | ||
|
|
456221d165 | ||
|
|
f09c51c34e | ||
|
|
ad35fbef03 | ||
|
|
79f05591c9 | ||
|
|
ed244d3b54 | ||
|
|
890812af1b | ||
|
|
052648c3f5 | ||
|
|
042aa9023b | ||
|
|
886dda0962 | ||
|
|
6414efe83b | ||
|
|
7785cde587 | ||
|
|
a6b9844296 |
@@ -36,6 +36,12 @@ matrix:
|
||||
# Serde implementation
|
||||
- env: EXTRA_ARGS="--features serde"
|
||||
|
||||
# 128 bit numbers
|
||||
- env: EXTRA_ARGS="--features i128"
|
||||
|
||||
# `Either` impls
|
||||
- env: EXTRA_ARGS="--features either"
|
||||
|
||||
# WASM support
|
||||
- rust: beta
|
||||
script:
|
||||
|
||||
@@ -1,3 +1,25 @@
|
||||
# 0.4.12 (March 6, 2019)
|
||||
|
||||
### Added
|
||||
- Implement `FromIterator<&'a u8>` for `BytesMut`/`Bytes` (#244).
|
||||
- Implement `Buf` for `VecDeque` (#249).
|
||||
|
||||
# 0.4.11 (November 17, 2018)
|
||||
|
||||
* Use raw pointers for potentially racy loads (#233).
|
||||
* Implement `BufRead` for `buf::Reader` (#232).
|
||||
* Documentation tweaks (#234).
|
||||
|
||||
# 0.4.10 (September 4, 2018)
|
||||
|
||||
* impl `Buf` and `BufMut` for `Either` (#225).
|
||||
* Add `Bytes::slice_ref` (#208).
|
||||
|
||||
# 0.4.9 (July 12, 2018)
|
||||
|
||||
* Add 128 bit number support behind a feature flag (#209).
|
||||
* Implement `IntoBuf` for `&mut [u8]`
|
||||
|
||||
# 0.4.8 (May 25, 2018)
|
||||
|
||||
* Fix panic in `BytesMut` `FromIterator` implementation.
|
||||
|
||||
+16
-4
@@ -1,11 +1,16 @@
|
||||
[package]
|
||||
|
||||
name = "bytes"
|
||||
version = "0.4.8" # don't forget to update html_root_url
|
||||
license = "MIT/Apache-2.0"
|
||||
# When releasing to crates.io:
|
||||
# - Update html_root_url.
|
||||
# - Update CHANGELOG.md.
|
||||
# - Update doc URL.
|
||||
# - Create "v0.4.x" git tag.
|
||||
version = "0.4.12"
|
||||
license = "MIT"
|
||||
authors = ["Carl Lerche <[email protected]>"]
|
||||
description = "Types and traits for working with bytes"
|
||||
documentation = "https://carllerche.github.io/bytes/bytes"
|
||||
documentation = "https://docs.rs/bytes/0.4.12/bytes"
|
||||
homepage = "https://github.com/carllerche/bytes"
|
||||
repository = "https://github.com/carllerche/bytes"
|
||||
readme = "README.md"
|
||||
@@ -19,10 +24,17 @@ exclude = [
|
||||
]
|
||||
categories = ["network-programming", "data-structures"]
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
features = ["i128"]
|
||||
|
||||
[dependencies]
|
||||
byteorder = "1.0.0"
|
||||
byteorder = "1.1.0"
|
||||
iovec = "0.1"
|
||||
serde = { version = "1.0", optional = true }
|
||||
either = { version = "1.5", default-features = false, optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
serde_test = "1.0"
|
||||
|
||||
[features]
|
||||
i128 = ["byteorder/i128"]
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Copyright (c) 2017 Carl Lerche
|
||||
Copyright (c) 2018 Carl Lerche
|
||||
|
||||
Permission is hereby granted, free of charge, to any
|
||||
person obtaining a copy of this software and associated
|
||||
-201
@@ -1,201 +0,0 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright 2017 Carl Lerche
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
@@ -5,7 +5,7 @@ A utility library for working with bytes.
|
||||
[](https://crates.io/crates/bytes)
|
||||
[](https://travis-ci.org/carllerche/bytes)
|
||||
|
||||
[Documentation](https://carllerche.github.io/bytes/bytes/index.html)
|
||||
[Documentation](https://docs.rs/bytes/0.4.12/bytes/)
|
||||
|
||||
## Usage
|
||||
|
||||
@@ -13,7 +13,7 @@ To use `bytes`, first add this to your `Cargo.toml`:
|
||||
|
||||
```toml
|
||||
[dependencies]
|
||||
bytes = "0.4"
|
||||
bytes = "0.4.12"
|
||||
```
|
||||
|
||||
Next, add this to your crate:
|
||||
@@ -30,13 +30,16 @@ Serde support is optional and disabled by default. To enable use the feature `se
|
||||
|
||||
```toml
|
||||
[dependencies]
|
||||
bytes = { version = "0.4", features = ["serde"] }
|
||||
bytes = { version = "0.4.12", features = ["serde"] }
|
||||
```
|
||||
|
||||
# License
|
||||
## License
|
||||
|
||||
`bytes` is primarily distributed under the terms of both the MIT license and the
|
||||
Apache License (Version 2.0), with portions covered by various BSD-like
|
||||
licenses.
|
||||
This project is licensed under the [MIT license](LICENSE).
|
||||
|
||||
### Contribution
|
||||
|
||||
Unless you explicitly state otherwise, any contribution intentionally submitted
|
||||
for inclusion in `bytes` by you, shall be licensed as MIT, without any additional
|
||||
terms or conditions.
|
||||
|
||||
See LICENSE-APACHE, and LICENSE-MIT for details.
|
||||
|
||||
@@ -113,6 +113,39 @@ fn deref_two(b: &mut Bencher) {
|
||||
})
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn clone_inline(b: &mut Bencher) {
|
||||
let bytes = Bytes::from_static(b"hello world");
|
||||
|
||||
b.iter(|| {
|
||||
for _ in 0..1024 {
|
||||
test::black_box(&bytes.clone());
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn clone_static(b: &mut Bencher) {
|
||||
let bytes = Bytes::from_static("hello world 1234567890 and have a good byte 0987654321".as_bytes());
|
||||
|
||||
b.iter(|| {
|
||||
for _ in 0..1024 {
|
||||
test::black_box(&bytes.clone());
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn clone_arc(b: &mut Bencher) {
|
||||
let bytes = Bytes::from("hello world 1234567890 and have a good byte 0987654321".as_bytes());
|
||||
|
||||
b.iter(|| {
|
||||
for _ in 0..1024 {
|
||||
test::black_box(&bytes.clone());
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn alloc_write_split_to_mid(b: &mut Bencher) {
|
||||
b.iter(|| {
|
||||
|
||||
@@ -9,6 +9,9 @@ race:arc*Weak*drop
|
||||
# rust runtime logic.
|
||||
race:std*mpsc_queue
|
||||
|
||||
# Some test runtime races. Allocation should be race free
|
||||
race:alloc::alloc
|
||||
|
||||
# Not sure why this is warning, but it is in the test harness and not the library.
|
||||
race:TestEvent*clone
|
||||
race:test::run_tests_console::*closure
|
||||
@@ -16,6 +19,10 @@ race:test::run_tests_console::*closure
|
||||
# Probably more fences in std.
|
||||
race:__call_tls_dtors
|
||||
|
||||
# `is_inline` is explicitly called concurrently without synchronization. The
|
||||
# safety explanation can be found in a comment.
|
||||
race:Inner::is_inline
|
||||
# `is_inline_or_static` is explicitly called concurrently without synchronization.
|
||||
# The safety explanation can be found in a comment.
|
||||
race:Inner::is_inline_or_static
|
||||
|
||||
# This ignores a false positive caused by `thread::park()`/`thread::unpark()`.
|
||||
# See: https://github.com/rust-lang/rust/pull/54806#issuecomment-436193353
|
||||
race:pthread_cond_destroy
|
||||
|
||||
+94
-1
@@ -91,7 +91,8 @@ pub trait Buf {
|
||||
fn remaining(&self) -> usize;
|
||||
|
||||
/// Returns a slice starting at the current position and of length between 0
|
||||
/// and `Buf::remaining()`.
|
||||
/// and `Buf::remaining()`. Note that this *can* return shorter slice (this allows
|
||||
/// non-continuous internal representation).
|
||||
///
|
||||
/// This is a lower level function. Most operations are done with other
|
||||
/// functions.
|
||||
@@ -605,6 +606,98 @@ pub trait Buf {
|
||||
buf_get_impl!(self, 8, LittleEndian::read_i64);
|
||||
}
|
||||
|
||||
/// Gets an unsigned 128 bit integer from `self` in big-endian byte order.
|
||||
///
|
||||
/// **NOTE:** This method requires the `i128` feature.
|
||||
/// The current position is advanced by 16.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use bytes::Buf;
|
||||
/// use std::io::Cursor;
|
||||
///
|
||||
/// let mut buf = Cursor::new(b"\x01\x02\x03\x04\x05\x06\x07\x08\x09\x10\x11\x12\x13\x14\x15\x16 hello");
|
||||
/// assert_eq!(0x01020304050607080910111213141516, buf.get_u128_be());
|
||||
/// ```
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// This function panics if there is not enough remaining data in `self`.
|
||||
#[cfg(feature = "i128")]
|
||||
fn get_u128_be(&mut self) -> u128 {
|
||||
buf_get_impl!(self, 16, BigEndian::read_u128);
|
||||
}
|
||||
|
||||
/// Gets an unsigned 128 bit integer from `self` in little-endian byte order.
|
||||
///
|
||||
/// **NOTE:** This method requires the `i128` feature.
|
||||
/// The current position is advanced by 16.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use bytes::Buf;
|
||||
/// use std::io::Cursor;
|
||||
///
|
||||
/// let mut buf = Cursor::new(b"\x16\x15\x14\x13\x12\x11\x10\x09\x08\x07\x06\x05\x04\x03\x02\x01 hello");
|
||||
/// assert_eq!(0x01020304050607080910111213141516, buf.get_u128_le());
|
||||
/// ```
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// This function panics if there is not enough remaining data in `self`.
|
||||
#[cfg(feature = "i128")]
|
||||
fn get_u128_le(&mut self) -> u128 {
|
||||
buf_get_impl!(self, 16, LittleEndian::read_u128);
|
||||
}
|
||||
|
||||
/// Gets a signed 128 bit integer from `self` in big-endian byte order.
|
||||
///
|
||||
/// **NOTE:** This method requires the `i128` feature.
|
||||
/// The current position is advanced by 16.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use bytes::Buf;
|
||||
/// use std::io::Cursor;
|
||||
///
|
||||
/// let mut buf = Cursor::new(b"\x01\x02\x03\x04\x05\x06\x07\x08\x09\x10\x11\x12\x13\x14\x15\x16 hello");
|
||||
/// assert_eq!(0x01020304050607080910111213141516, buf.get_i128_be());
|
||||
/// ```
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// This function panics if there is not enough remaining data in `self`.
|
||||
#[cfg(feature = "i128")]
|
||||
fn get_i128_be(&mut self) -> i128 {
|
||||
buf_get_impl!(self, 16, BigEndian::read_i128);
|
||||
}
|
||||
|
||||
/// Gets a signed 128 bit integer from `self` in little-endian byte order.
|
||||
///
|
||||
/// **NOTE:** This method requires the `i128` feature.
|
||||
/// The current position is advanced by 16.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use bytes::Buf;
|
||||
/// use std::io::Cursor;
|
||||
///
|
||||
/// let mut buf = Cursor::new(b"\x16\x15\x14\x13\x12\x11\x10\x09\x08\x07\x06\x05\x04\x03\x02\x01 hello");
|
||||
/// assert_eq!(0x01020304050607080910111213141516, buf.get_i128_le());
|
||||
/// ```
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// This function panics if there is not enough remaining data in `self`.
|
||||
#[cfg(feature = "i128")]
|
||||
fn get_i128_le(&mut self) -> i128 {
|
||||
buf_get_impl!(self, 16, LittleEndian::read_i128);
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[deprecated(note="use get_uint_be or get_uint_le")]
|
||||
fn get_uint<T: ByteOrder>(&mut self, nbytes: usize) -> u64 where Self: Sized {
|
||||
|
||||
+106
-1
@@ -121,7 +121,8 @@ pub trait BufMut {
|
||||
}
|
||||
|
||||
/// Returns a mutable slice starting at the current BufMut position and of
|
||||
/// length between 0 and `BufMut::remaining_mut()`.
|
||||
/// length between 0 and `BufMut::remaining_mut()`. Note that this *can* be shorter than the
|
||||
/// whole remainder of the buffer (this allows non-continuous implementation).
|
||||
///
|
||||
/// This is a lower level function. Most operations are done with other
|
||||
/// functions.
|
||||
@@ -674,6 +675,110 @@ pub trait BufMut {
|
||||
self.put_slice(&buf)
|
||||
}
|
||||
|
||||
/// Writes an unsigned 128 bit integer to `self` in the big-endian byte order.
|
||||
///
|
||||
/// **NOTE:** This method requires the `i128` feature.
|
||||
/// The current position is advanced by 16.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use bytes::BufMut;
|
||||
///
|
||||
/// let mut buf = vec![];
|
||||
/// buf.put_u128_be(0x01020304050607080910111213141516);
|
||||
/// assert_eq!(buf, b"\x01\x02\x03\x04\x05\x06\x07\x08\x09\x10\x11\x12\x13\x14\x15\x16");
|
||||
/// ```
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// This function panics if there is not enough remaining capacity in
|
||||
/// `self`.
|
||||
#[cfg(feature = "i128")]
|
||||
fn put_u128_be(&mut self, n: u128) {
|
||||
let mut buf = [0; 16];
|
||||
BigEndian::write_u128(&mut buf, n);
|
||||
self.put_slice(&buf)
|
||||
}
|
||||
|
||||
/// Writes an unsigned 128 bit integer to `self` in little-endian byte order.
|
||||
///
|
||||
/// **NOTE:** This method requires the `i128` feature.
|
||||
/// The current position is advanced by 16.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use bytes::BufMut;
|
||||
///
|
||||
/// let mut buf = vec![];
|
||||
/// buf.put_u128_le(0x01020304050607080910111213141516);
|
||||
/// assert_eq!(buf, b"\x16\x15\x14\x13\x12\x11\x10\x09\x08\x07\x06\x05\x04\x03\x02\x01");
|
||||
/// ```
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// This function panics if there is not enough remaining capacity in
|
||||
/// `self`.
|
||||
#[cfg(feature = "i128")]
|
||||
fn put_u128_le(&mut self, n: u128) {
|
||||
let mut buf = [0; 16];
|
||||
LittleEndian::write_u128(&mut buf, n);
|
||||
self.put_slice(&buf)
|
||||
}
|
||||
|
||||
/// Writes a signed 128 bit integer to `self` in the big-endian byte order.
|
||||
///
|
||||
/// **NOTE:** This method requires the `i128` feature.
|
||||
/// The current position is advanced by 16.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use bytes::BufMut;
|
||||
///
|
||||
/// let mut buf = vec![];
|
||||
/// buf.put_i128_be(0x01020304050607080910111213141516);
|
||||
/// assert_eq!(buf, b"\x01\x02\x03\x04\x05\x06\x07\x08\x09\x10\x11\x12\x13\x14\x15\x16");
|
||||
/// ```
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// This function panics if there is not enough remaining capacity in
|
||||
/// `self`.
|
||||
#[cfg(feature = "i128")]
|
||||
fn put_i128_be(&mut self, n: i128) {
|
||||
let mut buf = [0; 16];
|
||||
BigEndian::write_i128(&mut buf, n);
|
||||
self.put_slice(&buf)
|
||||
}
|
||||
|
||||
/// Writes a signed 128 bit integer to `self` in little-endian byte order.
|
||||
///
|
||||
/// **NOTE:** This method requires the `i128` feature.
|
||||
/// The current position is advanced by 16.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use bytes::BufMut;
|
||||
///
|
||||
/// let mut buf = vec![];
|
||||
/// buf.put_i128_le(0x01020304050607080910111213141516);
|
||||
/// assert_eq!(buf, b"\x16\x15\x14\x13\x12\x11\x10\x09\x08\x07\x06\x05\x04\x03\x02\x01");
|
||||
/// ```
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// This function panics if there is not enough remaining capacity in
|
||||
/// `self`.
|
||||
#[cfg(feature = "i128")]
|
||||
fn put_i128_le(&mut self, n: i128) {
|
||||
let mut buf = [0; 16];
|
||||
LittleEndian::write_i128(&mut buf, n);
|
||||
self.put_slice(&buf)
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[deprecated(note="use put_uint_be or put_uint_le")]
|
||||
fn put_uint<T: ByteOrder>(&mut self, n: u64, nbytes: usize) where Self: Sized {
|
||||
|
||||
@@ -63,6 +63,14 @@ impl<'a> IntoBuf for &'a [u8] {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> IntoBuf for &'a mut [u8] {
|
||||
type Buf = io::Cursor<&'a mut [u8]>;
|
||||
|
||||
fn into_buf(self) -> Self::Buf {
|
||||
io::Cursor::new(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> IntoBuf for &'a str {
|
||||
type Buf = io::Cursor<&'a [u8]>;
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@ mod into_buf;
|
||||
mod iter;
|
||||
mod reader;
|
||||
mod take;
|
||||
mod vec_deque;
|
||||
mod writer;
|
||||
|
||||
pub use self::buf::Buf;
|
||||
|
||||
@@ -86,3 +86,12 @@ impl<B: Buf + Sized> io::Read for Reader<B> {
|
||||
Ok(len)
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: Buf + Sized> io::BufRead for Reader<B> {
|
||||
fn fill_buf(&mut self) -> io::Result<&[u8]> {
|
||||
Ok(self.buf.bytes())
|
||||
}
|
||||
fn consume(&mut self, amt: usize) {
|
||||
self.buf.advance(amt)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
use std::collections::VecDeque;
|
||||
|
||||
use super::Buf;
|
||||
|
||||
impl Buf for VecDeque<u8> {
|
||||
fn remaining(&self) -> usize {
|
||||
self.len()
|
||||
}
|
||||
|
||||
fn bytes(&self) -> &[u8] {
|
||||
let (s1, s2) = self.as_slices();
|
||||
if s1.is_empty() {
|
||||
s2
|
||||
} else {
|
||||
s1
|
||||
}
|
||||
}
|
||||
|
||||
fn advance(&mut self, cnt: usize) {
|
||||
self.drain(..cnt);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn hello_world() {
|
||||
let mut buffer: VecDeque<u8> = VecDeque::new();
|
||||
buffer.extend(b"hello world");
|
||||
assert_eq!(11, buffer.remaining());
|
||||
assert_eq!(b"hello world", buffer.bytes());
|
||||
buffer.advance(6);
|
||||
assert_eq!(b"world", buffer.bytes());
|
||||
buffer.extend(b" piece");
|
||||
assert_eq!(b"world piece" as &[u8], &buffer.collect::<Vec<u8>>()[..]);
|
||||
}
|
||||
}
|
||||
+261
-141
@@ -95,11 +95,12 @@ use std::iter::{FromIterator, Iterator};
|
||||
/// # Inline bytes
|
||||
///
|
||||
/// As an optimization, when the slice referenced by a `Bytes` or `BytesMut`
|
||||
/// handle is small enough [1], `Bytes` will avoid the allocation by inlining
|
||||
/// the slice directly in the handle. In this case, a clone is no longer
|
||||
/// "shallow" and the data will be copied.
|
||||
/// handle is small enough [^1], `with_capacity` will avoid the allocation by
|
||||
/// inlining the slice directly in the handle. In this case, a clone is no
|
||||
/// longer "shallow" and the data will be copied. Converting from a `Vec` will
|
||||
/// never use inlining.
|
||||
///
|
||||
/// [1] Small enough: 31 bytes on 64 bit systems, 15 on 32 bit systems.
|
||||
/// [^1]: Small enough: 31 bytes on 64 bit systems, 15 on 32 bit systems.
|
||||
///
|
||||
pub struct Bytes {
|
||||
inner: Inner,
|
||||
@@ -272,7 +273,7 @@ pub struct BytesMut {
|
||||
// The rest of `arc`'s bytes are used as part of the inline buffer, which means
|
||||
// that those bytes need to be located next to the `ptr`, `len`, and `cap`
|
||||
// fields, which make up the rest of the inline buffer. This requires special
|
||||
// casing the layout of `Inner` depending on if the target platform is bit or
|
||||
// casing the layout of `Inner` depending on if the target platform is big or
|
||||
// little endian.
|
||||
//
|
||||
// On little endian platforms, the `arc` field must be the first field in the
|
||||
@@ -464,6 +465,7 @@ impl Bytes {
|
||||
/// let b = Bytes::from(&b"hello"[..]);
|
||||
/// assert_eq!(b.len(), 5);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn len(&self) -> usize {
|
||||
self.inner.len()
|
||||
}
|
||||
@@ -478,6 +480,7 @@ impl Bytes {
|
||||
/// let b = Bytes::new();
|
||||
/// assert!(b.is_empty());
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.inner.is_empty()
|
||||
}
|
||||
@@ -573,6 +576,46 @@ impl Bytes {
|
||||
self.slice(0, end)
|
||||
}
|
||||
|
||||
/// Returns a slice of self that is equivalent to the given `subset`.
|
||||
///
|
||||
/// When processing a `Bytes` buffer with other tools, one often gets a
|
||||
/// `&[u8]` which is in fact a slice of the `Bytes`, i.e. a subset of it.
|
||||
/// This function turns that `&[u8]` into another `Bytes`, as if one had
|
||||
/// called `self.slice()` with the offsets that correspond to `subset`.
|
||||
///
|
||||
/// This operation is `O(1)`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use bytes::Bytes;
|
||||
///
|
||||
/// let bytes = Bytes::from(&b"012345678"[..]);
|
||||
/// let as_slice = bytes.as_ref();
|
||||
/// let subset = &as_slice[2..6];
|
||||
/// let subslice = bytes.slice_ref(&subset);
|
||||
/// assert_eq!(&subslice[..], b"2345");
|
||||
/// ```
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Requires that the given `sub` slice is in fact contained within the
|
||||
/// `Bytes` buffer; otherwise this function will panic.
|
||||
pub fn slice_ref(&self, subset: &[u8]) -> Bytes {
|
||||
let bytes_p = self.as_ptr() as usize;
|
||||
let bytes_len = self.len();
|
||||
|
||||
let sub_p = subset.as_ptr() as usize;
|
||||
let sub_len = subset.len();
|
||||
|
||||
assert!(sub_p >= bytes_p);
|
||||
assert!(sub_p + sub_len <= bytes_p + bytes_len);
|
||||
|
||||
let sub_offset = sub_p - bytes_p;
|
||||
|
||||
self.slice(sub_offset, sub_offset + sub_len)
|
||||
}
|
||||
|
||||
/// Splits the bytes into two at the given index.
|
||||
///
|
||||
/// Afterwards `self` contains elements `[0, at)`, and the returned `Bytes`
|
||||
@@ -883,6 +926,18 @@ impl FromIterator<u8> for Bytes {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> FromIterator<&'a u8> for BytesMut {
|
||||
fn from_iter<T: IntoIterator<Item = &'a u8>>(into_iter: T) -> Self {
|
||||
BytesMut::from_iter(into_iter.into_iter().map(|b| *b))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> FromIterator<&'a u8> for Bytes {
|
||||
fn from_iter<T: IntoIterator<Item = &'a u8>>(into_iter: T) -> Self {
|
||||
BytesMut::from_iter(into_iter).freeze()
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for Bytes {
|
||||
fn eq(&self, other: &Bytes) -> bool {
|
||||
self.inner.as_ref() == other.inner.as_ref()
|
||||
@@ -1210,6 +1265,8 @@ impl BytesMut {
|
||||
///
|
||||
/// Panics if `at > len`.
|
||||
pub fn split_to(&mut self, at: usize) -> BytesMut {
|
||||
assert!(at <= self.len());
|
||||
|
||||
BytesMut {
|
||||
inner: self.inner.split_to(at),
|
||||
}
|
||||
@@ -2051,126 +2108,139 @@ impl Inner {
|
||||
unsafe fn shallow_clone(&self, mut_self: bool) -> Inner {
|
||||
// Always check `inline` first, because if the handle is using inline
|
||||
// data storage, all of the `Inner` struct fields will be gibberish.
|
||||
if self.is_inline() {
|
||||
// In this case, a shallow_clone still involves copying the data.
|
||||
//
|
||||
// TODO: Just copy the fields
|
||||
let mut inner: Inner = mem::uninitialized();
|
||||
let len = self.inline_len();
|
||||
//
|
||||
// Additionally, if kind is STATIC, then Arc is *never* changed, making
|
||||
// it safe and faster to check for it now before an atomic acquire.
|
||||
|
||||
inner.arc = AtomicPtr::new(KIND_INLINE as *mut Shared);
|
||||
inner.set_inline_len(len);
|
||||
inner.as_raw()[0..len].copy_from_slice(self.as_ref());
|
||||
if self.is_inline_or_static() {
|
||||
// In this case, a shallow_clone still involves copying the data.
|
||||
let mut inner: Inner = mem::uninitialized();
|
||||
ptr::copy_nonoverlapping(
|
||||
self,
|
||||
&mut inner,
|
||||
1,
|
||||
);
|
||||
inner
|
||||
} else {
|
||||
// The function requires `&self`, this means that `shallow_clone`
|
||||
// could be called concurrently.
|
||||
//
|
||||
// The first step is to load the value of `arc`. This will determine
|
||||
// how to proceed. The `Acquire` ordering synchronizes with the
|
||||
// `compare_and_swap` that comes later in this function. The goal is
|
||||
// to ensure that if `arc` is currently set to point to a `Shared`,
|
||||
// that the current thread acquires the associated memory.
|
||||
let mut arc = self.arc.load(Acquire);
|
||||
|
||||
// If the buffer is still tracked in a `Vec<u8>`. It is time to
|
||||
// promote the vec to an `Arc`. This could potentially be called
|
||||
// concurrently, so some care must be taken.
|
||||
if arc as usize & KIND_MASK == KIND_VEC {
|
||||
let original_capacity_repr =
|
||||
(arc as usize & ORIGINAL_CAPACITY_MASK) >> ORIGINAL_CAPACITY_OFFSET;
|
||||
|
||||
// The vec offset cannot be concurrently mutated, so there
|
||||
// should be no danger reading it.
|
||||
let off = (arc as usize) >> VEC_POS_OFFSET;
|
||||
|
||||
// First, allocate a new `Shared` instance containing the
|
||||
// `Vec` fields. It's important to note that `ptr`, `len`,
|
||||
// and `cap` cannot be mutated without having `&mut self`.
|
||||
// This means that these fields will not be concurrently
|
||||
// updated and since the buffer hasn't been promoted to an
|
||||
// `Arc`, those three fields still are the components of the
|
||||
// vector.
|
||||
let shared = Box::new(Shared {
|
||||
vec: rebuild_vec(self.ptr, self.len, self.cap, off),
|
||||
original_capacity_repr: original_capacity_repr,
|
||||
// Initialize refcount to 2. One for this reference, and one
|
||||
// for the new clone that will be returned from
|
||||
// `shallow_clone`.
|
||||
ref_count: AtomicUsize::new(2),
|
||||
});
|
||||
|
||||
let shared = Box::into_raw(shared);
|
||||
|
||||
// The pointer should be aligned, so this assert should
|
||||
// always succeed.
|
||||
debug_assert!(0 == (shared as usize & 0b11));
|
||||
|
||||
// If there are no references to self in other threads,
|
||||
// expensive atomic operations can be avoided.
|
||||
if mut_self {
|
||||
self.arc.store(shared, Relaxed);
|
||||
return Inner {
|
||||
arc: AtomicPtr::new(shared),
|
||||
.. *self
|
||||
};
|
||||
}
|
||||
|
||||
// Try compare & swapping the pointer into the `arc` field.
|
||||
// `Release` is used synchronize with other threads that
|
||||
// will load the `arc` field.
|
||||
//
|
||||
// If the `compare_and_swap` fails, then the thread lost the
|
||||
// race to promote the buffer to shared. The `Acquire`
|
||||
// ordering will synchronize with the `compare_and_swap`
|
||||
// that happened in the other thread and the `Shared`
|
||||
// pointed to by `actual` will be visible.
|
||||
let actual = self.arc.compare_and_swap(arc, shared, AcqRel);
|
||||
|
||||
if actual == arc {
|
||||
// The upgrade was successful, the new handle can be
|
||||
// returned.
|
||||
return Inner {
|
||||
arc: AtomicPtr::new(shared),
|
||||
.. *self
|
||||
};
|
||||
}
|
||||
|
||||
// The upgrade failed, a concurrent clone happened. Release
|
||||
// the allocation that was made in this thread, it will not
|
||||
// be needed.
|
||||
let shared = Box::from_raw(shared);
|
||||
mem::forget(*shared);
|
||||
|
||||
// Update the `arc` local variable and fall through to a ref
|
||||
// count update
|
||||
arc = actual;
|
||||
} else if arc as usize & KIND_MASK == KIND_STATIC {
|
||||
// Static buffer
|
||||
return Inner {
|
||||
arc: AtomicPtr::new(arc),
|
||||
.. *self
|
||||
};
|
||||
}
|
||||
|
||||
// Buffer already promoted to shared storage, so increment ref
|
||||
// count.
|
||||
//
|
||||
// Relaxed ordering is acceptable as the memory has already been
|
||||
// acquired via the `Acquire` load above.
|
||||
let old_size = (*arc).ref_count.fetch_add(1, Relaxed);
|
||||
|
||||
if old_size == usize::MAX {
|
||||
panic!(); // TODO: abort
|
||||
}
|
||||
|
||||
Inner {
|
||||
arc: AtomicPtr::new(arc),
|
||||
.. *self
|
||||
}
|
||||
self.shallow_clone_sync(mut_self)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[cold]
|
||||
unsafe fn shallow_clone_sync(&self, mut_self: bool) -> Inner {
|
||||
// The function requires `&self`, this means that `shallow_clone`
|
||||
// could be called concurrently.
|
||||
//
|
||||
// The first step is to load the value of `arc`. This will determine
|
||||
// how to proceed. The `Acquire` ordering synchronizes with the
|
||||
// `compare_and_swap` that comes later in this function. The goal is
|
||||
// to ensure that if `arc` is currently set to point to a `Shared`,
|
||||
// that the current thread acquires the associated memory.
|
||||
let arc = self.arc.load(Acquire);
|
||||
let kind = arc as usize & KIND_MASK;
|
||||
|
||||
if kind == KIND_ARC {
|
||||
self.shallow_clone_arc(arc)
|
||||
} else {
|
||||
assert!(kind == KIND_VEC);
|
||||
self.shallow_clone_vec(arc as usize, mut_self)
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn shallow_clone_arc(&self, arc: *mut Shared) -> Inner {
|
||||
debug_assert!(arc as usize & KIND_MASK == KIND_ARC);
|
||||
|
||||
let old_size = (*arc).ref_count.fetch_add(1, Relaxed);
|
||||
|
||||
if old_size == usize::MAX {
|
||||
abort();
|
||||
}
|
||||
|
||||
Inner {
|
||||
arc: AtomicPtr::new(arc),
|
||||
.. *self
|
||||
}
|
||||
}
|
||||
|
||||
#[cold]
|
||||
unsafe fn shallow_clone_vec(&self, arc: usize, mut_self: bool) -> Inner {
|
||||
// If the buffer is still tracked in a `Vec<u8>`. It is time to
|
||||
// promote the vec to an `Arc`. This could potentially be called
|
||||
// concurrently, so some care must be taken.
|
||||
|
||||
debug_assert!(arc & KIND_MASK == KIND_VEC);
|
||||
|
||||
let original_capacity_repr =
|
||||
(arc as usize & ORIGINAL_CAPACITY_MASK) >> ORIGINAL_CAPACITY_OFFSET;
|
||||
|
||||
// The vec offset cannot be concurrently mutated, so there
|
||||
// should be no danger reading it.
|
||||
let off = (arc as usize) >> VEC_POS_OFFSET;
|
||||
|
||||
// First, allocate a new `Shared` instance containing the
|
||||
// `Vec` fields. It's important to note that `ptr`, `len`,
|
||||
// and `cap` cannot be mutated without having `&mut self`.
|
||||
// This means that these fields will not be concurrently
|
||||
// updated and since the buffer hasn't been promoted to an
|
||||
// `Arc`, those three fields still are the components of the
|
||||
// vector.
|
||||
let shared = Box::new(Shared {
|
||||
vec: rebuild_vec(self.ptr, self.len, self.cap, off),
|
||||
original_capacity_repr: original_capacity_repr,
|
||||
// Initialize refcount to 2. One for this reference, and one
|
||||
// for the new clone that will be returned from
|
||||
// `shallow_clone`.
|
||||
ref_count: AtomicUsize::new(2),
|
||||
});
|
||||
|
||||
let shared = Box::into_raw(shared);
|
||||
|
||||
// The pointer should be aligned, so this assert should
|
||||
// always succeed.
|
||||
debug_assert!(0 == (shared as usize & 0b11));
|
||||
|
||||
// If there are no references to self in other threads,
|
||||
// expensive atomic operations can be avoided.
|
||||
if mut_self {
|
||||
self.arc.store(shared, Relaxed);
|
||||
return Inner {
|
||||
arc: AtomicPtr::new(shared),
|
||||
.. *self
|
||||
};
|
||||
}
|
||||
|
||||
// Try compare & swapping the pointer into the `arc` field.
|
||||
// `Release` is used synchronize with other threads that
|
||||
// will load the `arc` field.
|
||||
//
|
||||
// If the `compare_and_swap` fails, then the thread lost the
|
||||
// race to promote the buffer to shared. The `Acquire`
|
||||
// ordering will synchronize with the `compare_and_swap`
|
||||
// that happened in the other thread and the `Shared`
|
||||
// pointed to by `actual` will be visible.
|
||||
let actual = self.arc.compare_and_swap(arc as *mut Shared, shared, AcqRel);
|
||||
|
||||
if actual as usize == arc {
|
||||
// The upgrade was successful, the new handle can be
|
||||
// returned.
|
||||
return Inner {
|
||||
arc: AtomicPtr::new(shared),
|
||||
.. *self
|
||||
};
|
||||
}
|
||||
|
||||
// The upgrade failed, a concurrent clone happened. Release
|
||||
// the allocation that was made in this thread, it will not
|
||||
// be needed.
|
||||
let shared = Box::from_raw(shared);
|
||||
mem::forget(*shared);
|
||||
|
||||
// Buffer already promoted to shared storage, so increment ref
|
||||
// count.
|
||||
self.shallow_clone_arc(actual)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn reserve(&mut self, additional: usize) {
|
||||
let len = self.len();
|
||||
@@ -2327,6 +2397,18 @@ impl Inner {
|
||||
self.kind() == KIND_INLINE
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn is_inline_or_static(&self) -> bool {
|
||||
// The value returned by `kind` isn't itself safe, but the value could
|
||||
// inform what operations to take, and unsafely do something without
|
||||
// synchronization.
|
||||
//
|
||||
// KIND_INLINE and KIND_STATIC will *never* change, so branches on that
|
||||
// information is safe.
|
||||
let kind = self.kind();
|
||||
kind == KIND_INLINE || kind == KIND_STATIC
|
||||
}
|
||||
|
||||
/// Used for `debug_assert` statements. &mut is used to guarantee that it is
|
||||
/// safe to check VEC_KIND
|
||||
#[inline]
|
||||
@@ -2361,6 +2443,10 @@ impl Inner {
|
||||
// bits, so even without any explicit atomic operations, reading the
|
||||
// flag will be correct.
|
||||
//
|
||||
// This is undefind behavior due to a data race, but experimental
|
||||
// evidence shows that it works in practice (discussion:
|
||||
// https://internals.rust-lang.org/t/bit-wise-reasoning-for-atomic-accesses/8853).
|
||||
//
|
||||
// This function is very critical performance wise as it is called for
|
||||
// every operation. Performing an atomic load would mess with the
|
||||
// compiler's ability to optimize. Simple benchmarks show up to a 10%
|
||||
@@ -2370,7 +2456,7 @@ impl Inner {
|
||||
#[inline]
|
||||
fn imp(arc: &AtomicPtr<Shared>) -> usize {
|
||||
unsafe {
|
||||
let p: &u8 = mem::transmute(arc);
|
||||
let p: *const u8 = mem::transmute(arc);
|
||||
(*p as usize) & KIND_MASK
|
||||
}
|
||||
}
|
||||
@@ -2379,7 +2465,7 @@ impl Inner {
|
||||
#[inline]
|
||||
fn imp(arc: &AtomicPtr<Shared>) -> usize {
|
||||
unsafe {
|
||||
let p: &usize = mem::transmute(arc);
|
||||
let p: *const usize = mem::transmute(arc);
|
||||
*p & KIND_MASK
|
||||
}
|
||||
}
|
||||
@@ -2395,7 +2481,7 @@ impl Inner {
|
||||
// function.
|
||||
let prev = unsafe {
|
||||
let p: &AtomicPtr<Shared> = &self.arc;
|
||||
let p: &usize = mem::transmute(p);
|
||||
let p: *const usize = mem::transmute(p);
|
||||
*p
|
||||
};
|
||||
|
||||
@@ -2502,35 +2588,51 @@ fn original_capacity_from_repr(repr: usize) -> usize {
|
||||
|
||||
#[test]
|
||||
fn test_original_capacity_to_repr() {
|
||||
for &cap in &[0, 1, 16, 1000] {
|
||||
assert_eq!(0, original_capacity_to_repr(cap));
|
||||
}
|
||||
assert_eq!(original_capacity_to_repr(0), 0);
|
||||
|
||||
for &cap in &[1024, 1025, 1100, 2000, 2047] {
|
||||
assert_eq!(1, original_capacity_to_repr(cap));
|
||||
}
|
||||
let max_width = 32;
|
||||
|
||||
for &cap in &[2048, 2049] {
|
||||
assert_eq!(2, original_capacity_to_repr(cap));
|
||||
}
|
||||
for width in 1..(max_width + 1) {
|
||||
let cap = 1 << width - 1;
|
||||
|
||||
// TODO: more
|
||||
let expected = if width < MIN_ORIGINAL_CAPACITY_WIDTH {
|
||||
0
|
||||
} else if width < MAX_ORIGINAL_CAPACITY_WIDTH {
|
||||
width - MIN_ORIGINAL_CAPACITY_WIDTH
|
||||
} else {
|
||||
MAX_ORIGINAL_CAPACITY_WIDTH - MIN_ORIGINAL_CAPACITY_WIDTH
|
||||
};
|
||||
|
||||
for &cap in &[65536, 65537, 68000, 1 << 17, 1 << 18, 1 << 20, 1 << 30] {
|
||||
assert_eq!(7, original_capacity_to_repr(cap), "cap={}", cap);
|
||||
assert_eq!(original_capacity_to_repr(cap), expected);
|
||||
|
||||
if width > 1 {
|
||||
assert_eq!(original_capacity_to_repr(cap + 1), expected);
|
||||
}
|
||||
|
||||
// MIN_ORIGINAL_CAPACITY_WIDTH must be bigger than 7 to pass tests below
|
||||
if width == MIN_ORIGINAL_CAPACITY_WIDTH + 1 {
|
||||
assert_eq!(original_capacity_to_repr(cap - 24), expected - 1);
|
||||
assert_eq!(original_capacity_to_repr(cap + 76), expected);
|
||||
} else if width == MIN_ORIGINAL_CAPACITY_WIDTH + 2 {
|
||||
assert_eq!(original_capacity_to_repr(cap - 1), expected - 1);
|
||||
assert_eq!(original_capacity_to_repr(cap - 48), expected - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_original_capacity_from_repr() {
|
||||
assert_eq!(0, original_capacity_from_repr(0));
|
||||
assert_eq!(1024, original_capacity_from_repr(1));
|
||||
assert_eq!(1024 * 2, original_capacity_from_repr(2));
|
||||
assert_eq!(1024 * 4, original_capacity_from_repr(3));
|
||||
assert_eq!(1024 * 8, original_capacity_from_repr(4));
|
||||
assert_eq!(1024 * 16, original_capacity_from_repr(5));
|
||||
assert_eq!(1024 * 32, original_capacity_from_repr(6));
|
||||
assert_eq!(1024 * 64, original_capacity_from_repr(7));
|
||||
|
||||
let min_cap = 1 << MIN_ORIGINAL_CAPACITY_WIDTH;
|
||||
|
||||
assert_eq!(min_cap, original_capacity_from_repr(1));
|
||||
assert_eq!(min_cap * 2, original_capacity_from_repr(2));
|
||||
assert_eq!(min_cap * 4, original_capacity_from_repr(3));
|
||||
assert_eq!(min_cap * 8, original_capacity_from_repr(4));
|
||||
assert_eq!(min_cap * 16, original_capacity_from_repr(5));
|
||||
assert_eq!(min_cap * 32, original_capacity_from_repr(6));
|
||||
assert_eq!(min_cap * 64, original_capacity_from_repr(7));
|
||||
}
|
||||
|
||||
unsafe impl Send for Inner {}
|
||||
@@ -2827,3 +2929,21 @@ impl PartialEq<Bytes> for BytesMut
|
||||
&other[..] == &self[..]
|
||||
}
|
||||
}
|
||||
|
||||
// While there is `std::process:abort`, it's only available in Rust 1.17, and
|
||||
// our minimum supported version is currently 1.15. So, this acts as an abort
|
||||
// by triggering a double panic, which always aborts in Rust.
|
||||
struct Abort;
|
||||
|
||||
impl Drop for Abort {
|
||||
fn drop(&mut self) {
|
||||
panic!();
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(never)]
|
||||
#[cold]
|
||||
fn abort() {
|
||||
let _a = Abort;
|
||||
panic!();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
extern crate either;
|
||||
|
||||
use {Buf, BufMut};
|
||||
|
||||
use self::either::Either;
|
||||
use self::either::Either::*;
|
||||
use iovec::IoVec;
|
||||
|
||||
impl<L, R> Buf for Either<L, R>
|
||||
where
|
||||
L: Buf,
|
||||
R: Buf,
|
||||
{
|
||||
fn remaining(&self) -> usize {
|
||||
match *self {
|
||||
Left(ref b) => b.remaining(),
|
||||
Right(ref b) => b.remaining(),
|
||||
}
|
||||
}
|
||||
|
||||
fn bytes(&self) -> &[u8] {
|
||||
match *self {
|
||||
Left(ref b) => b.bytes(),
|
||||
Right(ref b) => b.bytes(),
|
||||
}
|
||||
}
|
||||
|
||||
fn bytes_vec<'a>(&'a self, dst: &mut [&'a IoVec]) -> usize {
|
||||
match *self {
|
||||
Left(ref b) => b.bytes_vec(dst),
|
||||
Right(ref b) => b.bytes_vec(dst),
|
||||
}
|
||||
}
|
||||
|
||||
fn advance(&mut self, cnt: usize) {
|
||||
match *self {
|
||||
Left(ref mut b) => b.advance(cnt),
|
||||
Right(ref mut b) => b.advance(cnt),
|
||||
}
|
||||
}
|
||||
|
||||
fn copy_to_slice(&mut self, dst: &mut [u8]) {
|
||||
match *self {
|
||||
Left(ref mut b) => b.copy_to_slice(dst),
|
||||
Right(ref mut b) => b.copy_to_slice(dst),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<L, R> BufMut for Either<L, R>
|
||||
where
|
||||
L: BufMut,
|
||||
R: BufMut,
|
||||
{
|
||||
fn remaining_mut(&self) -> usize {
|
||||
match *self {
|
||||
Left(ref b) => b.remaining_mut(),
|
||||
Right(ref b) => b.remaining_mut(),
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn bytes_mut(&mut self) -> &mut [u8] {
|
||||
match *self {
|
||||
Left(ref mut b) => b.bytes_mut(),
|
||||
Right(ref mut b) => b.bytes_mut(),
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn bytes_vec_mut<'a>(&'a mut self, dst: &mut [&'a mut IoVec]) -> usize {
|
||||
match *self {
|
||||
Left(ref mut b) => b.bytes_vec_mut(dst),
|
||||
Right(ref mut b) => b.bytes_vec_mut(dst),
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn advance_mut(&mut self, cnt: usize) {
|
||||
match *self {
|
||||
Left(ref mut b) => b.advance_mut(cnt),
|
||||
Right(ref mut b) => b.advance_mut(cnt),
|
||||
}
|
||||
}
|
||||
|
||||
fn put_slice(&mut self, src: &[u8]) {
|
||||
match *self {
|
||||
Left(ref mut b) => b.put_slice(src),
|
||||
Right(ref mut b) => b.put_slice(src),
|
||||
}
|
||||
}
|
||||
}
|
||||
+7
-3
@@ -18,8 +18,8 @@
|
||||
//! using a reference count to track when the memory is no longer needed and can
|
||||
//! be freed.
|
||||
//!
|
||||
//! A `Bytes` handle can be created directly from an existing byte store (such as &[u8]
|
||||
//! or Vec<u8>), but usually a `BytesMut` is used first and written to. For
|
||||
//! A `Bytes` handle can be created directly from an existing byte store (such as `&[u8]`
|
||||
//! or `Vec<u8>`), but usually a `BytesMut` is used first and written to. For
|
||||
//! example:
|
||||
//!
|
||||
//! ```rust
|
||||
@@ -69,7 +69,7 @@
|
||||
//! and `BufMut` are infallible.
|
||||
|
||||
#![deny(warnings, missing_docs, missing_debug_implementations)]
|
||||
#![doc(html_root_url = "https://docs.rs/bytes/0.4.8")]
|
||||
#![doc(html_root_url = "https://docs.rs/bytes/0.4.12")]
|
||||
|
||||
extern crate byteorder;
|
||||
extern crate iovec;
|
||||
@@ -99,3 +99,7 @@ pub use byteorder::{ByteOrder, BigEndian, LittleEndian};
|
||||
#[cfg(feature = "serde")]
|
||||
#[doc(hidden)]
|
||||
pub mod serde;
|
||||
|
||||
// Optional `Either` support
|
||||
#[cfg(feature = "either")]
|
||||
mod either;
|
||||
|
||||
+64
-8
@@ -1,6 +1,6 @@
|
||||
extern crate bytes;
|
||||
|
||||
use bytes::{Bytes, BytesMut, BufMut};
|
||||
use bytes::{Bytes, BytesMut, BufMut, IntoBuf};
|
||||
|
||||
const LONG: &'static [u8] = b"mary had a little lamb, little lamb, little lamb";
|
||||
const SHORT: &'static [u8] = b"hello world";
|
||||
@@ -258,15 +258,10 @@ fn split_to_oob_mut() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn split_to_uninitialized() {
|
||||
let mut bytes = BytesMut::with_capacity(1024);
|
||||
let other = bytes.split_to(128);
|
||||
|
||||
assert_eq!(bytes.len(), 0);
|
||||
assert_eq!(bytes.capacity(), 896);
|
||||
|
||||
assert_eq!(other.len(), 0);
|
||||
assert_eq!(other.capacity(), 128);
|
||||
let _other = bytes.split_to(128);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -303,6 +298,13 @@ fn fns_defined_for_bytes_mut() {
|
||||
assert_eq!(&v[..], bytes);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn mut_into_buf() {
|
||||
let mut v = vec![0, 0, 0, 0];
|
||||
let s = &mut v[..];
|
||||
s.into_buf().put_u32_le(42);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn reserve_convert() {
|
||||
// Inline -> Vec
|
||||
@@ -710,3 +712,57 @@ fn from_iter_no_size_hint() {
|
||||
|
||||
assert_eq!(&actual[..], &expect[..]);
|
||||
}
|
||||
|
||||
fn test_slice_ref(bytes: &Bytes, start: usize, end: usize, expected: &[u8]) {
|
||||
let slice = &(bytes.as_ref()[start..end]);
|
||||
let sub = bytes.slice_ref(&slice);
|
||||
assert_eq!(&sub[..], expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn slice_ref_works() {
|
||||
let bytes = Bytes::from(&b"012345678"[..]);
|
||||
|
||||
test_slice_ref(&bytes, 0, 0, b"");
|
||||
test_slice_ref(&bytes, 0, 3, b"012");
|
||||
test_slice_ref(&bytes, 2, 6, b"2345");
|
||||
test_slice_ref(&bytes, 7, 9, b"78");
|
||||
test_slice_ref(&bytes, 9, 9, b"");
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
fn slice_ref_empty() {
|
||||
let bytes = Bytes::from(&b""[..]);
|
||||
let slice = &(bytes.as_ref()[0..0]);
|
||||
|
||||
let sub = bytes.slice_ref(&slice);
|
||||
assert_eq!(&sub[..], b"");
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn slice_ref_catches_not_a_subset() {
|
||||
let bytes = Bytes::from(&b"012345678"[..]);
|
||||
let slice = &b"012345"[0..4];
|
||||
|
||||
bytes.slice_ref(slice);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn slice_ref_catches_not_an_empty_subset() {
|
||||
let bytes = Bytes::from(&b"012345678"[..]);
|
||||
let slice = &b""[0..0];
|
||||
|
||||
bytes.slice_ref(slice);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn empty_slice_ref_catches_not_an_empty_subset() {
|
||||
let bytes = Bytes::from(&b""[..]);
|
||||
let slice = &b""[0..0];
|
||||
|
||||
bytes.slice_ref(slice);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
extern crate bytes;
|
||||
|
||||
use std::io::{BufRead, Cursor, Read};
|
||||
|
||||
use bytes::Buf;
|
||||
|
||||
#[test]
|
||||
fn read() {
|
||||
let buf1 = Cursor::new(b"hello ");
|
||||
let buf2 = Cursor::new(b"world");
|
||||
let buf = Buf::chain(buf1, buf2); // Disambiguate with Read::chain
|
||||
let mut buffer = Vec::new();
|
||||
buf.reader().read_to_end(&mut buffer).unwrap();
|
||||
assert_eq!(b"hello world", &buffer[..]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn buf_read() {
|
||||
let buf1 = Cursor::new(b"hell");
|
||||
let buf2 = Cursor::new(b"o\nworld");
|
||||
let mut reader = Buf::chain(buf1, buf2).reader();
|
||||
let mut line = String::new();
|
||||
reader.read_line(&mut line).unwrap();
|
||||
assert_eq!("hello\n", &line);
|
||||
line.clear();
|
||||
reader.read_line(&mut line).unwrap();
|
||||
assert_eq!("world", &line);
|
||||
}
|
||||
Reference in New Issue
Block a user