Skip to content

Commit

Permalink
std: Implement bare bones of the new io module
Browse files Browse the repository at this point in the history
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
alexcrichton authored and Ericson2314 committed Feb 1, 2015
1 parent 30062bc commit e950a8a
Show file tree
Hide file tree
Showing 25 changed files with 1,658 additions and 126 deletions.
101 changes: 101 additions & 0 deletions src/libcollections/io.rs
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())
}
}
3 changes: 2 additions & 1 deletion src/libcollections/string.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ use core::iter::FromIterator;
use core::mem;
use core::ops::{self, Deref, Add, Index};
use core::ptr;
use core::str as core_str;
use core::raw::Slice as RawSlice;
use unicode::str as unicode_str;
use unicode::str::Utf16Item;
Expand Down Expand Up @@ -199,7 +200,7 @@ impl String {
if byte < 128u8 {
// subseqidx handles this
} else {
let w = unicode_str::utf8_char_width(byte);
let w = core_str::utf8_char_width(byte);

match w {
2 => {
Expand Down
9 changes: 9 additions & 0 deletions src/libcore/borrow.rs
Original file line number Diff line number Diff line change
Expand Up @@ -263,3 +263,12 @@ impl<'a, T, B: ?Sized> fmt::Display for Cow<'a, T, B> where
}
}
}

/// A helper structure whose sole purpose is to contain an inner reference.
///
/// This structure is often returned from methods called `by_ref` on iterators,
/// readers, and writers.
pub struct ByRef<'a, T: ?Sized + 'a> {
/// The contained reference in this structure.
pub inner: &'a mut T,
}
185 changes: 185 additions & 0 deletions src/libcore/io/mem.rs
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" }
}
Loading

0 comments on commit e950a8a

Please sign in to comment.