]> git.lizzy.rs Git - rust.git/blob - src/libstd/rt/io/mod.rs
Revert "auto merge of #8645 : alexcrichton/rust/issue-6436-run-non-blocking, r=brson"
[rust.git] / src / libstd / rt / io / mod.rs
1 // Copyright 2013 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 /*! Synchronous I/O
12
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` and called 'streams',
16 and automatically implement trait `Stream`.
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.
21
22 This will likely live in std::io, not std::rt::io.
23
24 # Examples
25
26 Some examples of obvious things you might want to do
27
28 * Read lines from stdin
29
30     for stdin().each_line |line| {
31         println(line)
32     }
33
34 * Read a complete file to a string, (converting newlines?)
35
36     let contents = File::open("message.txt").read_to_str(); // read_to_str??
37
38 * Write a line to a file
39
40     let file = File::open("message.txt", Create, Write);
41     file.write_line("hello, file!");
42
43 * Iterate over the lines of a file
44
45     do File::open("message.txt").each_line |line| {
46         println(line)
47     }
48
49 * Pull the lines of a file into a vector of strings
50
51     let lines = File::open("message.txt").line_iter().to_vec();
52
53 * Make an simple HTTP request
54
55     let socket = TcpStream::open("localhost:8080");
56     socket.write_line("GET / HTTP/1.0");
57     socket.write_line("");
58     let response = socket.read_to_end();
59
60 * Connect based on URL? Requires thinking about where the URL type lives
61   and how to make protocol handlers extensible, e.g. the "tcp" protocol
62   yields a `TcpStream`.
63
64     connect("tcp://localhost:8080");
65
66 # Terms
67
68 * Reader - An I/O source, reads bytes into a buffer
69 * Writer - An I/O sink, writes bytes from a buffer
70 * Stream - Typical I/O sources like files and sockets are both Readers and Writers,
71   and are collectively referred to a `streams`.
72 * Decorator - A Reader or Writer that composes with others to add additional capabilities
73   such as encoding or decoding
74
75 # Blocking and synchrony
76
77 When discussing I/O you often hear the terms 'synchronous' and
78 'asynchronous', along with 'blocking' and 'non-blocking' compared and
79 contrasted. A synchronous I/O interface performs each I/O operation to
80 completion before proceeding to the next. Synchronous interfaces are
81 usually used in imperative style as a sequence of commands. An
82 asynchronous interface allows multiple I/O requests to be issued
83 simultaneously, without waiting for each to complete before proceeding
84 to the next.
85
86 Asynchronous interfaces are used to achieve 'non-blocking' I/O. In
87 traditional single-threaded systems, performing a synchronous I/O
88 operation means that the program stops all activity (it 'blocks')
89 until the I/O is complete. Blocking is bad for performance when
90 there are other computations that could be done.
91
92 Asynchronous interfaces are most often associated with the callback
93 (continuation-passing) style popularised by node.js. Such systems rely
94 on all computations being run inside an event loop which maintains a
95 list of all pending I/O events; when one completes the registered
96 callback is run and the code that made the I/O request continues.
97 Such interfaces achieve non-blocking at the expense of being more
98 difficult to reason about.
99
100 Rust's I/O interface is synchronous - easy to read - and non-blocking by default.
101
102 Remember that Rust tasks are 'green threads', lightweight threads that
103 are multiplexed onto a single operating system thread. If that system
104 thread blocks then no other task may proceed. Rust tasks are
105 relatively cheap to create, so as long as other tasks are free to
106 execute then non-blocking code may be written by simply creating a new
107 task.
108
109 When discussing blocking in regards to Rust's I/O model, we are
110 concerned with whether performing I/O blocks other Rust tasks from
111 proceeding. In other words, when a task calls `read`, it must then
112 wait (or 'sleep', or 'block') until the call to `read` is complete.
113 During this time, other tasks may or may not be executed, depending on
114 how `read` is implemented.
115
116
117 Rust's default I/O implementation is non-blocking; by cooperating
118 directly with the task scheduler it arranges to never block progress
119 of *other* tasks. Under the hood, Rust uses asynchronous I/O via a
120 per-scheduler (and hence per-thread) event loop. Synchronous I/O
121 requests are implemented by descheduling the running task and
122 performing an asynchronous request; the task is only resumed once the
123 asynchronous request completes.
124
125 For blocking (but possibly more efficient) implementations, look
126 in the `io::native` module.
127
128 # Error Handling
129
130 I/O is an area where nearly every operation can result in unexpected
131 errors. It should allow errors to be handled efficiently.
132 It needs to be convenient to use I/O when you don't care
133 about dealing with specific errors.
134
135 Rust's I/O employs a combination of techniques to reduce boilerplate
136 while still providing feedback about errors. The basic strategy:
137
138 * Errors are fatal by default, resulting in task failure
139 * Errors raise the `io_error` condition which provides an opportunity to inspect
140   an IoError object containing details.
141 * Return values must have a sensible null or zero value which is returned
142   if a condition is handled successfully. This may be an `Option`, an empty
143   vector, or other designated error value.
144 * Common traits are implemented for `Option`, e.g. `impl<R: Reader> Reader for Option<R>`,
145   so that nullable values do not have to be 'unwrapped' before use.
146
147 These features combine in the API to allow for expressions like
148 `File::new("diary.txt").write_line("met a girl")` without having to
149 worry about whether "diary.txt" exists or whether the write
150 succeeds. As written, if either `new` or `write_line` encounters
151 an error the task will fail.
152
153 If you wanted to handle the error though you might write
154
155     let mut error = None;
156     do io_error::cond(|e: IoError| {
157         error = Some(e);
158     }).in {
159         File::new("diary.txt").write_line("met a girl");
160     }
161
162     if error.is_some() {
163         println("failed to write my diary");
164     }
165
166 XXX: Need better condition handling syntax
167
168 In this case the condition handler will have the opportunity to
169 inspect the IoError raised by either the call to `new` or the call to
170 `write_line`, but then execution will continue.
171
172 So what actually happens if `new` encounters an error? To understand
173 that it's important to know that what `new` returns is not a `File`
174 but an `Option<File>`.  If the file does not open, and the condition
175 is handled, then `new` will simply return `None`. Because there is an
176 implementation of `Writer` (the trait required ultimately required for
177 types to implement `write_line`) there is no need to inspect or unwrap
178 the `Option<File>` and we simply call `write_line` on it.  If `new`
179 returned a `None` then the followup call to `write_line` will also
180 raise an error.
181
182 ## Concerns about this strategy
183
184 This structure will encourage a programming style that is prone
185 to errors similar to null pointer dereferences.
186 In particular code written to ignore errors and expect conditions to be unhandled
187 will start passing around null or zero objects when wrapped in a condition handler.
188
189 * XXX: How should we use condition handlers that return values?
190 * XXX: Should EOF raise default conditions when EOF is not an error?
191
192 # Issues with i/o scheduler affinity, work stealing, task pinning
193
194 # Resource management
195
196 * `close` vs. RAII
197
198 # Paths, URLs and overloaded constructors
199
200
201
202 # Scope
203
204 In scope for core
205
206 * Url?
207
208 Some I/O things don't belong in core
209
210   - url
211   - net - `fn connect`
212     - http
213   - flate
214
215 Out of scope
216
217 * Async I/O. We'll probably want it eventually
218
219
220 # XXX Questions and issues
221
222 * Should default constructors take `Path` or `&str`? `Path` makes simple cases verbose.
223   Overloading would be nice.
224 * Add overloading for Path and &str and Url &str
225 * stdin/err/out
226 * print, println, etc.
227 * fsync
228 * relationship with filesystem querying, Directory, File types etc.
229 * Rename Reader/Writer to ByteReader/Writer, make Reader/Writer generic?
230 * Can Port and Chan be implementations of a generic Reader<T>/Writer<T>?
231 * Trait for things that are both readers and writers, Stream?
232 * How to handle newline conversion
233 * String conversion
234 * File vs. FileStream? File is shorter but could also be used for getting file info
235   - maybe File is for general file querying and *also* has a static `open` method
236 * open vs. connect for generic stream opening
237 * Do we need `close` at all? dtors might be good enough
238 * How does I/O relate to the Iterator trait?
239 * std::base64 filters
240 * Using conditions is a big unknown since we don't have much experience with them
241 * Too many uses of OtherIoError
242
243 */
244
245 use prelude::*;
246 use to_str::ToStr;
247 use str::{StrSlice, OwnedStr};
248
249 // Reexports
250 pub use self::stdio::stdin;
251 pub use self::stdio::stdout;
252 pub use self::stdio::stderr;
253 pub use self::stdio::print;
254 pub use self::stdio::println;
255
256 pub use self::file::FileStream;
257 pub use self::timer::Timer;
258 pub use self::net::ip::IpAddr;
259 pub use self::net::tcp::TcpListener;
260 pub use self::net::tcp::TcpStream;
261 pub use self::net::udp::UdpStream;
262
263 // Some extension traits that all Readers and Writers get.
264 pub use self::extensions::ReaderUtil;
265 pub use self::extensions::ReaderByteConversions;
266 pub use self::extensions::WriterByteConversions;
267
268 /// Synchronous, non-blocking file I/O.
269 pub mod file;
270
271 /// Synchronous, non-blocking network I/O.
272 pub mod net {
273     pub mod tcp;
274     pub mod udp;
275     pub mod ip;
276     #[cfg(unix)]
277     pub mod unix;
278 }
279
280 /// Readers and Writers for memory buffers and strings.
281 pub mod mem;
282
283 /// Non-blocking access to stdin, stdout, stderr
284 pub mod stdio;
285
286 /// Implementations for Option
287 mod option;
288
289 /// Basic stream compression. XXX: Belongs with other flate code
290 pub mod flate;
291
292 /// Interop between byte streams and pipes. Not sure where it belongs
293 pub mod comm_adapters;
294
295 /// Extension traits
296 mod extensions;
297
298 /// Non-I/O things needed by the I/O module
299 mod support;
300
301 /// Basic Timer
302 pub mod timer;
303
304 /// Thread-blocking implementations
305 pub mod native {
306     /// Posix file I/O
307     pub mod file;
308     /// # XXX - implement this
309     pub mod stdio { }
310     /// Sockets
311     /// # XXX - implement this
312     pub mod net {
313         pub mod tcp { }
314         pub mod udp { }
315         #[cfg(unix)]
316         pub mod unix { }
317     }
318 }
319
320 /// Mock implementations for testing
321 mod mock;
322
323 /// The default buffer size for various I/O operations
324 /// XXX: Not pub
325 pub static DEFAULT_BUF_SIZE: uint = 1024 * 64;
326
327 /// The type passed to I/O condition handlers to indicate error
328 ///
329 /// # XXX
330 ///
331 /// Is something like this sufficient? It's kind of archaic
332 pub struct IoError {
333     kind: IoErrorKind,
334     desc: &'static str,
335     detail: Option<~str>
336 }
337
338 // FIXME: #8242 implementing manually because deriving doesn't work for some reason
339 impl ToStr for IoError {
340     fn to_str(&self) -> ~str {
341         let mut s = ~"IoError { kind: ";
342         s.push_str(self.kind.to_str());
343         s.push_str(", desc: ");
344         s.push_str(self.desc);
345         s.push_str(", detail: ");
346         s.push_str(self.detail.to_str());
347         s.push_str(" }");
348         s
349     }
350 }
351
352 #[deriving(Eq)]
353 pub enum IoErrorKind {
354     PreviousIoError,
355     OtherIoError,
356     EndOfFile,
357     FileNotFound,
358     PermissionDenied,
359     ConnectionFailed,
360     Closed,
361     ConnectionRefused,
362     ConnectionReset,
363     BrokenPipe
364 }
365
366 // FIXME: #8242 implementing manually because deriving doesn't work for some reason
367 impl ToStr for IoErrorKind {
368     fn to_str(&self) -> ~str {
369         match *self {
370             PreviousIoError => ~"PreviousIoError",
371             OtherIoError => ~"OtherIoError",
372             EndOfFile => ~"EndOfFile",
373             FileNotFound => ~"FileNotFound",
374             PermissionDenied => ~"PermissionDenied",
375             ConnectionFailed => ~"ConnectionFailed",
376             Closed => ~"Closed",
377             ConnectionRefused => ~"ConnectionRefused",
378             ConnectionReset => ~"ConnectionReset",
379             BrokenPipe => ~"BrokenPipe"
380         }
381     }
382 }
383
384 // XXX: Can't put doc comments on macros
385 // Raised by `I/O` operations on error.
386 condition! {
387     // FIXME (#6009): uncomment `pub` after expansion support lands.
388     /*pub*/ io_error: super::IoError -> ();
389 }
390
391 // XXX: Can't put doc comments on macros
392 // Raised by `read` on error
393 condition! {
394     // FIXME (#6009): uncomment `pub` after expansion support lands.
395     /*pub*/ read_error: super::IoError -> ();
396 }
397
398 pub trait Reader {
399     /// Read bytes, up to the length of `buf` and place them in `buf`.
400     /// Returns the number of bytes read. The number of bytes read my
401     /// be less than the number requested, even 0. Returns `None` on EOF.
402     ///
403     /// # Failure
404     ///
405     /// Raises the `read_error` condition on error. If the condition
406     /// is handled then no guarantee is made about the number of bytes
407     /// read and the contents of `buf`. If the condition is handled
408     /// returns `None` (XXX see below).
409     ///
410     /// # XXX
411     ///
412     /// * Should raise_default error on eof?
413     /// * If the condition is handled it should still return the bytes read,
414     ///   in which case there's no need to return Option - but then you *have*
415     ///   to install a handler to detect eof.
416     ///
417     /// This doesn't take a `len` argument like the old `read`.
418     /// Will people often need to slice their vectors to call this
419     /// and will that be annoying?
420     /// Is it actually possible for 0 bytes to be read successfully?
421     fn read(&mut self, buf: &mut [u8]) -> Option<uint>;
422
423     /// Return whether the Reader has reached the end of the stream.
424     ///
425     /// # Example
426     ///
427     ///     let reader = FileStream::new()
428     ///     while !reader.eof() {
429     ///         println(reader.read_line());
430     ///     }
431     ///
432     /// # Failure
433     ///
434     /// Returns `true` on failure.
435     fn eof(&mut self) -> bool;
436 }
437
438 pub trait Writer {
439     /// Write the given buffer
440     ///
441     /// # Failure
442     ///
443     /// Raises the `io_error` condition on error
444     fn write(&mut self, buf: &[u8]);
445
446     /// Flush output
447     fn flush(&mut self);
448 }
449
450 pub trait Stream: Reader + Writer { }
451
452 pub enum SeekStyle {
453     /// Seek from the beginning of the stream
454     SeekSet,
455     /// Seek from the end of the stream
456     SeekEnd,
457     /// Seek from the current position
458     SeekCur,
459 }
460
461 /// # XXX
462 /// * Are `u64` and `i64` the right choices?
463 pub trait Seek {
464     /// Return position of file cursor in the stream
465     fn tell(&self) -> u64;
466
467     /// Seek to an offset in a stream
468     ///
469     /// A successful seek clears the EOF indicator.
470     ///
471     /// # XXX
472     ///
473     /// * What is the behavior when seeking past the end of a stream?
474     fn seek(&mut self, pos: i64, style: SeekStyle);
475 }
476
477 /// A listener is a value that listens for connections
478 pub trait Listener<S> {
479     /// Wait for and accept an incoming connection
480     ///
481     /// Returns `None` on timeout.
482     ///
483     /// # Failure
484     ///
485     /// Raises `io_error` condition. If the condition is handled,
486     /// then `accept` returns `None`.
487     fn accept(&mut self) -> Option<S>;
488 }
489
490 /// Common trait for decorator types.
491 ///
492 /// Provides accessors to get the inner, 'decorated' values. The I/O library
493 /// uses decorators to add functionality like compression and encryption to I/O
494 /// streams.
495 ///
496 /// # XXX
497 ///
498 /// Is this worth having a trait for? May be overkill
499 pub trait Decorator<T> {
500     /// Destroy the decorator and extract the decorated value
501     ///
502     /// # XXX
503     ///
504     /// Because this takes `self' one could never 'undecorate' a Reader/Writer
505     /// that has been boxed. Is that ok? This feature is mostly useful for
506     /// extracting the buffer from MemWriter
507     fn inner(self) -> T;
508
509     /// Take an immutable reference to the decorated value
510     fn inner_ref<'a>(&'a self) -> &'a T;
511
512     /// Take a mutable reference to the decorated value
513     fn inner_mut_ref<'a>(&'a mut self) -> &'a mut T;
514 }
515
516 pub fn standard_error(kind: IoErrorKind) -> IoError {
517     match kind {
518         PreviousIoError => {
519             IoError {
520                 kind: PreviousIoError,
521                 desc: "Failing due to a previous I/O error",
522                 detail: None
523             }
524         }
525         EndOfFile => {
526             IoError {
527                 kind: EndOfFile,
528                 desc: "End of file",
529                 detail: None
530             }
531         }
532         _ => fail!()
533     }
534 }
535
536 pub fn placeholder_error() -> IoError {
537     IoError {
538         kind: OtherIoError,
539         desc: "Placeholder error. You shouldn't be seeing this",
540         detail: None
541     }
542 }
543
544 /// Instructions on how to open a file and return a `FileStream`.
545 pub enum FileMode {
546     /// Opens an existing file. IoError if file does not exist.
547     Open,
548     /// Creates a file. IoError if file exists.
549     Create,
550     /// Opens an existing file or creates a new one.
551     OpenOrCreate,
552     /// Opens an existing file or creates a new one, positioned at EOF.
553     Append,
554     /// Opens an existing file, truncating it to 0 bytes.
555     Truncate,
556     /// Opens an existing file or creates a new one, truncating it to 0 bytes.
557     CreateOrTruncate,
558 }
559
560 /// Access permissions with which the file should be opened.
561 /// `FileStream`s opened with `Read` will raise an `io_error` condition if written to.
562 pub enum FileAccess {
563     Read,
564     Write,
565     ReadWrite
566 }