Skip to content

Commit 1a7493b

Browse files
authored
Bytes improvements (#711)
1 parent 45ff08c commit 1a7493b

File tree

30 files changed

+461
-235
lines changed

30 files changed

+461
-235
lines changed

.github/workflows/cov.yml

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,19 +30,19 @@ jobs:
3030
run: cargo llvm-cov clean --workspace
3131

3232
- name: Code coverage (neon-poling)
33-
run: cargo llvm-cov nextest --retries=3 --no-report --all --no-default-features --features="ntex/neon-polling,ntex/cookie,ntex/url,ntex/compress,ntex/openssl,ntex/rustls,ntex/ws"
33+
run: cargo +nightly llvm-cov nextest --no-report --retries=3 --all --no-default-features --features="ntex/neon-polling,ntex/cookie,ntex/url,ntex/compress,ntex/openssl,ntex/rustls,ntex/ws"
3434

3535
- name: Code coverage (neon-uring)
36-
run: cargo llvm-cov nextest --retries=3 --no-report --all --no-default-features --features="ntex/neon-uring,ntex/cookie,ntex/url,ntex/compress,ntex/openssl,ntex/rustls,ntex/ws"
36+
run: cargo +nightly llvm-cov nextest --no-report --retries=3 --all --no-default-features --features="ntex/neon-uring,ntex/cookie,ntex/url,ntex/compress,ntex/openssl,ntex/rustls,ntex/ws"
3737

3838
- name: Code coverage (tokio)
39-
run: cargo llvm-cov nextest --retries=3 --no-report --all --no-default-features --features="ntex/tokio,ntex/cookie,ntex/url,ntex/compress,ntex/openssl,ntex/rustls,ntex/ws"
39+
run: cargo +nightly llvm-cov test --no-report --doctests --all --no-default-features --features="ntex/tokio,ntex/cookie,ntex/url,ntex/compress,ntex/openssl,ntex/rustls,ntex/ws"
4040

41-
#- name: Code coverage (compio)
42-
# run: cargo llvm-cov nextest --retries=3 --no-report --all --no-default-features --features="ntex/compio,ntex/cookie,ntex/url,ntex/compress,ntex/openssl,ntex/rustls,ntex/ws"
41+
- name: Code coverage (compio)
42+
run: cargo +nightly llvm-cov nextest --no-report --retries=3 --all --no-default-features --features="ntex/compio,ntex/cookie,ntex/url,ntex/compress,ntex/openssl,ntex/rustls,ntex/ws"
4343

4444
- name: Generate coverage report
45-
run: cargo llvm-cov report --lcov --output-path lcov.info --ignore-filename-regex="ntex-compio|ntex-tokio"
45+
run: cargo +nightly llvm-cov report --lcov --output-path lcov.info
4646

4747
- name: Upload coverage to Codecov
4848
uses: codecov/codecov-action@v4

.github/workflows/linux.yml

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,18 +37,39 @@ jobs:
3737
run: |
3838
cargo nextest run --retries=3 --all --no-default-features --features="ntex/neon-polling,ntex/cookie,ntex/url,ntex/compress,ntex/openssl,ntex/rustls,ntex/ws"
3939
40+
- name: Run doc tests (neon-polling)
41+
timeout-minutes: 15
42+
run: |
43+
cargo test --doc --all --no-default-features --features="ntex/neon-polling,ntex/cookie,ntex/url,ntex/compress,ntex/openssl,ntex/rustls,ntex/ws"
44+
4045
- name: Run tests (neon-uring)
4146
timeout-minutes: 15
4247
run: |
4348
cargo nextest run --retries=3 --all --no-default-features --features="ntex/neon-uring,ntex/cookie,ntex/url,ntex/compress,ntex/openssl,ntex/rustls,ntex/ws"
4449
50+
- name: Run doc tests (neon-uring)
51+
timeout-minutes: 15
52+
run: |
53+
cargo test --doc --all --no-default-features --features="ntex/neon-uring,ntex/cookie,ntex/url,ntex/compress,ntex/openssl,ntex/rustls,ntex/ws"
54+
4555
- name: Run tests (tokio)
4656
timeout-minutes: 15
4757
run: |
4858
cargo nextest run --retries=3 --all --no-default-features --features="ntex/tokio,ntex/cookie,ntex/url,ntex/compress,ntex/openssl,ntex/rustls,ntex/ws"
4959
60+
- name: Run doc tests (tokio)
61+
timeout-minutes: 15
62+
run: |
63+
cargo test --doc --all --no-default-features --features="ntex/tokio,ntex/cookie,ntex/url,ntex/compress,ntex/openssl,ntex/rustls,ntex/ws"
64+
5065
- name: Run tests (compio)
5166
timeout-minutes: 15
5267
if: matrix.version != '1.86.0'
5368
run: |
5469
cargo nextest run --retries=3 --all --no-default-features --features="ntex/compio,ntex/cookie,ntex/url,ntex/compress,ntex/openssl,ntex/rustls,ntex/ws"
70+
71+
- name: Run doc tests (compio)
72+
timeout-minutes: 15
73+
if: matrix.version != '1.86.0'
74+
run: |
75+
cargo test --doc --all --no-default-features --features="ntex/compio,ntex/cookie,ntex/url,ntex/compress,ntex/openssl,ntex/rustls,ntex/ws"

ntex-bytes/CHANGELOG.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,15 @@
11
# Changes
22

3+
## [1.2.0] (2026-01-04)
4+
5+
* Rename .split() to .take()
6+
7+
* Add .advance_to() method, same as Buf::advance()
8+
9+
* Add .take_bytes() method, same as .take().freeze()
10+
11+
* Add .split_to_bytes() method, same as .split_to(at).freeze()
12+
313
## [1.1.0] (2025-12-27)
414

515
* Use alloc create for BytesVec

ntex-bytes/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "ntex-bytes"
3-
version = "1.1.0"
3+
version = "1.2.0"
44
authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
55
description = "Types and traits for working with bytes (bytes crate fork)"
66
documentation = "https://docs.rs/ntex-bytes"

ntex-bytes/src/bvec.rs

Lines changed: 107 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -94,15 +94,15 @@ impl BytesVec {
9494

9595
/// Creates a new `BytesVec` from slice, by copying it.
9696
pub fn copy_from_slice<T: AsRef<[u8]>>(src: T) -> Self {
97+
let slice = src.as_ref();
9798
BytesVec {
98-
storage: StorageVec::from_slice(src.as_ref()),
99+
storage: StorageVec::from_slice(slice.len(), slice),
99100
}
100101
}
101102

102103
/// Creates a new `BytesVec` with default capacity.
103104
///
104105
/// Resulting object has length 0 and unspecified capacity.
105-
/// This function does not allocate.
106106
///
107107
/// # Examples
108108
///
@@ -121,7 +121,7 @@ impl BytesVec {
121121
#[inline]
122122
pub fn new() -> BytesVec {
123123
BytesVec {
124-
storage: StorageVec::with_capacity(0),
124+
storage: StorageVec::with_capacity(104),
125125
}
126126
}
127127

@@ -202,7 +202,7 @@ impl BytesVec {
202202
}
203203

204204
/// Removes the bytes from the current view, returning them in a new
205-
/// `Bytes` instance.
205+
/// `BytesMut` instance.
206206
///
207207
/// Afterwards, `self` will be empty, but will retain any additional
208208
/// capacity that it had before the operation. This is identical to
@@ -219,15 +219,47 @@ impl BytesVec {
219219
/// let mut buf = BytesVec::with_capacity(1024);
220220
/// buf.put(&b"hello world"[..]);
221221
///
222-
/// let other = buf.split();
222+
/// let other = buf.take();
223223
///
224224
/// assert!(buf.is_empty());
225225
/// assert_eq!(1013, buf.capacity());
226226
///
227227
/// assert_eq!(other, b"hello world"[..]);
228228
/// ```
229+
#[inline]
230+
pub fn take(&mut self) -> BytesMut {
231+
BytesMut {
232+
storage: self.storage.split_to(self.len()),
233+
}
234+
}
235+
236+
/// Removes the bytes from the current view, returning them in a new
237+
/// `Bytes` handle.
238+
///
239+
/// This is identical to `self.take().freeze()`.
240+
///
241+
/// # Examples
242+
///
243+
/// ```
244+
/// use ntex_bytes::{BytesMut, BufMut};
245+
///
246+
/// let mut buf = BytesMut::with_capacity(1024);
247+
/// buf.put(&b"hello world"[..]);
248+
///
249+
/// let other = buf.take_bytes();
250+
///
251+
/// assert_eq!(other, b"hello world"[..]);
252+
/// ```
253+
pub fn take_bytes(&mut self) -> Bytes {
254+
Bytes {
255+
storage: self.storage.split_to(self.len()),
256+
}
257+
}
258+
259+
#[doc(hidden)]
260+
#[deprecated]
229261
pub fn split(&mut self) -> BytesMut {
230-
self.split_to(self.len())
262+
self.take()
231263
}
232264

233265
/// Splits the buffer into two at the given index.
@@ -255,18 +287,76 @@ impl BytesVec {
255287
/// # Panics
256288
///
257289
/// Panics if `at > len`.
290+
#[inline]
258291
pub fn split_to(&mut self, at: usize) -> BytesMut {
259292
self.split_to_checked(at)
260293
.expect("at value must be <= self.len()`")
261294
}
262295

296+
/// Splits the buffer into two at the given index.
297+
///
298+
/// Same as .split_to() but returns `Bytes` instance.
299+
///
300+
/// # Examples
301+
///
302+
/// ```
303+
/// use ntex_bytes::BytesVec;
304+
///
305+
/// let mut a = BytesVec::copy_from_slice(&b"hello world"[..]);
306+
/// let mut b = a.split_to_bytes(5);
307+
///
308+
/// a[0] = b'!';
309+
///
310+
/// assert_eq!(&a[..], b"!world");
311+
/// assert_eq!(&b[..], b"hello");
312+
/// ```
313+
///
314+
/// # Panics
315+
///
316+
/// Panics if `at > len`.
317+
#[inline]
318+
pub fn split_to_bytes(&mut self, at: usize) -> Bytes {
319+
Bytes {
320+
storage: self.split_to(at).storage,
321+
}
322+
}
323+
324+
/// Advance the internal cursor.
325+
///
326+
/// Afterwards `self` contains elements `[cnt, len)`.
327+
/// This is an `O(1)` operation.
328+
///
329+
/// # Examples
330+
///
331+
/// ```
332+
/// use ntex_bytes::BytesVec;
333+
///
334+
/// let mut a = BytesVec::copy_from_slice(&b"hello world"[..]);
335+
/// a.advance_to(5);
336+
///
337+
/// a[0] = b'!';
338+
///
339+
/// assert_eq!(&a[..], b"!world");
340+
/// ```
341+
///
342+
/// # Panics
343+
///
344+
/// Panics if `cnt > len`.
345+
#[inline]
346+
pub fn advance_to(&mut self, cnt: usize) {
347+
unsafe {
348+
self.storage.set_start(cnt as u32);
349+
}
350+
}
351+
263352
/// Splits the bytes into two at the given index.
264353
///
265354
/// Does nothing if `at > len`.
355+
#[inline]
266356
pub fn split_to_checked(&mut self, at: usize) -> Option<BytesMut> {
267357
if at <= self.len() {
268358
Some(BytesMut {
269-
storage: self.storage.split_to(at, false),
359+
storage: self.storage.split_to(at),
270360
})
271361
} else {
272362
None
@@ -293,6 +383,7 @@ impl BytesVec {
293383
/// ```
294384
///
295385
/// [`split_off`]: #method.split_off
386+
#[inline]
296387
pub fn truncate(&mut self, len: usize) {
297388
self.storage.truncate(len);
298389
}
@@ -308,6 +399,7 @@ impl BytesVec {
308399
/// buf.clear();
309400
/// assert!(buf.is_empty());
310401
/// ```
402+
#[inline]
311403
pub fn clear(&mut self) {
312404
self.truncate(0);
313405
}
@@ -419,7 +511,7 @@ impl BytesVec {
419511
/// buf.put(&[0; 64][..]);
420512
///
421513
/// let ptr = buf.as_ptr();
422-
/// let other = buf.split();
514+
/// let other = buf.take();
423515
///
424516
/// assert!(buf.is_empty());
425517
/// assert_eq!(buf.capacity(), 64);
@@ -503,15 +595,7 @@ impl Buf for BytesVec {
503595

504596
#[inline]
505597
fn advance(&mut self, cnt: usize) {
506-
assert!(
507-
cnt <= self.storage.len(),
508-
"cannot advance past `remaining` len:{} delta:{}",
509-
self.storage.len(),
510-
cnt
511-
);
512-
unsafe {
513-
self.storage.set_start(cnt as u32);
514-
}
598+
self.advance_to(cnt);
515599
}
516600
}
517601

@@ -575,7 +659,7 @@ impl bytes::buf::Buf for BytesVec {
575659

576660
#[inline]
577661
fn advance(&mut self, cnt: usize) {
578-
Buf::advance(self, cnt)
662+
self.advance_to(cnt);
579663
}
580664
}
581665

@@ -760,7 +844,10 @@ impl Extend<u8> for BytesVec {
760844
let (lower, _) = iter.size_hint();
761845
self.reserve(lower);
762846

763-
for b in iter {
847+
for (idx, b) in iter.enumerate() {
848+
if idx >= lower {
849+
self.reserve(1);
850+
}
764851
self.put_u8(b);
765852
}
766853
}
@@ -913,7 +1000,7 @@ impl From<BytesVec> for BytesMut {
9131000
#[inline]
9141001
fn from(src: BytesVec) -> BytesMut {
9151002
BytesMut {
916-
storage: src.storage.into_storage(),
1003+
storage: src.storage.freeze(),
9171004
}
9181005
}
9191006
}

ntex-bytes/src/bytes.rs

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -395,14 +395,39 @@ impl Bytes {
395395
Some(Bytes::new())
396396
} else {
397397
Some(Bytes {
398-
storage: self.storage.split_to(at, true),
398+
storage: self.storage.split_to(at),
399399
})
400400
}
401401
} else {
402402
None
403403
}
404404
}
405405

406+
/// Advance the internal cursor.
407+
///
408+
/// Afterwards `self` contains elements `[cnt, len)`.
409+
/// This is an `O(1)` operation.
410+
///
411+
/// # Examples
412+
///
413+
/// ```
414+
/// use ntex_bytes::Bytes;
415+
///
416+
/// let mut a = Bytes::copy_from_slice(&b"hello world"[..]);
417+
/// a.advance_to(5);
418+
///
419+
/// assert_eq!(&a[..], b" world");
420+
/// ```
421+
///
422+
/// # Panics
423+
///
424+
/// Panics if `cnt > len`.
425+
pub fn advance_to(&mut self, cnt: usize) {
426+
unsafe {
427+
self.storage.set_start(cnt);
428+
}
429+
}
430+
406431
/// Shortens the buffer, keeping the first `len` bytes and dropping the
407432
/// rest.
408433
///
@@ -539,10 +564,7 @@ impl Buf for Bytes {
539564

540565
#[inline]
541566
fn advance(&mut self, cnt: usize) {
542-
assert!(cnt <= self.storage.len(), "cannot advance past `remaining`");
543-
unsafe {
544-
self.storage.set_start(cnt);
545-
}
567+
self.advance_to(cnt)
546568
}
547569
}
548570

@@ -559,10 +581,7 @@ impl bytes::buf::Buf for Bytes {
559581

560582
#[inline]
561583
fn advance(&mut self, cnt: usize) {
562-
assert!(cnt <= self.storage.len(), "cannot advance past `remaining`");
563-
unsafe {
564-
self.storage.set_start(cnt);
565-
}
584+
self.advance_to(cnt)
566585
}
567586
}
568587

0 commit comments

Comments
 (0)