Skip to content

Commit b29112c

Browse files
authored
Implement BufMut for &mut [MaybeUninit<u8>] (#597)
1 parent 99a2754 commit b29112c

File tree

2 files changed

+145
-13
lines changed

2 files changed

+145
-13
lines changed

src/buf/buf_mut.rs

+35
Original file line numberDiff line numberDiff line change
@@ -1419,6 +1419,41 @@ unsafe impl BufMut for &mut [u8] {
14191419
}
14201420
}
14211421

1422+
unsafe impl BufMut for &mut [core::mem::MaybeUninit<u8>] {
1423+
#[inline]
1424+
fn remaining_mut(&self) -> usize {
1425+
self.len()
1426+
}
1427+
1428+
#[inline]
1429+
fn chunk_mut(&mut self) -> &mut UninitSlice {
1430+
UninitSlice::from_uninit_slice(self)
1431+
}
1432+
1433+
#[inline]
1434+
unsafe fn advance_mut(&mut self, cnt: usize) {
1435+
// Lifetime dance taken from `impl Write for &mut [u8]`.
1436+
let (_, b) = core::mem::replace(self, &mut []).split_at_mut(cnt);
1437+
*self = b;
1438+
}
1439+
1440+
#[inline]
1441+
fn put_slice(&mut self, src: &[u8]) {
1442+
self.chunk_mut()[..src.len()].copy_from_slice(src);
1443+
unsafe {
1444+
self.advance_mut(src.len());
1445+
}
1446+
}
1447+
1448+
fn put_bytes(&mut self, val: u8, cnt: usize) {
1449+
assert!(self.remaining_mut() >= cnt);
1450+
unsafe {
1451+
ptr::write_bytes(self.as_mut_ptr() as *mut u8, val, cnt);
1452+
self.advance_mut(cnt);
1453+
}
1454+
}
1455+
}
1456+
14221457
unsafe impl BufMut for Vec<u8> {
14231458
#[inline]
14241459
fn remaining_mut(&self) -> usize {

tests/test_buf_mut.rs

+110-13
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
use bytes::buf::UninitSlice;
44
use bytes::{BufMut, BytesMut};
55
use core::fmt::Write;
6+
use core::mem::MaybeUninit;
67
use core::usize;
78

89
#[test]
@@ -101,24 +102,120 @@ fn test_clone() {
101102
assert!(buf != buf2);
102103
}
103104

105+
fn do_test_slice_small<T: ?Sized>(make: impl Fn(&mut [u8]) -> &mut T)
106+
where
107+
for<'r> &'r mut T: BufMut,
108+
{
109+
let mut buf = [b'X'; 8];
110+
111+
let mut slice = make(&mut buf[..]);
112+
slice.put_bytes(b'A', 2);
113+
slice.put_u8(b'B');
114+
slice.put_slice(b"BCC");
115+
assert_eq!(2, slice.remaining_mut());
116+
assert_eq!(b"AABBCCXX", &buf[..]);
117+
118+
let mut slice = make(&mut buf[..]);
119+
slice.put_u32(0x61626364);
120+
assert_eq!(4, slice.remaining_mut());
121+
assert_eq!(b"abcdCCXX", &buf[..]);
122+
123+
let mut slice = make(&mut buf[..]);
124+
slice.put_u32_le(0x30313233);
125+
assert_eq!(4, slice.remaining_mut());
126+
assert_eq!(b"3210CCXX", &buf[..]);
127+
}
128+
129+
fn do_test_slice_large<T: ?Sized>(make: impl Fn(&mut [u8]) -> &mut T)
130+
where
131+
for<'r> &'r mut T: BufMut,
132+
{
133+
const LEN: usize = 100;
134+
const FILL: [u8; LEN] = [b'Y'; LEN];
135+
136+
let test = |fill: &dyn Fn(&mut &mut T, usize)| {
137+
for buf_len in 0..LEN {
138+
let mut buf = [b'X'; LEN];
139+
for fill_len in 0..=buf_len {
140+
let mut slice = make(&mut buf[..buf_len]);
141+
fill(&mut slice, fill_len);
142+
assert_eq!(buf_len - fill_len, slice.remaining_mut());
143+
let (head, tail) = buf.split_at(fill_len);
144+
assert_eq!(&FILL[..fill_len], head);
145+
assert!(tail.iter().all(|b| *b == b'X'));
146+
}
147+
}
148+
};
149+
150+
test(&|slice, fill_len| slice.put_slice(&FILL[..fill_len]));
151+
test(&|slice, fill_len| slice.put_bytes(FILL[0], fill_len));
152+
}
153+
154+
fn do_test_slice_put_slice_panics<T: ?Sized>(make: impl Fn(&mut [u8]) -> &mut T)
155+
where
156+
for<'r> &'r mut T: BufMut,
157+
{
158+
let mut buf = [b'X'; 4];
159+
let mut slice = make(&mut buf[..]);
160+
slice.put_slice(b"12345");
161+
}
162+
163+
fn do_test_slice_put_bytes_panics<T: ?Sized>(make: impl Fn(&mut [u8]) -> &mut T)
164+
where
165+
for<'r> &'r mut T: BufMut,
166+
{
167+
let mut buf = [b'X'; 4];
168+
let mut slice = make(&mut buf[..]);
169+
slice.put_bytes(b'1', 5);
170+
}
171+
172+
#[test]
173+
fn test_slice_buf_mut_small() {
174+
do_test_slice_small(|x| x);
175+
}
176+
104177
#[test]
105-
fn test_mut_slice() {
106-
let mut v = vec![0, 0, 0, 0];
107-
let mut s = &mut v[..];
108-
s.put_u32(42);
178+
fn test_slice_buf_mut_large() {
179+
do_test_slice_large(|x| x);
180+
}
109181

110-
assert_eq!(s.len(), 0);
111-
assert_eq!(&v, &[0, 0, 0, 42]);
182+
#[test]
183+
#[should_panic]
184+
fn test_slice_buf_mut_put_slice_overflow() {
185+
do_test_slice_put_slice_panics(|x| x);
112186
}
113187

114188
#[test]
115-
fn test_slice_put_bytes() {
116-
let mut v = [0, 0, 0, 0];
117-
let mut s = &mut v[..];
118-
s.put_u8(17);
119-
s.put_bytes(19, 2);
120-
assert_eq!(1, s.remaining_mut());
121-
assert_eq!(&[17, 19, 19, 0], &v[..]);
189+
#[should_panic]
190+
fn test_slice_buf_mut_put_bytes_overflow() {
191+
do_test_slice_put_bytes_panics(|x| x);
192+
}
193+
194+
fn make_maybe_uninit_slice(slice: &mut [u8]) -> &mut [MaybeUninit<u8>] {
195+
// SAFETY: [u8] has the same layout as [MaybeUninit<u8>].
196+
unsafe { core::mem::transmute(slice) }
197+
}
198+
199+
#[test]
200+
fn test_maybe_uninit_buf_mut_small() {
201+
do_test_slice_small(make_maybe_uninit_slice);
202+
}
203+
204+
#[test]
205+
fn test_maybe_uninit_buf_mut_large() {
206+
do_test_slice_large(make_maybe_uninit_slice);
207+
}
208+
209+
#[test]
210+
#[should_panic]
211+
fn test_maybe_uninit_buf_mut_put_slice_overflow() {
212+
do_test_slice_put_slice_panics(make_maybe_uninit_slice);
213+
}
214+
215+
#[test]
216+
#[should_panic]
217+
fn test_maybe_uninit_buf_mut_put_bytes_overflow() {
218+
do_test_slice_put_bytes_panics(make_maybe_uninit_slice);
122219
}
123220

124221
#[test]

0 commit comments

Comments
 (0)