Skip to content

Commit aaece75

Browse files
committed
Add std::io::Seek instance for std::io::Take
1 parent f9e0239 commit aaece75

File tree

2 files changed

+166
-1
lines changed

2 files changed

+166
-1
lines changed

library/std/src/io/mod.rs

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1173,7 +1173,7 @@ pub trait Read {
11731173
where
11741174
Self: Sized,
11751175
{
1176-
Take { inner: self, limit }
1176+
Take { inner: self, len: limit, limit }
11771177
}
11781178
}
11791179

@@ -2822,6 +2822,7 @@ impl<T, U> SizeHint for Chain<T, U> {
28222822
#[derive(Debug)]
28232823
pub struct Take<T> {
28242824
inner: T,
2825+
len: u64,
28252826
limit: u64,
28262827
}
28272828

@@ -2856,6 +2857,12 @@ impl<T> Take<T> {
28562857
self.limit
28572858
}
28582859

2860+
/// Returns the number of bytes read so far.
2861+
#[stable(feature = "seek_io_take", since = "CURRENT_RUSTC_VERSION")]
2862+
pub fn position(&self) -> u64 {
2863+
self.len - self.limit
2864+
}
2865+
28592866
/// Sets the number of bytes that can be read before this instance will
28602867
/// return EOF. This is the same as constructing a new `Take` instance, so
28612868
/// the amount of bytes read and the previous limit value don't matter when
@@ -2881,6 +2888,7 @@ impl<T> Take<T> {
28812888
/// ```
28822889
#[stable(feature = "take_set_limit", since = "1.27.0")]
28832890
pub fn set_limit(&mut self, limit: u64) {
2891+
self.len = limit;
28842892
self.limit = limit;
28852893
}
28862894

@@ -3064,6 +3072,53 @@ impl<T> SizeHint for Take<T> {
30643072
}
30653073
}
30663074

3075+
#[stable(feature = "seek_io_take", since = "CURRENT_RUSTC_VERSION")]
3076+
impl<T: Seek> Seek for Take<T> {
3077+
fn seek(&mut self, pos: SeekFrom) -> Result<u64> {
3078+
let offset_from_start = match pos {
3079+
SeekFrom::Start(offset) => offset,
3080+
SeekFrom::End(offset) => {
3081+
if offset > 0 {
3082+
return Ok(self.position());
3083+
}
3084+
if offset.unsigned_abs() > self.len {
3085+
return Err(Error::from(ErrorKind::InvalidInput));
3086+
}
3087+
self.len - offset.unsigned_abs()
3088+
}
3089+
SeekFrom::Current(offset) => {
3090+
if offset >= 0 {
3091+
self.position() + offset.unsigned_abs()
3092+
} else {
3093+
self.position() - offset.unsigned_abs()
3094+
}
3095+
}
3096+
};
3097+
let offset_from_start = offset_from_start.min(self.len);
3098+
if offset_from_start > self.position() {
3099+
let mut offset_from_current = offset_from_start - self.position();
3100+
while offset_from_current > i64::MAX as u64 {
3101+
self.inner.seek(SeekFrom::Current(i64::MAX))?;
3102+
self.limit -= i64::MAX as u64;
3103+
offset_from_current -= i64::MAX as u64;
3104+
}
3105+
self.inner.seek(SeekFrom::Current(offset_from_current as i64))?;
3106+
self.limit -= offset_from_current;
3107+
Ok(self.position())
3108+
} else {
3109+
let mut offset_from_current = self.position() - offset_from_start;
3110+
while offset_from_current > i64::MIN.unsigned_abs() {
3111+
self.inner.seek(SeekFrom::Current(i64::MIN))?;
3112+
self.limit += i64::MIN.unsigned_abs();
3113+
offset_from_current -= i64::MIN.unsigned_abs();
3114+
}
3115+
self.inner.seek(SeekFrom::Current(-(offset_from_current as i64)))?;
3116+
self.limit += offset_from_current;
3117+
Ok(self.position())
3118+
}
3119+
}
3120+
}
3121+
30673122
/// An iterator over `u8` values of a reader.
30683123
///
30693124
/// This struct is generally created by calling [`bytes`] on a reader.

library/std/src/io/tests.rs

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -416,6 +416,116 @@ fn seek_position() -> io::Result<()> {
416416
Ok(())
417417
}
418418

419+
#[test]
420+
fn take_seek() -> io::Result<()> {
421+
let mut buf = Cursor::new(b"0123456789");
422+
buf.set_position(2);
423+
let mut take = buf.by_ref().take(4);
424+
let mut buf1 = [0u8; 1];
425+
let mut buf2 = [0u8; 2];
426+
assert_eq!(take.position(), 0);
427+
428+
assert_eq!(take.seek(SeekFrom::Start(0))?, 0);
429+
take.read_exact(&mut buf2)?;
430+
assert_eq!(buf2, [b'2', b'3']);
431+
assert_eq!(take.seek(SeekFrom::Start(1))?, 1);
432+
take.read_exact(&mut buf2)?;
433+
assert_eq!(buf2, [b'3', b'4']);
434+
assert_eq!(take.seek(SeekFrom::Start(2))?, 2);
435+
take.read_exact(&mut buf2)?;
436+
assert_eq!(buf2, [b'4', b'5']);
437+
assert_eq!(take.seek(SeekFrom::Start(3))?, 3);
438+
take.read_exact(&mut buf1)?;
439+
assert_eq!(buf1, [b'5']);
440+
assert_eq!(take.seek(SeekFrom::Start(4))?, 4);
441+
assert_eq!(take.seek(SeekFrom::Start(5))?, 4);
442+
443+
assert_eq!(take.seek(SeekFrom::End(1))?, 4);
444+
assert_eq!(take.seek(SeekFrom::End(0))?, 4);
445+
assert_eq!(take.seek(SeekFrom::End(-1))?, 3);
446+
take.read_exact(&mut buf1)?;
447+
assert_eq!(buf1, [b'5']);
448+
assert_eq!(take.seek(SeekFrom::End(-2))?, 2);
449+
take.read_exact(&mut buf2)?;
450+
assert_eq!(buf2, [b'4', b'5']);
451+
assert_eq!(take.seek(SeekFrom::End(-3))?, 1);
452+
take.read_exact(&mut buf2)?;
453+
assert_eq!(buf2, [b'3', b'4']);
454+
assert_eq!(take.seek(SeekFrom::End(-4))?, 0);
455+
take.read_exact(&mut buf2)?;
456+
assert_eq!(buf2, [b'2', b'3']);
457+
458+
assert_eq!(take.seek(SeekFrom::Current(0))?, 2);
459+
take.read_exact(&mut buf2)?;
460+
assert_eq!(buf2, [b'4', b'5']);
461+
462+
assert_eq!(take.seek(SeekFrom::Current(-3))?, 1);
463+
take.read_exact(&mut buf2)?;
464+
assert_eq!(buf2, [b'3', b'4']);
465+
466+
assert_eq!(take.seek(SeekFrom::Current(-1))?, 2);
467+
take.read_exact(&mut buf2)?;
468+
assert_eq!(buf2, [b'4', b'5']);
469+
470+
assert_eq!(take.seek(SeekFrom::Current(-4))?, 0);
471+
take.read_exact(&mut buf2)?;
472+
assert_eq!(buf2, [b'2', b'3']);
473+
474+
assert_eq!(take.seek(SeekFrom::Current(2))?, 4);
475+
assert_eq!(take.seek(SeekFrom::Current(10))?, 4);
476+
477+
Ok(())
478+
}
479+
480+
struct ExampleHugeRangeOfZeroes {
481+
position: u64,
482+
}
483+
484+
impl Read for ExampleHugeRangeOfZeroes {
485+
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
486+
let max = buf.len().min(usize::MAX);
487+
for i in 0..max {
488+
if self.position == u64::MAX {
489+
return Ok(i);
490+
}
491+
self.position += 1;
492+
buf[i] = 0;
493+
}
494+
Ok(max)
495+
}
496+
}
497+
498+
impl Seek for ExampleHugeRangeOfZeroes {
499+
fn seek(&mut self, pos: io::SeekFrom) -> io::Result<u64> {
500+
match pos {
501+
io::SeekFrom::Start(i) => self.position = i,
502+
io::SeekFrom::End(i) if i >= 0 => self.position = u64::MAX,
503+
io::SeekFrom::End(i) => self.position = self.position - i.unsigned_abs(),
504+
io::SeekFrom::Current(i) => {
505+
self.position = if i >= 0 {
506+
self.position.saturating_add(i.unsigned_abs())
507+
} else {
508+
self.position.saturating_sub(i.unsigned_abs())
509+
};
510+
}
511+
}
512+
Ok(self.position)
513+
}
514+
}
515+
516+
#[test]
517+
fn take_seek_big_offsets() -> io::Result<()> {
518+
let inner = ExampleHugeRangeOfZeroes { position: 1 };
519+
let mut take = inner.take(u64::MAX - 2);
520+
assert_eq!(take.seek(io::SeekFrom::Start(u64::MAX))?, u64::MAX - 2);
521+
assert_eq!(take.inner.position, u64::MAX - 1);
522+
assert_eq!(take.seek(io::SeekFrom::Start(0))?, 0);
523+
assert_eq!(take.inner.position, 1);
524+
assert_eq!(take.seek(io::SeekFrom::End(-1))?, u64::MAX - 3);
525+
assert_eq!(take.inner.position, u64::MAX - 2);
526+
Ok(())
527+
}
528+
419529
// A simple example reader which uses the default implementation of
420530
// read_to_end.
421531
struct ExampleSliceReader<'a> {

0 commit comments

Comments
 (0)