From 06ac0c2b1da2592c53462e1d3675bf1198175aed Mon Sep 17 00:00:00 2001 From: Erick Tryzelaar Date: Fri, 20 Jul 2012 21:49:20 -0700 Subject: [PATCH] Switch reader to work with preallocated vecs This closes #2901. --- src/libcore/io.rs | 48 +++++++++++++++++++++++++++--------------- src/libcore/run.rs | 1 + src/libstd/net_tcp.rs | 49 ++++++++++++++++++++++++------------------- 3 files changed, 60 insertions(+), 38 deletions(-) diff --git a/src/libcore/io.rs b/src/libcore/io.rs index 659fdbc6d7e81..4da7044e48b13 100644 --- a/src/libcore/io.rs +++ b/src/libcore/io.rs @@ -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; @@ -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) { @@ -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); } @@ -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 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() } @@ -262,13 +274,15 @@ fn file_reader(path: ~str) -> result { 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; } diff --git a/src/libcore/run.rs b/src/libcore/run.rs index a466971b9bdf2..1229d0724de79 100644 --- a/src/libcore/run.rs +++ b/src/libcore/run.rs @@ -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; diff --git a/src/libstd/net_tcp.rs b/src/libstd/net_tcp.rs index c7dc2d0cdab48..4826bc760c237 100644 --- a/src/libstd/net_tcp.rs +++ b/src/libstd/net_tcp.rs @@ -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; @@ -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);