{"action":"created","comment":{"url":"https://api.github.com/repos/rust-lang/rust/pulls/comments/24745986","id":24745986,"diff_hunk":"@@ -1,588 +1,365 @@\n % Macros\n \n-# Introduction\n-\n-Functions are the primary tool that programmers can use to build abstractions.\n-Sometimes, however, programmers want to abstract over compile-time syntax\n-rather than run-time values.\n-Macros provide syntactic abstraction.\n-For an example of how this can be useful, consider the following two code fragments,\n-which both pattern-match on their input and both return early in one case,\n-doing nothing otherwise:\n-\n-~~~~\n-# enum T { SpecialA(u32), SpecialB(u32) }\n-# fn f() -> u32 {\n-# let input_1 = T::SpecialA(0);\n-# let input_2 = T::SpecialA(0);\n-match input_1 {\n-    T::SpecialA(x) => { return x; }\n-    _ => {}\n-}\n-// ...\n-match input_2 {\n-    T::SpecialB(x) => { return x; }\n-    _ => {}\n-}\n-# return 0;\n-# }\n-~~~~\n-\n-This code could become tiresome if repeated many times.\n-However, no function can capture its functionality to make it possible\n-to abstract the repetition away.\n-Rust's macro system, however, can eliminate the repetition. Macros are\n-lightweight custom syntax extensions, themselves defined using the\n-`macro_rules!` syntax extension. The following `early_return` macro captures\n-the pattern in the above code:\n-\n-~~~~\n-# enum T { SpecialA(u32), SpecialB(u32) }\n-# fn f() -> u32 {\n-# let input_1 = T::SpecialA(0);\n-# let input_2 = T::SpecialA(0);\n-macro_rules! early_return {\n-    ($inp:expr, $sp:path) => ( // invoke it like `(input_5, SpecialE)`\n-        match $inp {\n-            $sp(x) => { return x; }\n-            _ => {}\n-        }\n-    );\n-}\n-// ...\n-early_return!(input_1, T::SpecialA);\n-// ...\n-early_return!(input_2, T::SpecialB);\n-# return 0;\n-# }\n-# fn main() {}\n-~~~~\n-\n-Macros are defined in pattern-matching style: in the above example, the text\n-`($inp:expr, $sp:path)` that appears on the left-hand side of the `=>` is the\n-*macro invocation syntax*, a pattern denoting how to write a call to the\n-macro. The text on the right-hand side of the `=>`, beginning with `match\n-$inp`, is the *macro transcription syntax*: what the macro expands to.\n-\n-# Invocation syntax\n-\n-The macro invocation syntax specifies the syntax for the arguments to the\n-macro. It appears on the left-hand side of the `=>` in a macro definition. It\n-conforms to the following rules:\n-\n-1. It must be surrounded by parentheses.\n-2. `$` has special meaning (described below).\n-3. The `()`s, `[]`s, and `{}`s it contains must balance. For example, `([)` is\n-forbidden.\n-4. Some arguments can be followed only by a limited set of separators, to\n-avoid ambiguity (described below).\n-\n-Otherwise, the invocation syntax is free-form.\n-\n-To take a fragment of Rust code as an argument, write `$` followed by a name\n- (for use on the right-hand side), followed by a `:`, followed by a *fragment\n- specifier*. The fragment specifier denotes the sort of fragment to match. The\n- most common fragment specifiers are:\n-\n-* `ident` (an identifier, referring to a variable or item. Examples: `f`, `x`,\n-  `foo`.)\n-* `expr` (an expression. Examples: `2 + 2`; `if true then { 1 } else { 2 }`;\n-  `f(42)`.)\n-* `ty` (a type. Examples: `i32`, `Vec<(char, String)>`, `&T`.)\n-* `path` (a path to struct or enum variant. Example: `T::SpecialA`)\n-* `pat` (a pattern, usually appearing in a `match` or on the left-hand side of\n-  a declaration. Examples: `Some(t)`; `(17, 'a')`; `_`.)\n-* `block` (a sequence of actions. Example: `{ log(error, \"hi\"); return 12; }`)\n-\n-The parser interprets any token that's not preceded by a `$` literally. Rust's usual\n-rules of tokenization apply,\n-\n-So `($x:ident -> (($e:expr)))`, though excessively fancy, would designate a macro\n-that could be invoked like: `my_macro!(i->(( 2+2 )))`.\n-\n-To avoid ambiguity, macro invocation syntax must conform to the following rules:\n-\n-* `expr` must be followed by `=>`, `,` or `;`.\n-* `ty` and `path` must be followed by `=>`, `,`, `:`, `=`, `>` or `as`.\n-* `pat` must be followed by `=>`, `,` or `=`.\n-* `ident` and `block` can be followed by any token.\n-\n-## Invocation location\n-\n-A macro invocation may take the place of (and therefore expand to) an\n-expression, item, statement, or pattern.  The Rust parser will parse the macro\n-invocation as a \"placeholder\" for whichever syntactic form is appropriate for\n-the location.\n-\n-At expansion time, the output of the macro will be parsed as whichever of the\n-three nonterminals it stands in for. This means that a single macro might,\n-for example, expand to an item or an expression, depending on its arguments\n-(and cause a syntax error if it is called with the wrong argument for its\n-location). Although this behavior sounds excessively dynamic, it is known to\n-be useful under some circumstances.\n-\n-\n-# Transcription syntax\n-\n-The right-hand side of the `=>` follows the same rules as the left-hand side,\n-except that a `$` need only be followed by the name of the syntactic fragment\n-to transcribe into the macro expansion; its type need not be repeated.\n-\n-The right-hand side must be enclosed by delimiters, which the transcriber ignores.\n-Therefore `() => ((1,2,3))` is a macro that expands to a tuple expression,\n-`() => (let $x=$val)` is a macro that expands to a statement,\n-and `() => (1,2,3)` is a macro that expands to a syntax error\n-(since the transcriber interprets the parentheses on the right-hand-size as delimiters,\n-and `1,2,3` is not a valid Rust expression on its own).\n-\n-Except for permissibility of `$name` (and `$(...)*`, discussed below), the\n-right-hand side of a macro definition is ordinary Rust syntax. In particular,\n-macro invocations (including invocations of the macro currently being defined)\n-are permitted in expression, statement, and item locations. However, nothing\n-else about the code is examined or executed by the macro system; execution\n-still has to wait until run-time.\n-\n-## Interpolation location\n-\n-The interpolation `$argument_name` may appear in any location consistent with\n-its fragment specifier (i.e., if it is specified as `ident`, it may be used\n-anywhere an identifier is permitted).\n-\n-# Multiplicity\n-\n-## Invocation\n-\n-Going back to the motivating example, recall that `early_return` expanded into\n-a `match` that would `return` if the `match`'s scrutinee matched the\n-\"special case\" identifier provided as the second argument to `early_return`,\n-and do nothing otherwise. Now suppose that we wanted to write a\n-version of `early_return` that could handle a variable number of \"special\"\n-cases.\n-\n-The syntax `$(...)*` on the left-hand side of the `=>` in a macro definition\n-accepts zero or more occurrences of its contents. It works much\n-like the `*` operator in regular expressions. It also supports a\n-separator token (a comma-separated list could be written `$(...),*`), and `+`\n-instead of `*` to mean \"at least one\".\n-\n-~~~~\n-# enum T { SpecialA(u32), SpecialB(u32), SpecialC(u32), SpecialD(u32) }\n-# fn f() -> u32 {\n-# let input_1 = T::SpecialA(0);\n-# let input_2 = T::SpecialA(0);\n-macro_rules! early_return {\n-    ($inp:expr, [ $($sp:path),+ ]) => (\n-        match $inp {\n+By now you've learned about many of the tools Rust provides for abstracting and\n+reusing code.  These units of code reuse have a rich semantic structure.  For\n+example, functions have a type signature, type parameters have trait bounds,\n+and overloaded functions must belong to a particular trait.\n+\n+This structure means that Rust's core abstractions have powerful compile-time\n+correctness checking.  But this comes at the price of reduced flexibility.  If\n+you visually identify a pattern of repeated code, you may find it's difficult\n+or cumbersome to express that pattern as a generic function, a trait, or\n+anything else within Rust's semantics.\n+\n+Macros allow us to abstract at a *syntactic* level.  A macro invocation is\n+shorthand for an \"expanded\" syntactic form.  This expansion happens early in\n+compilation, before any static checking.  As a result, macros can capture many\n+patterns of code reuse that Rust's core abstractions cannot.\n+\n+The drawback is that macro-based code can be harder to understand, because\n+fewer of the built-in rules apply.  Like an ordinary function, a well-behaved\n+macro can be used without understanding its implementation.  However, it can be\n+difficult to design a well-behaved macro!  Additionally, compiler errors in\n+macro code are harder to interpret, because they describe problems in the\n+expanded code, not the source-level form that developers use.\n+\n+These drawbacks make macros something of a \"feature of last resort\".  That's\n+not to say that macros are bad; they are part of Rust because sometimes they're\n+needed for truly concise, well-abstracted code.  Just keep this tradeoff in\n+mind.\n+\n+# Defining a macro\n+\n+You may have seen the `vec!` macro, used to initialize a [vector][] with any\n+number of elements.\n+\n+[vector]: arrays-vectors-and-slices.html\n+\n+```rust\n+let x: Vec<u32> = vec![1, 2, 3];\n+# assert_eq!(&[1,2,3], &x);\n+```\n+\n+This can't be an ordinary function, because it takes any number of arguments.\n+But we can imagine it as syntactic shorthand for\n+\n+```rust\n+let x: Vec<u32> = {\n+    let mut temp_vec = Vec::new();\n+    temp_vec.push(1);\n+    temp_vec.push(2);\n+    temp_vec.push(3);\n+    temp_vec\n+};\n+# assert_eq!(&[1,2,3], &x);\n+```\n+\n+We can implement this shorthand, using a macro: [^actual]\n+\n+[^actual]: The actual definition of `vec!` in libcollections differs from the\n+           one presented here, for reasons of efficiency and reusability.  Some\n+           of these are mentioned in the [advanced macros chapter][].\n+\n+```rust\n+macro_rules! vec {\n+    ( $( $x:expr ),* ) => {\n+        {\n+            let mut temp_vec = Vec::new();\n             $(\n-                $sp(x) => { return x; }\n-            )+\n-            _ => {}\n+                temp_vec.push($x);\n+            )*\n+            temp_vec\n         }\n-    )\n-}\n-// ...\n-early_return!(input_1, [T::SpecialA,T::SpecialC,T::SpecialD]);\n-// ...\n-early_return!(input_2, [T::SpecialB]);\n-# return 0;\n-# }\n-# fn main() {}\n-~~~~\n-\n-### Transcription\n-\n-As the above example demonstrates, `$(...)*` is also valid on the right-hand\n-side of a macro definition. The behavior of `*` in transcription,\n-especially in cases where multiple `*`s are nested, and multiple different\n-names are involved, can seem somewhat magical and unintuitive at first. The\n-system that interprets them is called \"Macro By Example\". The two rules to\n-keep in mind are (1) the behavior of `$(...)*` is to walk through one \"layer\"\n-of repetitions for all of the `$name`s it contains in lockstep, and (2) each\n-`$name` must be under at least as many `$(...)*`s as it was matched against.\n-If it is under more, it'll be repeated, as appropriate.\n-\n-## Parsing limitations\n-\n-\n-For technical reasons, there are two limitations to the treatment of syntax\n-fragments by the macro parser:\n-\n-1. The parser will always parse as much as possible of a Rust syntactic\n-fragment. For example, if the comma were omitted from the syntax of\n-`early_return!` above, `input_1 [` would've been interpreted as the beginning\n-of an array index. In fact, invoking the macro would have been impossible.\n-2. The parser must have eliminated all ambiguity by the time it reaches a\n-`$name:fragment_specifier` declaration. This limitation can result in parse\n-errors when declarations occur at the beginning of, or immediately after,\n-a `$(...)*`. For example, the grammar `$($t:ty)* $e:expr` will always fail to\n-parse because the parser would be forced to choose between parsing `t` and\n-parsing `e`. Changing the invocation syntax to require a distinctive token in\n-front can solve the problem. In the above example, `$(T $t:ty)* E $e:exp`\n-solves the problem.\n-\n-# Macro argument pattern matching\n-\n-## Motivation\n-\n-Now consider code like the following:\n-\n-~~~~\n-# enum T1 { Good1(T2, u32), Bad1}\n-# struct T2 { body: T3 }\n-# enum T3 { Good2(u32), Bad2}\n-# fn f(x: T1) -> u32 {\n-match x {\n-    T1::Good1(g1, val) => {\n-        match g1.body {\n-            T3::Good2(result) => {\n-                // complicated stuff goes here\n-                return result + val;\n-            },\n-            _ => panic!(\"Didn't get good_2\")\n-        }\n-    }\n-    _ => return 0 // default value\n+    };\n }\n+# fn main() {\n+#     assert_eq!(&[1,2,3], &vec![1,2,3]);\n # }\n-# fn main() {}\n-~~~~\n-\n-All the complicated stuff is deeply indented, and the error-handling code is\n-separated from matches that fail. We'd like to write a macro that performs\n-a match, but with a syntax that suits the problem better. The following macro\n-can solve the problem:\n-\n-~~~~\n-macro_rules! biased_match {\n-    // special case: `let (x) = ...` is illegal, so use `let x = ...` instead\n-    ( ($e:expr) -> ($p:pat) else $err:stmt ;\n-      binds $bind_res:ident\n-    ) => (\n-        let $bind_res = match $e {\n-            $p => ( $bind_res ),\n-            _ => { $err }\n-        };\n-    );\n-    // more than one name; use a tuple\n-    ( ($e:expr) -> ($p:pat) else $err:stmt ;\n-      binds $( $bind_res:ident ),*\n-    ) => (\n-        let ( $( $bind_res ),* ) = match $e {\n-            $p => ( $( $bind_res ),* ),\n-            _ => { $err }\n-        };\n-    )\n-}\n+```\n \n-# enum T1 { Good1(T2, u32), Bad1}\n-# struct T2 { body: T3 }\n-# enum T3 { Good2(u32), Bad2}\n-# fn f(x: T1) -> u32 {\n-biased_match!((x)       -> (T1::Good1(g1, val)) else { return 0 };\n-              binds g1, val );\n-biased_match!((g1.body) -> (T3::Good2(result) )\n-                  else { panic!(\"Didn't get good_2\") };\n-              binds result );\n-// complicated stuff goes here\n-return result + val;\n-# }\n-# fn main() {}\n-~~~~\n-\n-This solves the indentation problem. But if we have a lot of chained matches\n-like this, we might prefer to write a single macro invocation. The input\n-pattern we want is clear:\n-\n-~~~~\n-# fn main() {}\n-# macro_rules! b {\n-    ( $( ($e:expr) -> ($p:pat) else $err:stmt ; )*\n-      binds $( $bind_res:ident ),*\n-    )\n-# => (0) }\n-~~~~\n-\n-However, it's not possible to directly expand to nested match statements. But\n-there is a solution.\n-\n-## The recursive approach to macro writing\n-\n-A macro may accept multiple different input grammars. The first one to\n-successfully match the actual argument to a macro invocation is the one that\n-\"wins\".\n-\n-In the case of the example above, we want to write a recursive macro to\n-process the semicolon-terminated lines, one-by-one. So, we want the following\n-input patterns:\n-\n-~~~~\n-# macro_rules! b {\n-    ( binds $( $bind_res:ident ),* )\n-# => (0) }\n-# fn main() {}\n-~~~~\n-\n-...and:\n-\n-~~~~\n-# fn main() {}\n-# macro_rules! b {\n-    (    ($e     :expr) -> ($p     :pat) else $err     :stmt ;\n-      $( ($e_rest:expr) -> ($p_rest:pat) else $err_rest:stmt ; )*\n-      binds  $( $bind_res:ident ),*\n-    )\n-# => (0) }\n-~~~~\n-\n-The resulting macro looks like this. Note that the separation into\n-`biased_match!` and `biased_match_rec!` occurs only because we have an outer\n-piece of syntax (the `let`) which we only want to transcribe once.\n-\n-~~~~\n-# fn main() {\n+Whoa, that's a lot of new syntax! Let's break it down.\n \n-macro_rules! biased_match_rec {\n-    // Handle the first layer\n-    (   ($e     :expr) -> ($p     :pat) else $err     :stmt ;\n-     $( ($e_rest:expr) -> ($p_rest:pat) else $err_rest:stmt ; )*\n-     binds $( $bind_res:ident ),*\n-    ) => (\n-        match $e {\n-            $p => {\n-                // Recursively handle the next layer\n-                biased_match_rec!($( ($e_rest) -> ($p_rest) else $err_rest ; )*\n-                                  binds $( $bind_res ),*\n-                )\n-            }\n-            _ => { $err }\n-        }\n-    );\n-    // Produce the requested values\n-    ( binds $( $bind_res:ident ),* ) => ( ($( $bind_res ),*) )\n-}\n+```ignore\n+macro_rules! vec { ... }\n+```\n \n-// Wrap the whole thing in a `let`.\n-macro_rules! biased_match {\n-    // special case: `let (x) = ...` is illegal, so use `let x = ...` instead\n-    ( $( ($e:expr) -> ($p:pat) else $err:stmt ; )*\n-      binds $bind_res:ident\n-    ) => (\n-        let $bind_res = biased_match_rec!(\n-            $( ($e) -> ($p) else $err ; )*\n-            binds $bind_res\n-        );\n-    );\n-    // more than one name: use a tuple\n-    ( $( ($e:expr) -> ($p:pat) else $err:stmt ; )*\n-      binds  $( $bind_res:ident ),*\n-    ) => (\n-        let ( $( $bind_res ),* ) = biased_match_rec!(\n-            $( ($e) -> ($p) else $err ; )*\n-            binds $( $bind_res ),*\n-        );\n-    )\n-}\n+This says we're defining a macro named `vec`, much as `fn vec` would define a\n+function named `vec`.  In prose, we informally write a macro's name with an\n+exclamation point, e.g. `vec!`.  The exclamation point is part of the\n+invocation syntax and serves to distinguish a macro from an ordinary function.\n \n+## Matching\n \n-# enum T1 { Good1(T2, u32), Bad1}\n-# struct T2 { body: T3 }\n-# enum T3 { Good2(u32), Bad2}\n-# fn f(x: T1) -> u32 {\n-biased_match!(\n-    (x)       -> (T1::Good1(g1, val)) else { return 0 };\n-    (g1.body) -> (T3::Good2(result) ) else { panic!(\"Didn't get Good2\") };\n-    binds val, result );\n-// complicated stuff goes here\n-return result + val;\n-# }\n-# }\n-~~~~\n-\n-This technique applies to many cases where transcribing a result all at once is not possible.\n-The resulting code resembles ordinary functional programming in some respects,\n-but has some important differences from functional programming.\n-\n-The first difference is important, but also easy to forget: the transcription\n-(right-hand) side of a `macro_rules!` rule is literal syntax, which can only\n-be executed at run-time. If a piece of transcription syntax does not itself\n-appear inside another macro invocation, it will become part of the final\n-program. If it is inside a macro invocation (for example, the recursive\n-invocation of `biased_match_rec!`), it does have the opportunity to affect\n-transcription, but only through the process of attempted pattern matching.\n-\n-The second, related, difference is that the evaluation order of macros feels\n-\"backwards\" compared to ordinary programming. Given an invocation\n-`m1!(m2!())`, the expander first expands `m1!`, giving it as input the literal\n-syntax `m2!()`. If it transcribes its argument unchanged into an appropriate\n-position (in particular, not as an argument to yet another macro invocation),\n-the expander will then proceed to evaluate `m2!()` (along with any other macro\n-invocations `m1!(m2!())` produced).\n+The macro is defined through a series of *rules*, which are pattern-matching\n+cases.  Above, we had\n \n-# Hygiene\n+```ignore\n+( $( $x:expr ),* ) => { ... };\n+```","path":"src/doc/trpl/macros.md","position":507,"original_position":507,"commit_id":"80e11976ddc2623e711c093fd4bcc952289ebba0","original_commit_id":"80e11976ddc2623e711c093fd4bcc952289ebba0","user":{"login":"steveklabnik","id":27786,"avatar_url":"https://avatars.githubusercontent.com/u/27786?v=3","gravatar_id":"","url":"https://api.github.com/users/steveklabnik","html_url":"https://github.com/steveklabnik","followers_url":"https://api.github.com/users/steveklabnik/followers","following_url":"https://api.github.com/users/steveklabnik/following{/other_user}","gists_url":"https://api.github.com/users/steveklabnik/gists{/gist_id}","starred_url":"https://api.github.com/users/steveklabnik/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/steveklabnik/subscriptions","organizations_url":"https://api.github.com/users/steveklabnik/orgs","repos_url":"https://api.github.com/users/steveklabnik/repos","events_url":"https://api.github.com/users/steveklabnik/events{/privacy}","received_events_url":"https://api.github.com/users/steveklabnik/received_events","type":"User","site_admin":false},"body":"it can be nice to use `#` so that you don't need the `ignore`, ","created_at":"2015-02-16T11:47:00Z","updated_at":"2015-02-16T11:47:00Z","html_url":"https://github.com/rust-lang/rust/pull/22393#discussion_r24745986","pull_request_url":"https://api.github.com/repos/rust-lang/rust/pulls/22393","_links":{"self":{"href":"https://api.github.com/repos/rust-lang/rust/pulls/comments/24745986"},"html":{"href":"https://github.com/rust-lang/rust/pull/22393#discussion_r24745986"},"pull_request":{"href":"https://api.github.com/repos/rust-lang/rust/pulls/22393"}}},"pull_request":{"url":"https://api.github.com/repos/rust-lang/rust/pulls/22393","id":29348893,"html_url":"https://github.com/rust-lang/rust/pull/22393","diff_url":"https://github.com/rust-lang/rust/pull/22393.diff","patch_url":"https://github.com/rust-lang/rust/pull/22393.patch","issue_url":"https://api.github.com/repos/rust-lang/rust/issues/22393","number":22393,"state":"open","locked":false,"title":"Rewrite the macros chapter","user":{"login":"kmcallister","id":444997,"avatar_url":"https://avatars.githubusercontent.com/u/444997?v=3","gravatar_id":"","url":"https://api.github.com/users/kmcallister","html_url":"https://github.com/kmcallister","followers_url":"https://api.github.com/users/kmcallister/followers","following_url":"https://api.github.com/users/kmcallister/following{/other_user}","gists_url":"https://api.github.com/users/kmcallister/gists{/gist_id}","starred_url":"https://api.github.com/users/kmcallister/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/kmcallister/subscriptions","organizations_url":"https://api.github.com/users/kmcallister/orgs","repos_url":"https://api.github.com/users/kmcallister/repos","events_url":"https://api.github.com/users/kmcallister/events{/privacy}","received_events_url":"https://api.github.com/users/kmcallister/received_events","type":"User","site_admin":false},"body":"This is a more introductory document, suitable for Part II.  The arcane details move to an \"Advanced macros\" chapter in Part III.","created_at":"2015-02-16T04:03:56Z","updated_at":"2015-02-16T11:47:00Z","closed_at":null,"merged_at":null,"merge_commit_sha":"1ef12a979d5eccead90e877362f19a37f6e555c2","assignee":{"login":"steveklabnik","id":27786,"avatar_url":"https://avatars.githubusercontent.com/u/27786?v=3","gravatar_id":"","url":"https://api.github.com/users/steveklabnik","html_url":"https://github.com/steveklabnik","followers_url":"https://api.github.com/users/steveklabnik/followers","following_url":"https://api.github.com/users/steveklabnik/following{/other_user}","gists_url":"https://api.github.com/users/steveklabnik/gists{/gist_id}","starred_url":"https://api.github.com/users/steveklabnik/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/steveklabnik/subscriptions","organizations_url":"https://api.github.com/users/steveklabnik/orgs","repos_url":"https://api.github.com/users/steveklabnik/repos","events_url":"https://api.github.com/users/steveklabnik/events{/privacy}","received_events_url":"https://api.github.com/users/steveklabnik/received_events","type":"User","site_admin":false},"milestone":null,"commits_url":"https://api.github.com/repos/rust-lang/rust/pulls/22393/commits","review_comments_url":"https://api.github.com/repos/rust-lang/rust/pulls/22393/comments","review_comment_url":"https://api.github.com/repos/rust-lang/rust/pulls/comments/{number}","comments_url":"https://api.github.com/repos/rust-lang/rust/issues/22393/comments","statuses_url":"https://api.github.com/repos/rust-lang/rust/statuses/80e11976ddc2623e711c093fd4bcc952289ebba0","head":{"label":"kmcallister:macros-chapter","ref":"macros-chapter","sha":"80e11976ddc2623e711c093fd4bcc952289ebba0","user":{"login":"kmcallister","id":444997,"avatar_url":"https://avatars.githubusercontent.com/u/444997?v=3","gravatar_id":"","url":"https://api.github.com/users/kmcallister","html_url":"https://github.com/kmcallister","followers_url":"https://api.github.com/users/kmcallister/followers","following_url":"https://api.github.com/users/kmcallister/following{/other_user}","gists_url":"https://api.github.com/users/kmcallister/gists{/gist_id}","starred_url":"https://api.github.com/users/kmcallister/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/kmcallister/subscriptions","organizations_url":"https://api.github.com/users/kmcallister/orgs","repos_url":"https://api.github.com/users/kmcallister/repos","events_url":"https://api.github.com/users/kmcallister/events{/privacy}","received_events_url":"https://api.github.com/users/kmcallister/received_events","type":"User","site_admin":false},"repo":{"id":11487393,"name":"rust","full_name":"kmcallister/rust","owner":{"login":"kmcallister","id":444997,"avatar_url":"https://avatars.githubusercontent.com/u/444997?v=3","gravatar_id":"","url":"https://api.github.com/users/kmcallister","html_url":"https://github.com/kmcallister","followers_url":"https://api.github.com/users/kmcallister/followers","following_url":"https://api.github.com/users/kmcallister/following{/other_user}","gists_url":"https://api.github.com/users/kmcallister/gists{/gist_id}","starred_url":"https://api.github.com/users/kmcallister/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/kmcallister/subscriptions","organizations_url":"https://api.github.com/users/kmcallister/orgs","repos_url":"https://api.github.com/users/kmcallister/repos","events_url":"https://api.github.com/users/kmcallister/events{/privacy}","received_events_url":"https://api.github.com/users/kmcallister/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/kmcallister/rust","description":"a safe, concurrent, practical language","fork":true,"url":"https://api.github.com/repos/kmcallister/rust","forks_url":"https://api.github.com/repos/kmcallister/rust/forks","keys_url":"https://api.github.com/repos/kmcallister/rust/keys{/key_id}","collaborators_url":"https://api.github.com/repos/kmcallister/rust/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/kmcallister/rust/teams","hooks_url":"https://api.github.com/repos/kmcallister/rust/hooks","issue_events_url":"https://api.github.com/repos/kmcallister/rust/issues/events{/number}","events_url":"https://api.github.com/repos/kmcallister/rust/events","assignees_url":"https://api.github.com/repos/kmcallister/rust/assignees{/user}","branches_url":"https://api.github.com/repos/kmcallister/rust/branches{/branch}","tags_url":"https://api.github.com/repos/kmcallister/rust/tags","blobs_url":"https://api.github.com/repos/kmcallister/rust/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/kmcallister/rust/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/kmcallister/rust/git/refs{/sha}","trees_url":"https://api.github.com/repos/kmcallister/rust/git/trees{/sha}","statuses_url":"https://api.github.com/repos/kmcallister/rust/statuses/{sha}","languages_url":"https://api.github.com/repos/kmcallister/rust/languages","stargazers_url":"https://api.github.com/repos/kmcallister/rust/stargazers","contributors_url":"https://api.github.com/repos/kmcallister/rust/contributors","subscribers_url":"https://api.github.com/repos/kmcallister/rust/subscribers","subscription_url":"https://api.github.com/repos/kmcallister/rust/subscription","commits_url":"https://api.github.com/repos/kmcallister/rust/commits{/sha}","git_commits_url":"https://api.github.com/repos/kmcallister/rust/git/commits{/sha}","comments_url":"https://api.github.com/repos/kmcallister/rust/comments{/number}","issue_comment_url":"https://api.github.com/repos/kmcallister/rust/issues/comments/{number}","contents_url":"https://api.github.com/repos/kmcallister/rust/contents/{+path}","compare_url":"https://api.github.com/repos/kmcallister/rust/compare/{base}...{head}","merges_url":"https://api.github.com/repos/kmcallister/rust/merges","archive_url":"https://api.github.com/repos/kmcallister/rust/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/kmcallister/rust/downloads","issues_url":"https://api.github.com/repos/kmcallister/rust/issues{/number}","pulls_url":"https://api.github.com/repos/kmcallister/rust/pulls{/number}","milestones_url":"https://api.github.com/repos/kmcallister/rust/milestones{/number}","notifications_url":"https://api.github.com/repos/kmcallister/rust/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/kmcallister/rust/labels{/name}","releases_url":"https://api.github.com/repos/kmcallister/rust/releases{/id}","created_at":"2013-07-17T20:58:11Z","updated_at":"2014-06-25T03:42:03Z","pushed_at":"2015-02-16T04:27:20Z","git_url":"git://github.com/kmcallister/rust.git","ssh_url":"git@github.com:kmcallister/rust.git","clone_url":"https://github.com/kmcallister/rust.git","svn_url":"https://github.com/kmcallister/rust","homepage":"http://www.rust-lang.org","size":234333,"stargazers_count":0,"watchers_count":0,"language":"Rust","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":0,"default_branch":"master"}},"base":{"label":"rust-lang:master","ref":"master","sha":"c5db290bf6df986a6acd5ce993f278c18e55ca37","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":724712,"name":"rust","full_name":"rust-lang/rust","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/rust","description":"a safe, concurrent, practical language","fork":false,"url":"https://api.github.com/repos/rust-lang/rust","forks_url":"https://api.github.com/repos/rust-lang/rust/forks","keys_url":"https://api.github.com/repos/rust-lang/rust/keys{/key_id}","collaborators_url":"https://api.github.com/repos/rust-lang/rust/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/rust-lang/rust/teams","hooks_url":"https://api.github.com/repos/rust-lang/rust/hooks","issue_events_url":"https://api.github.com/repos/rust-lang/rust/issues/events{/number}","events_url":"https://api.github.com/repos/rust-lang/rust/events","assignees_url":"https://api.github.com/repos/rust-lang/rust/assignees{/user}","branches_url":"https://api.github.com/repos/rust-lang/rust/branches{/branch}","tags_url":"https://api.github.com/repos/rust-lang/rust/tags","blobs_url":"https://api.github.com/repos/rust-lang/rust/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/rust-lang/rust/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/rust-lang/rust/git/refs{/sha}","trees_url":"https://api.github.com/repos/rust-lang/rust/git/trees{/sha}","statuses_url":"https://api.github.com/repos/rust-lang/rust/statuses/{sha}","languages_url":"https://api.github.com/repos/rust-lang/rust/languages","stargazers_url":"https://api.github.com/repos/rust-lang/rust/stargazers","contributors_url":"https://api.github.com/repos/rust-lang/rust/contributors","subscribers_url":"https://api.github.com/repos/rust-lang/rust/subscribers","subscription_url":"https://api.github.com/repos/rust-lang/rust/subscription","commits_url":"https://api.github.com/repos/rust-lang/rust/commits{/sha}","git_commits_url":"https://api.github.com/repos/rust-lang/rust/git/commits{/sha}","comments_url":"https://api.github.com/repos/rust-lang/rust/comments{/number}","issue_comment_url":"https://api.github.com/repos/rust-lang/rust/issues/comments/{number}","contents_url":"https://api.github.com/repos/rust-lang/rust/contents/{+path}","compare_url":"https://api.github.com/repos/rust-lang/rust/compare/{base}...{head}","merges_url":"https://api.github.com/repos/rust-lang/rust/merges","archive_url":"https://api.github.com/repos/rust-lang/rust/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/rust-lang/rust/downloads","issues_url":"https://api.github.com/repos/rust-lang/rust/issues{/number}","pulls_url":"https://api.github.com/repos/rust-lang/rust/pulls{/number}","milestones_url":"https://api.github.com/repos/rust-lang/rust/milestones{/number}","notifications_url":"https://api.github.com/repos/rust-lang/rust/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/rust-lang/rust/labels{/name}","releases_url":"https://api.github.com/repos/rust-lang/rust/releases{/id}","created_at":"2010-06-16T20:39:03Z","updated_at":"2015-02-16T10:39:18Z","pushed_at":"2015-02-16T10:35:23Z","git_url":"git://github.com/rust-lang/rust.git","ssh_url":"git@github.com:rust-lang/rust.git","clone_url":"https://github.com/rust-lang/rust.git","svn_url":"https://github.com/rust-lang/rust","homepage":"http://www.rust-lang.org","size":476830,"stargazers_count":9400,"watchers_count":9400,"language":"Rust","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":1799,"mirror_url":null,"open_issues_count":1957,"forks":1799,"open_issues":1957,"watchers":9400,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/rust-lang/rust/pulls/22393"},"html":{"href":"https://github.com/rust-lang/rust/pull/22393"},"issue":{"href":"https://api.github.com/repos/rust-lang/rust/issues/22393"},"comments":{"href":"https://api.github.com/repos/rust-lang/rust/issues/22393/comments"},"review_comments":{"href":"https://api.github.com/repos/rust-lang/rust/pulls/22393/comments"},"review_comment":{"href":"https://api.github.com/repos/rust-lang/rust/pulls/comments/{number}"},"commits":{"href":"https://api.github.com/repos/rust-lang/rust/pulls/22393/commits"},"statuses":{"href":"https://api.github.com/repos/rust-lang/rust/statuses/80e11976ddc2623e711c093fd4bcc952289ebba0"}}}}