GitHub PullRequestReviewCommentEvent at 2014-12-13 10:16:26
Repository: rfcs
Actor: erickt
Payload: {"action":"created","comment":{"url":"https://api.github.com/repos/rust-lang/rfcs/pulls/comments/21787370","id":21787370,"diff_hunk":"@@ -0,0 +1,1639 @@\n+- Start Date: 2014-12-07\n+- RFC PR: (leave this empty)\n+- Rust Issue: (leave this empty)\n+\n+# Summary\n+[Summary]: #summary\n+\n+This RFC proposes a significant redesign of the `std::io` and `std::os` modules\n+in preparation for API stabilization. The specific problems addressed by the\n+redesign are given in the [Problems] section below, and the key ideas of the\n+design are given in [Vision for IO].\n+\n+# Table of contents\n+[Table of contents]: #table-of-contents\n+* [Summary]\n+* [Table of contents]\n+* [Problems]\n+    * [Atomicity and the `Reader`/`Writer` traits]\n+    * [Timeouts]\n+    * [Posix and libuv bias]\n+    * [Unicode]\n+    * [stdio]\n+    * [Overly high-level abstractions]\n+    * [The error chaining pattern]\n+* [Detailed design]\n+    * [Vision for IO]\n+        * [Goals]\n+        * [Design principles]\n+            * [What cross-platform means]\n+            * [Relation to the system-level APIs]\n+            * [Platform-specific opt-in]\n+        * [Proposed organization]\n+    * [Revising `Reader` and `Writer`]\n+        * [Nonatomic results]\n+        * [Reader]\n+        * [Writer]\n+    * [String handling]\n+        * [Key observations]\n+        * [The design: `os_str`]\n+        * [The future]\n+    * [Deadlines]\n+        * [Timeouts versus deadlines]\n+    * [Splitting streams and cancellation]\n+    * [Modules]\n+        * [core::io]\n+            * [Adapters]\n+            * [Seeking]\n+            * [Buffering]\n+            * [MemReader and MemWriter]\n+        * [The std::io facade]\n+            * [Errors]\n+            * [Channel adapters]\n+            * [stdin, stdout, stderr]\n+        * [std::env]\n+        * [std::fs]\n+            * [Free functions]\n+            * [Files]\n+            * [File kinds]\n+            * [File permissions]\n+        * [std::net]\n+            * [TCP]\n+            * [UDP]\n+            * [Addresses]\n+        * [std::process]\n+            * [Command]\n+            * [Child]\n+        * [std::os]\n+    * [Odds and ends]\n+        * [The io prelude]\n+        * [Functionality moved elsewhere]\n+        * [Functionality removed outright]\n+* [Drawbacks]\n+* [Alternatives]\n+* [Unresolved questions]\n+\n+# Problems\n+[Problems]: #problems\n+\n+The `io` and `os` modules are the last large API surfaces of `std` that need to\n+be stabilized. While the basic functionality offered in these modules is\n+*largely* traditional, many problems with the APIs have emerged over time. The\n+RFC discusses the most significant problems below.\n+\n+This section only covers specific problems with the current library; see\n+[Vision for IO] for a higher-level view.  section.\n+\n+## Atomicity and the `Reader`/`Writer` traits\n+[Atomicity and the `Reader`/`Writer` traits]: #atomicity-and-the-readerwriter-traits\n+\n+One of the most pressing -- but also most subtle -- problems with `std::io` is\n+the lack of *atomicity* in its `Reader` and `Writer` traits.\n+\n+For example, the `Reader` trait offers a `read_to_end` method:\n+\n+```rust\n+fn read_to_end(&mut self) -> IoResult<Vec<u8>>\n+```\n+\n+Executing this method may involve many calls to the underlying `read`\n+method. And it is possible that the first several calls succeed, and then a call\n+returns an `Err` -- which, like `TimedOut`, could represent a transient\n+problem. Unfortunately, given the above signature, there is no choice but to\n+simply _throw this data away_.\n+\n+The `Writer` trait suffers from a more fundamental problem, since its primary\n+method, `write`, may actually involve several calls to the underlying system --\n+and if a failure occurs, there is no indication of how much was written.\n+\n+Existing blocking APIs all have to deal with this problem, and Rust can and\n+should follow the existing tradition here. See [io] for the proposed\n+solution.\n+\n+## Timeouts\n+[Timeouts]: #timeouts\n+\n+The `std::io` module supports \"timeouts\" on virtually all IO objects via a\n+`set_timeout` method. In this design, every IO object (file, socket, etc.) has\n+an optional timeout associated with it, and `set_timeout` mutates the associated\n+timeout. All subsequent blocking operations are implicitly subject to this timeout.\n+\n+This API choice suffers from two problems, one cosmetic and the other deeper:\n+\n+* The \"timeout\" is\n+  [actually a *deadline*](https://github.com/rust-lang/rust/issues/15802) and\n+  should be named accordingly.\n+\n+* The stateful API has poor composability: when passing a mutable reference of\n+  an IO object to another function, it's possible that the deadline has been\n+  changed. In other words, users of the API can easily interfere with each other\n+  by accident.\n+\n+See [Deadlines] for the proposed solution.\n+\n+## Posix and libuv bias\n+[Posix and libuv bias]: #posix-and-libuv-bias\n+\n+The current `io` and `os` modules were originally designed when `librustuv` was\n+providing IO support, and to some extent they reflect the capabilities and\n+conventions of `libuv` -- which in turn are loosely based on Posix.\n+\n+As such, the modules are not always ideal from a cross-platform standpoint, both\n+in terms of forcing Windows programmings into a Posix mold, and also of offering\n+APIs that are not actually usable on all platforms.\n+\n+The modules have historically also provided *no* platform-specific APIs.\n+\n+Part of the goal of this RFC is to set out a clear and extensible story for both\n+cross-platform and platform-specific APIs in `std`. See [Design principles] for\n+the details.\n+\n+## Unicode\n+[Unicode]: #unicode\n+\n+Rust has followed the [utf8 everywhere](http://utf8everywhere.org/) approach to\n+its strings. However, at the borders to platform APIs, it is revealed that the\n+world is not, in fact, UTF-8 (or even Unicode) everywhere.\n+\n+Currently our story for platform APIs is that we either assume they can take or\n+return Unicode strings (suitably encoded) or an uninterpreted byte\n+sequence. Sadly, this approach does *not* actually cover all platform needs, and\n+is also not highly ergonomic as presently implemented. (Consider `os::getev`\n+which introduces replacement characters (!) versus `os::getenv_as_bytes` which\n+yields a `Vec<u8>`; neither is ideal.)\n+\n+This topic was covered in some detail in the\n+[Path Reform RFC](https://github.com/rust-lang/rfcs/pull/474), but this RFC\n+gives a more general account in [String handling].\n+\n+## `stdio`\n+[stdio]: #stdio\n+\n+The `stdio` module provides access to readers/writers for `stdin`, `stdout` and\n+`stderr`, which is essential functionality. However, it *also* provides a means\n+of changing e.g. \"stdout\" -- but there is no connection between these two! In\n+particular, `set_stdout` affects only the writer that `println!` and friends\n+use, while `set_stderr` affects `panic!`.\n+\n+This module needs to be clarified. See [io] and\n+[Functionality moved elsewhere] for the detailed design.\n+\n+## Overly high-level abstractions\n+[Overly high-level abstractions]: #overly-high-level-abstractions\n+\n+There are a few places where `io` provides high-level abstractions over system\n+services without also providing more direct access to the service as-is. For example:\n+\n+* The `Writer` trait's `write` method -- a cornerstone of IO -- actually\n+  corresponds to an unbounded number of invocations of writes to the underlying\n+  IO object. This RFC changes `write` to follow more standard, lower-level\n+  practice; see [io].\n+\n+* Objects like `TcpStream` are `Clone`, which involves a fair amount of\n+  supporting infrastructure. This RFC tackles the problems that `Clone` was\n+  trying to solve more directly; see [Splitting streams and cancellation].\n+\n+The motivation for going lower-level is described in [Design principles] below.\n+\n+## The error chaining pattern\n+[The error chaining pattern]: #the-error-chaining-pattern\n+\n+The `std::io` module is somewhat unusual in that most of the functionality it\n+proves are used through a few key traits (like `Reader`) and these traits are in\n+turn \"lifted\" over `IoResult`:\n+\n+```rust\n+impl<R: Reader> Reader for IoResult<R> { ... }\n+```\n+\n+This lifting and others makes it possible to chain IO operations that might\n+produce errors, without any explicit mention of error handling:\n+\n+```rust\n+File::open(some_path).read_to_end()\n+                      ^~~~~~~~~~~ can produce an error\n+      ^~~~ can produce an error\n+```\n+\n+The result of such a chain is either `Ok` of the outcome, or `Err` of the first\n+error.\n+\n+While this pattern is highly ergonomic, it does not fit particularly well into\n+our evolving error story\n+([interoperation](https://github.com/rust-lang/rfcs/pull/201) or\n+[try blocks](https://github.com/rust-lang/rfcs/pull/243)), and it is the only\n+module in `std` to follow this pattern.\n+\n+Eventually, we would like to write\n+\n+```rust\n+File::open(some_path)?.read_to_end()\n+```\n+\n+to take advantage of the `FromError` infrastructure, hook into error handling\n+control flow, and to provide good chaining ergonomics throughout *all* Rust APIs\n+-- all while keeping this handling a bit more explicit via the `?`\n+operator. (See https://github.com/rust-lang/rfcs/pull/243 for the rough direction).\n+\n+In the meantime, this RFC proposes to phase out the use of impls for\n+`IoResult`. This will require use of `try!` for the time being.\n+\n+(Note: this may put some additional pressure on at least landing the basic use\n+of `?` instead of today's `try!` before 1.0 final.)\n+\n+# Detailed design\n+[Detailed design]: #detailed-design\n+\n+There's a lot of material here, so the RFC starts with high-level goals,\n+principles, and organization, and then works its way through the various modules\n+involved.\n+\n+## Vision for IO\n+[Vision for IO]: #vision-for-io\n+\n+Rust's IO story had undergone significant evolution, starting from a\n+`libuv`-style pure green-threaded model to a dual green/native model and now to\n+a [pure native model](https://github.com/rust-lang/rfcs/pull/230). Given that\n+history, it's worthwhile to set out explicitly what is, and is not, in scope for\n+`std::io`\n+\n+### Goals\n+[Goals]: #goals\n+\n+For Rust 1.0, the aim is to:\n+\n+* Provide a *blocking* API based directly on the services provided by the native\n+  OS for native threads.\n+\n+  These APIs should cover the basics (files, basic networking, basic process\n+  management, etc) and suffice to write servers following the classic Apache\n+  thread-per-connection model. They should impose essentially zero cost over the\n+  underlying OS services; the core APIs should map down to a single syscall\n+  unless more are needed for cross-platform compatibility.\n+\n+* Provide basic blocking abstractions and building blocks (various stream and\n+  buffer types and adapters) based on traditional blocking IO models but adapted\n+  to fit well within Rust.\n+\n+* Provide hooks for integrating with low-level and/or platform-specific APIs.\n+\n+* Ensure reasonable forwards-compatibility with future async IO models.\n+\n+It is explicitly *not* a goal at this time to support asynchronous programming\n+models or nonblocking IO, nor is it a goal for the blocking APIs to eventually\n+be used in a nonblocking \"mode\" or style.\n+\n+Rather, the hope is that the basic abstractions of files, paths, sockets, and so\n+on will eventually be usable directly within an async IO programing model and/or\n+with nonblocking APIs. This is the case for most existing languages, which offer\n+multiple interoperating IO models.\n+\n+The *long term* intent is certainly to support async IO in some form, which is\n+needed for some kinds of high-performance servers among other things. But doing\n+so will require new research and experimentation.\n+\n+### Design principles\n+[Design principles]: #design-principles\n+\n+Now that the scope has been clarified, it's important to lay out some broad\n+principles for the `io` and `os` modules. Many of these principles are already\n+being followed to some extent, but this RFC makes them more explicit and applies\n+them more uniformly.\n+\n+#### What cross-platform means\n+[What cross-platform means]: #what-cross-platform-means\n+\n+Historically, Rust's `std` has always been \"cross-platform\", but as discussed in\n+[Posix and libuv bias] this hasn't always played out perfectly. The proposed\n+policy is below. **With this policies, the APIs should largely feel like part of\n+\"Rust\" rather than part of any legacy, and they should enable truly portable\n+code**.\n+\n+Except for an explicit opt-in (see [Platform-specific opt-in] below), all APIs\n+in `std` should be cross-platform:\n+\n+* The APIs should **only expose a service or a configuration if it is supported on\n+  all platforms**, and if the semantics on those platforms is or can be made\n+  loosely equivalent. (The latter requires exercising some\n+  judgment). Platform-specific functionality can be handled separately\n+  ([Platform-specific opt-in]) and interoperate with normal `std` abstractions.\n+\n+  This policy rules out functions like `chown` which have a clear meaning on\n+  Unix and no clear interpretation on Windows; the ownership and permissions\n+  models are *very* different.\n+\n+* The APIs should **follow Rust's conventions**, including their naming, which\n+  should be platform-neutral.\n+\n+  This policy rules out names like `fstat` that are the legacy of a particular\n+  platform family.\n+\n+* The APIs should **never directly expose the representation** of underlying\n+  platform types, even if they happen to coincide on the currently-supported\n+  platforms. Cross-platform types in `std` should be newtyped.\n+\n+  This policy rules out exposing e.g. error numbers directly as an integer type.\n+\n+The next subsection gives detail on what these APIs should look like in relation\n+to system services.\n+\n+#### Relation to the system-level APIs\n+[Relation to the system-level APIs]: #relation-to-the-system-level-apis\n+\n+How should Rust APIs map into system services? This question breaks down along\n+several axes which are in tension with one another:\n+\n+* **Guarantees**. The APIs provided in the mainline `io` modules should be\n+  predominantly safe, aside from the occasional `unsafe` function. In\n+  particular, the representation should be sufficiently hidden that most use\n+  cases are safe by construction. Beyond memory safety, though, the APIs should\n+  strive to provide a clear multithreaded semantics (using the `Send`/`Sync`\n+  kinds), and should use Rust's type system to rule out various kinds of bugs\n+  when it is reasonably ergonomic to do so (following the usual Rust\n+  conventions).\n+\n+* **Ergonomics**. The APIs should present a Rust view of things, making use of\n+  the trait system, newtypes, and so on to make system services fit well with\n+  the rest of Rust.\n+\n+* **Abstraction/cost**. On the other hand, the abstractions introduced in `std`\n+  must not induce significant costs over the system services -- or at least,\n+  there must be a way to safely access the services directly without incurring\n+  this penalty. When useful abstractions would impose an extra cost, they must\n+  be pay-as-you-go.\n+\n+Putting the above bullets together, **the abstractions must be safe, and they\n+should be as high-level as possible without imposing a tax**.\n+\n+* **Coverage**. Finally, the `std` APIs should over time strive for full\n+  coverage of non-niche, cross-platform capabilities.\n+\n+#### Platform-specific opt-in\n+[Platform-specific opt-in]: #platform-specific-opt-in\n+\n+Rust is a systems language, and as such it should expose seamless, no/low-cost\n+access to system services. In many cases, however, this cannot be done in a\n+cross-platform way, either because a given service is only available on some\n+platforms, or because providing a cross-platform abstraction over it would be\n+costly.\n+\n+This RFC proposes *platform-specific opt-in*: submodules of `os` that are named\n+by platform, and made available via `#[cfg]` switches. For example, `os::unix`\n+can provide APIs only available on Unix systems, and `os::linux` can drill\n+further down into Linux-only APIs. (You could even imagine subdividing by OS\n+versions.) This is \"opt-in\" in the sense that, like the `unsafe` keyword, it is\n+very easy to audit for potential platform-specificity: just search for\n+`os::anyplatform`. Moreover, by separating out subsets like `linux`, it's clear\n+exactly how specific the platform dependency is.\n+\n+The APIs in these submodules are intended to have the same flavor as other `io`\n+APIs and should interoperate seamlessly with cross-platform types, but:\n+\n+* They should be named according to the underlying system services when there is\n+  a close correspondence.\n+\n+* They may reveal the underlying OS type if there is nothing to be gained by\n+  hiding it behind an abstraction.\n+\n+For example, the `os::unix` module could provide a `stat` function that takes a\n+standard `Path` and yields a custom struct. More interestingly, `os::linux`\n+might include an `epoll` function that could operate *directly* on many `io`\n+types (e.g. various socket types), without any explicit conversion to a file\n+descriptor; that's what \"seamless\" means.\n+\n+Each of the platform modules will offer a custom `prelude` submodule,\n+intended for glob import, that includes all of the extension traits\n+applied to standard IO objects.\n+\n+The precise design of these modules is in the very early stages and will likely\n+remain `#[unstable]` for some time.\n+\n+### Proposed organization\n+[Proposed organization]: #proposed-organization\n+\n+The `io` module is currently the biggest in `std`, with an entire hierarchy\n+nested underneath; it mixes general abstractions/tools with specific IO objects.\n+The `os` module is currently a bit of a dumping ground for facilities that don't\n+fit into the `io` category.\n+\n+This RFC proposes the revamp the organization by flattening out the hierarchy\n+and clarifying the role of each module:\n+\n+```\n+std\n+  env           environment manipulation\n+  fs            file system\n+  io            core io abstractions/adapters\n+    prelude     the io prelude\n+  net           networking\n+  os\n+    unix        platform-specific APIs\n+    linux         ..\n+    windows       ..\n+  os_str        platform-sensitive string handling\n+  process       process management\n+```\n+\n+In particular:\n+\n+* The contents of `os` will largely move to `env`, a new module for\n+inspecting and updating the \"environment\" (including environment variables, CPU\n+counts, arguments to `main`, and so on).\n+\n+* The `io` module will include things like `Reader` and `BufferedWriter` --\n+  cross-cutting abstractions that are needed throughout IO.\n+\n+  The `prelude` submodule will export all of the traits and most of the types\n+  for IO-related APIs; a single glob import should suffice to set you up for\n+  working with IO. (Note: this goes hand-in-hand with *removing* the bits of\n+  `io` currently in the prelude, as\n+  [recently proposed](https://github.com/rust-lang/rfcs/pull/503).)\n+\n+* The root `os` module is used purely to house the platform submodules discussed\n+  [above](#platform-specific-opt-in).\n+\n+* The `os_str` module is part of the solution to the Unicode problem; see\n+  [String handling] below.\n+\n+* The `process` module over time will grow to include querying/manipulating\n+  already-running processes, not just spawning them.\n+\n+## Revising `Reader` and `Writer`\n+[Revising `Reader` and `Writer`]: #revising-reader-and-writer\n+\n+The `Reader` and `Writer` traits are the backbone of IO, representing\n+the ability to (respectively) pull bytes from and push bytes to an IO\n+object. The core operations provided by these traits follows a very\n+long tradition for blocking IO, but they are still surprisingly subtle\n+-- and they need to be revised.\n+\n+* **Atomicity and data loss**. As discussed\n+  [above](#atomicity-and-the-reader-writer-traits), the `Reader` and\n+  `Writer` traits currently expose methods that involve multiple\n+  actual reads or writes, and data is lost when an error occurs after\n+  some (but not all) operations have completed.\n+\n+  The proposed strategy for `Reader` operations is to return the\n+  already-read data together with an error. For writers, the main\n+  change is to make `write` only perform a single underlying write\n+  (returning the number of bytes written on success), and provide a\n+  separate `write_all` method.\n+\n+* **Parsing/serialization**. The `Reader` and `Writer` traits\n+  currently provide a large number of default methods for\n+  (de)serialization of various integer types to bytes with a given\n+  endianness. Unfortunately, these operations pose atomicity problems\n+  as well (e.g., a read could fail after reading two of the bytes\n+  needed for a `u32` value).\n+\n+  Rather than complicate the signatures of these methods, the\n+  (de)serialization infrastructure is removed entirely -- in favor of\n+  instead eventually introducing a much richer\n+  parsing/formatting/(de)serialization framework that works seamlessly\n+  with `Reader` and `Writer`.\n+\n+  Such a framework is out of scope for this RFC, however, so the\n+  endian-sensitive functionality will likely be provided elsewhere\n+  (likely out of tree).\n+\n+* **The error type**. The traits currently use `IoResult` in their\n+  return types, which ties them to `IoError` in particular. Besides\n+  being an unnecessary restriction, this type prevents `Reader` and\n+  `Writer` (and various adapters built on top of them) from moving to\n+  `libcore` -- `IoError` currently requires the `String` type.\n+\n+  With associated types, there is essentially no downside in making\n+  the error type generic.\n+\n+With those general points out of the way, let's look at the details.\n+\n+### Nonatomic results\n+[Nonatomic results]: #nonatomic-results\n+\n+To clarity dealing with nonatomic operations and improve their\n+ergonomics, we introduce some new types into `std::error`:\n+\n+```rust\n+// The progress so far (T) paired with an err (Err)\n+struct PartialResult<T, Err>(T, Err);\n+\n+// An operation that may fail after having made some progress:\n+// - S is what's produced on complete success,\n+// - T is what's produced if an operation fails part of the way through\n+type NonatomicResult<S, T, Err> = Result<S, PartialResult<T, Err>>;\n+\n+// Ergonomically throw out the partial result\n+impl<T, Err> FromError<PartialResult<T, Err> for Err { ... }\n+```\n+\n+The `NonatomicResult` type (which could use a shorter name)\n+encapsulates the common pattern of operations that may fail after\n+having made some progress. The `PartialResult` type then returns the\n+progress that was made along with the error, but with a `FromError`\n+implementation that makes it trivial to throw out the partial result\n+if desired.\n+\n+### `Reader`\n+[Reader]: #reader\n+\n+The updated `Reader` trait (and its extension) is as follows:\n+\n+```rust\n+trait Reader {\n+    type Err; // new associated error type\n+\n+    // unchanged except for error type\n+    fn read(&mut self, buf: &mut [u8]) -> Result<uint, Err>;\n+\n+    // these all return partial results on error\n+    fn read_to_end(&mut self) -> NonatomicResult<Vec<u8>, Vec<u8>, Err> { ... }\n+    fn read_to_string(&self) -> NonatomicResult<String, Vec<u8>, Err> { ... }\n+    fn read_at_least(&mut self, min: uint,  buf: &mut [u8]) -> NonatomicResult<uint, uint, Err>  { ... }\n+}\n+\n+// extension trait needed for object safety\n+trait ReaderExt: Reader {\n+    fn bytes(&mut self) -> Bytes<Self> { ... }\n+    fn chars<'r>(&'r mut self) -> Chars<'r, Self, Err> { ... }\n+\n+    ... // more to come later in the RFC\n+}\n+impl<R: Reader> ReaderExt for R {}\n+```\n+\n+#### Removed methods\n+\n+The proposed `Reader` trait is much slimmer than today's. The vast\n+majority of removed methods are parsing/deserialization, which were\n+discussed above.\n+\n+The remaining methods (`read_exact`, `push`, `push_at_least`) were\n+removed largely because they are *not memory safe*: they involve\n+extending a vector's capacity, and then *passing in the resulting\n+uninitialized memory* to the `read` method, which is not marked\n+`unsafe`! Thus the current design can lead to undefined behavior in\n+safe code.\n+\n+The solution is to instead extend `Vec<T>` with a useful unsafe method:\n+\n+```rust\n+unsafe fn with_extra(&mut self, n: uint) -> &mut [T];\n+```\n+\n+This method is equivalent to calling `reserve(n)` and then providing a\n+slice to the memory starting just after `len()` entries. Using this\n+method, clients of `Reader` can easily recover the above removed\n+methods, but they are explicitly marking the unsafety of doing so.\n+\n+(Note: `read_to_end` is currently not memory safe for the same reason,\n+but is considered a very important convenience. Thus, we will continue\n+to provide it, but will zero the slice beforehand.)\n+\n+### `Writer`\n+[Writer]: #writer\n+\n+The `Writer` trait is cut down to even smaller size:\n+\n+```rust\n+trait Writer {\n+    type Err;\n+    fn write(&mut self, buf: &[u8]) -> Result<uint, Err>;\n+\n+    fn write_all(&mut self, buf: &[u8]) -> NonatomicResult<(), uint, Err> { ... };\n+    fn write_fmt(&mut self, fmt: &fmt::Arguments) -> Result<(), Err> { ... }\n+    fn flush(&mut self) -> Result<(), Err> { ... }\n+}\n+```\n+\n+The biggest change here is to the semantics of `write`. Instead of\n+repeatedly writing to the underlying IO object until all of `buf` is\n+written, it attempts a *single* write and on success returns the\n+number of bytes written. This follows the long tradition of blocking\n+IO, and is a more fundamental building block than the looping write we\n+currently have.\n+\n+For convenience, `write_all` recovers the behavior of today's `write`,\n+looping until either the entire buffer is written or an error\n+occurs. In the latter case, however, it now also yields the number of\n+bytes that had been written prior to the error.\n+\n+The `write_fmt` method, like `write_all`, will loop until its entire\n+input is written or an error occurs. However, it does not return a\n+`NonatomicResult` because the number of bytes written cannot be\n+straightforwardly interpreted -- the actual byte sequence written is\n+determined by the formatting system.\n+\n+The other methods include endian conversions (covered by\n+serialization) and a few conveniences like `write_str` for other basic\n+types. The latter, at least, is already uniformly (and extensibly)\n+covered via the `write!` macro. The other helpers, as with `Reader`,\n+should migrate into a more general (de)serialization library.\n+\n+## String handling\n+[String handling]: #string-handling\n+\n+The fundamental problem with Rust's full embrace of UTF-8 strings is that not\n+all strings taken or returned by system APIs are Unicode, let alone UTF-8\n+encoded.\n+\n+In the past, `std` has assumed that all strings are *either* in some form of\n+Unicode (Windows), *or* are simply `u8` sequences (Unix). Unfortunately, this is\n+wrong, and the situation is more subtle:\n+\n+* Unix platforms do indeed work with arbitrary `u8` sequences (without interior\n+  nulls) and today's platforms usually interpret them as UTF-8 when displayed.\n+\n+* Windows, however, works with *arbitrary `u16` sequences* that are roughly\n+  interpreted at UTF-16, but may not actually be valid UTF-16 -- an \"encoding\"\n+  often call UCS-2; see http://justsolve.archiveteam.org/wiki/UCS-2 for a bit\n+  more detail.\n+\n+What this means is that all of Rust's platforms go beyond Unicode, but they do\n+so in different and incompatible ways.\n+\n+The current solution of providing both `str` and `[u8]` versions of\n+APIs is therefore problematic for multiple reasons. For one, **the\n+`[u8]` versions are not actually cross-platform** -- even today, they\n+panic on Windows when given non-UTF-8 data, a platform-specific\n+behavior. But they are also incomplete, because on Windows you should\n+be able to work directly with UCS-2 data.\n+\n+### Key observations\n+[Key observations]: #key-observations\n+\n+Fortunately, there is a solution that fits well with Rust's UTF-8 strings *and*\n+offers the possibility of platform-specific APIs.\n+\n+**Observation 1**: it is possible to re-encode UCS-2 data in a way that is also\n+  compatible with UTF-8. This is the\n+  [WTF-8 encoding format](http://simonsapin.github.io/wtf-8/) proposed by Simon\n+  Sapin. This encoding has some remarkable properties:\n+\n+* Valid UTF-8 data is valid WTF-8 data. When decoded to UCS-2, the result is\n+  exactly what would be produced by going straight from UTF-8 to UTF-16. In\n+  other words, making up some methods:\n+\n+  ```rust\n+  my_ut8_data.to_wtf_8().to_ucs2().as_u16_slice() == my_utf8_data.to_utf16().as_16_slice()\n+  ```\n+\n+* Valid UTF-16 data re-encoded as WTF-8 produces the corresponding UTF-8 data:\n+\n+  ```rust\n+  my_utf16_data.to_wtf_8().as_bytes() == my_utf16_data.to_utf8().as_bytes()\n+  ```\n+\n+These two properties mean that, when working with Unicode data, the WTF-8\n+encoding is highly compatible with both UTF-8 *and* UTF-16. In particular, the\n+conversion from a Rust string to a WTF-8 string is a no-op, and the conversion\n+in the other direction is just a validation.\n+\n+**Observation 2**: all platforms can *consume* Unicode data (suitably\n+  re-encoded), and it's also possible to validate the data they produce as\n+  Unicode and extract it.\n+\n+**Observation 3**: the non-Unicode spaces on various platforms are deeply\n+  incompatible: there is no standard way to port non-Unicode data from one to\n+  another. Therefore, the only cross-platform APIs are those that work entirely\n+  with Unicode.\n+\n+### The design: `os_str`\n+[The design: `os_str`]: #the-design-os_str\n+\n+The observations above lead to a somewhat radical new treatment of strings,\n+first proposed in the\n+[Path Reform RFC](https://github.com/rust-lang/rfcs/pull/474). This RFC proposes\n+to introduce new string and string slice types that (opaquely) represent\n+*platform-sensitive strings*, housed in the `std::os_str` module.\n+\n+The `OsStrBuf` type is analogous to `String`, and `OsStr` is analogous to `str`.\n+Their backing implementation is platform-dependent, but they offer a\n+cross-platform API:\n+\n+```rust\n+pub mod os_str {\n+    /// Owned OS strings\n+    struct OsStrBuf {\n+        inner: imp::Buf\n+    }\n+    /// Slices into OS strings\n+    struct OsStr {\n+        inner: imp::Slice\n+    }\n+\n+    // Platform-specific implementation details:\n+    #[cfg(unix)]\n+    mod imp {\n+        type Buf = Vec<u8>;\n+        type Slice = [u8;\n+        ...\n+    }\n+\n+    #[cfg(windows)]\n+    mod imp {\n+        type Buf = Wtf8Buf; // See https://github.com/SimonSapin/rust-wtf8\n+        type Slice = Wtf8;\n+        ...\n+    }\n+\n+    impl OsStrBuf {\n+        pub fn from_string(String) -> OsStrBuf;\n+        pub fn from_str(&str) -> OsStrBuf;\n+        pub fn as_slice(&self) -> &OsStr;\n+        pub fn into_string(Self) -> Result<String, OsStrBuf>;\n+        pub fn into_string_lossy(Self) -> String;\n+\n+        // and ultimately other functionality typically found on vectors,\n+        // but CRUCIALLY NOT as_bytes\n+    }\n+\n+    impl Deref<OsStr> for OsStrBuf { ... }\n+\n+    impl OsStr {\n+        pub fn from_str(value: &str) -> &OsStr;\n+        pub fn as_str(&self) -> Option<&str>;\n+        pub fn to_string_lossy(&self) -> CowString;\n+\n+        // and ultimately other functionality typically found on slices,\n+        // but CRUCIALLY NOT as_bytes\n+    }\n+\n+    trait IntoOsStrBuf {\n+        fn into_os_str_buf(self) -> OsStrBuf;\n+    }\n+\n+    impl IntoOsStrBuf for OsStrBuf { ... }\n+    impl<'a> IntoOsStrBuf for &'a OsStr { ... }\n+\n+    ...\n+}\n+```\n+\n+These APIs make OS strings appear roughly as opaque vectors (you\n+cannot see the byte representation directly), and can always be\n+produced starting from Unicode data. They make it possible to collapse\n+functions like `getenv` and `getenv_as_bytes` into a single function\n+that produces an OS string, allowing the client to decide how (or\n+whether) to extract Unicode data. It will be possible to do things\n+like concatenate OS strings without ever going through Unicode.\n+\n+It will also likely be possible to do things like search for Unicode\n+substrings. The exact details of the API are left open and are likely\n+to grow over time.\n+\n+In addition to APIs like the above, there will also be\n+platform-specific ways of viewing or constructing OS strings that\n+reveals more about the space of possible values:\n+\n+```rust\n+pub mod os {\n+    #[cfg(unix)]\n+    pub mod unix {\n+        trait OsStrBufExt {\n+            fn from_vec(Vec<u8>) -> Self;\n+            fn into_vec(Self) -> Vec<u8>;\n+        }\n+\n+        impl OsStrBufExt for os_str::OsStrBuf { ... }\n+\n+        trait OsStrExt {\n+            fn as_bytes(&self) -> &[u8];\n+            fn from_bytes(&[u8]) -> &Self;\n+        }\n+\n+        impl OsStrExt for os_str::OsStr { ... }\n+\n+        ...\n+    }\n+\n+    #[cfg(windows)]\n+    pub mod windows{\n+        // The following extension traits provide a UCS-2 view of OS strings\n+\n+        trait OsStrBufExt {\n+            fn from_vec(Vec<u16>) -> Self;\n+            fn into_vec(Self) -> Vec<u16>;\n+        }\n+\n+        impl OsStrBufExt for os_str::OsStrBuf { ... }\n+\n+        trait OsStrExt {\n+            fn to_wide(&self) -> &[u16];\n+        }\n+\n+        impl OsStrExt for os_str::OsStr { ... }\n+\n+        ...\n+    }\n+\n+    ...\n+}\n+```\n+\n+By placing these APIs under `os`, using them requires a clear *opt in*\n+to platform-specific functionality.\n+\n+### The future\n+[The future]: #the-future\n+\n+Introducing an additional string type is a bit daunting, since many\n+existing APIs take and consume only standard Rust strings. Today's\n+solution demands that strings coming from the OS be assumed or turned\n+into Unicode, and the proposed API continues to allow that (with more\n+explicit and finer-grained control).\n+\n+In the long run, however, robust applications are likely to work\n+opaquely with OS strings far beyond the boundary to the system to\n+avoid data loss and ensure maximal compatibility. If this situation\n+becomes common, it should be possible to introduce an abstraction over\n+various string types and generalize most functions that work with\n+`String`/`str` to instead work generically. This RFC does *not*\n+propose taking any such steps now -- but it's important that we *can*\n+do so later if Rust's standard strings turn out to not be sufficient\n+and OS strings become commonplace.\n+\n+## Deadlines\n+[Deadlines]: #deadlines\n+\n+Most blocking system operations can take a timeout or a deadline\n+(depending on the platform) for completion, and it's important that\n+Rusts IO APIs offer the same capability. This poses a bit of a\n+challenge, however, because adding variants to all of the blocking\n+APIs would significantly increase the API surface, while taking an\n+`Option` argument would decrease their ergonomics.\n+\n+The current solution is to offer `set_timeout` methods on various IO\n+objects (a variant of a builder-style API), which allows configuration\n+to be done independently of the blocking operation being configured.\n+\n+Unfortunately, as explained [above](#timeouts), this stateful approach\n+has poor composability, since users of an IO objects can accidentally\n+interfere with one another.\n+\n+The proposed solution is to instead offer a `with_deadline` method\n+(correcting the terminology) that, rather than changing the state of\n+an object, creates a *wrapper* object with the given deadline.\n+\n+```rust\n+struct Deadlined<T> {\n+    deadline: Duration,\n+    inner: T,\n+}\n+\n+impl<T> Deadlined<T> {\n+    pub fn new(inner: T, deadline: Duration) -> Deadlined<T> {\n+        Deadlined { deadline: deadline, inner: inner }\n+    }\n+\n+    pub fn deadline(&self) -> Duration {\n+        self.deadline\n+    }\n+\n+    pub fn inner(&self) -> &T {\n+        &self.inner\n+    }\n+\n+    pub fn inner_mut(&mut self) -> &mut T {\n+        &mut self.inner\n+    }\n+\n+    pub fn into_inner(self) -> T {\n+        self.inner\n+    }\n+}\n+\n+impl Reader for Deadlined<TcpStream> {\n+    type Err = IoError;\n+    fn read(&mut self, buf: &mut [u8]) -> Result<uint, Err> {\n+        // read, using the specified deadline\n+    }\n+}\n+\n+// And so on for other traits and concrete types\n+```\n+\n+### Timeouts versus deadlines\n+[Timeouts versus deadlines]: #timeouts-versus-deadlines\n+\n+This RFC is not going to delve deeply into the timeout versus deadline\n+debate, but the main motivation for using deadlines is for *compound*\n+operations like `write_all`. With a deadline-based approach, it's\n+possible to bound the total amount of time taken even though an\n+operation involves many system calls. Doing so with timeouts is\n+harder, since the timeout must change as the operations progress\n+(requiring re-checking the clock each time).\n+\n+## Splitting streams and cancellation\n+[Splitting streams and cancellation]: #splitting-streams-and-cancellation\n+\n+In the current design of `std::io`, types like `TcpStream` serve as\n+both readers and writers -- which means that, in order for one thread\n+to read from the stream and another to write, the stream must be\n+`Clone`.  A side benefit of cloneability is that one side of a stream\n+can be closed (via `close_read`, for example), which effectively\n+cancels any blocking operations in progress, allowing for a clean shutdown of\n+other threads.\n+\n+While `Clone` addresses important use cases, it has some downsides. It\n+requires that the IO object internally use an `Arc`, and it means that\n+the implementation must be fully thread-safe. More generally, it\n+increases the distance from the underlying descriptors and adds\n+potentially costly functionality on the Rust side -- going against\n+this RFC's [Design principles] and potentially making forward\n+compatibility with async IO more difficult.\n+\n+This RFC proposes to solve stream splitting and cancellation in a different way:\n+\n+* To allow splitting up a stream, we will provide separable `Reader`\n+  and `Writer` components that can be extracted from an owned\n+  stream. That means that there is precisely one owner of each side\n+  (so thread safety is no longer an issue). An `Arc` is still needed\n+  to know when the entire stream should be dropped.\n+\n+* To provide cancellation, we will make it possible to acquire a\n+  \"cancellation token\" for each side of a stream. This token can be\n+  freely cloned, and can be used to shutdown that side of the stream,\n+  cancelling any in-progress blocking operations. *But you pay for\n+  these tokens only if you use them*.\n+\n+The details of this design will be given concretely in the section on\n+[std::net].\n+\n+## Modules\n+[Modules]: #modules\n+\n+Now that we've covered the core principles and techniques used\n+throughout IO, we can go on to explore the modules in detail.\n+\n+### `core::io`\n+[core::io]: #coreio\n+\n+The `io` module is split into a the parts that can live in `libcore`\n+(most of it) and the parts that are added in the `std::io`\n+facade. Being able to move components into `libcore` at all is made\n+possible through the use of\n+[associated error types](#revising-reader-and-writer) for `Reader` and\n+`Writer`.\n+\n+#### Adapters\n+[Adapters]: #adapters\n+\n+The current `std::io::util` module offers a number of `Reader` and\n+`Writer` \"adapters\". This RFC refactors the design to more closely\n+follow `std::iter`. Along the way, it generalizes the `by_ref` adapter:\n+\n+```rust\n+trait ReaderExt: Reader {\n+    // already introduced above\n+    fn bytes(&mut self) -> Bytes<Self> { ... }\n+    fn chars<'r>(&'r mut self) -> Chars<'r, Self, Err> { ... }\n+\n+    // Reify a borrowed reader as owned\n+    fn by_ref<'a>(&'a mut self) -> ByRef<'a, Self> { ... }\n+\n+    // Read everything from `self`, then read from `next`\n+    fn chain<R: Reader>(self, next: R) -> Chain<Self, R> { ... }\n+\n+    // Adapt `self` to yield only the first `limit` bytes\n+    fn take(self, limit: u64) -> Take<Self> { ... }\n+\n+    // Whenever reading from `self`, push the bytes read to `out`\n+    fn tee<W: Writer>(self, out: W) -> Tee<Self, W> { ... }\n+}\n+impl<T: Reader> ReaderExt for T {}\n+\n+trait WriterExt: Writer {\n+    // Reify a borrowed writer as owned\n+    fn by_ref<'a>(&'a mut self) -> ByRef<'a, Self> { ... }\n+\n+    // Whenever bytes are written to `self`, write them to `other` as well\n+    fn carbon_copy<W: Writer>(self, other: W) -> CarbonCopy<Self, W> { ... }\n+}\n+impl<T: Writer> WriterExt for T {}\n+\n+// An adaptor converting an `Iterator<u8>` to a `Reader`.\n+pub struct IterReader<T> { ... }\n+```\n+\n+As with `std::iter`, these adapters are object unsafe an hence placed\n+in an extension trait with a blanket `impl`.\n+\n+Note that the same `ByRef` type is used for both `Reader` and `Writer`\n+-- and this RFC proposes to use it for `std::iter` as well. The\n+insight is that there is no difference between the *type* used for\n+by-ref adapters in any of these cases; what changes is just which\n+trait defers through it. So, we propose to add the following to `core::borrow`:\n+\n+```rust\n+pub struct ByRef<'a, Sized? T:'a> {\n+    pub inner: &'a mut T\n+}\n+```\n+\n+which will allow `impl`s like the following in `core::io`:\n+\n+```rust\n+impl<'a, W: Writer> Writer for ByRef<'a, W> {\n+    #[inline]\n+    fn write(&mut self, buf: &[u8]) -> IoResult<()> { self.inner.write(buf) }\n+\n+    #[inline]\n+    fn flush(&mut self) -> IoResult<()> { self.inner.flush() }\n+}\n+```\n+\n+#### Free functions\n+[Free functions]: #free-functions\n+\n+The current `std::io::util` module also includes a number of primitive\n+readers and writers, as well as `copy`. These are updated as follows:\n+\n+```rust\n+// A reader that yields no bytes\n+fn empty() -> Empty;\n+\n+// A reader that yields `byte` repeatedly (generalizes today's ZeroReader)\n+fn repeat(byte: u8) -> Repeat;\n+\n+// A writer that ignores the bytes written to it (/dev/null)\n+fn sink() -> Sink;\n+\n+// Copies all data from a Reader to a Writer\n+pub fn copy<E, R, W>(r: &mut R, w: &mut W) -> NonatomicResult<(), uint, E> where\n+    R: Reader<Err = E>,\n+    W: Writer<Err = E>\n+```\n+\n+#### Seeking\n+[Seeking]: #seeking\n+\n+The seeking infrastructure is largely the same as today's, except that\n+`tell` is renamed to follow the RFC's design principles and the `seek`\n+signature is refactored with more precise types:\n+\n+```rust\n+pub trait Seek {\n+    fn position(&self) -> IoResult<u64>;\n+    fn seek(&mut self, pos: SeekPos) -> IoResult<()>;\n+}\n+\n+pub enum SeekPos {\n+    FromStart(u64),\n+    FromEnd(u64),\n+    FromCur(i64),\n+}\n+```\n+\n+#### Buffering\n+[Buffering]: #buffering\n+\n+The current `Buffer` trait will be renamed to `BufferedReader` for\n+clarity (and to open the door to `BufferedWriter` at some later\n+point):\n+\n+```rust\n+pub trait BufferedReader: Reader {\n+    fn fill_buf(&mut self) -> Result<&[u8], Self::Err>;\n+    fn consume(&mut self, amt: uint);\n+\n+    // This should perhaps yield an iterator\n+    fn read_until(&mut self, byte: u8) -> NonatomicResult<Vec<u8>, Vec<u8>, Self::Err> { ... }\n+}\n+\n+pub trait BufferedReaderExt: BufferedReader {\n+    fn lines(&mut self) -> Lines<Self, Self::Err> { ... };\n+}\n+```\n+\n+In addition, `read_line` is removed in favor of the `lines` iterator,\n+and `read_char` is removed in favor of the `chars` iterator (now on\n+`ReaderExt`). These iterators will be changed to yield\n+`NonatomicResult` values.\n+\n+The `BufferedReader`, `BufferedWriter` and `BufferedStream` types stay\n+essentially as they are today, except that for streams and writers the\n+`into_inner` method yields any errors encountered when flushing,\n+together with the remaining data:\n+\n+```rust\n+// If flushing fails, you get the unflushed data back\n+fn into_inner(self) -> NonatomicResult<W, Vec<u8>, W::Err>;\n+```\n+\n+#### `MemReader` and `MemWriter`\n+[MemReader and MemWriter]: #memreader-and-memwriter\n+\n+The various in-memory readers and writers available today will be\n+consolidated into just `MemReader` and `MemWriter`:\n+\n+`MemReader` (like today's `BufReader`)\n+ - construct from `&[u8]`\n+ - implements `Seek`\n+\n+`MemWriter`\n+ - construct freshly, or from a `Vec`\n+ - implements `Seek`\n+\n+Both will allow decomposing into their inner parts, though the exact\n+details are left to the implementation.\n+\n+The rationale for this design is that, if you want to read from a\n+`Vec`, it's easy enough to get a slice to read from instead; on the\n+other hand, it's rare to want to write into a mutable slice on the\n+stack, as opposed to an owned vector. So these two readers and writers\n+cover the vast majority of in-memory readers/writers for Rust.\n+\n+### The `std::io` facade\n+[The std::io facade]: #the-stdio-facade\n+\n+The `std::io` module will largely be a facade over `core::io`, but it\n+will add some functionality that can live only in `std`.\n+\n+#### `Errors`\n+[Errors]: #error\n+\n+The `IoError` type will be renamed to `std::io::Error`, following our\n+[non-prefixing convention](https://github.com/rust-lang/rfcs/pull/356).\n+It will remain largely as it is today, but its fields will be made\n+private. It may eventually grow a field to track the underlying OS\n+error code.\n+\n+The `IoErrorKind` type will become `std::io::ErrorKind`, and\n+`ShortWrite` will be dropped (it is no longer needed with the new\n+`Writer` semantics), which should decrease its footprint. The\n+`OtherIoError` variant will become `Other` now that `enum`s are\n+namespaced.\n+\n+#### Channel adapters\n+[Channel adapters]: #channel-adapters\n+\n+The `ChanReader` and `ChanWriter` adapters will be kept exactly as they are today.\n+\n+#### `stdin`, `stdout`, `stderr`\n+[stdin, stdout, stderr]: #stdin-stdout-stderr\n+\n+Finally, `std::io` will provide a `stdin` reader and `stdout` and\n+`stderr` writers. These will largely work as they do today, except\n+that we will hew more closely to the traditional setup:\n+\n+* `stderr` will be unbuffered and `stderr_raw` will therefore be dropped.\n+* `stdout` will be line-buffered for TTY, fully buffered otherwise.\n+* most TTY functionality in `StdReader` and `StdWriter` will be moved\n+   to `os::unix`, since it's not yet implemented on Windows.\n+* `stdout_raw` and `stderr_raw` will be removed.\n+\n+### `std::env`\n+[std::env]: #stdenv\n+\n+Most of what's available in `std::os` today will move to `std::env`,\n+and the signatures will be updated to follow this RFC's\n+[Desgin principles] as follows.\n+\n+**Arguments**:\n+\n+* `args`: change to yield an iterator rather than vector if possible; in any case, it should produce an `OsStrBuf`.\n+\n+**Environment variables**:\n+\n+* `vars` (renamed from `env`): yields a vector of `(OsStrBuf, OsStrBuf)` pairs.\n+* `var` (renamed from `getenv`): take a value bounded by `IntoOsStrBuf`,\n+  allowing Rust strings and slices to be ergonomically passed in. Yields an `Option<OsStrBuf>`.\n+* `set_var` (renamed from `setenv`): takes two `IntoOsStrBuf`-bounded values.\n+* `remove_var` (renamed from `unsetenv`): takes a `IntoOsStrBuf`-bounded value.\n+\n+* `join_paths`: take an `IntoIterator<T>` where `T: IntoOsStrBuf`, yield a `Result<OsString, JoinPathsError>`.\n+* `split_paths` take a `IntoOsStrBuf`, yield an `Iterator<Path>`.\n+\n+**Working directory**:\n+\n+* `current_dir` (renamed from `getcwd`): yields a `PathBuf`.\n+* `set_current_dir` (renamed from `change_dir`): takes an `AsPath` value.\n+\n+**Important locations**:\n+\n+* `home_dir` (renamed from `homedir`): returns home directory as a `PathBuf`\n+* `temp_dir` (renamed from `tmpdir`): returns a temporary directly as a `PathBuf`\n+* `current_exe` (renamed from `self_exe_name`): returns the full path\n+  to the current binary as a `PathBuf`.\n+\n+**Exit status**:\n+\n+* `get_exit_status` and `set_exit_status` stay as they are, but with\n+  updated docs that reflect that these only affect the return value of\n+  `std::rt::start`.\n+\n+**Architecture information**:\n+\n+* `num_cpus`, `page_size`: stay as they are\n+\n+**Constants**:\n+\n+* Stabilize `ARCH`, `DLL_PREFIX`, `DLL_EXTENSION`, `DLL_SUFFIX`, `EXE_EXTENSION`, `EXE_SUFFIX`, `FAMILY` as they are.\n+* Rename `SYSNAME` to `OS`.\n+* Remove `TMPBUF_SZ`.\n+\n+This brings the constants into line with our naming conventions elsewhere.\n+\n+#### Items to move to `os::platform`\n+\n+* `pipe` will move to `os::unix`. It is currently primarily used for\n+  hooking to the IO of a child process, which will now be done behind\n+  a trait object abstraction.\n+\n+#### Removed items\n+\n+* `errno`, `error_string` and `last_os_error` provide redundant,\n+  platform-specific functionality and will be removed for now. They\n+  may reappear later in `os::unix` and `os::windows` in a modified\n+  form.\n+* `dll_filename`: deprecated in favor of working directly with the constants.\n+* `_NSGetArgc`, `_NSGetArgv`: these should never have been public.\n+* `self_exe_path`: deprecated in favor of `current_exe` plus path operations.\n+* `make_absolute`: deprecated in favor of explicitly joining with the working directory.\n+* all `_as_bytes` variants: deprecated in favor of yielding `OsStrBuf` values\n+\n+### `std::fs`\n+[std::fs]: #stdfs\n+\n+The `fs` module will provide most of the functionality it does today,\n+but with a stronger cross-platform orientation.\n+\n+Note that all path-consuming functions will now take an\n+`AsPath`-bounded parameter for ergonomic reasons (this will allow\n+passing in Rust strings and literals directly, for example).\n+\n+#### Free functions\n+[Free functions]: #free-functions\n+\n+**Files**:\n+\n+* `copy`. Take `AsPath` bound.\n+* `rename`. Take `AsPath` bound.\n+* `remove_file` (renamed from `unlink`). Take `AsPath` bound.\n+\n+* `file_attr` (renamed from `stat`). Take `AsPath` bound. Yield a new\n+  struct, `FileAttr`, with no public fields, but `size`, `kind` and\n+  `perm` accessors. The various `os::platform` modules will offer\n+  extension methods on this structure.\n+\n+* `set_perm` (renamed from `chmod`). Take `AsPath` bound, and a\n+  `FilePermissions` value. The `FilePermissions` type will be revamped\n+  as a struct with private implementation; see below.\n+\n+**Directories**:\n+\n+* `make_dir` (renamed from `mkdir`). Take `AsPath` bound.\n+* `make_dir_all` (renamed from `mkdir_recursive`). Take `AsPath` bound.\n+* `read_dir` (renamed from `readdir`). Take `AsPath` bound. Yield a\n+  newtypes iterator, which yields a new type `DirEntry` which has an\n+  accessor for `Path`, but will eventually provide other information\n+  as well (possibly via platform-specific extensions).\n+* `remove_dir` (renamed from `rmdir`). Take `AsPath` bound.\n+* `remove_dir_all` (renamed from `rmdir_recursive`). Take\n+  `AsPath` bound.\n+* `walk_dir`. Take `AsPath` bound. Yield an iterator over `IoResult<DirEntry>`.\n+\n+**Links**:\n+\n+* `hard_link` (renamed from `link`). Take `AsPath` bound.\n+* `sym_link` (renamed from `symlink`). Take `AsPath` bound.\n+* `read_link` (renamed form `readlink`). Take `AsPath` bound.\n+\n+#### Files\n+[Files]: #files\n+\n+The `File` type will largely stay as it is today, except that it will\n+use the `AsPath` bound everywhere.\n+\n+The `stat` method will be renamed to `attr`, yield a `FileAttr`, and\n+take `&self`.\n+\n+The `fsync` method will be renamed to `flush_os`, and `datasync` will\n+be moved to `os::unix` (since it has no meaning on Windows)\n+\n+The `path` method wil remain `#[unstable]`, as we do not yet want to\n+commit to its API.\n+\n+The `open_mode` function will take an `OpenOptions` struct, which will\n+encompass today's `FileMode` and `FileAccess` and support a\n+builder-style API.\n+\n+#### File kinds\n+[File kinds]: #file-kinds\n+\n+The `FileType` module will be renamed to `FileKind`, and the\n+underlying `enum` will be hidden (to allow for platform differences\n+and growth). It will expose at least `is_file` and `is_dir`; the other\n+methods need to be audited for compatibility across\n+platforms. Platform-specific kinds will be relegated to extension\n+traits in `std::os::platform`.\n+\n+#### File permissions\n+[File permissions]: #file-permissions\n+\n+Unfortunately, the permission models on Unix and Windows vary\n+greatly. Rather than offer an API that has no meaning on some\n+platforms, we will provide a very limited `FilePermissions` structure\n+in `std::fs`, and then rich extension traits in `std::os::unix` and\n+`std::os::windows`.\n+\n+On the Unix side, the constructors and accessors for `FilePermissions`\n+will resemble the flags we have today; details are left to the implementation.\n+\n+On the Windows side, initially there will be no extensions, as Windows\n+has a very complex permissions model that will take some time to build\n+out.\n+\n+For `std::fs` itself, `FilePermissions` will provide constructors and\n+accessors for \"world readable\" -- and that is all. At the moment, that\n+is all that is known to be compatible across the platforms that Rust\n+supports.\n+\n+#### `PathExt`\n+[PathExt]: #pathext\n+\n+This trait will essentially remain stay as it is (renamed from\n+`PathExtensions`), following the same changes made to `fs` free functions.\n+\n+#### Items to move to `os::platform`\n+\n+* `change_file_times` will move to `os::unix` for now (cf\n+  `SetFileTime` on Windows). Eventually we will add back a\n+  cross-platform function, when we have grown a notion of time in\n+  `std` and have a good compatibility story across all platforms.\n+\n+* `lstat` will move to `os::unix` since it is unsupported by Windows.\n+\n+* `chown` will move to `os::unix` (it currently does *nothing* on\n+  Windows), and eventually `os::windows` will grow support for\n+  Windows's permission model. If at some point a reasonable\n+  intersection is found, we will re-introduce a cross-platform\n+  function in `std::fs`.\n+\n+* In general, offer all of the `stat` fields as an extension trait on\n+  `FileAttr` (e.g. `os::unix::FileAttrExt`).\n+\n+### `std::net`\n+[std::net]: #stdnet\n+\n+The contents of `std::io::net` submodules `tcp`, `udp`, `ip` and\n+`addrinfo` will be retained but moved into a single `std::net` module;\n+the other modules are being moved or removed and are described\n+elsewhere.\n+\n+#### TCP\n+[TCP]: #tcp\n+\n+For `TcpStream`, the changes are most easily expressed by giving the signatures directly:\n+\n+```rust\n+// TcpStream, which contains both a reader and a writer\n+\n+impl TcpStream {\n+    fn connect<A: ToSocketAddr>(addr: A) -> IoResult<TcpStreama>;\n+    fn connect_deadline<A: ToSocketAddr>(addr: A, deadline: Duration) -> IoResult<TcpStreama>;\n+\n+    fn reader(&mut self) -> &mut TcpReader;\n+    fn writer(&mut self) -> &mut TcpWriter;\n+    fn split(self) -> (TcpReader, TcpWriter);\n+\n+    fn peer_addr(&mut self) -> IoResult<SocketAddr>;\n+    fn socket_addr(&mut self) -> IoResult<SocketAddr>;\n+}\n+\n+impl Reader for TcpStream { ... }\n+impl Writer for TcpStream { ... }\n+\n+impl Reader for Deadlined<TcpStream> { ... }\n+impl Writer for Deadlined<TcpStream> { ... }\n+\n+// TcpReader\n+\n+impl Reader for TcpReader { ... }\n+impl Reader for Deadlined<TcpReader> { ... }\n+\n+impl TcpReader {\n+    fn peer_addr(&mut self) -> IoResult<SocketAddr>;\n+    fn socket_addr(&mut self) -> IoResult<SocketAddr>;\n+\n+    fn shutdown_token(&mut self) -> ShutdownToken;\n+}\n+\n+// TcpWriter\n+\n+impl Writer for TcpWriter { ... }\n+impl Writer for Deadlined<TcpWriter> { ... }\n+\n+impl TcpWriter {\n+    fn peer_addr(&mut self) -> IoResult<SocketAddr>;\n+    fn socket_addr(&mut self) -> IoResult<SocketAddr>;\n+\n+    fn shutdown_token(&mut self) -> ShutdownToken;\n+}\n+\n+// ShutdownToken\n+\n+impl ShutdownToken {\n+    fn shutdown(self);\n+}\n+\n+impl Clone for ShutdownToken { ... }\n+```\n+\n+The idea is that a `TcpStream` provides both a reader and a writer,\n+and can be used directly as such, just as it can today. However, the\n+two sides can also be broken apart via the `split` method, which\n+allows them to be shipped off to separate threads. Moreover, each side\n+can yield a `ShutdownToken`, a `Clone` and `Send` value that can be\n+used to shut down that side of the socket, cancelling any in-progress\n+blocking operations, much like e.g. `close_read` does today.\n+\n+The implementation of the `ShutdownToken` infrastructure should ensure\n+that there is essentially no cost imposed when the feature is not used\n+-- in particular, if a `ShutdownToken` has not been requested, a\n+single `read` or `write` should correspond to a single syscall.\n+\n+For `TcpListener`, the only change is to rename `socket_name` to\n+`socket_addr`.\n+\n+For `TcpAcceptor` we will:\n+\n+* Add a `socket_addr` method.\n+* Possibly provide a convenience constructor for `bind`.\n+* Replace `close_accept` with `cancel_token()`.\n+* Remove `Clone`.\n+* Rename `IncomingConnecitons` to `Incoming`.\n+\n+#### UDP\n+[UDP]: #udp\n+\n+The UDP infrastructure should change to use the new deadline\n+infrastructure, but should not provide `Clone`, `ShutdownToken`s, or a\n+reader/writer split. In addition:\n+\n+* `recv_from` should become `recv`.","path":"text/0000-io-os-reform.md","position":1506,"original_position":1474,"commit_id":"8cb74e60dde678c3277e6d85280b4cc7d17bfe1a","original_commit_id":"6a19ab291616c4ea8ac6aa7b5a7ff89806a06746","user":{"login":"erickt","id":84711,"avatar_url":"https://avatars.githubusercontent.com/u/84711?v=3","gravatar_id":"","url":"https://api.github.com/users/erickt","html_url":"https://github.com/erickt","followers_url":"https://api.github.com/users/erickt/followers","following_url":"https://api.github.com/users/erickt/following{/other_user}","gists_url":"https://api.github.com/users/erickt/gists{/gist_id}","starred_url":"https://api.github.com/users/erickt/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/erickt/subscriptions","organizations_url":"https://api.github.com/users/erickt/orgs","repos_url":"https://api.github.com/users/erickt/repos","events_url":"https://api.github.com/users/erickt/events{/privacy}","received_events_url":"https://api.github.com/users/erickt/received_events","type":"User","site_admin":false},"body":"I've got some concern about renaming `send_to`/`recv_from` to `send`/`recv`, becuase that limits us from exposing the `send`/`recv` functions, allows for us to add special flags to the socket.\r\n\r\nI'd also like to mention again how nice it'd be to have support for `send_msg`/`recv_msg`/iovec support, but we can add that later :)","created_at":"2014-12-13T10:16:26Z","updated_at":"2014-12-13T10:16:26Z","html_url":"https://github.com/rust-lang/rfcs/pull/517#discussion_r21787370","pull_request_url":"https://api.github.com/repos/rust-lang/rfcs/pulls/517","_links":{"self":{"href":"https://api.github.com/repos/rust-lang/rfcs/pulls/comments/21787370"},"html":{"href":"https://github.com/rust-lang/rfcs/pull/517#discussion_r21787370"},"pull_request":{"href":"https://api.github.com/repos/rust-lang/rfcs/pulls/517"}}},"pull_request":{"url":"https://api.github.com/repos/rust-lang/rfcs/pulls/517","id":25954876,"html_url":"https://github.com/rust-lang/rfcs/pull/517","diff_url":"https://github.com/rust-lang/rfcs/pull/517.diff","patch_url":"https://github.com/rust-lang/rfcs/pull/517.patch","issue_url":"https://api.github.com/repos/rust-lang/rfcs/issues/517","number":517,"state":"open","locked":false,"title":"RFC: io and os reform","user":{"login":"aturon","id":709807,"avatar_url":"https://avatars.githubusercontent.com/u/709807?v=3","gravatar_id":"","url":"https://api.github.com/users/aturon","html_url":"https://github.com/aturon","followers_url":"https://api.github.com/users/aturon/followers","following_url":"https://api.github.com/users/aturon/following{/other_user}","gists_url":"https://api.github.com/users/aturon/gists{/gist_id}","starred_url":"https://api.github.com/users/aturon/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/aturon/subscriptions","organizations_url":"https://api.github.com/users/aturon/orgs","repos_url":"https://api.github.com/users/aturon/repos","events_url":"https://api.github.com/users/aturon/events{/privacy}","received_events_url":"https://api.github.com/users/aturon/received_events","type":"User","site_admin":false},"body":"This RFC proposes a significant redesign of the `std::io` and `std::os` modules\r\nin preparation for API stabilization. The specific problems addressed by the\r\nredesign are given in the Problems section below, and the key ideas of the\r\ndesign are given in Vision for IO.\r\n\r\n[Rendered](https://github.com/aturon/rfcs/blob/io-os-reform/text/0000-io-os-reform.md)","created_at":"2014-12-12T06:35:30Z","updated_at":"2014-12-13T10:16:26Z","closed_at":null,"merged_at":null,"merge_commit_sha":"8a469f4758d20d1918e020824945874157c9b318","assignee":{"login":"aturon","id":709807,"avatar_url":"https://avatars.githubusercontent.com/u/709807?v=3","gravatar_id":"","url":"https://api.github.com/users/aturon","html_url":"https://github.com/aturon","followers_url":"https://api.github.com/users/aturon/followers","following_url":"https://api.github.com/users/aturon/following{/other_user}","gists_url":"https://api.github.com/users/aturon/gists{/gist_id}","starred_url":"https://api.github.com/users/aturon/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/aturon/subscriptions","organizations_url":"https://api.github.com/users/aturon/orgs","repos_url":"https://api.github.com/users/aturon/repos","events_url":"https://api.github.com/users/aturon/events{/privacy}","received_events_url":"https://api.github.com/users/aturon/received_events","type":"User","site_admin":false},"milestone":null,"commits_url":"https://api.github.com/repos/rust-lang/rfcs/pulls/517/commits","review_comments_url":"https://api.github.com/repos/rust-lang/rfcs/pulls/517/comments","review_comment_url":"https://api.github.com/repos/rust-lang/rfcs/pulls/comments/{number}","comments_url":"https://api.github.com/repos/rust-lang/rfcs/issues/517/comments","statuses_url":"https://api.github.com/repos/rust-lang/rfcs/statuses/8cb74e60dde678c3277e6d85280b4cc7d17bfe1a","head":{"label":"aturon:io-os-reform","ref":"io-os-reform","sha":"8cb74e60dde678c3277e6d85280b4cc7d17bfe1a","user":{"login":"aturon","id":709807,"avatar_url":"https://avatars.githubusercontent.com/u/709807?v=3","gravatar_id":"","url":"https://api.github.com/users/aturon","html_url":"https://github.com/aturon","followers_url":"https://api.github.com/users/aturon/followers","following_url":"https://api.github.com/users/aturon/following{/other_user}","gists_url":"https://api.github.com/users/aturon/gists{/gist_id}","starred_url":"https://api.github.com/users/aturon/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/aturon/subscriptions","organizations_url":"https://api.github.com/users/aturon/orgs","repos_url":"https://api.github.com/users/aturon/repos","events_url":"https://api.github.com/users/aturon/events{/privacy}","received_events_url":"https://api.github.com/users/aturon/received_events","type":"User","site_admin":false},"repo":{"id":20423396,"name":"rfcs","full_name":"aturon/rfcs","owner":{"login":"aturon","id":709807,"avatar_url":"https://avatars.githubusercontent.com/u/709807?v=3","gravatar_id":"","url":"https://api.github.com/users/aturon","html_url":"https://github.com/aturon","followers_url":"https://api.github.com/users/aturon/followers","following_url":"https://api.github.com/users/aturon/following{/other_user}","gists_url":"https://api.github.com/users/aturon/gists{/gist_id}","starred_url":"https://api.github.com/users/aturon/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/aturon/subscriptions","organizations_url":"https://api.github.com/users/aturon/orgs","repos_url":"https://api.github.com/users/aturon/repos","events_url":"https://api.github.com/users/aturon/events{/privacy}","received_events_url":"https://api.github.com/users/aturon/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/aturon/rfcs","description":"RFCs for changes to Rust","fork":true,"url":"https://api.github.com/repos/aturon/rfcs","forks_url":"https://api.github.com/repos/aturon/rfcs/forks","keys_url":"https://api.github.com/repos/aturon/rfcs/keys{/key_id}","collaborators_url":"https://api.github.com/repos/aturon/rfcs/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/aturon/rfcs/teams","hooks_url":"https://api.github.com/repos/aturon/rfcs/hooks","issue_events_url":"https://api.github.com/repos/aturon/rfcs/issues/events{/number}","events_url":"https://api.github.com/repos/aturon/rfcs/events","assignees_url":"https://api.github.com/repos/aturon/rfcs/assignees{/user}","branches_url":"https://api.github.com/repos/aturon/rfcs/branches{/branch}","tags_url":"https://api.github.com/repos/aturon/rfcs/tags","blobs_url":"https://api.github.com/repos/aturon/rfcs/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/aturon/rfcs/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/aturon/rfcs/git/refs{/sha}","trees_url":"https://api.github.com/repos/aturon/rfcs/git/trees{/sha}","statuses_url":"https://api.github.com/repos/aturon/rfcs/statuses/{sha}","languages_url":"https://api.github.com/repos/aturon/rfcs/languages","stargazers_url":"https://api.github.com/repos/aturon/rfcs/stargazers","contributors_url":"https://api.github.com/repos/aturon/rfcs/contributors","subscribers_url":"https://api.github.com/repos/aturon/rfcs/subscribers","subscription_url":"https://api.github.com/repos/aturon/rfcs/subscription","commits_url":"https://api.github.com/repos/aturon/rfcs/commits{/sha}","git_commits_url":"https://api.github.com/repos/aturon/rfcs/git/commits{/sha}","comments_url":"https://api.github.com/repos/aturon/rfcs/comments{/number}","issue_comment_url":"https://api.github.com/repos/aturon/rfcs/issues/comments/{number}","contents_url":"https://api.github.com/repos/aturon/rfcs/contents/{+path}","compare_url":"https://api.github.com/repos/aturon/rfcs/compare/{base}...{head}","merges_url":"https://api.github.com/repos/aturon/rfcs/merges","archive_url":"https://api.github.com/repos/aturon/rfcs/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/aturon/rfcs/downloads","issues_url":"https://api.github.com/repos/aturon/rfcs/issues{/number}","pulls_url":"https://api.github.com/repos/aturon/rfcs/pulls{/number}","milestones_url":"https://api.github.com/repos/aturon/rfcs/milestones{/number}","notifications_url":"https://api.github.com/repos/aturon/rfcs/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/aturon/rfcs/labels{/name}","releases_url":"https://api.github.com/repos/aturon/rfcs/releases{/id}","created_at":"2014-06-02T23:35:56Z","updated_at":"2014-11-06T06:25:17Z","pushed_at":"2014-12-13T07:45:30Z","git_url":"git://github.com/aturon/rfcs.git","ssh_url":"git@github.com:aturon/rfcs.git","clone_url":"https://github.com/aturon/rfcs.git","svn_url":"https://github.com/aturon/rfcs","homepage":"","size":1600,"stargazers_count":2,"watchers_count":2,"language":null,"has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":2,"default_branch":"master"}},"base":{"label":"rust-lang:master","ref":"master","sha":"3436244877bbbe267d0e974a8155098a833c322b","user":{"login":"rust-lang","id":5430905,"avatar_url":"https://avatars.githubusercontent.com/u/5430905?v=3","gravatar_id":"","url":"https://api.github.com/users/rust-lang","html_url":"https://github.com/rust-lang","followers_url":"https://api.github.com/users/rust-lang/followers","following_url":"https://api.github.com/users/rust-lang/following{/other_user}","gists_url":"https://api.github.com/users/rust-lang/gists{/gist_id}","starred_url":"https://api.github.com/users/rust-lang/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/rust-lang/subscriptions","organizations_url":"https://api.github.com/users/rust-lang/orgs","repos_url":"https://api.github.com/users/rust-lang/repos","events_url":"https://api.github.com/users/rust-lang/events{/privacy}","received_events_url":"https://api.github.com/users/rust-lang/received_events","type":"Organization","site_admin":false},"repo":{"id":17527989,"name":"rfcs","full_name":"rust-lang/rfcs","owner":{"login":"rust-lang","id":5430905,"avatar_url":"https://avatars.githubusercontent.com/u/5430905?v=3","gravatar_id":"","url":"https://api.github.com/users/rust-lang","html_url":"https://github.com/rust-lang","followers_url":"https://api.github.com/users/rust-lang/followers","following_url":"https://api.github.com/users/rust-lang/following{/other_user}","gists_url":"https://api.github.com/users/rust-lang/gists{/gist_id}","starred_url":"https://api.github.com/users/rust-lang/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/rust-lang/subscriptions","organizations_url":"https://api.github.com/users/rust-lang/orgs","repos_url":"https://api.github.com/users/rust-lang/repos","events_url":"https://api.github.com/users/rust-lang/events{/privacy}","received_events_url":"https://api.github.com/users/rust-lang/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/rust-lang/rfcs","description":"RFCs for changes to Rust","fork":false,"url":"https://api.github.com/repos/rust-lang/rfcs","forks_url":"https://api.github.com/repos/rust-lang/rfcs/forks","keys_url":"https://api.github.com/repos/rust-lang/rfcs/keys{/key_id}","collaborators_url":"https://api.github.com/repos/rust-lang/rfcs/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/rust-lang/rfcs/teams","hooks_url":"https://api.github.com/repos/rust-lang/rfcs/hooks","issue_events_url":"https://api.github.com/repos/rust-lang/rfcs/issues/events{/number}","events_url":"https://api.github.com/repos/rust-lang/rfcs/events","assignees_url":"https://api.github.com/repos/rust-lang/rfcs/assignees{/user}","branches_url":"https://api.github.com/repos/rust-lang/rfcs/branches{/branch}","tags_url":"https://api.github.com/repos/rust-lang/rfcs/tags","blobs_url":"https://api.github.com/repos/rust-lang/rfcs/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/rust-lang/rfcs/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/rust-lang/rfcs/git/refs{/sha}","trees_url":"https://api.github.com/repos/rust-lang/rfcs/git/trees{/sha}","statuses_url":"https://api.github.com/repos/rust-lang/rfcs/statuses/{sha}","languages_url":"https://api.github.com/repos/rust-lang/rfcs/languages","stargazers_url":"https://api.github.com/repos/rust-lang/rfcs/stargazers","contributors_url":"https://api.github.com/repos/rust-lang/rfcs/contributors","subscribers_url":"https://api.github.com/repos/rust-lang/rfcs/subscribers","subscription_url":"https://api.github.com/repos/rust-lang/rfcs/subscription","commits_url":"https://api.github.com/repos/rust-lang/rfcs/commits{/sha}","git_commits_url":"https://api.github.com/repos/rust-lang/rfcs/git/commits{/sha}","comments_url":"https://api.github.com/repos/rust-lang/rfcs/comments{/number}","issue_comment_url":"https://api.github.com/repos/rust-lang/rfcs/issues/comments/{number}","contents_url":"https://api.github.com/repos/rust-lang/rfcs/contents/{+path}","compare_url":"https://api.github.com/repos/rust-lang/rfcs/compare/{base}...{head}","merges_url":"https://api.github.com/repos/rust-lang/rfcs/merges","archive_url":"https://api.github.com/repos/rust-lang/rfcs/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/rust-lang/rfcs/downloads","issues_url":"https://api.github.com/repos/rust-lang/rfcs/issues{/number}","pulls_url":"https://api.github.com/repos/rust-lang/rfcs/pulls{/number}","milestones_url":"https://api.github.com/repos/rust-lang/rfcs/milestones{/number}","notifications_url":"https://api.github.com/repos/rust-lang/rfcs/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/rust-lang/rfcs/labels{/name}","releases_url":"https://api.github.com/repos/rust-lang/rfcs/releases{/id}","created_at":"2014-03-07T21:29:00Z","updated_at":"2014-12-13T06:57:43Z","pushed_at":"2014-12-11T23:07:24Z","git_url":"git://github.com/rust-lang/rfcs.git","ssh_url":"git@github.com:rust-lang/rfcs.git","clone_url":"https://github.com/rust-lang/rfcs.git","svn_url":"https://github.com/rust-lang/rfcs","homepage":"","size":4802,"stargazers_count":193,"watchers_count":193,"language":null,"has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":129,"mirror_url":null,"open_issues_count":197,"forks":129,"open_issues":197,"watchers":193,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/rust-lang/rfcs/pulls/517"},"html":{"href":"https://github.com/rust-lang/rfcs/pull/517"},"issue":{"href":"https://api.github.com/repos/rust-lang/rfcs/issues/517"},"comments":{"href":"https://api.github.com/repos/rust-lang/rfcs/issues/517/comments"},"review_comments":{"href":"https://api.github.com/repos/rust-lang/rfcs/pulls/517/comments"},"review_comment":{"href":"https://api.github.com/repos/rust-lang/rfcs/pulls/comments/{number}"},"commits":{"href":"https://api.github.com/repos/rust-lang/rfcs/pulls/517/commits"},"statuses":{"href":"https://api.github.com/repos/rust-lang/rfcs/statuses/8cb74e60dde678c3277e6d85280b4cc7d17bfe1a"}}}}