2013-03-13 22:02:48 -05:00
|
|
|
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
|
|
|
// file at the top-level directory of this distribution and at
|
|
|
|
// http://rust-lang.org/COPYRIGHT.
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
|
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
|
|
// option. This file may not be copied, modified, or distributed
|
|
|
|
// except according to those terms.
|
|
|
|
|
2013-04-17 19:55:21 -05:00
|
|
|
/*! Synchronous I/O
|
|
|
|
|
2013-04-23 21:21:37 -05:00
|
|
|
This module defines the Rust interface for synchronous I/O.
|
|
|
|
It models byte-oriented input and output with the Reader and Writer traits.
|
2013-10-21 20:23:00 -05:00
|
|
|
Types that implement both `Reader` and `Writer` are called 'streams',
|
|
|
|
and automatically implement the `Stream` trait.
|
2013-04-23 21:21:37 -05:00
|
|
|
Implementations are provided for common I/O streams like
|
|
|
|
file, TCP, UDP, Unix domain sockets.
|
|
|
|
Readers and Writers may be composed to add capabilities like string
|
|
|
|
parsing, encoding, and compression.
|
2013-04-17 19:55:21 -05:00
|
|
|
|
2013-08-16 00:54:14 -05:00
|
|
|
This will likely live in std::io, not std::rt::io.
|
2013-04-17 19:55:21 -05:00
|
|
|
|
|
|
|
# Examples
|
|
|
|
|
|
|
|
Some examples of obvious things you might want to do
|
|
|
|
|
|
|
|
* Read lines from stdin
|
|
|
|
|
|
|
|
for stdin().each_line |line| {
|
|
|
|
println(line)
|
|
|
|
}
|
|
|
|
|
|
|
|
* Read a complete file to a string, (converting newlines?)
|
|
|
|
|
2013-04-23 21:21:37 -05:00
|
|
|
let contents = File::open("message.txt").read_to_str(); // read_to_str??
|
2013-04-17 19:55:21 -05:00
|
|
|
|
|
|
|
* Write a line to a file
|
|
|
|
|
2013-04-23 21:21:37 -05:00
|
|
|
let file = File::open("message.txt", Create, Write);
|
2013-04-17 19:55:21 -05:00
|
|
|
file.write_line("hello, file!");
|
|
|
|
|
|
|
|
* Iterate over the lines of a file
|
|
|
|
|
2013-04-23 21:21:37 -05:00
|
|
|
do File::open("message.txt").each_line |line| {
|
2013-04-19 20:47:31 -05:00
|
|
|
println(line)
|
|
|
|
}
|
|
|
|
|
2013-04-17 19:55:21 -05:00
|
|
|
* Pull the lines of a file into a vector of strings
|
|
|
|
|
2013-04-23 21:21:37 -05:00
|
|
|
let lines = File::open("message.txt").line_iter().to_vec();
|
2013-04-19 20:47:31 -05:00
|
|
|
|
|
|
|
* Make an simple HTTP request
|
|
|
|
|
|
|
|
let socket = TcpStream::open("localhost:8080");
|
|
|
|
socket.write_line("GET / HTTP/1.0");
|
|
|
|
socket.write_line("");
|
|
|
|
let response = socket.read_to_end();
|
|
|
|
|
2013-04-17 19:55:21 -05:00
|
|
|
* Connect based on URL? Requires thinking about where the URL type lives
|
|
|
|
and how to make protocol handlers extensible, e.g. the "tcp" protocol
|
|
|
|
yields a `TcpStream`.
|
|
|
|
|
2013-04-19 20:47:31 -05:00
|
|
|
connect("tcp://localhost:8080");
|
2013-04-17 19:55:21 -05:00
|
|
|
|
|
|
|
# Terms
|
|
|
|
|
2013-04-23 21:21:37 -05:00
|
|
|
* Reader - An I/O source, reads bytes into a buffer
|
|
|
|
* Writer - An I/O sink, writes bytes from a buffer
|
|
|
|
* Stream - Typical I/O sources like files and sockets are both Readers and Writers,
|
|
|
|
and are collectively referred to a `streams`.
|
|
|
|
* Decorator - A Reader or Writer that composes with others to add additional capabilities
|
|
|
|
such as encoding or decoding
|
|
|
|
|
|
|
|
# Blocking and synchrony
|
|
|
|
|
|
|
|
When discussing I/O you often hear the terms 'synchronous' and
|
|
|
|
'asynchronous', along with 'blocking' and 'non-blocking' compared and
|
|
|
|
contrasted. A synchronous I/O interface performs each I/O operation to
|
|
|
|
completion before proceeding to the next. Synchronous interfaces are
|
|
|
|
usually used in imperative style as a sequence of commands. An
|
|
|
|
asynchronous interface allows multiple I/O requests to be issued
|
|
|
|
simultaneously, without waiting for each to complete before proceeding
|
|
|
|
to the next.
|
|
|
|
|
|
|
|
Asynchronous interfaces are used to achieve 'non-blocking' I/O. In
|
|
|
|
traditional single-threaded systems, performing a synchronous I/O
|
|
|
|
operation means that the program stops all activity (it 'blocks')
|
|
|
|
until the I/O is complete. Blocking is bad for performance when
|
|
|
|
there are other computations that could be done.
|
|
|
|
|
|
|
|
Asynchronous interfaces are most often associated with the callback
|
|
|
|
(continuation-passing) style popularised by node.js. Such systems rely
|
|
|
|
on all computations being run inside an event loop which maintains a
|
|
|
|
list of all pending I/O events; when one completes the registered
|
2013-08-16 00:41:28 -05:00
|
|
|
callback is run and the code that made the I/O request continues.
|
2013-04-23 21:21:37 -05:00
|
|
|
Such interfaces achieve non-blocking at the expense of being more
|
|
|
|
difficult to reason about.
|
|
|
|
|
|
|
|
Rust's I/O interface is synchronous - easy to read - and non-blocking by default.
|
|
|
|
|
|
|
|
Remember that Rust tasks are 'green threads', lightweight threads that
|
|
|
|
are multiplexed onto a single operating system thread. If that system
|
|
|
|
thread blocks then no other task may proceed. Rust tasks are
|
|
|
|
relatively cheap to create, so as long as other tasks are free to
|
|
|
|
execute then non-blocking code may be written by simply creating a new
|
|
|
|
task.
|
|
|
|
|
|
|
|
When discussing blocking in regards to Rust's I/O model, we are
|
|
|
|
concerned with whether performing I/O blocks other Rust tasks from
|
|
|
|
proceeding. In other words, when a task calls `read`, it must then
|
|
|
|
wait (or 'sleep', or 'block') until the call to `read` is complete.
|
|
|
|
During this time, other tasks may or may not be executed, depending on
|
|
|
|
how `read` is implemented.
|
|
|
|
|
|
|
|
|
|
|
|
Rust's default I/O implementation is non-blocking; by cooperating
|
|
|
|
directly with the task scheduler it arranges to never block progress
|
|
|
|
of *other* tasks. Under the hood, Rust uses asynchronous I/O via a
|
|
|
|
per-scheduler (and hence per-thread) event loop. Synchronous I/O
|
|
|
|
requests are implemented by descheduling the running task and
|
|
|
|
performing an asynchronous request; the task is only resumed once the
|
|
|
|
asynchronous request completes.
|
|
|
|
|
|
|
|
For blocking (but possibly more efficient) implementations, look
|
|
|
|
in the `io::native` module.
|
2013-04-17 19:55:21 -05:00
|
|
|
|
|
|
|
# Error Handling
|
|
|
|
|
2013-04-23 21:21:37 -05:00
|
|
|
I/O is an area where nearly every operation can result in unexpected
|
|
|
|
errors. It should allow errors to be handled efficiently.
|
|
|
|
It needs to be convenient to use I/O when you don't care
|
|
|
|
about dealing with specific errors.
|
|
|
|
|
|
|
|
Rust's I/O employs a combination of techniques to reduce boilerplate
|
|
|
|
while still providing feedback about errors. The basic strategy:
|
|
|
|
|
|
|
|
* Errors are fatal by default, resulting in task failure
|
2013-08-16 00:41:28 -05:00
|
|
|
* Errors raise the `io_error` condition which provides an opportunity to inspect
|
2013-04-23 21:21:37 -05:00
|
|
|
an IoError object containing details.
|
|
|
|
* Return values must have a sensible null or zero value which is returned
|
|
|
|
if a condition is handled successfully. This may be an `Option`, an empty
|
|
|
|
vector, or other designated error value.
|
|
|
|
* Common traits are implemented for `Option`, e.g. `impl<R: Reader> Reader for Option<R>`,
|
|
|
|
so that nullable values do not have to be 'unwrapped' before use.
|
|
|
|
|
|
|
|
These features combine in the API to allow for expressions like
|
|
|
|
`File::new("diary.txt").write_line("met a girl")` without having to
|
|
|
|
worry about whether "diary.txt" exists or whether the write
|
|
|
|
succeeds. As written, if either `new` or `write_line` encounters
|
|
|
|
an error the task will fail.
|
|
|
|
|
|
|
|
If you wanted to handle the error though you might write
|
|
|
|
|
|
|
|
let mut error = None;
|
|
|
|
do io_error::cond(|e: IoError| {
|
|
|
|
error = Some(e);
|
|
|
|
}).in {
|
|
|
|
File::new("diary.txt").write_line("met a girl");
|
|
|
|
}
|
|
|
|
|
|
|
|
if error.is_some() {
|
|
|
|
println("failed to write my diary");
|
|
|
|
}
|
|
|
|
|
|
|
|
XXX: Need better condition handling syntax
|
|
|
|
|
|
|
|
In this case the condition handler will have the opportunity to
|
|
|
|
inspect the IoError raised by either the call to `new` or the call to
|
|
|
|
`write_line`, but then execution will continue.
|
|
|
|
|
|
|
|
So what actually happens if `new` encounters an error? To understand
|
|
|
|
that it's important to know that what `new` returns is not a `File`
|
|
|
|
but an `Option<File>`. If the file does not open, and the condition
|
|
|
|
is handled, then `new` will simply return `None`. Because there is an
|
|
|
|
implementation of `Writer` (the trait required ultimately required for
|
|
|
|
types to implement `write_line`) there is no need to inspect or unwrap
|
|
|
|
the `Option<File>` and we simply call `write_line` on it. If `new`
|
|
|
|
returned a `None` then the followup call to `write_line` will also
|
|
|
|
raise an error.
|
|
|
|
|
|
|
|
## Concerns about this strategy
|
|
|
|
|
|
|
|
This structure will encourage a programming style that is prone
|
|
|
|
to errors similar to null pointer dereferences.
|
|
|
|
In particular code written to ignore errors and expect conditions to be unhandled
|
|
|
|
will start passing around null or zero objects when wrapped in a condition handler.
|
|
|
|
|
|
|
|
* XXX: How should we use condition handlers that return values?
|
2013-05-13 18:56:16 -05:00
|
|
|
* XXX: Should EOF raise default conditions when EOF is not an error?
|
2013-04-23 21:21:37 -05:00
|
|
|
|
2013-08-16 00:41:28 -05:00
|
|
|
# Issues with i/o scheduler affinity, work stealing, task pinning
|
2013-04-23 21:21:37 -05:00
|
|
|
|
2013-04-17 19:55:21 -05:00
|
|
|
# Resource management
|
|
|
|
|
|
|
|
* `close` vs. RAII
|
|
|
|
|
2013-04-23 21:21:37 -05:00
|
|
|
# Paths, URLs and overloaded constructors
|
|
|
|
|
|
|
|
|
2013-04-17 19:55:21 -05:00
|
|
|
|
2013-04-23 21:21:37 -05:00
|
|
|
# Scope
|
|
|
|
|
|
|
|
In scope for core
|
|
|
|
|
|
|
|
* Url?
|
2013-04-17 19:55:21 -05:00
|
|
|
|
|
|
|
Some I/O things don't belong in core
|
|
|
|
|
|
|
|
- url
|
|
|
|
- net - `fn connect`
|
|
|
|
- http
|
|
|
|
- flate
|
|
|
|
|
2013-04-23 21:21:37 -05:00
|
|
|
Out of scope
|
|
|
|
|
|
|
|
* Async I/O. We'll probably want it eventually
|
|
|
|
|
|
|
|
|
|
|
|
# XXX Questions and issues
|
2013-04-17 19:55:21 -05:00
|
|
|
|
|
|
|
* Should default constructors take `Path` or `&str`? `Path` makes simple cases verbose.
|
|
|
|
Overloading would be nice.
|
|
|
|
* Add overloading for Path and &str and Url &str
|
|
|
|
* stdin/err/out
|
|
|
|
* print, println, etc.
|
|
|
|
* fsync
|
|
|
|
* relationship with filesystem querying, Directory, File types etc.
|
|
|
|
* Rename Reader/Writer to ByteReader/Writer, make Reader/Writer generic?
|
2013-04-23 21:21:37 -05:00
|
|
|
* Can Port and Chan be implementations of a generic Reader<T>/Writer<T>?
|
2013-04-17 19:55:21 -05:00
|
|
|
* Trait for things that are both readers and writers, Stream?
|
|
|
|
* How to handle newline conversion
|
|
|
|
* String conversion
|
|
|
|
* File vs. FileStream? File is shorter but could also be used for getting file info
|
|
|
|
- maybe File is for general file querying and *also* has a static `open` method
|
|
|
|
* open vs. connect for generic stream opening
|
|
|
|
* Do we need `close` at all? dtors might be good enough
|
|
|
|
* How does I/O relate to the Iterator trait?
|
|
|
|
* std::base64 filters
|
2013-04-23 21:21:37 -05:00
|
|
|
* Using conditions is a big unknown since we don't have much experience with them
|
2013-04-26 20:59:59 -05:00
|
|
|
* Too many uses of OtherIoError
|
2013-04-17 19:55:21 -05:00
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
use prelude::*;
|
2013-08-03 18:59:24 -05:00
|
|
|
use to_str::ToStr;
|
|
|
|
use str::{StrSlice, OwnedStr};
|
2013-08-26 09:24:10 -05:00
|
|
|
use path::Path;
|
2013-04-17 19:55:21 -05:00
|
|
|
|
|
|
|
// Reexports
|
|
|
|
pub use self::stdio::stdin;
|
|
|
|
pub use self::stdio::stdout;
|
|
|
|
pub use self::stdio::stderr;
|
|
|
|
pub use self::stdio::print;
|
|
|
|
pub use self::stdio::println;
|
|
|
|
|
|
|
|
pub use self::file::FileStream;
|
2013-07-19 18:03:02 -05:00
|
|
|
pub use self::timer::Timer;
|
2013-04-17 19:55:21 -05:00
|
|
|
pub use self::net::ip::IpAddr;
|
|
|
|
pub use self::net::tcp::TcpListener;
|
|
|
|
pub use self::net::tcp::TcpStream;
|
|
|
|
pub use self::net::udp::UdpStream;
|
2013-09-16 17:28:56 -05:00
|
|
|
pub use self::pipe::PipeStream;
|
|
|
|
pub use self::process::Process;
|
2013-04-17 19:55:21 -05:00
|
|
|
|
|
|
|
// Some extension traits that all Readers and Writers get.
|
2013-04-19 17:18:38 -05:00
|
|
|
pub use self::extensions::ReaderUtil;
|
|
|
|
pub use self::extensions::ReaderByteConversions;
|
|
|
|
pub use self::extensions::WriterByteConversions;
|
2013-04-17 19:55:21 -05:00
|
|
|
|
|
|
|
/// Synchronous, non-blocking file I/O.
|
2013-03-13 22:02:48 -05:00
|
|
|
pub mod file;
|
|
|
|
|
2013-09-16 17:28:56 -05:00
|
|
|
/// Synchronous, in-memory I/O.
|
|
|
|
pub mod pipe;
|
|
|
|
|
|
|
|
/// Child process management.
|
|
|
|
pub mod process;
|
|
|
|
|
2013-04-17 19:55:21 -05:00
|
|
|
/// Synchronous, non-blocking network I/O.
|
2013-09-05 16:16:17 -05:00
|
|
|
pub mod net;
|
2013-04-17 19:55:21 -05:00
|
|
|
|
|
|
|
/// Readers and Writers for memory buffers and strings.
|
|
|
|
pub mod mem;
|
|
|
|
|
|
|
|
/// Non-blocking access to stdin, stdout, stderr
|
|
|
|
pub mod stdio;
|
|
|
|
|
2013-04-22 16:52:40 -05:00
|
|
|
/// Implementations for Option
|
|
|
|
mod option;
|
|
|
|
|
2013-04-17 19:55:21 -05:00
|
|
|
/// Basic stream compression. XXX: Belongs with other flate code
|
|
|
|
pub mod flate;
|
|
|
|
|
|
|
|
/// Interop between byte streams and pipes. Not sure where it belongs
|
|
|
|
pub mod comm_adapters;
|
|
|
|
|
|
|
|
/// Extension traits
|
2013-10-09 01:36:26 -05:00
|
|
|
pub mod extensions;
|
2013-04-17 19:55:21 -05:00
|
|
|
|
2013-07-19 18:03:02 -05:00
|
|
|
/// Basic Timer
|
2013-07-19 18:22:13 -05:00
|
|
|
pub mod timer;
|
2013-07-19 18:03:02 -05:00
|
|
|
|
2013-09-10 00:38:43 -05:00
|
|
|
/// Buffered I/O wrappers
|
|
|
|
pub mod buffered;
|
|
|
|
|
2013-04-17 19:55:21 -05:00
|
|
|
/// Thread-blocking implementations
|
2013-04-19 16:58:21 -05:00
|
|
|
pub mod native {
|
2013-04-17 19:55:21 -05:00
|
|
|
/// Posix file I/O
|
|
|
|
pub mod file;
|
2013-10-06 15:24:50 -05:00
|
|
|
/// Process spawning and child management
|
|
|
|
pub mod process;
|
|
|
|
/// Posix stdio
|
|
|
|
pub mod stdio;
|
|
|
|
|
2013-04-17 19:55:21 -05:00
|
|
|
/// Sockets
|
2013-04-19 14:04:19 -05:00
|
|
|
/// # XXX - implement this
|
2013-04-17 19:55:21 -05:00
|
|
|
pub mod net {
|
|
|
|
pub mod tcp { }
|
|
|
|
pub mod udp { }
|
|
|
|
#[cfg(unix)]
|
|
|
|
pub mod unix { }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-05-09 19:37:31 -05:00
|
|
|
/// Mock implementations for testing
|
|
|
|
mod mock;
|
2013-04-17 19:55:21 -05:00
|
|
|
|
2013-05-13 18:56:16 -05:00
|
|
|
/// The default buffer size for various I/O operations
|
2013-10-15 22:55:50 -05:00
|
|
|
static DEFAULT_BUF_SIZE: uint = 1024 * 64;
|
2013-05-13 18:56:16 -05:00
|
|
|
|
2013-04-17 19:55:21 -05:00
|
|
|
/// The type passed to I/O condition handlers to indicate error
|
|
|
|
///
|
2013-04-19 14:04:19 -05:00
|
|
|
/// # XXX
|
2013-04-17 19:55:21 -05:00
|
|
|
///
|
|
|
|
/// Is something like this sufficient? It's kind of archaic
|
|
|
|
pub struct IoError {
|
|
|
|
kind: IoErrorKind,
|
|
|
|
desc: &'static str,
|
|
|
|
detail: Option<~str>
|
|
|
|
}
|
|
|
|
|
2013-08-03 18:59:24 -05:00
|
|
|
// FIXME: #8242 implementing manually because deriving doesn't work for some reason
|
|
|
|
impl ToStr for IoError {
|
|
|
|
fn to_str(&self) -> ~str {
|
|
|
|
let mut s = ~"IoError { kind: ";
|
|
|
|
s.push_str(self.kind.to_str());
|
|
|
|
s.push_str(", desc: ");
|
|
|
|
s.push_str(self.desc);
|
|
|
|
s.push_str(", detail: ");
|
|
|
|
s.push_str(self.detail.to_str());
|
|
|
|
s.push_str(" }");
|
|
|
|
s
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-04-22 16:52:40 -05:00
|
|
|
#[deriving(Eq)]
|
2013-04-17 19:55:21 -05:00
|
|
|
pub enum IoErrorKind {
|
2013-04-24 22:20:03 -05:00
|
|
|
PreviousIoError,
|
|
|
|
OtherIoError,
|
|
|
|
EndOfFile,
|
2013-04-17 19:55:21 -05:00
|
|
|
FileNotFound,
|
2013-04-24 22:20:03 -05:00
|
|
|
PermissionDenied,
|
2013-04-17 19:55:21 -05:00
|
|
|
ConnectionFailed,
|
|
|
|
Closed,
|
2013-04-24 22:20:03 -05:00
|
|
|
ConnectionRefused,
|
2013-05-14 23:18:47 -05:00
|
|
|
ConnectionReset,
|
2013-10-04 16:10:02 -05:00
|
|
|
NotConnected,
|
2013-09-15 14:23:53 -05:00
|
|
|
BrokenPipe,
|
|
|
|
PathAlreadyExists,
|
|
|
|
PathDoesntExist,
|
2013-10-16 19:05:28 -05:00
|
|
|
MismatchedFileTypeForOperation,
|
2013-10-17 19:04:51 -05:00
|
|
|
ResourceUnavailable,
|
2013-10-16 19:05:28 -05:00
|
|
|
IoUnavailable,
|
2013-04-17 19:55:21 -05:00
|
|
|
}
|
2013-03-13 22:02:48 -05:00
|
|
|
|
2013-08-03 18:59:24 -05:00
|
|
|
// FIXME: #8242 implementing manually because deriving doesn't work for some reason
|
|
|
|
impl ToStr for IoErrorKind {
|
|
|
|
fn to_str(&self) -> ~str {
|
|
|
|
match *self {
|
|
|
|
PreviousIoError => ~"PreviousIoError",
|
|
|
|
OtherIoError => ~"OtherIoError",
|
|
|
|
EndOfFile => ~"EndOfFile",
|
|
|
|
FileNotFound => ~"FileNotFound",
|
|
|
|
PermissionDenied => ~"PermissionDenied",
|
|
|
|
ConnectionFailed => ~"ConnectionFailed",
|
|
|
|
Closed => ~"Closed",
|
|
|
|
ConnectionRefused => ~"ConnectionRefused",
|
|
|
|
ConnectionReset => ~"ConnectionReset",
|
2013-10-04 16:10:02 -05:00
|
|
|
NotConnected => ~"NotConnected",
|
2013-09-15 14:23:53 -05:00
|
|
|
BrokenPipe => ~"BrokenPipe",
|
|
|
|
PathAlreadyExists => ~"PathAlreadyExists",
|
|
|
|
PathDoesntExist => ~"PathDoesntExist",
|
2013-10-16 19:05:28 -05:00
|
|
|
MismatchedFileTypeForOperation => ~"MismatchedFileTypeForOperation",
|
|
|
|
IoUnavailable => ~"IoUnavailable",
|
2013-10-17 19:04:51 -05:00
|
|
|
ResourceUnavailable => ~"ResourceUnavailable",
|
2013-08-03 18:59:24 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-03-13 22:02:48 -05:00
|
|
|
// XXX: Can't put doc comments on macros
|
2013-04-17 19:55:21 -05:00
|
|
|
// Raised by `I/O` operations on error.
|
2013-03-13 22:02:48 -05:00
|
|
|
condition! {
|
2013-09-17 01:34:40 -05:00
|
|
|
pub io_error: IoError -> ();
|
2013-03-13 22:02:48 -05:00
|
|
|
}
|
|
|
|
|
2013-09-16 23:56:51 -05:00
|
|
|
/// Helper for wrapper calls where you want to
|
|
|
|
/// ignore any io_errors that might be raised
|
|
|
|
pub fn ignore_io_error<T>(cb: &fn() -> T) -> T {
|
|
|
|
do io_error::cond.trap(|_| {
|
|
|
|
// just swallow the error.. downstream users
|
|
|
|
// who can make a decision based on a None result
|
|
|
|
// won't care
|
|
|
|
}).inside {
|
|
|
|
cb()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-04-17 19:55:21 -05:00
|
|
|
pub trait Reader {
|
|
|
|
/// Read bytes, up to the length of `buf` and place them in `buf`.
|
2013-05-12 23:24:48 -05:00
|
|
|
/// Returns the number of bytes read. The number of bytes read my
|
|
|
|
/// be less than the number requested, even 0. Returns `None` on EOF.
|
2013-03-13 22:02:48 -05:00
|
|
|
///
|
|
|
|
/// # Failure
|
|
|
|
///
|
2013-10-18 13:52:23 -05:00
|
|
|
/// Raises the `io_error` condition on error. If the condition
|
2013-05-12 23:24:48 -05:00
|
|
|
/// is handled then no guarantee is made about the number of bytes
|
|
|
|
/// read and the contents of `buf`. If the condition is handled
|
|
|
|
/// returns `None` (XXX see below).
|
2013-04-17 19:55:21 -05:00
|
|
|
///
|
2013-04-19 14:04:19 -05:00
|
|
|
/// # XXX
|
2013-04-17 19:55:21 -05:00
|
|
|
///
|
2013-05-13 18:56:16 -05:00
|
|
|
/// * Should raise_default error on eof?
|
2013-05-12 23:24:48 -05:00
|
|
|
/// * If the condition is handled it should still return the bytes read,
|
2013-05-13 17:23:52 -05:00
|
|
|
/// in which case there's no need to return Option - but then you *have*
|
|
|
|
/// to install a handler to detect eof.
|
2013-05-12 23:24:48 -05:00
|
|
|
///
|
2013-04-17 19:55:21 -05:00
|
|
|
/// This doesn't take a `len` argument like the old `read`.
|
|
|
|
/// Will people often need to slice their vectors to call this
|
|
|
|
/// and will that be annoying?
|
2013-05-09 19:37:31 -05:00
|
|
|
/// Is it actually possible for 0 bytes to be read successfully?
|
2013-04-17 19:55:21 -05:00
|
|
|
fn read(&mut self, buf: &mut [u8]) -> Option<uint>;
|
2013-03-13 22:02:48 -05:00
|
|
|
|
2013-04-17 19:55:21 -05:00
|
|
|
/// Return whether the Reader has reached the end of the stream.
|
|
|
|
///
|
|
|
|
/// # Example
|
|
|
|
///
|
|
|
|
/// let reader = FileStream::new()
|
|
|
|
/// while !reader.eof() {
|
|
|
|
/// println(reader.read_line());
|
|
|
|
/// }
|
|
|
|
///
|
2013-08-17 17:28:04 -05:00
|
|
|
/// # Failure
|
2013-04-17 19:55:21 -05:00
|
|
|
///
|
2013-04-22 16:52:40 -05:00
|
|
|
/// Returns `true` on failure.
|
2013-03-13 22:02:48 -05:00
|
|
|
fn eof(&mut self) -> bool;
|
2013-04-17 19:55:21 -05:00
|
|
|
}
|
2013-03-13 22:02:48 -05:00
|
|
|
|
2013-10-06 18:08:56 -05:00
|
|
|
impl Reader for ~Reader {
|
|
|
|
fn read(&mut self, buf: &mut [u8]) -> Option<uint> { self.read(buf) }
|
|
|
|
fn eof(&mut self) -> bool { self.eof() }
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'self> Reader for &'self mut Reader {
|
|
|
|
fn read(&mut self, buf: &mut [u8]) -> Option<uint> { self.read(buf) }
|
|
|
|
fn eof(&mut self) -> bool { self.eof() }
|
|
|
|
}
|
|
|
|
|
2013-04-17 19:55:21 -05:00
|
|
|
pub trait Writer {
|
2013-03-13 22:02:48 -05:00
|
|
|
/// Write the given buffer
|
|
|
|
///
|
|
|
|
/// # Failure
|
|
|
|
///
|
2013-04-17 19:55:21 -05:00
|
|
|
/// Raises the `io_error` condition on error
|
|
|
|
fn write(&mut self, buf: &[u8]);
|
|
|
|
|
|
|
|
/// Flush output
|
|
|
|
fn flush(&mut self);
|
|
|
|
}
|
|
|
|
|
2013-10-06 18:08:56 -05:00
|
|
|
impl Writer for ~Writer {
|
|
|
|
fn write(&mut self, buf: &[u8]) { self.write(buf) }
|
|
|
|
fn flush(&mut self) { self.flush() }
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'self> Writer for &'self mut Writer {
|
|
|
|
fn write(&mut self, buf: &[u8]) { self.write(buf) }
|
|
|
|
fn flush(&mut self) { self.flush() }
|
|
|
|
}
|
|
|
|
|
2013-04-24 20:26:49 -05:00
|
|
|
pub trait Stream: Reader + Writer { }
|
2013-04-17 19:55:21 -05:00
|
|
|
|
2013-09-19 14:09:52 -05:00
|
|
|
impl<T: Reader + Writer> Stream for T {}
|
2013-09-04 19:52:18 -05:00
|
|
|
|
2013-04-17 19:55:21 -05:00
|
|
|
pub enum SeekStyle {
|
|
|
|
/// Seek from the beginning of the stream
|
|
|
|
SeekSet,
|
|
|
|
/// Seek from the end of the stream
|
|
|
|
SeekEnd,
|
|
|
|
/// Seek from the current position
|
|
|
|
SeekCur,
|
|
|
|
}
|
|
|
|
|
2013-04-19 14:04:19 -05:00
|
|
|
/// # XXX
|
2013-04-17 19:55:21 -05:00
|
|
|
/// * Are `u64` and `i64` the right choices?
|
2013-04-19 16:58:21 -05:00
|
|
|
pub trait Seek {
|
2013-08-20 17:38:41 -05:00
|
|
|
/// Return position of file cursor in the stream
|
2013-04-17 19:55:21 -05:00
|
|
|
fn tell(&self) -> u64;
|
2013-04-20 19:25:00 -05:00
|
|
|
|
|
|
|
/// Seek to an offset in a stream
|
|
|
|
///
|
|
|
|
/// A successful seek clears the EOF indicator.
|
|
|
|
///
|
|
|
|
/// # XXX
|
|
|
|
///
|
|
|
|
/// * What is the behavior when seeking past the end of a stream?
|
2013-04-17 19:55:21 -05:00
|
|
|
fn seek(&mut self, pos: i64, style: SeekStyle);
|
|
|
|
}
|
|
|
|
|
2013-08-27 12:01:17 -05:00
|
|
|
/// A listener is a value that can consume itself to start listening for connections.
|
|
|
|
/// Doing so produces some sort of Acceptor.
|
|
|
|
pub trait Listener<T, A: Acceptor<T>> {
|
|
|
|
/// Spin up the listener and start queueing incoming connections
|
2013-04-22 15:26:37 -05:00
|
|
|
///
|
|
|
|
/// # Failure
|
|
|
|
///
|
|
|
|
/// Raises `io_error` condition. If the condition is handled,
|
2013-08-27 12:01:17 -05:00
|
|
|
/// then `listen` returns `None`.
|
|
|
|
fn listen(self) -> Option<A>;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// An acceptor is a value that presents incoming connections
|
|
|
|
pub trait Acceptor<T> {
|
|
|
|
/// Wait for and accept an incoming connection
|
|
|
|
///
|
|
|
|
/// # Failure
|
|
|
|
/// Raise `io_error` condition. If the condition is handled,
|
2013-04-22 15:26:37 -05:00
|
|
|
/// then `accept` returns `None`.
|
2013-08-27 12:01:17 -05:00
|
|
|
fn accept(&mut self) -> Option<T>;
|
|
|
|
|
2013-09-05 18:49:38 -05:00
|
|
|
/// Create an iterator over incoming connection attempts
|
2013-08-27 12:01:17 -05:00
|
|
|
fn incoming<'r>(&'r mut self) -> IncomingIterator<'r, Self> {
|
|
|
|
IncomingIterator { inc: self }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// An infinite iterator over incoming connection attempts.
|
|
|
|
/// Calling `next` will block the task until a connection is attempted.
|
2013-09-05 18:49:38 -05:00
|
|
|
///
|
|
|
|
/// Since connection attempts can continue forever, this iterator always returns Some.
|
|
|
|
/// The Some contains another Option representing whether the connection attempt was succesful.
|
|
|
|
/// A successful connection will be wrapped in Some.
|
|
|
|
/// A failed connection is represented as a None and raises a condition.
|
2013-08-27 12:01:17 -05:00
|
|
|
struct IncomingIterator<'self, A> {
|
|
|
|
priv inc: &'self mut A,
|
|
|
|
}
|
|
|
|
|
2013-09-05 18:49:38 -05:00
|
|
|
impl<'self, T, A: Acceptor<T>> Iterator<Option<T>> for IncomingIterator<'self, A> {
|
|
|
|
fn next(&mut self) -> Option<Option<T>> {
|
|
|
|
Some(self.inc.accept())
|
2013-08-27 12:01:17 -05:00
|
|
|
}
|
2013-04-22 15:26:37 -05:00
|
|
|
}
|
|
|
|
|
2013-04-17 19:55:21 -05:00
|
|
|
/// Common trait for decorator types.
|
|
|
|
///
|
|
|
|
/// Provides accessors to get the inner, 'decorated' values. The I/O library
|
|
|
|
/// uses decorators to add functionality like compression and encryption to I/O
|
|
|
|
/// streams.
|
|
|
|
///
|
2013-04-19 14:04:19 -05:00
|
|
|
/// # XXX
|
2013-04-17 19:55:21 -05:00
|
|
|
///
|
|
|
|
/// Is this worth having a trait for? May be overkill
|
|
|
|
pub trait Decorator<T> {
|
|
|
|
/// Destroy the decorator and extract the decorated value
|
|
|
|
///
|
2013-04-19 14:04:19 -05:00
|
|
|
/// # XXX
|
2013-04-17 19:55:21 -05:00
|
|
|
///
|
|
|
|
/// Because this takes `self' one could never 'undecorate' a Reader/Writer
|
|
|
|
/// that has been boxed. Is that ok? This feature is mostly useful for
|
|
|
|
/// extracting the buffer from MemWriter
|
|
|
|
fn inner(self) -> T;
|
|
|
|
|
|
|
|
/// Take an immutable reference to the decorated value
|
|
|
|
fn inner_ref<'a>(&'a self) -> &'a T;
|
|
|
|
|
|
|
|
/// Take a mutable reference to the decorated value
|
|
|
|
fn inner_mut_ref<'a>(&'a mut self) -> &'a mut T;
|
2013-03-13 22:02:48 -05:00
|
|
|
}
|
2013-04-22 16:52:40 -05:00
|
|
|
|
|
|
|
pub fn standard_error(kind: IoErrorKind) -> IoError {
|
|
|
|
match kind {
|
|
|
|
PreviousIoError => {
|
|
|
|
IoError {
|
|
|
|
kind: PreviousIoError,
|
|
|
|
desc: "Failing due to a previous I/O error",
|
|
|
|
detail: None
|
|
|
|
}
|
|
|
|
}
|
2013-05-13 17:23:52 -05:00
|
|
|
EndOfFile => {
|
|
|
|
IoError {
|
|
|
|
kind: EndOfFile,
|
|
|
|
desc: "End of file",
|
|
|
|
detail: None
|
|
|
|
}
|
|
|
|
}
|
2013-10-21 15:08:31 -05:00
|
|
|
_ => fail!()
|
2013-04-22 16:52:40 -05:00
|
|
|
}
|
|
|
|
}
|
2013-05-09 19:37:31 -05:00
|
|
|
|
|
|
|
pub fn placeholder_error() -> IoError {
|
|
|
|
IoError {
|
|
|
|
kind: OtherIoError,
|
|
|
|
desc: "Placeholder error. You shouldn't be seeing this",
|
|
|
|
detail: None
|
|
|
|
}
|
2013-08-03 18:59:24 -05:00
|
|
|
}
|
2013-08-22 18:31:23 -05:00
|
|
|
|
|
|
|
/// Instructions on how to open a file and return a `FileStream`.
|
|
|
|
pub 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,
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Access permissions with which the file should be opened.
|
|
|
|
/// `FileStream`s opened with `Read` will raise an `io_error` condition if written to.
|
|
|
|
pub enum FileAccess {
|
|
|
|
Read,
|
|
|
|
Write,
|
|
|
|
ReadWrite
|
|
|
|
}
|
2013-08-26 09:24:10 -05:00
|
|
|
|
|
|
|
pub struct FileStat {
|
|
|
|
/// A `Path` object containing information about the `PathInfo`'s location
|
|
|
|
path: Path,
|
|
|
|
/// `true` if the file pointed at by the `PathInfo` is a regular file
|
|
|
|
is_file: bool,
|
|
|
|
/// `true` if the file pointed at by the `PathInfo` is a directory
|
2013-09-16 15:24:23 -05:00
|
|
|
is_dir: bool,
|
2013-10-22 20:25:07 -05:00
|
|
|
/// The file pointed at by the `PathInfo`'s device
|
|
|
|
device: u64,
|
|
|
|
/// The file pointed at by the `PathInfo`'s mode
|
|
|
|
mode: u64,
|
|
|
|
/// The file pointed at by the `PathInfo`'s inode
|
|
|
|
inode: u64,
|
2013-08-26 09:24:10 -05:00
|
|
|
/// The file pointed at by the `PathInfo`'s size in bytes
|
|
|
|
size: u64,
|
2013-09-16 15:24:23 -05:00
|
|
|
/// The file pointed at by the `PathInfo`'s creation time
|
2013-08-26 09:24:10 -05:00
|
|
|
created: u64,
|
|
|
|
/// The file pointed at by the `PathInfo`'s last-modification time in
|
|
|
|
/// platform-dependent msecs
|
|
|
|
modified: u64,
|
|
|
|
/// The file pointed at by the `PathInfo`'s last-accessd time (e.g. read) in
|
|
|
|
/// platform-dependent msecs
|
|
|
|
accessed: u64,
|
|
|
|
}
|