Skip to content

Commit 766b10a

Browse files
committed
Auto merge of #62987 - Thomasdezeeuw:ioslice-advance, r=Thomasdezeeuw
Add {IoSlice, IoSliceMut}::advance API inspired by the [`Buf::advance`](https://docs.rs/bytes/0.4.12/bytes/trait.Buf.html#tymethod.advance) method found in the [bytes](https://docs.rs/bytes) crate. Closes #62726.
2 parents c471519 + dad56c3 commit 766b10a

File tree

9 files changed

+351
-1
lines changed

9 files changed

+351
-1
lines changed

src/libstd/io/mod.rs

+199-1
Original file line numberDiff line numberDiff line change
@@ -942,6 +942,62 @@ impl<'a> IoSliceMut<'a> {
942942
pub fn new(buf: &'a mut [u8]) -> IoSliceMut<'a> {
943943
IoSliceMut(sys::io::IoSliceMut::new(buf))
944944
}
945+
946+
/// Advance the internal cursor of the slice.
947+
///
948+
/// # Notes
949+
///
950+
/// Elements in the slice may be modified if the cursor is not advanced to
951+
/// the end of the slice. For example if we have a slice of buffers with 2
952+
/// `IoSliceMut`s, both of length 8, and we advance the cursor by 10 bytes
953+
/// the first `IoSliceMut` will be untouched however the second will be
954+
/// modified to remove the first 2 bytes (10 - 8).
955+
///
956+
/// # Examples
957+
///
958+
/// ```
959+
/// #![feature(io_slice_advance)]
960+
///
961+
/// use std::io::IoSliceMut;
962+
/// use std::mem;
963+
/// use std::ops::Deref;
964+
///
965+
/// let mut buf1 = [1; 8];
966+
/// let mut buf2 = [2; 16];
967+
/// let mut buf3 = [3; 8];
968+
/// let mut bufs = &mut [
969+
/// IoSliceMut::new(&mut buf1),
970+
/// IoSliceMut::new(&mut buf2),
971+
/// IoSliceMut::new(&mut buf3),
972+
/// ][..];
973+
///
974+
/// // Mark 10 bytes as read.
975+
/// bufs = IoSliceMut::advance(mem::replace(&mut bufs, &mut []), 10);
976+
/// assert_eq!(bufs[0].deref(), [2; 14].as_ref());
977+
/// assert_eq!(bufs[1].deref(), [3; 8].as_ref());
978+
/// ```
979+
#[unstable(feature = "io_slice_advance", issue = "62726")]
980+
#[inline]
981+
pub fn advance<'b>(bufs: &'b mut [IoSliceMut<'a>], n: usize) -> &'b mut [IoSliceMut<'a>] {
982+
// Number of buffers to remove.
983+
let mut remove = 0;
984+
// Total length of all the to be removed buffers.
985+
let mut accumulated_len = 0;
986+
for buf in bufs.iter() {
987+
if accumulated_len + buf.len() > n {
988+
break;
989+
} else {
990+
accumulated_len += buf.len();
991+
remove += 1;
992+
}
993+
}
994+
995+
let bufs = &mut bufs[remove..];
996+
if !bufs.is_empty() {
997+
bufs[0].0.advance(n - accumulated_len)
998+
}
999+
bufs
1000+
}
9451001
}
9461002

9471003
#[stable(feature = "iovec", since = "1.36.0")]
@@ -989,6 +1045,61 @@ impl<'a> IoSlice<'a> {
9891045
pub fn new(buf: &'a [u8]) -> IoSlice<'a> {
9901046
IoSlice(sys::io::IoSlice::new(buf))
9911047
}
1048+
1049+
/// Advance the internal cursor of the slice.
1050+
///
1051+
/// # Notes
1052+
///
1053+
/// Elements in the slice may be modified if the cursor is not advanced to
1054+
/// the end of the slice. For example if we have a slice of buffers with 2
1055+
/// `IoSlice`s, both of length 8, and we advance the cursor by 10 bytes the
1056+
/// first `IoSlice` will be untouched however the second will be modified to
1057+
/// remove the first 2 bytes (10 - 8).
1058+
///
1059+
/// # Examples
1060+
///
1061+
/// ```
1062+
/// #![feature(io_slice_advance)]
1063+
///
1064+
/// use std::io::IoSlice;
1065+
/// use std::mem;
1066+
/// use std::ops::Deref;
1067+
///
1068+
/// let mut buf1 = [1; 8];
1069+
/// let mut buf2 = [2; 16];
1070+
/// let mut buf3 = [3; 8];
1071+
/// let mut bufs = &mut [
1072+
/// IoSlice::new(&mut buf1),
1073+
/// IoSlice::new(&mut buf2),
1074+
/// IoSlice::new(&mut buf3),
1075+
/// ][..];
1076+
///
1077+
/// // Mark 10 bytes as written.
1078+
/// bufs = IoSlice::advance(mem::replace(&mut bufs, &mut []), 10);
1079+
/// assert_eq!(bufs[0].deref(), [2; 14].as_ref());
1080+
/// assert_eq!(bufs[1].deref(), [3; 8].as_ref());
1081+
#[unstable(feature = "io_slice_advance", issue = "62726")]
1082+
#[inline]
1083+
pub fn advance<'b>(bufs: &'b mut [IoSlice<'a>], n: usize) -> &'b mut [IoSlice<'a>] {
1084+
// Number of buffers to remove.
1085+
let mut remove = 0;
1086+
// Total length of all the to be removed buffers.
1087+
let mut accumulated_len = 0;
1088+
for buf in bufs.iter() {
1089+
if accumulated_len + buf.len() > n {
1090+
break;
1091+
} else {
1092+
accumulated_len += buf.len();
1093+
remove += 1;
1094+
}
1095+
}
1096+
1097+
let bufs = &mut bufs[remove..];
1098+
if !bufs.is_empty() {
1099+
bufs[0].0.advance(n - accumulated_len)
1100+
}
1101+
bufs
1102+
}
9921103
}
9931104

9941105
#[stable(feature = "iovec", since = "1.36.0")]
@@ -2268,8 +2379,10 @@ impl<B: BufRead> Iterator for Lines<B> {
22682379
#[cfg(test)]
22692380
mod tests {
22702381
use crate::io::prelude::*;
2271-
use crate::io;
22722382
use super::{Cursor, SeekFrom, repeat};
2383+
use crate::io::{self, IoSlice, IoSliceMut};
2384+
use crate::mem;
2385+
use crate::ops::Deref;
22732386

22742387
#[test]
22752388
#[cfg_attr(target_os = "emscripten", ignore)]
@@ -2537,4 +2650,89 @@ mod tests {
25372650

25382651
Ok(())
25392652
}
2653+
2654+
#[test]
2655+
fn io_slice_mut_advance() {
2656+
let mut buf1 = [1; 8];
2657+
let mut buf2 = [2; 16];
2658+
let mut buf3 = [3; 8];
2659+
let mut bufs = &mut [
2660+
IoSliceMut::new(&mut buf1),
2661+
IoSliceMut::new(&mut buf2),
2662+
IoSliceMut::new(&mut buf3),
2663+
][..];
2664+
2665+
// Only in a single buffer..
2666+
bufs = IoSliceMut::advance(mem::replace(&mut bufs, &mut []), 1);
2667+
assert_eq!(bufs[0].deref(), [1; 7].as_ref());
2668+
assert_eq!(bufs[1].deref(), [2; 16].as_ref());
2669+
assert_eq!(bufs[2].deref(), [3; 8].as_ref());
2670+
2671+
// Removing a buffer, leaving others as is.
2672+
bufs = IoSliceMut::advance(mem::replace(&mut bufs, &mut []), 7);
2673+
assert_eq!(bufs[0].deref(), [2; 16].as_ref());
2674+
assert_eq!(bufs[1].deref(), [3; 8].as_ref());
2675+
2676+
// Removing a buffer and removing from the next buffer.
2677+
bufs = IoSliceMut::advance(mem::replace(&mut bufs, &mut []), 18);
2678+
assert_eq!(bufs[0].deref(), [3; 6].as_ref());
2679+
}
2680+
2681+
#[test]
2682+
fn io_slice_mut_advance_empty_slice() {
2683+
let mut empty_bufs = &mut [][..];
2684+
// Shouldn't panic.
2685+
IoSliceMut::advance(&mut empty_bufs, 1);
2686+
}
2687+
2688+
#[test]
2689+
fn io_slice_mut_advance_beyond_total_length() {
2690+
let mut buf1 = [1; 8];
2691+
let mut bufs = &mut [IoSliceMut::new(&mut buf1)][..];
2692+
2693+
// Going beyond the total length should be ok.
2694+
bufs = IoSliceMut::advance(mem::replace(&mut bufs, &mut []), 9);
2695+
assert!(bufs.is_empty());
2696+
}
2697+
2698+
#[test]
2699+
fn io_slice_advance() {
2700+
let mut buf1 = [1; 8];
2701+
let mut buf2 = [2; 16];
2702+
let mut buf3 = [3; 8];
2703+
let mut bufs =
2704+
&mut [IoSlice::new(&mut buf1), IoSlice::new(&mut buf2), IoSlice::new(&mut buf3)][..];
2705+
2706+
// Only in a single buffer..
2707+
bufs = IoSlice::advance(mem::replace(&mut bufs, &mut []), 1);
2708+
assert_eq!(bufs[0].deref(), [1; 7].as_ref());
2709+
assert_eq!(bufs[1].deref(), [2; 16].as_ref());
2710+
assert_eq!(bufs[2].deref(), [3; 8].as_ref());
2711+
2712+
// Removing a buffer, leaving others as is.
2713+
bufs = IoSlice::advance(mem::replace(&mut bufs, &mut []), 7);
2714+
assert_eq!(bufs[0].deref(), [2; 16].as_ref());
2715+
assert_eq!(bufs[1].deref(), [3; 8].as_ref());
2716+
2717+
// Removing a buffer and removing from the next buffer.
2718+
bufs = IoSlice::advance(mem::replace(&mut bufs, &mut []), 18);
2719+
assert_eq!(bufs[0].deref(), [3; 6].as_ref());
2720+
}
2721+
2722+
#[test]
2723+
fn io_slice_advance_empty_slice() {
2724+
let mut empty_bufs = &mut [][..];
2725+
// Shouldn't panic.
2726+
IoSlice::advance(&mut empty_bufs, 1);
2727+
}
2728+
2729+
#[test]
2730+
fn io_slice_advance_beyond_total_length() {
2731+
let mut buf1 = [1; 8];
2732+
let mut bufs = &mut [IoSlice::new(&mut buf1)][..];
2733+
2734+
// Going beyond the total length should be ok.
2735+
bufs = IoSlice::advance(mem::replace(&mut bufs, &mut []), 9);
2736+
assert!(bufs.is_empty());
2737+
}
25402738
}

src/libstd/sys/cloudabi/io.rs

+14
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use crate::mem;
2+
13
pub struct IoSlice<'a>(&'a [u8]);
24

35
impl<'a> IoSlice<'a> {
@@ -6,6 +8,11 @@ impl<'a> IoSlice<'a> {
68
IoSlice(buf)
79
}
810

11+
#[inline]
12+
pub fn advance(&mut self, n: usize) {
13+
self.0 = &self.0[n..]
14+
}
15+
916
#[inline]
1017
pub fn as_slice(&self) -> &[u8] {
1118
self.0
@@ -20,6 +27,13 @@ impl<'a> IoSliceMut<'a> {
2027
IoSliceMut(buf)
2128
}
2229

30+
#[inline]
31+
pub fn advance(&mut self, n: usize) {
32+
let slice = mem::replace(&mut self.0, &mut []);
33+
let (_, remaining) = slice.split_at_mut(n);
34+
self.0 = remaining;
35+
}
36+
2337
#[inline]
2438
pub fn as_slice(&self) -> &[u8] {
2539
self.0

src/libstd/sys/redox/io.rs

+14
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use crate::mem;
2+
13
pub struct IoSlice<'a>(&'a [u8]);
24

35
impl<'a> IoSlice<'a> {
@@ -6,6 +8,11 @@ impl<'a> IoSlice<'a> {
68
IoSlice(buf)
79
}
810

11+
#[inline]
12+
pub fn advance(&mut self, n: usize) {
13+
self.0 = &self.0[n..]
14+
}
15+
916
#[inline]
1017
pub fn as_slice(&self) -> &[u8] {
1118
self.0
@@ -20,6 +27,13 @@ impl<'a> IoSliceMut<'a> {
2027
IoSliceMut(buf)
2128
}
2229

30+
#[inline]
31+
pub fn advance(&mut self, n: usize) {
32+
let slice = mem::replace(&mut self.0, &mut []);
33+
let (_, remaining) = slice.split_at_mut(n);
34+
self.0 = remaining;
35+
}
36+
2337
#[inline]
2438
pub fn as_slice(&self) -> &[u8] {
2539
self.0

src/libstd/sys/sgx/io.rs

+14
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use crate::mem;
2+
13
pub struct IoSlice<'a>(&'a [u8]);
24

35
impl<'a> IoSlice<'a> {
@@ -6,6 +8,11 @@ impl<'a> IoSlice<'a> {
68
IoSlice(buf)
79
}
810

11+
#[inline]
12+
pub fn advance(&mut self, n: usize) {
13+
self.0 = &self.0[n..]
14+
}
15+
916
#[inline]
1017
pub fn as_slice(&self) -> &[u8] {
1118
self.0
@@ -20,6 +27,13 @@ impl<'a> IoSliceMut<'a> {
2027
IoSliceMut(buf)
2128
}
2229

30+
#[inline]
31+
pub fn advance(&mut self, n: usize) {
32+
let slice = mem::replace(&mut self.0, &mut []);
33+
let (_, remaining) = slice.split_at_mut(n);
34+
self.0 = remaining;
35+
}
36+
2337
#[inline]
2438
pub fn as_slice(&self) -> &[u8] {
2539
self.0

src/libstd/sys/unix/io.rs

+24
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,18 @@ impl<'a> IoSlice<'a> {
2121
}
2222
}
2323

24+
#[inline]
25+
pub fn advance(&mut self, n: usize) {
26+
if self.vec.iov_len < n {
27+
panic!("advancing IoSlice beyond its length");
28+
}
29+
30+
unsafe {
31+
self.vec.iov_len -= n;
32+
self.vec.iov_base = self.vec.iov_base.add(n);
33+
}
34+
}
35+
2436
#[inline]
2537
pub fn as_slice(&self) -> &[u8] {
2638
unsafe {
@@ -47,6 +59,18 @@ impl<'a> IoSliceMut<'a> {
4759
}
4860
}
4961

62+
#[inline]
63+
pub fn advance(&mut self, n: usize) {
64+
if self.vec.iov_len < n {
65+
panic!("advancing IoSliceMut beyond its length");
66+
}
67+
68+
unsafe {
69+
self.vec.iov_len -= n;
70+
self.vec.iov_base = self.vec.iov_base.add(n);
71+
}
72+
}
73+
5074
#[inline]
5175
pub fn as_slice(&self) -> &[u8] {
5276
unsafe {

src/libstd/sys/vxworks/io.rs

+24
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,18 @@ impl<'a> IoSlice<'a> {
2121
}
2222
}
2323

24+
#[inline]
25+
pub fn advance(&mut self, n: usize) {
26+
if self.vec.iov_len < n {
27+
panic!("advancing IoSlice beyond its length");
28+
}
29+
30+
unsafe {
31+
self.vec.iov_len -= n;
32+
self.vec.iov_base = self.vec.iov_base.add(n);
33+
}
34+
}
35+
2436
#[inline]
2537
pub fn as_slice(&self) -> &[u8] {
2638
unsafe {
@@ -46,6 +58,18 @@ impl<'a> IoSliceMut<'a> {
4658
}
4759
}
4860

61+
#[inline]
62+
pub fn advance(&mut self, n: usize) {
63+
if self.vec.iov_len < n {
64+
panic!("advancing IoSliceMut beyond its length");
65+
}
66+
67+
unsafe {
68+
self.vec.iov_len -= n;
69+
self.vec.iov_base = self.vec.iov_base.add(n);
70+
}
71+
}
72+
4973
#[inline]
5074
pub fn as_slice(&self) -> &[u8] {
5175
unsafe {

0 commit comments

Comments
 (0)