about summary refs log tree commit diff
path: root/src/libstd
diff options
context:
space:
mode:
authorJeff Olson <olson.jeffery@gmail.com>2013-08-19 21:57:47 -0700
committerJeff Olson <olson.jeffery@gmail.com>2013-08-22 16:31:57 -0700
commitf6d897d7d97c6f75126d487da196084aaafde659 (patch)
tree33b71a8ad866a355aaad3e04b40c6f87ed4dfc21 /src/libstd
parent47f0e91689403c8472dc63e58e735f42251427ab (diff)
downloadrust-f6d897d7d97c6f75126d487da196084aaafde659.tar.gz
rust-f6d897d7d97c6f75126d487da196084aaafde659.zip
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
Diffstat (limited to 'src/libstd')
-rw-r--r--src/libstd/rt/io/file.rs109
-rw-r--r--src/libstd/rt/rtio.rs5
-rw-r--r--src/libstd/rt/uv/file.rs40
-rw-r--r--src/libstd/rt/uv/uvio.rs13
4 files changed, 127 insertions, 40 deletions
diff --git a/src/libstd/rt/io/file.rs b/src/libstd/rt/io/file.rs
index 91289611659..0e972206ea7 100644
--- a/src/libstd/rt/io/file.rs
+++ b/src/libstd/rt/io/file.rs
@@ -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!() }
 }
 
+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]
-#[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() {
+    file_test_smoke_test_impl();
 }
diff --git a/src/libstd/rt/rtio.rs b/src/libstd/rt/rtio.rs
index 1095104773d..fedffa32844 100644
--- a/src/libstd/rt/rtio.rs
+++ b/src/libstd/rt/rtio.rs
@@ -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 {
diff --git a/src/libstd/rt/uv/file.rs b/src/libstd/rt/uv/file.rs
index f3f6c325162..056250ba968 100644
--- a/src/libstd/rt/uv/file.rs
+++ b/src/libstd/rt/uv/file.rs
@@ -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."); }
diff --git a/src/libstd/rt/uv/uvio.rs b/src/libstd/rt/uv/uvio.rs
index 913b19ec38f..2acf2cccfea 100644
--- a/src/libstd/rt/uv/uvio.rs
+++ b/src/libstd/rt/uv/uvio.rs
@@ -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));
     }
 }