Skip to content

Commit 4f1c20d

Browse files
Fix VecDeque ByteSource owner
1 parent e64d6e1 commit 4f1c20d

File tree

4 files changed

+103
-5
lines changed

4 files changed

+103
-5
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# Changelog
22

33
## Unreleased
4+
- added `ByteSource` support for `VecDeque<T>` when `zerocopy` is enabled and kept the deque as owner
45
- added `ByteSource` support for `Cow<'static, T>` where `T: AsRef<[u8]>`
56
- added `ByteArea` for staged file writes with `Section::freeze()` to return `Bytes`
67
- `SectionWriter::reserve` now accepts a zerocopy type instead of an alignment constant

INVENTORY.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55

66
## Desired Functionality
77
- Example demonstrating Python + winnow parsing.
8-
- `ByteSource` implementation for `VecDeque<u8>` to support ring buffers.
9-
8+
109
## Discovered Issues
1110
- None at the moment.

src/sources.rs

Lines changed: 50 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@
1010
//!
1111
//! | Feature | Implementations |
1212
//! | ------------ | ---------------------------------------------------------------- |
13-
//! | `zerocopy` | `&'static [T]`, `Box<T>`, `Vec<T>` for `T: IntoBytes + Immutable` |
14-
//! | *(none)* | `&'static [u8]`, `Box<[u8]>`, `Vec<u8>`, `String`, `&'static str`, `Cow<'static, T>` for `T: AsRef<[u8]>` |
13+
//! | `zerocopy` | `&'static [T]`, `Box<T>`, `Vec<T>`, `VecDeque<T>` for `T: IntoBytes + Immutable` |
14+
//! | *(none)* | `&'static [u8]`, `Box<[u8]>`, `Vec<u8>`, `VecDeque<u8>`, `String`, `&'static str`, `Cow<'static, T>` for `T: AsRef<[u8]>` |
1515
//! | `bytes` | `bytes::Bytes` |
1616
//! | `ownedbytes` | `ownedbytes::OwnedBytes` |
1717
//! | `mmap` | `memmap2::Mmap` and `ByteOwner` for `memmap2::MmapRaw` |
@@ -36,7 +36,7 @@
3636
//! # let _ = Bytes::from_source(MyData(vec![1, 2, 3]));
3737
//! ```
3838
39-
use std::borrow::Cow;
39+
use std::{borrow::Cow, collections::VecDeque};
4040
use zerocopy::Immutable;
4141
#[cfg(feature = "zerocopy")]
4242
use zerocopy::IntoBytes;
@@ -133,6 +133,53 @@ unsafe impl ByteSource for Vec<u8> {
133133
}
134134
}
135135

136+
#[cfg(feature = "zerocopy")]
137+
unsafe impl<T> ByteSource for VecDeque<T>
138+
where
139+
T: IntoBytes + Immutable + Sync + Send + 'static,
140+
{
141+
type Owner = Self;
142+
143+
fn as_bytes(&self) -> &[u8] {
144+
let (front, back) = self.as_slices();
145+
assert!(
146+
back.is_empty(),
147+
"VecDeque is not contiguous; call make_contiguous before creating Bytes",
148+
);
149+
IntoBytes::as_bytes(front)
150+
}
151+
152+
fn get_owner(self) -> Self::Owner {
153+
assert!(
154+
self.as_slices().1.is_empty(),
155+
"VecDeque is not contiguous; call make_contiguous before creating Bytes",
156+
);
157+
self
158+
}
159+
}
160+
161+
#[cfg(not(feature = "zerocopy"))]
162+
unsafe impl ByteSource for VecDeque<u8> {
163+
type Owner = Self;
164+
165+
fn as_bytes(&self) -> &[u8] {
166+
let (front, back) = self.as_slices();
167+
assert!(
168+
back.is_empty(),
169+
"VecDeque is not contiguous; call make_contiguous before creating Bytes",
170+
);
171+
front
172+
}
173+
174+
fn get_owner(self) -> Self::Owner {
175+
assert!(
176+
self.as_slices().1.is_empty(),
177+
"VecDeque is not contiguous; call make_contiguous before creating Bytes",
178+
);
179+
self
180+
}
181+
}
182+
136183
unsafe impl ByteSource for String {
137184
type Owner = Self;
138185

src/tests.rs

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,57 @@ fn test_slice_to_bytes_unrelated_slice() {
103103
assert!(bytes.slice_to_bytes(slice).is_none());
104104
}
105105

106+
#[test]
107+
fn test_vecdeque_source() {
108+
use std::collections::VecDeque;
109+
110+
let mut deque = VecDeque::new();
111+
deque.extend([1u8, 2, 3, 4]);
112+
deque.make_contiguous();
113+
let bytes = Bytes::from_source(deque);
114+
assert_eq!(bytes.as_ref(), &[1, 2, 3, 4]);
115+
let owner = bytes
116+
.downcast_to_owner::<VecDeque<u8>>()
117+
.expect("downcast VecDeque owner");
118+
assert_eq!(&*owner, &VecDeque::from([1u8, 2, 3, 4]));
119+
}
120+
121+
#[cfg(feature = "zerocopy")]
122+
#[test]
123+
fn test_vecdeque_generic_source() {
124+
use std::collections::VecDeque;
125+
126+
let mut deque = VecDeque::new();
127+
deque.extend([1u16, 2, 3, 4]);
128+
deque.make_contiguous();
129+
let bytes = Bytes::from_source(deque);
130+
131+
let mut expected = Vec::new();
132+
for n in [1u16, 2, 3, 4] {
133+
expected.extend_from_slice(&n.to_ne_bytes());
134+
}
135+
assert_eq!(bytes.as_ref(), expected.as_slice());
136+
let owner = bytes
137+
.downcast_to_owner::<VecDeque<u16>>()
138+
.expect("downcast VecDeque owner");
139+
assert_eq!(&*owner, &VecDeque::from([1u16, 2, 3, 4]));
140+
}
141+
142+
#[test]
143+
#[should_panic]
144+
fn test_vecdeque_noncontiguous_panics() {
145+
use std::collections::VecDeque;
146+
147+
let mut deque: VecDeque<u8> = VecDeque::with_capacity(3);
148+
deque.push_back(1);
149+
deque.push_back(2);
150+
deque.push_back(3);
151+
let _ = deque.pop_front();
152+
deque.push_back(4); // wraps around
153+
assert!(!deque.as_slices().1.is_empty());
154+
let _ = Bytes::from_source(deque);
155+
}
156+
106157
#[test]
107158
fn test_pop_front() {
108159
let mut bytes = Bytes::from(b"abc".to_vec());

0 commit comments

Comments
 (0)