Skip to content

Newrt file io #8655

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 26 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
a901b16
std: bootstrapping libuv-based fileio in newrt... open & close
olsonjeffery Aug 15, 2013
dabbac1
std: working tests for low-level libuv open, write and close operations
olsonjeffery Aug 16, 2013
c49c292
std: add read and unlink to low-level FileDescriptor + end-to-end CRU…
olsonjeffery Aug 17, 2013
e0a80ee
std: support async/threadpool & sync paths in uv_fs_* calls + add syn…
olsonjeffery Aug 17, 2013
f60bd75
std: remove fcntl const bindings + making valgrind clean w/ no owned …
olsonjeffery Aug 19, 2013
47f0e91
std: CRUD file io bindings in uvio, fs_open()/unlink() in IoFactory +…
olsonjeffery Aug 19, 2013
f6d897d
std: rt::io::file::FileStream fleshed out.. needs more work.. see ext…
olsonjeffery Aug 20, 2013
4015b4a
std: add FileStream::unlink + more tests
olsonjeffery Aug 20, 2013
48d6761
std: adding #[fixed_stack_segment] as needed in new uvll calls
olsonjeffery Aug 20, 2013
05c8cc7
std: rework file io.. support [p]read,[p]write, impl seek/tell + more…
olsonjeffery Aug 20, 2013
0e99641
std: lint appeasement for unused param in condition handler
olsonjeffery Aug 21, 2013
a7ee85b
std: stripping unneeded fcntl.h include from rust_uv.cpp
olsonjeffery Aug 21, 2013
c3a819b
std: writing to stdout only works when using -1 offset..
olsonjeffery Aug 21, 2013
10ff535
std: UvFileStream implements HomingIO + .home_for_io() wrapper usage
olsonjeffery Aug 21, 2013
c0fba3c
rt: re-adding lines erroneous stripped out in merge conflict
olsonjeffery Aug 21, 2013
320ccbe
std: naive stdio print test in uvio
olsonjeffery Aug 21, 2013
ece709f
std: more seek tests
olsonjeffery Aug 22, 2013
13eb259
change FileDescriptor instance methods to use &mut self
olsonjeffery Aug 22, 2013
429b5f8
std: rename tmp file paths to go into ./tmp folder in builddir
olsonjeffery Aug 22, 2013
f85d3b3
std: reform fn sigs of FileDescriptor methods (better result signalling)
olsonjeffery Aug 22, 2013
f01e265
std: moved static file actions (open,unlink) to FsRequest
olsonjeffery Aug 22, 2013
94b84a8
std: all of the calls in rt::uv::file take a &Loop
olsonjeffery Aug 22, 2013
6311856
std: slight refactor on UvFilestream seek behavior, pre-seek-refactor
olsonjeffery Aug 22, 2013
8d997fb
std: put FileMode/Access->whence-mask in uvio, open/unlink as fns in …
olsonjeffery Aug 22, 2013
744c462
make check appeasement
olsonjeffery Aug 22, 2013
b7cbd8a
fix 32bit mac build error
olsonjeffery Aug 23, 2013
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
343 changes: 303 additions & 40 deletions src/libstd/rt/io/file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,69 +11,332 @@
use prelude::*;
use super::support::PathLike;
use super::{Reader, Writer, Seek};
use super::SeekStyle;
use super::{SeekSet, SeekCur, SeekEnd, SeekStyle};
use rt::rtio::{RtioFileStream, IoFactory, IoFactoryObject};
use rt::io::{io_error, read_error, EndOfFile,
FileMode, FileAccess, Open, Read, Create, ReadWrite};
use rt::local::Local;
use rt::test::*;

/// # FIXME #7785
/// * Ugh, this is ridiculous. What is the best way to represent these options?
enum FileMode {
/// Opens an existing file. IoError if file does not exist.
Open,
/// Creates a file. IoError if file exists.
Create,
/// Opens an existing file or creates a new one.
OpenOrCreate,
/// Opens an existing file or creates a new one, positioned at EOF.
Append,
/// Opens an existing file, truncating it to 0 bytes.
Truncate,
/// Opens an existing file or creates a new one, truncating it to 0 bytes.
CreateOrTruncate,
/// Open a file for reading/writing, as indicated by `path`.
pub fn open<P: PathLike>(path: &P,
mode: FileMode,
access: FileAccess
) -> Option<FileStream> {
let open_result = unsafe {
let io = Local::unsafe_borrow::<IoFactoryObject>();
(*io).fs_open(path, mode, access)
};
match open_result {
Ok(fd) => Some(FileStream {
fd: fd,
last_nread: -1
}),
Err(ioerr) => {
io_error::cond.raise(ioerr);
None
}
}
}

enum FileAccess {
Read,
Write,
ReadWrite
/// Unlink (remove) a file from the filesystem, as indicated
/// by `path`.
pub fn unlink<P: PathLike>(path: &P) {
let unlink_result = unsafe {
let io = Local::unsafe_borrow::<IoFactoryObject>();
(*io).fs_unlink(path)
};
match unlink_result {
Ok(_) => (),
Err(ioerr) => {
io_error::cond.raise(ioerr);
}
}
}

pub struct FileStream;
/// Abstraction representing *positional* access to a file. In this case,
/// *positional* refers to it keeping an encounter *cursor* of where in the
/// file a subsequent `read` or `write` will begin from. Users of a `FileStream`
/// can `seek` to move the cursor to a given location *within the bounds of the
/// file* and can ask to have the `FileStream` `tell` them the location, in
/// bytes, of the cursor.
///
/// This abstraction is roughly modeled on the access workflow as represented
/// by `open(2)`, `read(2)`, `write(2)` and friends.
///
/// The `open` and `unlink` static methods are provided to manage creation/removal
/// of files. All other methods operatin on an instance of `FileStream`.
pub struct FileStream {
fd: ~RtioFileStream,
last_nread: int,
}

impl FileStream {
pub fn open<P: PathLike>(_path: &P,
_mode: FileMode,
_access: FileAccess
) -> Option<FileStream> {
fail!()
}
}

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) {
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) {
Ok(_) => (),
Err(ioerr) => {
io_error::cond.raise(ioerr);
}
}
}

fn flush(&mut self) { fail!() }
fn flush(&mut self) {
match self.fd.flush() {
Ok(_) => (),
Err(ioerr) => {
read_error::cond.raise(ioerr);
}
}
}
}

impl Seek for FileStream {
fn tell(&self) -> u64 { fail!() }
fn tell(&self) -> u64 {
let res = self.fd.tell();
match res {
Ok(cursor) => cursor,
Err(ioerr) => {
read_error::cond.raise(ioerr);
return -1;
}
}
}

fn seek(&mut self, pos: i64, style: SeekStyle) {
match self.fd.seek(pos, style) {
Ok(_) => {
// successful seek resets EOF indicator
self.last_nread = -1;
()
},
Err(ioerr) => {
read_error::cond.raise(ioerr);
}
}
}
}

fn seek(&mut self, _pos: i64, _style: SeekStyle) { fail!() }
fn file_test_smoke_test_impl() {
do run_in_newsched_task {
let message = "it's alright. have a good time";
let filename = &Path("./tmp/file_rt_io_file_test.txt");
{
let mut write_stream = open(filename, Create, ReadWrite).unwrap();
write_stream.write(message.as_bytes());
}
{
use str;
let mut read_stream = 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());
}
unlink(filename);
}
}

#[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_io_smoke_test() {
file_test_smoke_test_impl();
}

fn file_test_invalid_path_opened_without_create_should_raise_condition_impl() {
do run_in_newsched_task {
let filename = &Path("./tmp/file_that_does_not_exist.txt");
let mut called = false;
do io_error::cond.trap(|_| {
called = true;
}).inside {
let result = open(filename, Open, Read);
assert!(result.is_none());
}
assert!(called);
}
}
#[test]
fn file_test_io_invalid_path_opened_without_create_should_raise_condition() {
file_test_invalid_path_opened_without_create_should_raise_condition_impl();
}

fn file_test_unlinking_invalid_path_should_raise_condition_impl() {
do run_in_newsched_task {
let filename = &Path("./tmp/file_another_file_that_does_not_exist.txt");
let mut called = false;
do io_error::cond.trap(|_| {
called = true;
}).inside {
unlink(filename);
}
assert!(called);
}
}
#[test]
fn file_test_iounlinking_invalid_path_should_raise_condition() {
file_test_unlinking_invalid_path_should_raise_condition_impl();
}

fn file_test_io_non_positional_read_impl() {
do run_in_newsched_task {
use str;
let message = "ten-four";
let mut read_mem = [0, .. 8];
let filename = &Path("./tmp/file_rt_io_file_test_positional.txt");
{
let mut rw_stream = open(filename, Create, ReadWrite).unwrap();
rw_stream.write(message.as_bytes());
}
{
let mut read_stream = open(filename, Open, Read).unwrap();
{
let read_buf = read_mem.mut_slice(0, 4);
read_stream.read(read_buf);
}
{
let read_buf = read_mem.mut_slice(4, 8);
read_stream.read(read_buf);
}
}
unlink(filename);
let read_str = str::from_bytes(read_mem);
assert!(read_str == message.to_owned());
}
}

#[test]
fn file_test_io_non_positional_read() {
file_test_io_non_positional_read_impl();
}

fn file_test_io_seeking_impl() {
do run_in_newsched_task {
use str;
let message = "ten-four";
let mut read_mem = [0, .. 4];
let set_cursor = 4 as u64;
let mut tell_pos_pre_read;
let mut tell_pos_post_read;
let filename = &Path("./tmp/file_rt_io_file_test_seeking.txt");
{
let mut rw_stream = open(filename, Create, ReadWrite).unwrap();
rw_stream.write(message.as_bytes());
}
{
let mut read_stream = open(filename, Open, Read).unwrap();
read_stream.seek(set_cursor as i64, SeekSet);
tell_pos_pre_read = read_stream.tell();
read_stream.read(read_mem);
tell_pos_post_read = read_stream.tell();
}
unlink(filename);
let read_str = str::from_bytes(read_mem);
assert!(read_str == message.slice(4, 8).to_owned());
assert!(tell_pos_pre_read == set_cursor);
assert!(tell_pos_post_read == message.len() as u64);
}
}
#[test]
fn file_test_io_seek_and_tell_smoke_test() {
file_test_io_seeking_impl();
}

fn file_test_io_seek_and_write_impl() {
use io;
do run_in_newsched_task {
use str;
let initial_msg = "food-is-yummy";
let overwrite_msg = "-the-bar!!";
let final_msg = "foo-the-bar!!";
let seek_idx = 3;
let mut read_mem = [0, .. 13];
let filename = &Path("./tmp/file_rt_io_file_test_seek_and_write.txt");
{
let mut rw_stream = open(filename, Create, ReadWrite).unwrap();
rw_stream.write(initial_msg.as_bytes());
rw_stream.seek(seek_idx as i64, SeekSet);
rw_stream.write(overwrite_msg.as_bytes());
}
{
let mut read_stream = open(filename, Open, Read).unwrap();
read_stream.read(read_mem);
}
unlink(filename);
let read_str = str::from_bytes(read_mem);
io::println(fmt!("read_str: '%?' final_msg: '%?'", read_str, final_msg));
assert!(read_str == final_msg.to_owned());
}
}
#[test]
fn file_test_io_seek_and_write() {
file_test_io_seek_and_write_impl();
}

fn file_test_io_seek_shakedown_impl() {
do run_in_newsched_task {
use str; // 01234567890123
let initial_msg = "qwer-asdf-zxcv";
let chunk_one = "qwer";
let chunk_two = "asdf";
let chunk_three = "zxcv";
let mut read_mem = [0, .. 4];
let filename = &Path("./tmp/file_rt_io_file_test_seek_shakedown.txt");
{
let mut rw_stream = open(filename, Create, ReadWrite).unwrap();
rw_stream.write(initial_msg.as_bytes());
}
{
let mut read_stream = open(filename, Open, Read).unwrap();

read_stream.seek(-4, SeekEnd);
read_stream.read(read_mem);
let read_str = str::from_bytes(read_mem);
assert!(read_str == chunk_three.to_owned());

read_stream.seek(-9, SeekCur);
read_stream.read(read_mem);
let read_str = str::from_bytes(read_mem);
assert!(read_str == chunk_two.to_owned());

read_stream.seek(0, SeekSet);
read_stream.read(read_mem);
let read_str = str::from_bytes(read_mem);
assert!(read_str == chunk_one.to_owned());
}
unlink(filename);
}
}
#[test]
fn file_test_io_seek_shakedown() {
file_test_io_seek_shakedown_impl();
}
Loading