std: rt::io::file::FileStream fleshed out.. needs more work.. see extended
- change all uses of Path in fn args to &P - FileStream.read assumptions were wrong (libuv file io is non-positional) - the above will mean that we "own" Seek impl info .. should probably push it in UvFileDescriptor.. - needs more tests
This commit is contained in:
parent
47f0e91689
commit
f6d897d7d9
4 changed files with 128 additions and 41 deletions
|
@ -12,6 +12,11 @@ use prelude::*;
|
|||
use super::support::PathLike;
|
||||
use super::{Reader, Writer, Seek};
|
||||
use super::SeekStyle;
|
||||
use rt::rtio::{RtioFileDescriptor, IoFactory, IoFactoryObject};
|
||||
use rt::io::{io_error, read_error, EndOfFile};
|
||||
use rt::local::Local;
|
||||
use libc::{O_RDWR, O_RDONLY, O_WRONLY, S_IWUSR, S_IRUSR,
|
||||
O_CREAT, O_TRUNC, O_APPEND};
|
||||
|
||||
/// # FIXME #7785
|
||||
/// * Ugh, this is ridiculous. What is the best way to represent these options?
|
||||
|
@ -36,29 +41,85 @@ enum FileAccess {
|
|||
ReadWrite
|
||||
}
|
||||
|
||||
pub struct FileStream;
|
||||
pub struct FileStream {
|
||||
fd: ~RtioFileDescriptor,
|
||||
last_nread: int
|
||||
}
|
||||
|
||||
impl FileStream {
|
||||
pub fn open<P: PathLike>(_path: &P,
|
||||
_mode: FileMode,
|
||||
_access: FileAccess
|
||||
pub fn open<P: PathLike>(path: &P,
|
||||
mode: FileMode,
|
||||
access: FileAccess
|
||||
) -> Option<FileStream> {
|
||||
fail!()
|
||||
let open_result = unsafe {
|
||||
let io = Local::unsafe_borrow::<IoFactoryObject>();
|
||||
let mut flags = match mode {
|
||||
Open => 0,
|
||||
Create => O_CREAT,
|
||||
OpenOrCreate => O_CREAT,
|
||||
Append => O_APPEND,
|
||||
Truncate => O_TRUNC,
|
||||
CreateOrTruncate => O_TRUNC | O_CREAT
|
||||
};
|
||||
flags = match access {
|
||||
Read => flags | O_RDONLY,
|
||||
Write => flags | O_WRONLY,
|
||||
ReadWrite => flags | O_RDWR
|
||||
};
|
||||
let create_mode = match mode {
|
||||
Create|OpenOrCreate|CreateOrTruncate =>
|
||||
S_IRUSR | S_IWUSR,
|
||||
_ => 0
|
||||
};
|
||||
(*io).fs_open(path, flags as int, create_mode as int)
|
||||
};
|
||||
match open_result {
|
||||
Ok(fd) => Some(FileStream {
|
||||
fd: fd,
|
||||
last_nread: -1
|
||||
}),
|
||||
Err(ioerr) => {
|
||||
io_error::cond.raise(ioerr);
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Reader for FileStream {
|
||||
fn read(&mut self, _buf: &mut [u8]) -> Option<uint> {
|
||||
fail!()
|
||||
fn read(&mut self, buf: &mut [u8]) -> Option<uint> {
|
||||
match self.fd.read(buf, 0) {
|
||||
Ok(read) => {
|
||||
self.last_nread = read;
|
||||
match read {
|
||||
0 => None,
|
||||
_ => Some(read as uint)
|
||||
}
|
||||
},
|
||||
Err(ioerr) => {
|
||||
// EOF is indicated by returning None
|
||||
if ioerr.kind != EndOfFile {
|
||||
read_error::cond.raise(ioerr);
|
||||
}
|
||||
return None;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn eof(&mut self) -> bool {
|
||||
fail!()
|
||||
self.last_nread == 0
|
||||
}
|
||||
}
|
||||
|
||||
impl Writer for FileStream {
|
||||
fn write(&mut self, _v: &[u8]) { fail!() }
|
||||
fn write(&mut self, buf: &[u8]) {
|
||||
match self.fd.write(buf, 0) {
|
||||
Ok(_) => (),
|
||||
Err(ioerr) => {
|
||||
io_error::cond.raise(ioerr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn flush(&mut self) { fail!() }
|
||||
}
|
||||
|
@ -69,11 +130,29 @@ impl Seek for FileStream {
|
|||
fn seek(&mut self, _pos: i64, _style: SeekStyle) { fail!() }
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn super_simple_smoke_test_lets_go_read_some_files_and_have_a_good_time() {
|
||||
let message = "it's alright. have a good time";
|
||||
let filename = &Path("test.txt");
|
||||
let mut outstream = FileStream::open(filename, Create, Read).unwrap();
|
||||
outstream.write(message.as_bytes());
|
||||
fn file_test_smoke_test_impl() {
|
||||
use rt::test::*;
|
||||
do run_in_newsched_task {
|
||||
let message = "it's alright. have a good time";
|
||||
let filename = &Path("rt_io_file_test.txt");
|
||||
{
|
||||
let mut write_stream = FileStream::open(filename, Create, ReadWrite).unwrap();
|
||||
write_stream.write(message.as_bytes());
|
||||
}
|
||||
{
|
||||
use str;
|
||||
let mut read_stream = FileStream::open(filename, Open, Read).unwrap();
|
||||
let mut read_buf = [0, .. 1028];
|
||||
let read_str = match read_stream.read(read_buf).unwrap() {
|
||||
-1|0 => fail!("shouldn't happen"),
|
||||
n => str::from_bytes(read_buf.slice_to(n))
|
||||
};
|
||||
assert!(read_str == message.to_owned());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn file_test_smoke_test() {
|
||||
file_test_smoke_test_impl();
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@ use rt::io::IoError;
|
|||
use super::io::net::ip::{IpAddr, SocketAddr};
|
||||
use rt::uv::uvio;
|
||||
use path::Path;
|
||||
use super::io::support::PathLike;
|
||||
|
||||
// XXX: ~object doesn't work currently so these are some placeholder
|
||||
// types to use instead
|
||||
|
@ -66,9 +67,9 @@ pub trait IoFactory {
|
|||
fn udp_bind(&mut self, addr: SocketAddr) -> Result<~RtioUdpSocketObject, IoError>;
|
||||
fn timer_init(&mut self) -> Result<~RtioTimerObject, IoError>;
|
||||
fn fs_from_raw_fd(&mut self, fd: c_int, close_on_drop: bool) -> ~RtioFileDescriptor;
|
||||
fn fs_open(&mut self, path: Path, flags: int, mode:int)
|
||||
fn fs_open<P: PathLike>(&mut self, path: &P, flags: int, mode:int)
|
||||
-> Result<~RtioFileDescriptor, IoError>;
|
||||
fn fs_unlink(&mut self, path: Path) -> Result<(), IoError>;
|
||||
fn fs_unlink<P: PathLike>(&mut self, path: &P) -> Result<(), IoError>;
|
||||
}
|
||||
|
||||
pub trait RtioTcpListener : RtioSocket {
|
||||
|
|
|
@ -15,7 +15,7 @@ use rt::uv::{Request, NativeHandle, Loop, FsCallback, Buf,
|
|||
status_to_maybe_uv_error_with_loop};
|
||||
use rt::uv::uvll;
|
||||
use rt::uv::uvll::*;
|
||||
use path::Path;
|
||||
use super::super::io::support::PathLike;
|
||||
use cast::transmute;
|
||||
use libc::{c_int};
|
||||
use option::{None, Some, Option};
|
||||
|
@ -97,7 +97,7 @@ impl FileDescriptor {
|
|||
FileDescriptor::new(req.get_result())
|
||||
}
|
||||
|
||||
fn open_common(loop_: Loop, path: Path, flags: int, mode: int,
|
||||
fn open_common<P: PathLike>(loop_: Loop, path: &P, flags: int, mode: int,
|
||||
cb: Option<FsCallback>) -> int {
|
||||
let complete_cb_ptr = match cb {
|
||||
Some(_) => compl_cb,
|
||||
|
@ -105,39 +105,44 @@ impl FileDescriptor {
|
|||
};
|
||||
let is_sync = cb.is_none();
|
||||
let req = FsRequest::new(cb);
|
||||
let result = path.to_str().to_c_str().with_ref(|p| unsafe {
|
||||
let result = path.path_as_str(|p| {
|
||||
p.to_c_str().with_ref(|p| unsafe {
|
||||
uvll::fs_open(loop_.native_handle(),
|
||||
req.native_handle(), p, flags, mode, complete_cb_ptr) as int
|
||||
})
|
||||
});
|
||||
if is_sync { req.cleanup_and_delete(); }
|
||||
result
|
||||
}
|
||||
pub fn open(loop_: Loop, path: Path, flags: int, mode: int,
|
||||
pub fn open<P: PathLike>(loop_: Loop, path: &P, flags: int, mode: int,
|
||||
cb: FsCallback) -> int {
|
||||
FileDescriptor::open_common(loop_, path, flags, mode, Some(cb))
|
||||
}
|
||||
pub fn open_sync(loop_: Loop, path: Path, flags: int, mode: int) -> int {
|
||||
|
||||
pub fn open_sync<P: PathLike>(loop_: Loop, path: &P, flags: int, mode: int) -> int {
|
||||
FileDescriptor::open_common(loop_, path, flags, mode, None)
|
||||
}
|
||||
|
||||
fn unlink_common(loop_: Loop, path: Path, cb: Option<FsCallback>) -> int {
|
||||
fn unlink_common<P: PathLike>(loop_: Loop, path: &P, cb: Option<FsCallback>) -> int {
|
||||
let complete_cb_ptr = match cb {
|
||||
Some(_) => compl_cb,
|
||||
None => 0 as *u8
|
||||
};
|
||||
let is_sync = cb.is_none();
|
||||
let req = FsRequest::new(cb);
|
||||
let result = path.to_str().to_c_str().with_ref(|p| unsafe {
|
||||
uvll::fs_unlink(loop_.native_handle(),
|
||||
req.native_handle(), p, complete_cb_ptr) as int
|
||||
let result = path.path_as_str(|p| {
|
||||
p.to_c_str().with_ref(|p| unsafe {
|
||||
uvll::fs_unlink(loop_.native_handle(),
|
||||
req.native_handle(), p, complete_cb_ptr) as int
|
||||
})
|
||||
});
|
||||
if is_sync { req.cleanup_and_delete(); }
|
||||
result
|
||||
}
|
||||
pub fn unlink(loop_: Loop, path: Path, cb: FsCallback) -> int {
|
||||
pub fn unlink<P: PathLike>(loop_: Loop, path: &P, cb: FsCallback) -> int {
|
||||
FileDescriptor::unlink_common(loop_, path, Some(cb))
|
||||
}
|
||||
pub fn unlink_sync(loop_: Loop, path: Path) -> int {
|
||||
pub fn unlink_sync<P: PathLike>(loop_: Loop, path: &P) -> int {
|
||||
FileDescriptor::unlink_common(loop_, path, None)
|
||||
}
|
||||
|
||||
|
@ -284,7 +289,8 @@ mod test {
|
|||
let read_mem = vec::from_elem(read_buf_len, 0u8);
|
||||
let read_buf = slice_to_uv_buf(read_mem);
|
||||
let read_buf_ptr: *Buf = &read_buf;
|
||||
do FileDescriptor::open(loop_, Path(path_str), create_flags as int, mode as int)
|
||||
let p = Path(path_str);
|
||||
do FileDescriptor::open(loop_, &p, create_flags as int, mode as int)
|
||||
|req, uverr| {
|
||||
let loop_ = req.get_loop();
|
||||
assert!(uverr.is_none());
|
||||
|
@ -296,7 +302,7 @@ mod test {
|
|||
do fd.close(loop_) |req, _| {
|
||||
let loop_ = req.get_loop();
|
||||
assert!(uverr.is_none());
|
||||
do FileDescriptor::open(loop_, Path(path_str), read_flags as int,0)
|
||||
do FileDescriptor::open(loop_, &Path(path_str), read_flags as int,0)
|
||||
|req, uverr| {
|
||||
assert!(uverr.is_none());
|
||||
let loop_ = req.get_loop();
|
||||
|
@ -319,7 +325,7 @@ mod test {
|
|||
assert!(read_str == ~"hello");
|
||||
do FileDescriptor(raw_fd).close(loop_) |_,uverr| {
|
||||
assert!(uverr.is_none());
|
||||
do FileDescriptor::unlink(loop_, Path(path_str))
|
||||
do FileDescriptor::unlink(loop_, &Path(path_str))
|
||||
|_,uverr| {
|
||||
assert!(uverr.is_none());
|
||||
};
|
||||
|
@ -350,7 +356,7 @@ mod test {
|
|||
let write_val = "hello".as_bytes().to_owned();
|
||||
let write_buf = slice_to_uv_buf(write_val);
|
||||
// open/create
|
||||
let result = FileDescriptor::open_sync(loop_, Path(path_str),
|
||||
let result = FileDescriptor::open_sync(loop_, &Path(path_str),
|
||||
create_flags as int, mode as int);
|
||||
assert!(status_to_maybe_uv_error_with_loop(
|
||||
loop_.native_handle(), result as i32).is_none());
|
||||
|
@ -364,7 +370,7 @@ mod test {
|
|||
assert!(status_to_maybe_uv_error_with_loop(
|
||||
loop_.native_handle(), result as i32).is_none());
|
||||
// re-open
|
||||
let result = FileDescriptor::open_sync(loop_, Path(path_str),
|
||||
let result = FileDescriptor::open_sync(loop_, &Path(path_str),
|
||||
read_flags as int,0);
|
||||
assert!(status_to_maybe_uv_error_with_loop(
|
||||
loop_.native_handle(), result as i32).is_none());
|
||||
|
@ -388,7 +394,7 @@ mod test {
|
|||
assert!(status_to_maybe_uv_error_with_loop(
|
||||
loop_.native_handle(), result as i32).is_none());
|
||||
// unlink
|
||||
let result = FileDescriptor::unlink_sync(loop_, Path(path_str));
|
||||
let result = FileDescriptor::unlink_sync(loop_, &Path(path_str));
|
||||
assert!(status_to_maybe_uv_error_with_loop(
|
||||
loop_.native_handle(), result as i32).is_none());
|
||||
} else { fail!("nread was 0.. wudn't expectin' that."); }
|
||||
|
|
|
@ -18,7 +18,6 @@ use ops::Drop;
|
|||
use option::*;
|
||||
use ptr;
|
||||
use str;
|
||||
use path::Path;
|
||||
use result::*;
|
||||
use rt::io::IoError;
|
||||
use rt::io::net::ip::{SocketAddr, IpAddr};
|
||||
|
@ -31,6 +30,7 @@ use rt::uv::*;
|
|||
use rt::uv::idle::IdleWatcher;
|
||||
use rt::uv::net::{UvIpv4SocketAddr, UvIpv6SocketAddr};
|
||||
use unstable::sync::Exclusive;
|
||||
use super::super::io::support::PathLike;
|
||||
|
||||
#[cfg(test)] use container::Container;
|
||||
#[cfg(test)] use unstable::run_in_bare_thread;
|
||||
|
@ -466,7 +466,7 @@ impl IoFactory for UvIoFactory {
|
|||
} as ~RtioFileDescriptor
|
||||
}
|
||||
|
||||
fn fs_open(&mut self, path: Path, flags: int, mode: int)
|
||||
fn fs_open<P: PathLike>(&mut self, path: &P, flags: int, mode: int)
|
||||
-> Result<~RtioFileDescriptor, IoError> {
|
||||
let loop_ = Loop {handle: self.uv_loop().native_handle()};
|
||||
let result_cell = Cell::new_empty();
|
||||
|
@ -497,7 +497,7 @@ impl IoFactory for UvIoFactory {
|
|||
return result_cell.take();
|
||||
}
|
||||
|
||||
fn fs_unlink(&mut self, path: Path) -> Result<(), IoError> {
|
||||
fn fs_unlink<P: PathLike>(&mut self, path: &P) -> Result<(), IoError> {
|
||||
let loop_ = Loop {handle: self.uv_loop().native_handle()};
|
||||
let result_cell = Cell::new_empty();
|
||||
let result_cell_ptr: *Cell<Result<(), IoError>> = &result_cell;
|
||||
|
@ -1636,6 +1636,7 @@ fn file_test_uvio_full_simple_impl() {
|
|||
use str::StrSlice; // why does this have to be explicitly imported to work?
|
||||
// compiler was complaining about no trait for str that
|
||||
// does .as_bytes() ..
|
||||
use path::Path;
|
||||
unsafe {
|
||||
let io = Local::unsafe_borrow::<IoFactoryObject>();
|
||||
let create_flags = O_RDWR | O_CREAT;
|
||||
|
@ -1644,18 +1645,18 @@ fn file_test_uvio_full_simple_impl() {
|
|||
let mode = S_IWUSR | S_IRUSR;
|
||||
let path = "./file_test_uvio_full.txt";
|
||||
{
|
||||
let mut fd = (*io).fs_open(Path(path), create_flags as int, mode as int).unwrap();
|
||||
let mut fd = (*io).fs_open(&Path(path), create_flags as int, mode as int).unwrap();
|
||||
let write_buf = write_val.as_bytes();
|
||||
fd.write(write_buf, 0);
|
||||
}
|
||||
{
|
||||
let mut fd = (*io).fs_open(Path(path), ro_flags as int, mode as int).unwrap();
|
||||
let mut fd = (*io).fs_open(&Path(path), ro_flags as int, mode as int).unwrap();
|
||||
let mut read_vec = [0, .. 1028];
|
||||
let nread = fd.read(read_vec, 0).unwrap();
|
||||
let read_val = str::from_bytes(read_vec.slice(0, nread as uint));
|
||||
assert!(read_val == write_val.to_owned());
|
||||
}
|
||||
(*io).fs_unlink(Path(path));
|
||||
(*io).fs_unlink(&Path(path));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue