forked from miselin/rust
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
std: Implement bare bones of the new
io
module
This commit is an implementation of [RFC 576][rfc] which focuses on some of the more core aspects of `std::io`. It re-introduces a new `std::io` module with the base set of traits, helpers, and adaptors. The module is not currently ready for prime time as it is not integrated into the rest of the system, but some proof-of-concept implementations and methods are now available. [rfc]: rust-lang/rfcs#576 This module will grow quickly over the next few weeks as more I/O RFCs land and as the `old_io` module is slowly deprecated and phased out. At this time it is not recommended for use, but it is helpful to land in-tree to start developing more implementations.
- Loading branch information
1 parent
30062bc
commit e950a8a
Showing
25 changed files
with
1,658 additions
and
126 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT | ||
// file at the top-level directory of this distribution and at | ||
// http://rust-lang.org/COPYRIGHT. | ||
// | ||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or | ||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license | ||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your | ||
// option. This file may not be copied, modified, or distributed | ||
// except according to those terms. | ||
|
||
use core::prelude::*; | ||
|
||
use core::io::prelude::*; | ||
use core::io::{Cursor, NegativeSeek, SeekPos}; | ||
use core::iter::repeat; | ||
use core::slice; | ||
use core::void::Void; | ||
|
||
use vec::Vec; | ||
|
||
impl Read for Cursor<Vec<u8>> { | ||
type Err = Void; | ||
fn read(&mut self, buf: &mut [u8]) -> Result<usize, Void> { | ||
let pos = self.position(); | ||
let n = { | ||
let inner = self.get_ref(); | ||
if pos > inner.len() as u64 { return Ok(0) } | ||
let mut slice = &inner[(pos as usize)..]; | ||
try!(slice.read(buf)) | ||
}; | ||
self.set_position(pos + n as u64); | ||
Ok(n) | ||
} | ||
} | ||
|
||
impl Seek for Cursor<Vec<u8>> { | ||
type Err = NegativeSeek; | ||
|
||
fn seek(&mut self, pos: SeekPos) -> Result<u64, NegativeSeek> { | ||
let old_pos = self.position(); | ||
let new_pos = { | ||
let mut c = Cursor::new(&self.get_mut()[]); | ||
c.set_position(old_pos); | ||
try!(c.seek(pos)) | ||
}; | ||
self.set_position(new_pos); | ||
Ok(new_pos) | ||
} | ||
} | ||
|
||
impl Write for Vec<u8> { | ||
type Err = Void; | ||
|
||
fn write(&mut self, buf: &[u8]) -> Result<usize, Void> { | ||
self.push_all(buf); | ||
Ok(buf.len()) | ||
} | ||
} | ||
|
||
impl Write for Cursor<Vec<u8>> { | ||
type Err = Void; | ||
|
||
fn write(&mut self, buf: &[u8]) -> Result<usize, Void> { | ||
let pos = self.position(); | ||
let mut len = self.get_ref().len(); | ||
if pos == len as u64 { | ||
self.get_mut().push_all(buf) | ||
} else { | ||
// Make sure the internal buffer is as least as big as where we | ||
// currently are | ||
let difference = pos as i64 - len as i64; | ||
if difference > 0 { | ||
self.get_mut().extend(repeat(0).take(difference as usize)); | ||
len += difference as usize; | ||
} | ||
|
||
// Figure out what bytes will be used to overwrite what's currently | ||
// there (left), and what will be appended on the end (right) | ||
let cap = len - (pos as usize); | ||
let (left, right) = if cap <= buf.len() { | ||
(&buf[..cap], &buf[cap..]) | ||
} else { | ||
let result: (_, &[_]) = (buf, &[]); | ||
result | ||
}; | ||
|
||
// Do the necessary writes | ||
if left.len() > 0 { | ||
let dst = &mut self.get_mut()[(pos as usize)..]; | ||
slice::bytes::copy_memory(dst, left); | ||
} | ||
if right.len() > 0 { | ||
self.get_mut().push_all(right); | ||
} | ||
} | ||
|
||
// Bump us forward | ||
self.set_position(pos + buf.len() as u64); | ||
Ok(buf.len()) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,185 @@ | ||
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT | ||
// file at the top-level directory of this distribution and at | ||
// http://rust-lang.org/COPYRIGHT. | ||
// | ||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or | ||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license | ||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your | ||
// option. This file may not be copied, modified, or distributed | ||
// except according to those terms. | ||
|
||
#![allow(missing_copy_implementations)] | ||
|
||
use prelude::*; | ||
|
||
use cmp; | ||
use error::Error; | ||
use fmt; | ||
use void::Void; | ||
use io::{Read, BufferedRead, Write, Seek, SeekPos}; | ||
use mem; | ||
use slice; | ||
|
||
/// A `Cursor` is a type which wraps another I/O object to provide a `Seek` | ||
/// implementation. | ||
/// | ||
/// Cursors are currently typically used with memory buffer objects in order to | ||
/// allow `Seek` plus `Read` and `Write` implementations. For example, common | ||
/// cursor types include: | ||
/// | ||
/// * `Cursor<Vec<u8>>` | ||
/// * `Cursor<&[u8]>` | ||
/// | ||
/// Cursors are not currently generic over the type contained within, but may | ||
/// become so. | ||
pub struct Cursor<T> { | ||
pos: u64, | ||
inner: T, | ||
} | ||
|
||
/// Error returned from primitive seek implementations indicating that a | ||
/// negative byte position was seeked to. | ||
#[derive(Show, PartialEq, Clone, Copy)] | ||
pub struct NegativeSeek; | ||
|
||
impl<T> Cursor<T> { | ||
/// Create a new cursor wrapping the provided underlying I/O object. | ||
pub fn new(inner: T) -> Cursor<T> { | ||
Cursor { pos: 0, inner: inner } | ||
} | ||
|
||
/// Consume this cursor, returning the underlying value. | ||
pub fn into_inner(self) -> T { self.inner } | ||
|
||
/// Get a reference to the underlying value in this cursor. | ||
pub fn get_ref(&self) -> &T { &self.inner } | ||
|
||
/// Get a mutable reference to the underlying value in this cursor. | ||
/// | ||
/// Care should be taken to avoid modifying the internal I/O state of the | ||
/// underlying value as it may corrupt this cursor's position. | ||
pub fn get_mut(&mut self) -> &mut T { &mut self.inner } | ||
|
||
/// Returns the current value of this cursor | ||
pub fn position(&self) -> u64 { self.pos } | ||
|
||
/// Sets the value of this cursor | ||
pub fn set_position(&mut self, pos: u64) { self.pos = pos; } | ||
} | ||
|
||
macro_rules! seek { | ||
() => { | ||
fn seek(&mut self, style: SeekPos) -> Result<u64, NegativeSeek> { | ||
let pos = match style { | ||
SeekPos::FromStart(n) => n as i64, | ||
SeekPos::FromEnd(n) => self.inner.len() as i64 + n, | ||
SeekPos::FromCur(n) => self.pos as i64 + n, | ||
}; | ||
|
||
if pos < 0 { | ||
Err(NegativeSeek) | ||
} else { | ||
self.pos = pos as u64; | ||
Ok(self.pos) | ||
} | ||
} | ||
} | ||
} | ||
|
||
impl<'a> Seek for Cursor<&'a [u8]> { type Err = NegativeSeek; seek!(); } | ||
impl<'a> Seek for Cursor<&'a mut [u8]> { type Err = NegativeSeek; seek!(); } | ||
|
||
impl<'a> Read for &'a [u8] { | ||
type Err = Void; | ||
#[inline] | ||
fn read(&mut self, buf: &mut [u8]) -> Result<usize, Void> { | ||
let write_len = cmp::min(buf.len(), self.len()); | ||
{ | ||
let input = &self[..write_len]; | ||
let output = &mut buf[.. write_len]; | ||
slice::bytes::copy_memory(output, input); | ||
} | ||
|
||
*self = &self[write_len..]; | ||
|
||
Ok(write_len) | ||
} | ||
} | ||
|
||
macro_rules! read { | ||
() => { | ||
fn read(&mut self, buf: &mut [u8]) -> Result<usize, Void> { | ||
if self.pos > self.inner.len() as u64 { return Ok(0) } | ||
let mut slice = &self.inner[(self.pos as usize)..]; | ||
let n = try!(slice.read(buf)); | ||
self.pos += n as u64; | ||
Ok(n) | ||
} | ||
} | ||
} | ||
|
||
impl<'a> Read for Cursor<&'a [u8]> { type Err = Void; read!(); } | ||
impl<'a> Read for Cursor<&'a mut [u8]> { type Err = Void; read!(); } | ||
|
||
macro_rules! buffer { | ||
() => { | ||
fn fill_buf(&mut self) -> Result<&[u8], Void> { | ||
if self.pos < (self.inner.len() as u64) { | ||
Ok(&self.inner[(self.pos as usize)..]) | ||
} else { | ||
Ok(&[]) | ||
} | ||
} | ||
fn consume(&mut self, amt: usize) { self.pos += amt as u64; } | ||
} | ||
} | ||
|
||
impl<'a> BufferedRead for Cursor<&'a [u8]> { buffer!(); } | ||
impl<'a> BufferedRead for Cursor<&'a mut [u8]> { buffer!(); } | ||
|
||
impl<'a> Write for &'a mut [u8] { | ||
type Err = Void; | ||
|
||
fn write(&mut self, data: &[u8]) -> Result<usize, Void> { | ||
let dst_len = self.len(); | ||
let data_len = data.len(); | ||
if dst_len >= data_len { | ||
slice::bytes::copy_memory(*self, data); | ||
// TODO: is this actually safe? | ||
*self = unsafe { | ||
let next: &'a mut [u8] = mem::transmute_copy(&*self); | ||
&mut next[data_len..] | ||
}; | ||
Ok(data_len) | ||
} else { | ||
slice::bytes::copy_memory(*self, &data[..dst_len]); | ||
*self = &mut []; | ||
Ok(dst_len) | ||
} | ||
} | ||
} | ||
|
||
impl<'a> Write for Cursor<&'a mut [u8]> { | ||
type Err = Void; | ||
|
||
fn write(&mut self, data: &[u8]) -> Result<usize, Void> { | ||
if self.pos >= self.inner.len() as u64 { return Ok(0) } | ||
|
||
let amt = { | ||
let mut s = &mut self.inner[(self.pos as usize)..]; | ||
try!(s.write(data)) | ||
}; | ||
self.pos += amt as u64; | ||
Ok(amt) | ||
} | ||
} | ||
|
||
impl fmt::Display for NegativeSeek { | ||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||
"cannot seek to a negative position".fmt(f) | ||
} | ||
} | ||
|
||
impl Error for NegativeSeek { | ||
fn description(&self) -> &str { "seek error" } | ||
} |
Oops, something went wrong.