Skip to content

Commit 47f0e91

Browse files
committed
std: CRUD file io bindings in uvio, fs_open()/unlink() in IoFactory + test
1 parent f60bd75 commit 47f0e91

File tree

2 files changed

+190
-0
lines changed

2 files changed

+190
-0
lines changed

src/libstd/rt/rtio.rs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,12 @@
1010

1111
use option::*;
1212
use result::*;
13+
use libc::c_int;
1314

1415
use rt::io::IoError;
1516
use super::io::net::ip::{IpAddr, SocketAddr};
1617
use rt::uv::uvio;
18+
use path::Path;
1719

1820
// XXX: ~object doesn't work currently so these are some placeholder
1921
// types to use instead
@@ -46,11 +48,27 @@ pub trait RemoteCallback {
4648
fn fire(&mut self);
4749
}
4850

51+
/// Data needed to make a successful open(2) call
52+
/// Using unix flag conventions for now, which happens to also be what's supported
53+
/// libuv (it does translation to windows under the hood).
54+
pub struct FileOpenConfig {
55+
/// Path to file to be opened
56+
path: Path,
57+
/// Flags for file access mode (as per open(2))
58+
flags: int,
59+
/// File creation mode, ignored unless O_CREAT is passed as part of flags
60+
mode: int
61+
}
62+
4963
pub trait IoFactory {
5064
fn tcp_connect(&mut self, addr: SocketAddr) -> Result<~RtioTcpStreamObject, IoError>;
5165
fn tcp_bind(&mut self, addr: SocketAddr) -> Result<~RtioTcpListenerObject, IoError>;
5266
fn udp_bind(&mut self, addr: SocketAddr) -> Result<~RtioUdpSocketObject, IoError>;
5367
fn timer_init(&mut self) -> Result<~RtioTimerObject, IoError>;
68+
fn fs_from_raw_fd(&mut self, fd: c_int, close_on_drop: bool) -> ~RtioFileDescriptor;
69+
fn fs_open(&mut self, path: Path, flags: int, mode:int)
70+
-> Result<~RtioFileDescriptor, IoError>;
71+
fn fs_unlink(&mut self, path: Path) -> Result<(), IoError>;
5472
}
5573

5674
pub trait RtioTcpListener : RtioSocket {
@@ -93,3 +111,8 @@ pub trait RtioUdpSocket : RtioSocket {
93111
pub trait RtioTimer {
94112
fn sleep(&mut self, msecs: u64);
95113
}
114+
115+
pub trait RtioFileDescriptor {
116+
fn read(&mut self, buf: &mut [u8], offset: i64) -> Result<int, IoError>;
117+
fn write(&mut self, buf: &[u8], offset: i64) -> Result<(), IoError>;
118+
}

src/libstd/rt/uv/uvio.rs

Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ use libc::{c_int, c_uint, c_void};
1717
use ops::Drop;
1818
use option::*;
1919
use ptr;
20+
use str;
21+
use path::Path;
2022
use result::*;
2123
use rt::io::IoError;
2224
use rt::io::net::ip::{SocketAddr, IpAddr};
@@ -455,6 +457,68 @@ impl IoFactory for UvIoFactory {
455457
let home = get_handle_to_current_scheduler!();
456458
Ok(~UvTimer::new(watcher, home))
457459
}
460+
461+
fn fs_from_raw_fd(&mut self, fd: c_int, close_on_drop: bool) -> ~RtioFileDescriptor {
462+
~UvFileDescriptor {
463+
loop_: Loop{handle:self.uv_loop().native_handle()},
464+
fd: file::FileDescriptor(fd),
465+
close_on_drop: close_on_drop
466+
} as ~RtioFileDescriptor
467+
}
468+
469+
fn fs_open(&mut self, path: Path, flags: int, mode: int)
470+
-> Result<~RtioFileDescriptor, IoError> {
471+
let loop_ = Loop {handle: self.uv_loop().native_handle()};
472+
let result_cell = Cell::new_empty();
473+
let result_cell_ptr: *Cell<Result<~RtioFileDescriptor, IoError>> = &result_cell;
474+
let path_cell = Cell::new(path);
475+
let scheduler = Local::take::<Scheduler>();
476+
do scheduler.deschedule_running_task_and_then |_, task| {
477+
let task_cell = Cell::new(task);
478+
let path = path_cell.take();
479+
do file::FileDescriptor::open(loop_, path, flags, mode) |req,err| {
480+
if err.is_none() {
481+
let res = Ok(~UvFileDescriptor {
482+
loop_: loop_,
483+
fd: file::FileDescriptor(req.get_result()),
484+
close_on_drop: true} as ~RtioFileDescriptor);
485+
unsafe { (*result_cell_ptr).put_back(res); }
486+
let scheduler = Local::take::<Scheduler>();
487+
scheduler.resume_blocked_task_immediately(task_cell.take());
488+
} else {
489+
let res = Err(uv_error_to_io_error(err.unwrap()));
490+
unsafe { (*result_cell_ptr).put_back(res); }
491+
let scheduler = Local::take::<Scheduler>();
492+
scheduler.resume_blocked_task_immediately(task_cell.take());
493+
}
494+
};
495+
};
496+
assert!(!result_cell.is_empty());
497+
return result_cell.take();
498+
}
499+
500+
fn fs_unlink(&mut self, path: Path) -> Result<(), IoError> {
501+
let loop_ = Loop {handle: self.uv_loop().native_handle()};
502+
let result_cell = Cell::new_empty();
503+
let result_cell_ptr: *Cell<Result<(), IoError>> = &result_cell;
504+
let path_cell = Cell::new(path);
505+
let scheduler = Local::take::<Scheduler>();
506+
do scheduler.deschedule_running_task_and_then |_, task| {
507+
let task_cell = Cell::new(task);
508+
let path = path_cell.take();
509+
do file::FileDescriptor::unlink(loop_, path) |_, err| {
510+
let res = match err {
511+
None => Ok(()),
512+
Some(err) => Err(uv_error_to_io_error(err))
513+
};
514+
unsafe { (*result_cell_ptr).put_back(res); }
515+
let scheduler = Local::take::<Scheduler>();
516+
scheduler.resume_blocked_task_immediately(task_cell.take());
517+
};
518+
};
519+
assert!(!result_cell.is_empty());
520+
return result_cell.take();
521+
}
458522
}
459523

460524
pub struct UvTcpListener {
@@ -992,6 +1056,73 @@ impl RtioTimer for UvTimer {
9921056
}
9931057
}
9941058

1059+
pub struct UvFileDescriptor {
1060+
loop_: Loop,
1061+
fd: file::FileDescriptor,
1062+
close_on_drop: bool
1063+
}
1064+
1065+
impl UvFileDescriptor {
1066+
}
1067+
1068+
impl Drop for UvFileDescriptor {
1069+
fn drop(&self) {
1070+
if self.close_on_drop {
1071+
let scheduler = Local::take::<Scheduler>();
1072+
do scheduler.deschedule_running_task_and_then |_, task| {
1073+
let task_cell = Cell::new(task);
1074+
do self.fd.close(self.loop_) |_,_| {
1075+
let scheduler = Local::take::<Scheduler>();
1076+
scheduler.resume_blocked_task_immediately(task_cell.take());
1077+
};
1078+
};
1079+
}
1080+
}
1081+
}
1082+
1083+
impl RtioFileDescriptor for UvFileDescriptor {
1084+
fn read(&mut self, buf: &mut [u8], offset: i64) -> Result<int, IoError> {
1085+
let scheduler = Local::take::<Scheduler>();
1086+
let result_cell = Cell::new_empty();
1087+
let result_cell_ptr: *Cell<Result<int, IoError>> = &result_cell;
1088+
let buf_ptr: *&mut [u8] = &buf;
1089+
do scheduler.deschedule_running_task_and_then |_, task| {
1090+
let buf = unsafe { slice_to_uv_buf(*buf_ptr) };
1091+
let task_cell = Cell::new(task);
1092+
do self.fd.read(self.loop_, buf, offset) |req, uverr| {
1093+
let res = match uverr {
1094+
None => Ok(req.get_result() as int),
1095+
Some(err) => Err(uv_error_to_io_error(err))
1096+
};
1097+
unsafe { (*result_cell_ptr).put_back(res); }
1098+
let scheduler = Local::take::<Scheduler>();
1099+
scheduler.resume_blocked_task_immediately(task_cell.take());
1100+
};
1101+
};
1102+
result_cell.take()
1103+
}
1104+
fn write(&mut self, buf: &[u8], offset: i64) -> Result<(), IoError> {
1105+
let scheduler = Local::take::<Scheduler>();
1106+
let result_cell = Cell::new_empty();
1107+
let result_cell_ptr: *Cell<Result<(), IoError>> = &result_cell;
1108+
let buf_ptr: *&[u8] = &buf;
1109+
do scheduler.deschedule_running_task_and_then |_, task| {
1110+
let buf = unsafe { slice_to_uv_buf(*buf_ptr) };
1111+
let task_cell = Cell::new(task);
1112+
do self.fd.write(self.loop_, buf, offset) |_, uverr| {
1113+
let res = match uverr {
1114+
None => Ok(()),
1115+
Some(err) => Err(uv_error_to_io_error(err))
1116+
};
1117+
unsafe { (*result_cell_ptr).put_back(res); }
1118+
let scheduler = Local::take::<Scheduler>();
1119+
scheduler.resume_blocked_task_immediately(task_cell.take());
1120+
};
1121+
};
1122+
result_cell.take()
1123+
}
1124+
}
1125+
9951126
#[test]
9961127
fn test_simple_io_no_connect() {
9971128
do run_in_newsched_task {
@@ -1498,3 +1629,39 @@ fn test_timer_sleep_simple() {
14981629
}
14991630
}
15001631
}
1632+
1633+
fn file_test_uvio_full_simple_impl() {
1634+
use libc::{O_CREAT, O_RDWR, O_RDONLY,
1635+
S_IWUSR, S_IRUSR};
1636+
use str::StrSlice; // why does this have to be explicitly imported to work?
1637+
// compiler was complaining about no trait for str that
1638+
// does .as_bytes() ..
1639+
unsafe {
1640+
let io = Local::unsafe_borrow::<IoFactoryObject>();
1641+
let create_flags = O_RDWR | O_CREAT;
1642+
let ro_flags = O_RDONLY;
1643+
let write_val = "hello uvio!";
1644+
let mode = S_IWUSR | S_IRUSR;
1645+
let path = "./file_test_uvio_full.txt";
1646+
{
1647+
let mut fd = (*io).fs_open(Path(path), create_flags as int, mode as int).unwrap();
1648+
let write_buf = write_val.as_bytes();
1649+
fd.write(write_buf, 0);
1650+
}
1651+
{
1652+
let mut fd = (*io).fs_open(Path(path), ro_flags as int, mode as int).unwrap();
1653+
let mut read_vec = [0, .. 1028];
1654+
let nread = fd.read(read_vec, 0).unwrap();
1655+
let read_val = str::from_bytes(read_vec.slice(0, nread as uint));
1656+
assert!(read_val == write_val.to_owned());
1657+
}
1658+
(*io).fs_unlink(Path(path));
1659+
}
1660+
}
1661+
1662+
#[test]
1663+
fn file_test_uvio_full_simple() {
1664+
do run_in_newsched_task {
1665+
file_test_uvio_full_simple_impl();
1666+
}
1667+
}

0 commit comments

Comments
 (0)