Skip to content

Allow io::reader to use preallocated buffers, plus other misc changes #2983

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
84 changes: 81 additions & 3 deletions src/libcore/vec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export init;
export last;
export last_opt;
export slice;
export view;
export view, mut_view, const_view;
export split;
export splitn;
export rsplit;
Expand Down Expand Up @@ -313,7 +313,7 @@ pure fn slice<T: copy>(v: &[const T], start: uint, end: uint) -> ~[T] {
ret result;
}

#[doc = "Return a slice that points into another slice."]
/// Return a slice that points into another slice.
pure fn view<T>(v: &[T], start: uint, end: uint) -> &[T] {
assert (start <= end);
assert (end <= len(v));
Expand All @@ -325,6 +325,30 @@ pure fn view<T>(v: &[T], start: uint, end: uint) -> &[T] {
}
}

/// Return a slice that points into another slice.
pure fn mut_view<T>(v: &[mut T], start: uint, end: uint) -> &[mut T] {
assert (start <= end);
assert (end <= len(v));
do unpack_slice(v) |p, _len| {
unsafe {
::unsafe::reinterpret_cast(
(ptr::offset(p, start), (end - start) * sys::size_of::<T>()))
}
}
}

/// Return a slice that points into another slice.
pure fn const_view<T>(v: &[const T], start: uint, end: uint) -> &[const T] {
assert (start <= end);
assert (end <= len(v));
do unpack_slice(v) |p, _len| {
unsafe {
::unsafe::reinterpret_cast(
(ptr::offset(p, start), (end - start) * sys::size_of::<T>()))
}
}
}

/// Split the vector `v` by applying each element against the predicate `f`.
fn split<T: copy>(v: &[T], f: fn(T) -> bool) -> ~[~[T]] {
let ln = len(v);
Expand Down Expand Up @@ -627,7 +651,6 @@ fn grow_set<T: copy>(&v: ~[mut T], index: uint, initval: T, val: T) {
v[index] = val;
}


// Functional utilities

/// Apply a function to each element of a vector and return the results
Expand Down Expand Up @@ -1574,13 +1597,42 @@ mod unsafe {
::unsafe::reinterpret_cast(ptr::addr_of(pair));
f(*v)
}

/**
* Copies data from one vector to another.
*
* Copies `count` bytes from `src` to `dst`. The source and destination
* may overlap.
*/
unsafe fn memcpy<T>(dst: &[mut T], src: &[const T], count: uint) {
do unpack_slice(dst) |p_dst, _len_dst| {
do unpack_slice(src) |p_src, _len_src| {
ptr::memcpy(p_dst, p_src, count)
}
}
}

/**
* Copies data from one vector to another.
*
* Copies `count` bytes from `src` to `dst`. The source and destination
* may overlap.
*/
unsafe fn memmove<T>(dst: &[mut T], src: &[const T], count: uint) {
do unpack_slice(dst) |p_dst, _len_dst| {
do unpack_slice(src) |p_src, _len_src| {
ptr::memmove(p_dst, p_src, count)
}
}
}
}

/// Operations on `[u8]`
mod u8 {
export cmp;
export lt, le, eq, ne, ge, gt;
export hash;
export memcpy, memmove;

/// Bytewise string comparison
pure fn cmp(&&a: ~[u8], &&b: ~[u8]) -> int {
Expand Down Expand Up @@ -1631,6 +1683,32 @@ mod u8 {
vec::iter(s, |c| {u *= 33u; u += c as uint;});
ret u;
}

/**
* Copies data from one vector to another.
*
* Copies `count` bytes from `src` to `dst`. The source and destination
* may not overlap.
*/
fn memcpy(dst: &[mut u8], src: &[const u8], count: uint) {
assert dst.len() >= count;
assert src.len() >= count;

unsafe { vec::unsafe::memcpy(dst, src, count) }
}

/**
* Copies data from one vector to another.
*
* Copies `count` bytes from `src` to `dst`. The source and destination
* may overlap.
*/
fn memmove(dst: &[mut u8], src: &[const u8], count: uint) {
assert dst.len() >= count;
assert src.len() >= count;

unsafe { vec::unsafe::memmove(dst, src, count) }
}
}

// ___________________________________________________________________________
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
2 changes: 1 addition & 1 deletion src/test/auxiliary/issue-2526.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#[link(name = "zmq",
#[link(name = "issue_2526",
vers = "0.2",
uuid = "54cc1bc9-02b8-447c-a227-75ebc923bc29")];
#[crate_type = "lib"];
Expand Down
4 changes: 2 additions & 2 deletions src/test/run-pass/issue-2526-a.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
// xfail-fast
// aux-build:issue-2526.rs

use zmq;
import zmq::*;
use issue_2526;
import issue_2526::*;

fn main() {}