std: bootstrapping libuv-based fileio in newrt... open & close
the test "touch"es a new file
This commit is contained in:
@@ -11,30 +11,87 @@
|
|||||||
use prelude::*;
|
use prelude::*;
|
||||||
use ptr::null;
|
use ptr::null;
|
||||||
use libc::c_void;
|
use libc::c_void;
|
||||||
use rt::uv::{Request, NativeHandle, Loop, FsCallback};
|
use rt::uv::{Request, NativeHandle, Loop, FsCallback,
|
||||||
|
status_to_maybe_uv_error_with_loop};
|
||||||
use rt::uv::uvll;
|
use rt::uv::uvll;
|
||||||
use rt::uv::uvll::*;
|
use rt::uv::uvll::*;
|
||||||
|
use path::Path;
|
||||||
|
use cast::transmute;
|
||||||
|
use libc::{c_int};
|
||||||
|
|
||||||
pub struct FsRequest(*uvll::uv_fs_t);
|
pub struct FsRequest(*uvll::uv_fs_t);
|
||||||
impl Request for FsRequest;
|
impl Request for FsRequest;
|
||||||
|
|
||||||
|
#[allow(non_camel_case_types)]
|
||||||
|
pub enum UvFileFlag {
|
||||||
|
O_RDONLY,
|
||||||
|
O_WRONLY,
|
||||||
|
O_RDWR,
|
||||||
|
O_CREAT,
|
||||||
|
O_TRUNC
|
||||||
|
}
|
||||||
|
pub fn map_flag(v: UvFileFlag) -> int {
|
||||||
|
unsafe {
|
||||||
|
match v {
|
||||||
|
O_RDONLY => uvll::get_O_RDONLY() as int,
|
||||||
|
O_WRONLY => uvll::get_O_WRONLY() as int,
|
||||||
|
O_RDWR => uvll::get_O_RDWR() as int,
|
||||||
|
O_CREAT => uvll::get_O_CREAT() as int,
|
||||||
|
O_TRUNC => uvll::get_O_TRUNC() as int
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct RequestData {
|
||||||
|
complete_cb: Option<FsCallback>
|
||||||
|
}
|
||||||
|
|
||||||
impl FsRequest {
|
impl FsRequest {
|
||||||
fn new() -> FsRequest {
|
pub fn new(cb: Option<FsCallback>) -> FsRequest {
|
||||||
let fs_req = unsafe { malloc_req(UV_FS) };
|
let fs_req = unsafe { malloc_req(UV_FS) };
|
||||||
assert!(fs_req.is_not_null());
|
assert!(fs_req.is_not_null());
|
||||||
let fs_req = fs_req as *uvll::uv_write_t;
|
let fs_req: FsRequest = NativeHandle::from_native_handle(fs_req);
|
||||||
unsafe { uvll::set_data_for_req(fs_req, null::<()>()); }
|
fs_req.install_req_data(cb);
|
||||||
NativeHandle::from_native_handle(fs_req)
|
fs_req
|
||||||
}
|
}
|
||||||
|
|
||||||
fn delete(self) {
|
pub fn install_req_data(&self, cb: Option<FsCallback>) {
|
||||||
unsafe { free_req(self.native_handle() as *c_void) }
|
let fs_req = (self.native_handle()) as *uvll::uv_write_t;
|
||||||
|
let data = ~RequestData {
|
||||||
|
complete_cb: cb
|
||||||
|
};
|
||||||
|
unsafe {
|
||||||
|
let data = transmute::<~RequestData, *c_void>(data);
|
||||||
|
uvll::set_data_for_req(fs_req, data);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn open(&mut self, _loop_: &Loop, _cb: FsCallback) {
|
fn get_req_data<'r>(&'r mut self) -> &'r mut RequestData {
|
||||||
|
unsafe {
|
||||||
|
let data = uvll::get_data_for_req((self.native_handle()));
|
||||||
|
let data = transmute::<&*c_void, &mut ~RequestData>(&data);
|
||||||
|
return &mut **data;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn close(&mut self, _loop_: &Loop, _cb: FsCallback) {
|
pub fn get_result(&mut self) -> c_int {
|
||||||
|
unsafe {
|
||||||
|
uvll::get_result_from_fs_req(self.native_handle())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_loop(&self) -> Loop {
|
||||||
|
unsafe { Loop{handle:uvll::get_loop_from_fs_req(self.native_handle())} }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cleanup_and_delete(self) {
|
||||||
|
unsafe {
|
||||||
|
uvll::fs_req_cleanup(self.native_handle());
|
||||||
|
let data = uvll::get_data_for_uv_handle(self.native_handle());
|
||||||
|
let _data = transmute::<*c_void, ~RequestData>(data);
|
||||||
|
uvll::set_data_for_uv_handle(self.native_handle(), null::<()>());
|
||||||
|
free_req(self.native_handle() as *c_void)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -46,3 +103,97 @@ impl NativeHandle<*uvll::uv_fs_t> for FsRequest {
|
|||||||
match self { &FsRequest(ptr) => ptr }
|
match self { &FsRequest(ptr) => ptr }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct FileDescriptor(c_int);
|
||||||
|
impl FileDescriptor {
|
||||||
|
fn new(fd: c_int) -> FileDescriptor {
|
||||||
|
FileDescriptor(fd)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_open_req(req: &mut FsRequest) -> FileDescriptor {
|
||||||
|
FileDescriptor::new(req.get_result())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn open(loop_: Loop, path: Path, flags: int, mode: int,
|
||||||
|
cb: FsCallback) -> int {
|
||||||
|
let req = FsRequest::new(Some(cb));
|
||||||
|
path.to_str().to_c_str().with_ref(|p| unsafe {
|
||||||
|
uvll::fs_open(loop_.native_handle(),
|
||||||
|
req.native_handle(), p, flags, mode, complete_cb) as int
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fn close(self, loop_: Loop, cb: FsCallback) -> int {
|
||||||
|
let req = FsRequest::new(Some(cb));
|
||||||
|
unsafe {
|
||||||
|
uvll::fs_close(loop_.native_handle(), req.native_handle(),
|
||||||
|
self.native_handle(), complete_cb) as int
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
extern fn complete_cb(req: *uv_fs_t) {
|
||||||
|
let mut req: FsRequest = NativeHandle::from_native_handle(req);
|
||||||
|
let loop_ = req.get_loop();
|
||||||
|
// pull the user cb out of the req data
|
||||||
|
let cb = {
|
||||||
|
let data = req.get_req_data();
|
||||||
|
assert!(data.complete_cb.is_some());
|
||||||
|
// option dance, option dance. oooooh yeah.
|
||||||
|
data.complete_cb.take_unwrap()
|
||||||
|
};
|
||||||
|
// in uv_fs_open calls, the result will be the fd in the
|
||||||
|
// case of success, otherwise it's -1 indicating an error
|
||||||
|
let result = req.get_result();
|
||||||
|
let status = status_to_maybe_uv_error_with_loop(
|
||||||
|
loop_.native_handle(), result);
|
||||||
|
// we have a req and status, call the user cb..
|
||||||
|
// only giving the user a ref to the FsRequest, as we
|
||||||
|
// have to clean it up, afterwards (and they aren't really
|
||||||
|
// reusable, anyways
|
||||||
|
cb(&mut req, status);
|
||||||
|
// clean up the req (and its data!) after calling the user cb
|
||||||
|
req.cleanup_and_delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
impl NativeHandle<c_int> for FileDescriptor {
|
||||||
|
fn from_native_handle(handle: c_int) -> FileDescriptor {
|
||||||
|
FileDescriptor(handle)
|
||||||
|
}
|
||||||
|
fn native_handle(&self) -> c_int {
|
||||||
|
match self { &FileDescriptor(ptr) => ptr }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mod test {
|
||||||
|
use super::*;
|
||||||
|
//use rt::test::*;
|
||||||
|
use unstable::run_in_bare_thread;
|
||||||
|
use path::Path;
|
||||||
|
use rt::uv::Loop;
|
||||||
|
|
||||||
|
// this is equiv to touch, i guess?
|
||||||
|
fn file_test_touch_impl() {
|
||||||
|
debug!("hello?")
|
||||||
|
do run_in_bare_thread {
|
||||||
|
debug!("In bare thread")
|
||||||
|
let loop_ = Loop::new();
|
||||||
|
let flags = map_flag(O_RDWR) |
|
||||||
|
map_flag(O_CREAT) | map_flag(O_TRUNC);
|
||||||
|
do FileDescriptor::open(loop_, Path("./foo.txt"), flags, 0644)
|
||||||
|
|req, uverr| {
|
||||||
|
let loop_ = req.get_loop();
|
||||||
|
assert!(uverr.is_none());
|
||||||
|
let fd = FileDescriptor::from_open_req(req);
|
||||||
|
do fd.close(loop_) |_, uverr| {
|
||||||
|
assert!(uverr.is_none());
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn file_test_touch() {
|
||||||
|
file_test_touch_impl();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ use rt::io::IoError;
|
|||||||
|
|
||||||
//#[cfg(test)] use unstable::run_in_bare_thread;
|
//#[cfg(test)] use unstable::run_in_bare_thread;
|
||||||
|
|
||||||
pub use self::file::FsRequest;
|
pub use self::file::{FsRequest};
|
||||||
pub use self::net::{StreamWatcher, TcpWatcher, UdpWatcher};
|
pub use self::net::{StreamWatcher, TcpWatcher, UdpWatcher};
|
||||||
pub use self::idle::IdleWatcher;
|
pub use self::idle::IdleWatcher;
|
||||||
pub use self::timer::TimerWatcher;
|
pub use self::timer::TimerWatcher;
|
||||||
@@ -125,7 +125,7 @@ pub type ReadCallback = ~fn(StreamWatcher, int, Buf, Option<UvError>);
|
|||||||
pub type NullCallback = ~fn();
|
pub type NullCallback = ~fn();
|
||||||
pub type IdleCallback = ~fn(IdleWatcher, Option<UvError>);
|
pub type IdleCallback = ~fn(IdleWatcher, Option<UvError>);
|
||||||
pub type ConnectionCallback = ~fn(StreamWatcher, Option<UvError>);
|
pub type ConnectionCallback = ~fn(StreamWatcher, Option<UvError>);
|
||||||
pub type FsCallback = ~fn(FsRequest, Option<UvError>);
|
pub type FsCallback = ~fn(&mut FsRequest, Option<UvError>);
|
||||||
pub type TimerCallback = ~fn(TimerWatcher, Option<UvError>);
|
pub type TimerCallback = ~fn(TimerWatcher, Option<UvError>);
|
||||||
pub type AsyncCallback = ~fn(AsyncWatcher, Option<UvError>);
|
pub type AsyncCallback = ~fn(AsyncWatcher, Option<UvError>);
|
||||||
pub type UdpReceiveCallback = ~fn(UdpWatcher, int, Buf, SocketAddr, uint, Option<UvError>);
|
pub type UdpReceiveCallback = ~fn(UdpWatcher, int, Buf, SocketAddr, uint, Option<UvError>);
|
||||||
@@ -281,6 +281,20 @@ pub fn uv_error_to_io_error(uverr: UvError) -> IoError {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Given a uv handle, convert a callback status to a UvError
|
||||||
|
pub fn status_to_maybe_uv_error_with_loop(
|
||||||
|
loop_: *uvll::uv_loop_t,
|
||||||
|
status: c_int) -> Option<UvError> {
|
||||||
|
if status != -1 {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
unsafe {
|
||||||
|
rtdebug!("loop: %x", loop_ as uint);
|
||||||
|
let err = uvll::last_error(loop_);
|
||||||
|
Some(UvError(err))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
/// Given a uv handle, convert a callback status to a UvError
|
/// Given a uv handle, convert a callback status to a UvError
|
||||||
pub fn status_to_maybe_uv_error<T, U: Watcher + NativeHandle<*T>>(handle: U,
|
pub fn status_to_maybe_uv_error<T, U: Watcher + NativeHandle<*T>>(handle: U,
|
||||||
status: c_int) -> Option<UvError> {
|
status: c_int) -> Option<UvError> {
|
||||||
@@ -290,9 +304,7 @@ pub fn status_to_maybe_uv_error<T, U: Watcher + NativeHandle<*T>>(handle: U,
|
|||||||
unsafe {
|
unsafe {
|
||||||
rtdebug!("handle: %x", handle.native_handle() as uint);
|
rtdebug!("handle: %x", handle.native_handle() as uint);
|
||||||
let loop_ = uvll::get_loop_for_uv_handle(handle.native_handle());
|
let loop_ = uvll::get_loop_for_uv_handle(handle.native_handle());
|
||||||
rtdebug!("loop: %x", loop_ as uint);
|
status_to_maybe_uv_error_with_loop(loop_, status)
|
||||||
let err = uvll::last_error(loop_);
|
|
||||||
Some(UvError(err))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -617,7 +617,40 @@ pub unsafe fn ip6_port(addr: *sockaddr_in6) -> c_uint {
|
|||||||
return rust_uv_ip6_port(addr);
|
return rust_uv_ip6_port(addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub unsafe fn fs_open(loop_ptr: *uv_loop_t, req: *uv_fs_t, path: *c_char, flags: int, mode: int,
|
||||||
|
cb: *u8) -> c_int {
|
||||||
|
rust_uv_fs_open(loop_ptr, req, path, flags as c_int, mode as c_int, cb)
|
||||||
|
}
|
||||||
|
pub unsafe fn fs_close(loop_ptr: *uv_loop_t, req: *uv_fs_t, fd: c_int,
|
||||||
|
cb: *u8) -> c_int {
|
||||||
|
rust_uv_fs_close(loop_ptr, req, fd, cb)
|
||||||
|
}
|
||||||
|
pub unsafe fn fs_req_cleanup(req: *uv_fs_t) {
|
||||||
|
rust_uv_fs_req_cleanup(req);
|
||||||
|
}
|
||||||
|
|
||||||
// data access helpers
|
// data access helpers
|
||||||
|
pub unsafe fn get_O_RDONLY() -> c_int {
|
||||||
|
rust_uv_get_O_RDONLY()
|
||||||
|
}
|
||||||
|
pub unsafe fn get_O_WRONLY() -> c_int {
|
||||||
|
rust_uv_get_O_WRONLY()
|
||||||
|
}
|
||||||
|
pub unsafe fn get_O_RDWR() -> c_int {
|
||||||
|
rust_uv_get_O_RDWR()
|
||||||
|
}
|
||||||
|
pub unsafe fn get_O_CREAT() -> c_int {
|
||||||
|
rust_uv_get_O_CREAT()
|
||||||
|
}
|
||||||
|
pub unsafe fn get_O_TRUNC() -> c_int {
|
||||||
|
rust_uv_get_O_TRUNC()
|
||||||
|
}
|
||||||
|
pub unsafe fn get_result_from_fs_req(req: *uv_fs_t) -> c_int {
|
||||||
|
rust_uv_get_result_from_fs_req(req)
|
||||||
|
}
|
||||||
|
pub unsafe fn get_loop_from_fs_req(req: *uv_fs_t) -> *uv_loop_t {
|
||||||
|
rust_uv_get_loop_from_fs_req(req)
|
||||||
|
}
|
||||||
pub unsafe fn get_loop_for_uv_handle<T>(handle: *T) -> *c_void {
|
pub unsafe fn get_loop_for_uv_handle<T>(handle: *T) -> *c_void {
|
||||||
#[fixed_stack_segment]; #[inline(never)];
|
#[fixed_stack_segment]; #[inline(never)];
|
||||||
|
|
||||||
@@ -784,6 +817,18 @@ extern {
|
|||||||
fn rust_uv_timer_start(timer_handle: *uv_timer_t, cb: uv_timer_cb, timeout: libc::uint64_t,
|
fn rust_uv_timer_start(timer_handle: *uv_timer_t, cb: uv_timer_cb, timeout: libc::uint64_t,
|
||||||
repeat: libc::uint64_t) -> c_int;
|
repeat: libc::uint64_t) -> c_int;
|
||||||
fn rust_uv_timer_stop(handle: *uv_timer_t) -> c_int;
|
fn rust_uv_timer_stop(handle: *uv_timer_t) -> c_int;
|
||||||
|
fn rust_uv_fs_open(loop_ptr: *c_void, req: *uv_fs_t, path: *c_char,
|
||||||
|
flags: c_int, mode: c_int, cb: *u8) -> c_int;
|
||||||
|
fn rust_uv_fs_close(loop_ptr: *c_void, req: *uv_fs_t, fd: c_int,
|
||||||
|
cb: *u8) -> c_int;
|
||||||
|
fn rust_uv_fs_req_cleanup(req: *uv_fs_t);
|
||||||
|
fn rust_uv_get_O_RDONLY() -> c_int;
|
||||||
|
fn rust_uv_get_O_WRONLY() -> c_int;
|
||||||
|
fn rust_uv_get_O_RDWR() -> c_int;
|
||||||
|
fn rust_uv_get_O_CREAT() -> c_int;
|
||||||
|
fn rust_uv_get_O_TRUNC() -> c_int;
|
||||||
|
fn rust_uv_get_result_from_fs_req(req: *uv_fs_t) -> c_int;
|
||||||
|
fn rust_uv_get_loop_from_fs_req(req: *uv_fs_t) -> *uv_loop_t;
|
||||||
|
|
||||||
fn rust_uv_get_stream_handle_from_connect_req(connect_req: *uv_connect_t) -> *uv_stream_t;
|
fn rust_uv_get_stream_handle_from_connect_req(connect_req: *uv_connect_t) -> *uv_stream_t;
|
||||||
fn rust_uv_get_stream_handle_from_write_req(write_req: *uv_write_t) -> *uv_stream_t;
|
fn rust_uv_get_stream_handle_from_write_req(write_req: *uv_write_t) -> *uv_stream_t;
|
||||||
|
|||||||
@@ -108,6 +108,16 @@ rust_uv_idle_delete
|
|||||||
rust_uv_idle_init
|
rust_uv_idle_init
|
||||||
rust_uv_idle_start
|
rust_uv_idle_start
|
||||||
rust_uv_idle_stop
|
rust_uv_idle_stop
|
||||||
|
rust_uv_fs_open
|
||||||
|
rust_uv_fs_close
|
||||||
|
rust_uv_get_O_RDONLY
|
||||||
|
rust_uv_get_O_WRONLY
|
||||||
|
rust_uv_get_O_RDWR
|
||||||
|
rust_uv_get_O_CREAT
|
||||||
|
rust_uv_get_O_TRUNC
|
||||||
|
rust_uv_get_result_from_fs_req
|
||||||
|
rust_uv_get_loop_from_fs_req
|
||||||
|
rust_uv_fs_req_cleanup
|
||||||
rust_dbg_lock_create
|
rust_dbg_lock_create
|
||||||
rust_dbg_lock_destroy
|
rust_dbg_lock_destroy
|
||||||
rust_dbg_lock_lock
|
rust_dbg_lock_lock
|
||||||
|
|||||||
Reference in New Issue
Block a user