Skip to content

Commit

Permalink
Switch reader to work with preallocated vecs
Browse files Browse the repository at this point in the history
This closes rust-lang#2901.
  • Loading branch information
erickt committed Jul 21, 2012
1 parent 5b62540 commit 3512e35
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 38 deletions.
48 changes: 31 additions & 17 deletions src/libcore/io.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,9 @@ enum seek_style { seek_set, seek_end, seek_cur, }
// The raw underlying reader iface. All readers must implement this.
iface reader {
// FIXME (#2004): Seekable really should be orthogonal.
fn read_bytes(uint) -> ~[u8];

// FIXME (#2982): This should probably return an error.
fn read(buf: &[mut u8], len: uint) -> uint;
fn read_byte() -> int;
fn unread_byte(int);
fn eof() -> bool;
Expand All @@ -41,6 +43,16 @@ iface reader {
// Generic utility functions defined on readers

impl reader_util for reader {
fn read_bytes(len: uint) -> ~[u8] {
let mut buf = ~[mut];
vec::reserve(buf, len);
unsafe { vec::unsafe::set_len(buf, len); }

let count = self.read(buf, len);

unsafe { vec::unsafe::set_len(buf, count); }
vec::from_mut(buf)
}
fn read_chars(n: uint) -> ~[char] {
// returns the (consumed offset, n_req), appends characters to &chars
fn chars_from_buf(buf: ~[u8], &chars: ~[char]) -> (uint, uint) {
Expand Down Expand Up @@ -192,15 +204,15 @@ fn convert_whence(whence: seek_style) -> i32 {
}

impl of reader for *libc::FILE {
fn read_bytes(len: uint) -> ~[u8] {
let mut buf : ~[mut u8] = ~[mut];
vec::reserve(buf, len);
do vec::as_mut_buf(buf) |b| {
let read = libc::fread(b as *mut c_void, 1u as size_t,
len as size_t, self);
unsafe { vec::unsafe::set_len(buf, read as uint) };
fn read(buf: &[mut u8], len: uint) -> uint {
do vec::unpack_slice(buf) |buf_p, buf_len| {
assert buf_len <= len;

let count = libc::fread(buf_p as *mut c_void, 1u as size_t,
len as size_t, self);

count as uint
}
ret vec::from_mut(buf);
}
fn read_byte() -> int { ret libc::fgetc(self) as int; }
fn unread_byte(byte: int) { libc::ungetc(byte as c_int, self); }
Expand All @@ -216,7 +228,7 @@ impl of reader for *libc::FILE {
// duration of its lifetime.
// FIXME there really should be a better way to do this // #2004
impl <T: reader, C> of reader for {base: T, cleanup: C} {
fn read_bytes(len: uint) -> ~[u8] { self.base.read_bytes(len) }
fn read(buf: &[mut u8], len: uint) -> uint { self.base.read(buf, len) }
fn read_byte() -> int { self.base.read_byte() }
fn unread_byte(byte: int) { self.base.unread_byte(byte); }
fn eof() -> bool { self.base.eof() }
Expand Down Expand Up @@ -262,13 +274,15 @@ fn file_reader(path: ~str) -> result<reader, ~str> {
type byte_buf = {buf: ~[const u8], mut pos: uint, len: uint};
impl of reader for byte_buf {
fn read_bytes(len: uint) -> ~[u8] {
let rest = self.len - self.pos;
let mut to_read = len;
if rest < to_read { to_read = rest; }
let range = vec::slice(self.buf, self.pos, self.pos + to_read);
self.pos += to_read;
ret range;
fn read(buf: &[mut u8], len: uint) -> uint {
let count = uint::min(len, self.len - self.pos);
vec::u8::memcpy(buf, vec::const_view(self.buf, self.pos, self.len),
count);
self.pos += count;
count
}
fn read_byte() -> int {
if self.pos == self.len { ret -1; }
Expand Down
1 change: 1 addition & 0 deletions src/libcore/run.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
//! Process spawning
import option::{some, none};
import libc::{pid_t, c_void, c_int};
import io::reader_util;

export program;
export run_program;
Expand Down
49 changes: 28 additions & 21 deletions src/libstd/net_tcp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import future::extensions;
import result::*;
import libc::size_t;
import str::extensions;
import io::{reader, writer};
import io::{reader, reader_util, writer};

// tcp interfaces
export tcp_socket;
Expand Down Expand Up @@ -766,34 +766,41 @@ impl tcp_socket for tcp_socket {

/// Implementation of `io::reader` iface for a buffered `net::tcp::tcp_socket`
impl tcp_socket_buf of io::reader for @tcp_socket_buf {
fn read_bytes(amt: uint) -> ~[u8] {
let has_amt_available =
vec::len((*(self.data)).buf) >= amt;
if has_amt_available {
// no arbitrary-length shift in vec::?
let mut ret_buf = ~[];
while vec::len(ret_buf) < amt {
ret_buf += ~[vec::shift((*(self.data)).buf)];
}
ret_buf
}
else {
let read_result = read((*(self.data)).sock, 0u);
fn read(buf: &[mut u8], len: uint) -> uint {
// Loop until our buffer has enough data in it for us to read from.
while self.data.buf.len() < len {
let read_result = read(self.data.sock, 0u);
if read_result.is_err() {
let err_data = read_result.get_err();
log(debug, #fmt("ERROR sock_buf as io::reader.read err %? %?",
err_data.err_name, err_data.err_msg));
~[]

if err_data.err_name == ~"EOF" {
break;
} else {
#debug("ERROR sock_buf as io::reader.read err %? %?",
err_data.err_name, err_data.err_msg);

ret 0;
}
}
else {
let new_chunk = result::unwrap(read_result);
(*(self.data)).buf += new_chunk;
self.read_bytes(amt)
vec::push_all(self.data.buf, result::unwrap(read_result));
}
}

let count = uint::min(len, self.data.buf.len());

let mut data = ~[];
self.data.buf <-> data;

vec::u8::memcpy(buf, vec::view(data, 0, data.len()), count);

vec::push_all(self.data.buf, vec::view(data, count, data.len()));

count
}
fn read_byte() -> int {
self.read_bytes(1u)[0] as int
let bytes = ~[0];
if self.read(bytes, 1u) == 0 { fail } else { bytes[0] as int }
}
fn unread_byte(amt: int) {
vec::unshift((*(self.data)).buf, amt as u8);
Expand Down

0 comments on commit 3512e35

Please sign in to comment.