8
8
// option. This file may not be copied, modified, or distributed
9
9
// except according to those terms.
10
10
11
- /*! Synchronous I/O
11
+ // FIXME: cover these topics:
12
+ // path, reader, writer, stream, raii (close not needed),
13
+ // stdio, print!, println!, file access, process spawning,
14
+ // error handling
12
15
13
- This module defines the Rust interface for synchronous I/O.
14
- It models byte-oriented input and output with the Reader and Writer traits.
15
- Types that implement both `Reader` and `Writer` are called 'streams',
16
- and automatically implement the `Stream` trait.
17
- Implementations are provided for common I/O streams like
18
- file, TCP, UDP, Unix domain sockets.
19
- Readers and Writers may be composed to add capabilities like string
20
- parsing, encoding, and compression.
16
+
17
+ /*! I/O, including files, networking, timers, and processes
18
+
19
+ `std::io` provides Rust's basic I/O types,
20
+ for reading and writing to files, TCP, UDP,
21
+ and other types of sockets and pipes,
22
+ manipulating the file system, spawning processes and signal handling.
21
23
22
24
# Examples
23
25
@@ -77,9 +79,7 @@ Some examples of obvious things you might want to do
77
79
let lines: ~[~str] = file.lines().collect();
78
80
```
79
81
80
- * Make a simple HTTP request
81
- FIXME This needs more improvement: TcpStream constructor taking &str,
82
- `write_str` and `write_line` methods.
82
+ * Make a simple TCP client connection and request
83
83
84
84
```rust,should_fail
85
85
# #[allow(unused_must_use)];
@@ -92,72 +92,35 @@ Some examples of obvious things you might want to do
92
92
let response = socket.read_to_end();
93
93
```
94
94
95
- * Connect based on URL? Requires thinking about where the URL type lives
96
- and how to make protocol handlers extensible, e.g. the "tcp" protocol
97
- yields a `TcpStream`.
98
- FIXME this is not implemented now.
95
+ * Make a simple TCP server
99
96
100
97
```rust
101
- // connect("tcp://localhost:8080");
98
+ # fn main() { }
99
+ # fn foo() {
100
+ # #[allow(unused_must_use, dead_code)];
101
+ use std::io::net::tcp::TcpListener;
102
+ use std::io::net::ip::{Ipv4Addr, SocketAddr};
103
+ use std::io::{Acceptor, Listener};
104
+
105
+ let addr = SocketAddr { ip: Ipv4Addr(127, 0, 0, 1), port: 80 };
106
+ let listener = TcpListener::bind(addr);
107
+
108
+ // bind the listener to the specified address
109
+ let mut acceptor = listener.listen();
110
+
111
+ // accept connections and process them
112
+ # fn handle_client<T>(_: T) {}
113
+ for stream in acceptor.incoming() {
114
+ spawn(proc() {
115
+ handle_client(stream);
116
+ });
117
+ }
118
+
119
+ // close the socket server
120
+ drop(acceptor);
121
+ # }
102
122
```
103
123
104
- # Terms
105
-
106
- * Reader - An I/O source, reads bytes into a buffer
107
- * Writer - An I/O sink, writes bytes from a buffer
108
- * Stream - Typical I/O sources like files and sockets are both Readers and Writers,
109
- and are collectively referred to a `streams`.
110
- such as encoding or decoding
111
-
112
- # Blocking and synchrony
113
-
114
- When discussing I/O you often hear the terms 'synchronous' and
115
- 'asynchronous', along with 'blocking' and 'non-blocking' compared and
116
- contrasted. A synchronous I/O interface performs each I/O operation to
117
- completion before proceeding to the next. Synchronous interfaces are
118
- usually used in imperative style as a sequence of commands. An
119
- asynchronous interface allows multiple I/O requests to be issued
120
- simultaneously, without waiting for each to complete before proceeding
121
- to the next.
122
-
123
- Asynchronous interfaces are used to achieve 'non-blocking' I/O. In
124
- traditional single-threaded systems, performing a synchronous I/O
125
- operation means that the program stops all activity (it 'blocks')
126
- until the I/O is complete. Blocking is bad for performance when
127
- there are other computations that could be done.
128
-
129
- Asynchronous interfaces are most often associated with the callback
130
- (continuation-passing) style popularised by node.js. Such systems rely
131
- on all computations being run inside an event loop which maintains a
132
- list of all pending I/O events; when one completes the registered
133
- callback is run and the code that made the I/O request continues.
134
- Such interfaces achieve non-blocking at the expense of being more
135
- difficult to reason about.
136
-
137
- Rust's I/O interface is synchronous - easy to read - and non-blocking by default.
138
-
139
- Remember that Rust tasks are 'green threads', lightweight threads that
140
- are multiplexed onto a single operating system thread. If that system
141
- thread blocks then no other task may proceed. Rust tasks are
142
- relatively cheap to create, so as long as other tasks are free to
143
- execute then non-blocking code may be written by simply creating a new
144
- task.
145
-
146
- When discussing blocking in regards to Rust's I/O model, we are
147
- concerned with whether performing I/O blocks other Rust tasks from
148
- proceeding. In other words, when a task calls `read`, it must then
149
- wait (or 'sleep', or 'block') until the call to `read` is complete.
150
- During this time, other tasks may or may not be executed, depending on
151
- how `read` is implemented.
152
-
153
-
154
- Rust's default I/O implementation is non-blocking; by cooperating
155
- directly with the task scheduler it arranges to never block progress
156
- of *other* tasks. Under the hood, Rust uses asynchronous I/O via a
157
- per-scheduler (and hence per-thread) event loop. Synchronous I/O
158
- requests are implemented by descheduling the running task and
159
- performing an asynchronous request; the task is only resumed once the
160
- asynchronous request completes.
161
124
162
125
# Error Handling
163
126
@@ -170,10 +133,11 @@ Rust's I/O employs a combination of techniques to reduce boilerplate
170
133
while still providing feedback about errors. The basic strategy:
171
134
172
135
* All I/O operations return `IoResult<T>` which is equivalent to
173
- `Result<T, IoError>`. The core `Result` type is defined in the `std::result`
136
+ `Result<T, IoError>`. The `Result` type is defined in the `std::result`
174
137
module.
175
138
* If the `Result` type goes unused, then the compiler will by default emit a
176
- warning about the unused result.
139
+ warning about the unused result. This is because `Result` has the
140
+ `#[must_use]` attribute.
177
141
* Common traits are implemented for `IoResult`, e.g.
178
142
`impl<R: Reader> Reader for IoResult<R>`, so that error values do not have
179
143
to be 'unwrapped' before use.
@@ -192,7 +156,7 @@ If you wanted to handle the error though you might write:
192
156
use std::io::File;
193
157
194
158
match File::create(&Path::new("diary.txt")).write(bytes!("Met a girl.\n")) {
195
- Ok(()) => { /* succeeded */ }
159
+ Ok(()) => (), // succeeded
196
160
Err(e) => println!("failed to write to my diary: {}", e),
197
161
}
198
162
@@ -208,55 +172,6 @@ need to inspect or unwrap the `IoResult<File>` and we simply call `write_line`
208
172
on it. If `new` returned an `Err(..)` then the followup call to `write_line`
209
173
will also return an error.
210
174
211
- # Issues with i/o scheduler affinity, work stealing, task pinning
212
-
213
- # Resource management
214
-
215
- * `close` vs. RAII
216
-
217
- # Paths, URLs and overloaded constructors
218
-
219
-
220
-
221
- # Scope
222
-
223
- In scope for core
224
-
225
- * Url?
226
-
227
- Some I/O things don't belong in core
228
-
229
- - url
230
- - net - `fn connect`
231
- - http
232
- - flate
233
-
234
- Out of scope
235
-
236
- * Async I/O. We'll probably want it eventually
237
-
238
-
239
- # FIXME Questions and issues
240
-
241
- * Should default constructors take `Path` or `&str`? `Path` makes simple cases verbose.
242
- Overloading would be nice.
243
- * Add overloading for Path and &str and Url &str
244
- * stdin/err/out
245
- * print, println, etc.
246
- * fsync
247
- * relationship with filesystem querying, Directory, File types etc.
248
- * Rename Reader/Writer to ByteReader/Writer, make Reader/Writer generic?
249
- * Can Port and Chan be implementations of a generic Reader<T>/Writer<T>?
250
- * Trait for things that are both readers and writers, Stream?
251
- * How to handle newline conversion
252
- * String conversion
253
- * open vs. connect for generic stream opening
254
- * Do we need `close` at all? dtors might be good enough
255
- * How does I/O relate to the Iterator trait?
256
- * std::base64 filters
257
- * Using conditions is a big unknown since we don't have much experience with them
258
- * Too many uses of OtherIoError
259
-
260
175
*/
261
176
262
177
#[ allow( missing_doc) ] ;
0 commit comments