std: Remove some nonsense from old std::io docs

Most of this stuff is irrelevant implementation notes from last year.
This trims out the stuff that isn't appropriate for user-facing docs.
This commit is contained in:
Brian Anderson 2014-02-22 15:53:54 -08:00
parent 2ba0a8a096
commit a8941c3e04

View File

@ -8,16 +8,18 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
/*! Synchronous I/O
// FIXME: cover these topics:
// path, reader, writer, stream, raii (close not needed),
// stdio, print!, println!, file access, process spawning,
// error handling
This module defines the Rust interface for synchronous I/O.
It models byte-oriented input and output with the Reader and Writer traits.
Types that implement both `Reader` and `Writer` are called 'streams',
and automatically implement the `Stream` trait.
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.
/*! I/O, including files, networking, timers, and processes
`std::io` provides Rust's basic I/O types,
for reading and writing to files, TCP, UDP,
and other types of sockets and pipes,
manipulating the file system, spawning processes and signal handling.
# Examples
@ -77,9 +79,7 @@ Some examples of obvious things you might want to do
let lines: ~[~str] = file.lines().collect();
```
* Make a simple HTTP request
FIXME This needs more improvement: TcpStream constructor taking &str,
`write_str` and `write_line` methods.
* Make a simple TCP client connection and request
```rust,should_fail
# #[allow(unused_must_use)];
@ -92,72 +92,35 @@ Some examples of obvious things you might want to do
let response = socket.read_to_end();
```
* 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`.
FIXME this is not implemented now.
* Make a simple TCP server
```rust
// connect("tcp://localhost:8080");
# fn main() { }
# fn foo() {
# #[allow(unused_must_use, dead_code)];
use std::io::net::tcp::TcpListener;
use std::io::net::ip::{Ipv4Addr, SocketAddr};
use std::io::{Acceptor, Listener};
let addr = SocketAddr { ip: Ipv4Addr(127, 0, 0, 1), port: 80 };
let listener = TcpListener::bind(addr);
// bind the listener to the specified address
let mut acceptor = listener.listen();
// accept connections and process them
# fn handle_client<T>(_: T) {}
for stream in acceptor.incoming() {
spawn(proc() {
handle_client(stream);
});
}
// close the socket server
drop(acceptor);
# }
```
# Terms
* 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`.
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
callback is run and the code that made the I/O request continues.
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.
# Error Handling
@ -170,10 +133,11 @@ Rust's I/O employs a combination of techniques to reduce boilerplate
while still providing feedback about errors. The basic strategy:
* All I/O operations return `IoResult<T>` which is equivalent to
`Result<T, IoError>`. The core `Result` type is defined in the `std::result`
`Result<T, IoError>`. The `Result` type is defined in the `std::result`
module.
* If the `Result` type goes unused, then the compiler will by default emit a
warning about the unused result.
warning about the unused result. This is because `Result` has the
`#[must_use]` attribute.
* Common traits are implemented for `IoResult`, e.g.
`impl<R: Reader> Reader for IoResult<R>`, so that error values do not have
to be 'unwrapped' before use.
@ -192,7 +156,7 @@ If you wanted to handle the error though you might write:
use std::io::File;
match File::create(&Path::new("diary.txt")).write(bytes!("Met a girl.\n")) {
Ok(()) => { /* succeeded */ }
Ok(()) => (), // succeeded
Err(e) => println!("failed to write to my diary: {}", e),
}
@ -208,55 +172,6 @@ need to inspect or unwrap the `IoResult<File>` and we simply call `write_line`
on it. If `new` returned an `Err(..)` then the followup call to `write_line`
will also return an error.
# Issues with i/o scheduler affinity, work stealing, task pinning
# Resource management
* `close` vs. RAII
# Paths, URLs and overloaded constructors
# Scope
In scope for core
* Url?
Some I/O things don't belong in core
- url
- net - `fn connect`
- http
- flate
Out of scope
* Async I/O. We'll probably want it eventually
# FIXME Questions and issues
* 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?
* Can Port and Chan be implementations of a generic Reader<T>/Writer<T>?
* Trait for things that are both readers and writers, Stream?
* How to handle newline conversion
* String conversion
* 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
* Using conditions is a big unknown since we don't have much experience with them
* Too many uses of OtherIoError
*/
#[allow(missing_doc)];