diff options
| author | Jeff Olson <olson.jeffery@gmail.com> | 2013-08-19 16:10:43 -0700 |
|---|---|---|
| committer | Jeff Olson <olson.jeffery@gmail.com> | 2013-08-22 16:31:57 -0700 |
| commit | 47f0e91689403c8472dc63e58e735f42251427ab (patch) | |
| tree | b74707b170483a9684054586a336d3e130504bee /src/libstd | |
| parent | f60bd75f4d8b776cf1e777b59d2d2262d03818a7 (diff) | |
| download | rust-47f0e91689403c8472dc63e58e735f42251427ab.tar.gz rust-47f0e91689403c8472dc63e58e735f42251427ab.zip | |
std: CRUD file io bindings in uvio, fs_open()/unlink() in IoFactory + test
Diffstat (limited to 'src/libstd')
| -rw-r--r-- | src/libstd/rt/rtio.rs | 23 | ||||
| -rw-r--r-- | src/libstd/rt/uv/uvio.rs | 167 |
2 files changed, 190 insertions, 0 deletions
diff --git a/src/libstd/rt/rtio.rs b/src/libstd/rt/rtio.rs index f36c96706e5..1095104773d 100644 --- a/src/libstd/rt/rtio.rs +++ b/src/libstd/rt/rtio.rs @@ -10,10 +10,12 @@ use option::*; use result::*; +use libc::c_int; use rt::io::IoError; use super::io::net::ip::{IpAddr, SocketAddr}; use rt::uv::uvio; +use path::Path; // XXX: ~object doesn't work currently so these are some placeholder // types to use instead @@ -46,11 +48,27 @@ pub trait RemoteCallback { fn fire(&mut self); } +/// Data needed to make a successful open(2) call +/// Using unix flag conventions for now, which happens to also be what's supported +/// libuv (it does translation to windows under the hood). +pub struct FileOpenConfig { + /// Path to file to be opened + path: Path, + /// Flags for file access mode (as per open(2)) + flags: int, + /// File creation mode, ignored unless O_CREAT is passed as part of flags + mode: int +} + pub trait IoFactory { fn tcp_connect(&mut self, addr: SocketAddr) -> Result<~RtioTcpStreamObject, IoError>; fn tcp_bind(&mut self, addr: SocketAddr) -> Result<~RtioTcpListenerObject, IoError>; 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) + -> Result<~RtioFileDescriptor, IoError>; + fn fs_unlink(&mut self, path: Path) -> Result<(), IoError>; } pub trait RtioTcpListener : RtioSocket { @@ -93,3 +111,8 @@ pub trait RtioUdpSocket : RtioSocket { pub trait RtioTimer { fn sleep(&mut self, msecs: u64); } + +pub trait RtioFileDescriptor { + fn read(&mut self, buf: &mut [u8], offset: i64) -> Result<int, IoError>; + fn write(&mut self, buf: &[u8], offset: i64) -> Result<(), IoError>; +} diff --git a/src/libstd/rt/uv/uvio.rs b/src/libstd/rt/uv/uvio.rs index 6920e776a09..913b19ec38f 100644 --- a/src/libstd/rt/uv/uvio.rs +++ b/src/libstd/rt/uv/uvio.rs @@ -17,6 +17,8 @@ use libc::{c_int, c_uint, c_void}; 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}; @@ -455,6 +457,68 @@ impl IoFactory for UvIoFactory { let home = get_handle_to_current_scheduler!(); Ok(~UvTimer::new(watcher, home)) } + + fn fs_from_raw_fd(&mut self, fd: c_int, close_on_drop: bool) -> ~RtioFileDescriptor { + ~UvFileDescriptor { + loop_: Loop{handle:self.uv_loop().native_handle()}, + fd: file::FileDescriptor(fd), + close_on_drop: close_on_drop + } as ~RtioFileDescriptor + } + + fn fs_open(&mut self, path: Path, flags: int, mode: int) + -> Result<~RtioFileDescriptor, IoError> { + let loop_ = Loop {handle: self.uv_loop().native_handle()}; + let result_cell = Cell::new_empty(); + let result_cell_ptr: *Cell<Result<~RtioFileDescriptor, IoError>> = &result_cell; + let path_cell = Cell::new(path); + let scheduler = Local::take::<Scheduler>(); + do scheduler.deschedule_running_task_and_then |_, task| { + let task_cell = Cell::new(task); + let path = path_cell.take(); + do file::FileDescriptor::open(loop_, path, flags, mode) |req,err| { + if err.is_none() { + let res = Ok(~UvFileDescriptor { + loop_: loop_, + fd: file::FileDescriptor(req.get_result()), + close_on_drop: true} as ~RtioFileDescriptor); + unsafe { (*result_cell_ptr).put_back(res); } + let scheduler = Local::take::<Scheduler>(); + scheduler.resume_blocked_task_immediately(task_cell.take()); + } else { + let res = Err(uv_error_to_io_error(err.unwrap())); + unsafe { (*result_cell_ptr).put_back(res); } + let scheduler = Local::take::<Scheduler>(); + scheduler.resume_blocked_task_immediately(task_cell.take()); + } + }; + }; + assert!(!result_cell.is_empty()); + return result_cell.take(); + } + + fn fs_unlink(&mut self, path: Path) -> 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; + let path_cell = Cell::new(path); + let scheduler = Local::take::<Scheduler>(); + do scheduler.deschedule_running_task_and_then |_, task| { + let task_cell = Cell::new(task); + let path = path_cell.take(); + do file::FileDescriptor::unlink(loop_, path) |_, err| { + let res = match err { + None => Ok(()), + Some(err) => Err(uv_error_to_io_error(err)) + }; + unsafe { (*result_cell_ptr).put_back(res); } + let scheduler = Local::take::<Scheduler>(); + scheduler.resume_blocked_task_immediately(task_cell.take()); + }; + }; + assert!(!result_cell.is_empty()); + return result_cell.take(); + } } pub struct UvTcpListener { @@ -992,6 +1056,73 @@ impl RtioTimer for UvTimer { } } +pub struct UvFileDescriptor { + loop_: Loop, + fd: file::FileDescriptor, + close_on_drop: bool +} + +impl UvFileDescriptor { +} + +impl Drop for UvFileDescriptor { + fn drop(&self) { + if self.close_on_drop { + let scheduler = Local::take::<Scheduler>(); + do scheduler.deschedule_running_task_and_then |_, task| { + let task_cell = Cell::new(task); + do self.fd.close(self.loop_) |_,_| { + let scheduler = Local::take::<Scheduler>(); + scheduler.resume_blocked_task_immediately(task_cell.take()); + }; + }; + } + } +} + +impl RtioFileDescriptor for UvFileDescriptor { + fn read(&mut self, buf: &mut [u8], offset: i64) -> Result<int, IoError> { + let scheduler = Local::take::<Scheduler>(); + let result_cell = Cell::new_empty(); + let result_cell_ptr: *Cell<Result<int, IoError>> = &result_cell; + let buf_ptr: *&mut [u8] = &buf; + do scheduler.deschedule_running_task_and_then |_, task| { + let buf = unsafe { slice_to_uv_buf(*buf_ptr) }; + let task_cell = Cell::new(task); + do self.fd.read(self.loop_, buf, offset) |req, uverr| { + let res = match uverr { + None => Ok(req.get_result() as int), + Some(err) => Err(uv_error_to_io_error(err)) + }; + unsafe { (*result_cell_ptr).put_back(res); } + let scheduler = Local::take::<Scheduler>(); + scheduler.resume_blocked_task_immediately(task_cell.take()); + }; + }; + result_cell.take() + } + fn write(&mut self, buf: &[u8], offset: i64) -> Result<(), IoError> { + let scheduler = Local::take::<Scheduler>(); + let result_cell = Cell::new_empty(); + let result_cell_ptr: *Cell<Result<(), IoError>> = &result_cell; + let buf_ptr: *&[u8] = &buf; + do scheduler.deschedule_running_task_and_then |_, task| { + let buf = unsafe { slice_to_uv_buf(*buf_ptr) }; + let task_cell = Cell::new(task); + do self.fd.write(self.loop_, buf, offset) |_, uverr| { + let res = match uverr { + None => Ok(()), + Some(err) => Err(uv_error_to_io_error(err)) + }; + unsafe { (*result_cell_ptr).put_back(res); } + let scheduler = Local::take::<Scheduler>(); + scheduler.resume_blocked_task_immediately(task_cell.take()); + }; + }; + result_cell.take() + } +} + #[test] fn test_simple_io_no_connect() { do run_in_newsched_task { @@ -1498,3 +1629,39 @@ fn test_timer_sleep_simple() { } } } + +fn file_test_uvio_full_simple_impl() { + use libc::{O_CREAT, O_RDWR, O_RDONLY, + S_IWUSR, S_IRUSR}; + 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() .. + unsafe { + let io = Local::unsafe_borrow::<IoFactoryObject>(); + let create_flags = O_RDWR | O_CREAT; + let ro_flags = O_RDONLY; + let write_val = "hello uvio!"; + 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 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 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)); + } +} + +#[test] +fn file_test_uvio_full_simple() { + do run_in_newsched_task { + file_test_uvio_full_simple_impl(); + } +} |
