Skip to content

Commit f6d897d

Browse files
committed
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
1 parent 47f0e91 commit f6d897d

File tree

4 files changed

+127
-40
lines changed

4 files changed

+127
-40
lines changed

src/libstd/rt/io/file.rs

Lines changed: 94 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,11 @@ use prelude::*;
1212
use super::support::PathLike;
1313
use super::{Reader, Writer, Seek};
1414
use super::SeekStyle;
15+
use rt::rtio::{RtioFileDescriptor, IoFactory, IoFactoryObject};
16+
use rt::io::{io_error, read_error, EndOfFile};
17+
use rt::local::Local;
18+
use libc::{O_RDWR, O_RDONLY, O_WRONLY, S_IWUSR, S_IRUSR,
19+
O_CREAT, O_TRUNC, O_APPEND};
1520

1621
/// # FIXME #7785
1722
/// * Ugh, this is ridiculous. What is the best way to represent these options?
@@ -36,29 +41,85 @@ enum FileAccess {
3641
ReadWrite
3742
}
3843

39-
pub struct FileStream;
44+
pub struct FileStream {
45+
fd: ~RtioFileDescriptor,
46+
last_nread: int
47+
}
4048

4149
impl FileStream {
42-
pub fn open<P: PathLike>(_path: &P,
43-
_mode: FileMode,
44-
_access: FileAccess
50+
pub fn open<P: PathLike>(path: &P,
51+
mode: FileMode,
52+
access: FileAccess
4553
) -> Option<FileStream> {
46-
fail!()
54+
let open_result = unsafe {
55+
let io = Local::unsafe_borrow::<IoFactoryObject>();
56+
let mut flags = match mode {
57+
Open => 0,
58+
Create => O_CREAT,
59+
OpenOrCreate => O_CREAT,
60+
Append => O_APPEND,
61+
Truncate => O_TRUNC,
62+
CreateOrTruncate => O_TRUNC | O_CREAT
63+
};
64+
flags = match access {
65+
Read => flags | O_RDONLY,
66+
Write => flags | O_WRONLY,
67+
ReadWrite => flags | O_RDWR
68+
};
69+
let create_mode = match mode {
70+
Create|OpenOrCreate|CreateOrTruncate =>
71+
S_IRUSR | S_IWUSR,
72+
_ => 0
73+
};
74+
(*io).fs_open(path, flags as int, create_mode as int)
75+
};
76+
match open_result {
77+
Ok(fd) => Some(FileStream {
78+
fd: fd,
79+
last_nread: -1
80+
}),
81+
Err(ioerr) => {
82+
io_error::cond.raise(ioerr);
83+
None
84+
}
85+
}
4786
}
4887
}
4988

5089
impl Reader for FileStream {
51-
fn read(&mut self, _buf: &mut [u8]) -> Option<uint> {
52-
fail!()
90+
fn read(&mut self, buf: &mut [u8]) -> Option<uint> {
91+
match self.fd.read(buf, 0) {
92+
Ok(read) => {
93+
self.last_nread = read;
94+
match read {
95+
0 => None,
96+
_ => Some(read as uint)
97+
}
98+
},
99+
Err(ioerr) => {
100+
// EOF is indicated by returning None
101+
if ioerr.kind != EndOfFile {
102+
read_error::cond.raise(ioerr);
103+
}
104+
return None;
105+
}
106+
}
53107
}
54108

55109
fn eof(&mut self) -> bool {
56-
fail!()
110+
self.last_nread == 0
57111
}
58112
}
59113

60114
impl Writer for FileStream {
61-
fn write(&mut self, _v: &[u8]) { fail!() }
115+
fn write(&mut self, buf: &[u8]) {
116+
match self.fd.write(buf, 0) {
117+
Ok(_) => (),
118+
Err(ioerr) => {
119+
io_error::cond.raise(ioerr);
120+
}
121+
}
122+
}
62123

63124
fn flush(&mut self) { fail!() }
64125
}
@@ -69,11 +130,29 @@ impl Seek for FileStream {
69130
fn seek(&mut self, _pos: i64, _style: SeekStyle) { fail!() }
70131
}
71132

133+
fn file_test_smoke_test_impl() {
134+
use rt::test::*;
135+
do run_in_newsched_task {
136+
let message = "it's alright. have a good time";
137+
let filename = &Path("rt_io_file_test.txt");
138+
{
139+
let mut write_stream = FileStream::open(filename, Create, ReadWrite).unwrap();
140+
write_stream.write(message.as_bytes());
141+
}
142+
{
143+
use str;
144+
let mut read_stream = FileStream::open(filename, Open, Read).unwrap();
145+
let mut read_buf = [0, .. 1028];
146+
let read_str = match read_stream.read(read_buf).unwrap() {
147+
-1|0 => fail!("shouldn't happen"),
148+
n => str::from_bytes(read_buf.slice_to(n))
149+
};
150+
assert!(read_str == message.to_owned());
151+
}
152+
}
153+
}
154+
72155
#[test]
73-
#[ignore]
74-
fn super_simple_smoke_test_lets_go_read_some_files_and_have_a_good_time() {
75-
let message = "it's alright. have a good time";
76-
let filename = &Path("test.txt");
77-
let mut outstream = FileStream::open(filename, Create, Read).unwrap();
78-
outstream.write(message.as_bytes());
156+
fn file_test_smoke_test() {
157+
file_test_smoke_test_impl();
79158
}

src/libstd/rt/rtio.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ use rt::io::IoError;
1616
use super::io::net::ip::{IpAddr, SocketAddr};
1717
use rt::uv::uvio;
1818
use path::Path;
19+
use super::io::support::PathLike;
1920

2021
// XXX: ~object doesn't work currently so these are some placeholder
2122
// types to use instead
@@ -66,9 +67,9 @@ pub trait IoFactory {
6667
fn udp_bind(&mut self, addr: SocketAddr) -> Result<~RtioUdpSocketObject, IoError>;
6768
fn timer_init(&mut self) -> Result<~RtioTimerObject, IoError>;
6869
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+
fn fs_open<P: PathLike>(&mut self, path: &P, flags: int, mode:int)
7071
-> Result<~RtioFileDescriptor, IoError>;
71-
fn fs_unlink(&mut self, path: Path) -> Result<(), IoError>;
72+
fn fs_unlink<P: PathLike>(&mut self, path: &P) -> Result<(), IoError>;
7273
}
7374

7475
pub trait RtioTcpListener : RtioSocket {

src/libstd/rt/uv/file.rs

Lines changed: 23 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use rt::uv::{Request, NativeHandle, Loop, FsCallback, Buf,
1515
status_to_maybe_uv_error_with_loop};
1616
use rt::uv::uvll;
1717
use rt::uv::uvll::*;
18-
use path::Path;
18+
use super::super::io::support::PathLike;
1919
use cast::transmute;
2020
use libc::{c_int};
2121
use option::{None, Some, Option};
@@ -97,47 +97,52 @@ impl FileDescriptor {
9797
FileDescriptor::new(req.get_result())
9898
}
9999

100-
fn open_common(loop_: Loop, path: Path, flags: int, mode: int,
100+
fn open_common<P: PathLike>(loop_: Loop, path: &P, flags: int, mode: int,
101101
cb: Option<FsCallback>) -> int {
102102
let complete_cb_ptr = match cb {
103103
Some(_) => compl_cb,
104104
None => 0 as *u8
105105
};
106106
let is_sync = cb.is_none();
107107
let req = FsRequest::new(cb);
108-
let result = path.to_str().to_c_str().with_ref(|p| unsafe {
108+
let result = path.path_as_str(|p| {
109+
p.to_c_str().with_ref(|p| unsafe {
109110
uvll::fs_open(loop_.native_handle(),
110111
req.native_handle(), p, flags, mode, complete_cb_ptr) as int
112+
})
111113
});
112114
if is_sync { req.cleanup_and_delete(); }
113115
result
114116
}
115-
pub fn open(loop_: Loop, path: Path, flags: int, mode: int,
117+
pub fn open<P: PathLike>(loop_: Loop, path: &P, flags: int, mode: int,
116118
cb: FsCallback) -> int {
117119
FileDescriptor::open_common(loop_, path, flags, mode, Some(cb))
118120
}
119-
pub fn open_sync(loop_: Loop, path: Path, flags: int, mode: int) -> int {
121+
122+
pub fn open_sync<P: PathLike>(loop_: Loop, path: &P, flags: int, mode: int) -> int {
120123
FileDescriptor::open_common(loop_, path, flags, mode, None)
121124
}
122125

123-
fn unlink_common(loop_: Loop, path: Path, cb: Option<FsCallback>) -> int {
126+
fn unlink_common<P: PathLike>(loop_: Loop, path: &P, cb: Option<FsCallback>) -> int {
124127
let complete_cb_ptr = match cb {
125128
Some(_) => compl_cb,
126129
None => 0 as *u8
127130
};
128131
let is_sync = cb.is_none();
129132
let req = FsRequest::new(cb);
130-
let result = path.to_str().to_c_str().with_ref(|p| unsafe {
131-
uvll::fs_unlink(loop_.native_handle(),
132-
req.native_handle(), p, complete_cb_ptr) as int
133+
let result = path.path_as_str(|p| {
134+
p.to_c_str().with_ref(|p| unsafe {
135+
uvll::fs_unlink(loop_.native_handle(),
136+
req.native_handle(), p, complete_cb_ptr) as int
137+
})
133138
});
134139
if is_sync { req.cleanup_and_delete(); }
135140
result
136141
}
137-
pub fn unlink(loop_: Loop, path: Path, cb: FsCallback) -> int {
142+
pub fn unlink<P: PathLike>(loop_: Loop, path: &P, cb: FsCallback) -> int {
138143
FileDescriptor::unlink_common(loop_, path, Some(cb))
139144
}
140-
pub fn unlink_sync(loop_: Loop, path: Path) -> int {
145+
pub fn unlink_sync<P: PathLike>(loop_: Loop, path: &P) -> int {
141146
FileDescriptor::unlink_common(loop_, path, None)
142147
}
143148

@@ -284,7 +289,8 @@ mod test {
284289
let read_mem = vec::from_elem(read_buf_len, 0u8);
285290
let read_buf = slice_to_uv_buf(read_mem);
286291
let read_buf_ptr: *Buf = &read_buf;
287-
do FileDescriptor::open(loop_, Path(path_str), create_flags as int, mode as int)
292+
let p = Path(path_str);
293+
do FileDescriptor::open(loop_, &p, create_flags as int, mode as int)
288294
|req, uverr| {
289295
let loop_ = req.get_loop();
290296
assert!(uverr.is_none());
@@ -296,7 +302,7 @@ mod test {
296302
do fd.close(loop_) |req, _| {
297303
let loop_ = req.get_loop();
298304
assert!(uverr.is_none());
299-
do FileDescriptor::open(loop_, Path(path_str), read_flags as int,0)
305+
do FileDescriptor::open(loop_, &Path(path_str), read_flags as int,0)
300306
|req, uverr| {
301307
assert!(uverr.is_none());
302308
let loop_ = req.get_loop();
@@ -319,7 +325,7 @@ mod test {
319325
assert!(read_str == ~"hello");
320326
do FileDescriptor(raw_fd).close(loop_) |_,uverr| {
321327
assert!(uverr.is_none());
322-
do FileDescriptor::unlink(loop_, Path(path_str))
328+
do FileDescriptor::unlink(loop_, &Path(path_str))
323329
|_,uverr| {
324330
assert!(uverr.is_none());
325331
};
@@ -350,7 +356,7 @@ mod test {
350356
let write_val = "hello".as_bytes().to_owned();
351357
let write_buf = slice_to_uv_buf(write_val);
352358
// open/create
353-
let result = FileDescriptor::open_sync(loop_, Path(path_str),
359+
let result = FileDescriptor::open_sync(loop_, &Path(path_str),
354360
create_flags as int, mode as int);
355361
assert!(status_to_maybe_uv_error_with_loop(
356362
loop_.native_handle(), result as i32).is_none());
@@ -364,7 +370,7 @@ mod test {
364370
assert!(status_to_maybe_uv_error_with_loop(
365371
loop_.native_handle(), result as i32).is_none());
366372
// re-open
367-
let result = FileDescriptor::open_sync(loop_, Path(path_str),
373+
let result = FileDescriptor::open_sync(loop_, &Path(path_str),
368374
read_flags as int,0);
369375
assert!(status_to_maybe_uv_error_with_loop(
370376
loop_.native_handle(), result as i32).is_none());
@@ -388,7 +394,7 @@ mod test {
388394
assert!(status_to_maybe_uv_error_with_loop(
389395
loop_.native_handle(), result as i32).is_none());
390396
// unlink
391-
let result = FileDescriptor::unlink_sync(loop_, Path(path_str));
397+
let result = FileDescriptor::unlink_sync(loop_, &Path(path_str));
392398
assert!(status_to_maybe_uv_error_with_loop(
393399
loop_.native_handle(), result as i32).is_none());
394400
} else { fail!("nread was 0.. wudn't expectin' that."); }

src/libstd/rt/uv/uvio.rs

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ use ops::Drop;
1818
use option::*;
1919
use ptr;
2020
use str;
21-
use path::Path;
2221
use result::*;
2322
use rt::io::IoError;
2423
use rt::io::net::ip::{SocketAddr, IpAddr};
@@ -31,6 +30,7 @@ use rt::uv::*;
3130
use rt::uv::idle::IdleWatcher;
3231
use rt::uv::net::{UvIpv4SocketAddr, UvIpv6SocketAddr};
3332
use unstable::sync::Exclusive;
33+
use super::super::io::support::PathLike;
3434

3535
#[cfg(test)] use container::Container;
3636
#[cfg(test)] use unstable::run_in_bare_thread;
@@ -466,7 +466,7 @@ impl IoFactory for UvIoFactory {
466466
} as ~RtioFileDescriptor
467467
}
468468

469-
fn fs_open(&mut self, path: Path, flags: int, mode: int)
469+
fn fs_open<P: PathLike>(&mut self, path: &P, flags: int, mode: int)
470470
-> Result<~RtioFileDescriptor, IoError> {
471471
let loop_ = Loop {handle: self.uv_loop().native_handle()};
472472
let result_cell = Cell::new_empty();
@@ -497,7 +497,7 @@ impl IoFactory for UvIoFactory {
497497
return result_cell.take();
498498
}
499499

500-
fn fs_unlink(&mut self, path: Path) -> Result<(), IoError> {
500+
fn fs_unlink<P: PathLike>(&mut self, path: &P) -> Result<(), IoError> {
501501
let loop_ = Loop {handle: self.uv_loop().native_handle()};
502502
let result_cell = Cell::new_empty();
503503
let result_cell_ptr: *Cell<Result<(), IoError>> = &result_cell;
@@ -1636,6 +1636,7 @@ fn file_test_uvio_full_simple_impl() {
16361636
use str::StrSlice; // why does this have to be explicitly imported to work?
16371637
// compiler was complaining about no trait for str that
16381638
// does .as_bytes() ..
1639+
use path::Path;
16391640
unsafe {
16401641
let io = Local::unsafe_borrow::<IoFactoryObject>();
16411642
let create_flags = O_RDWR | O_CREAT;
@@ -1644,18 +1645,18 @@ fn file_test_uvio_full_simple_impl() {
16441645
let mode = S_IWUSR | S_IRUSR;
16451646
let path = "./file_test_uvio_full.txt";
16461647
{
1647-
let mut fd = (*io).fs_open(Path(path), create_flags as int, mode as int).unwrap();
1648+
let mut fd = (*io).fs_open(&Path(path), create_flags as int, mode as int).unwrap();
16481649
let write_buf = write_val.as_bytes();
16491650
fd.write(write_buf, 0);
16501651
}
16511652
{
1652-
let mut fd = (*io).fs_open(Path(path), ro_flags as int, mode as int).unwrap();
1653+
let mut fd = (*io).fs_open(&Path(path), ro_flags as int, mode as int).unwrap();
16531654
let mut read_vec = [0, .. 1028];
16541655
let nread = fd.read(read_vec, 0).unwrap();
16551656
let read_val = str::from_bytes(read_vec.slice(0, nread as uint));
16561657
assert!(read_val == write_val.to_owned());
16571658
}
1658-
(*io).fs_unlink(Path(path));
1659+
(*io).fs_unlink(&Path(path));
16591660
}
16601661
}
16611662

0 commit comments

Comments
 (0)