{"action":"created","comment":{"url":"https://api.github.com/repos/rust-lang-nursery/reference/pulls/comments/212265679","pull_request_review_id":148856915,"id":212265679,"node_id":"MDI0OlB1bGxSZXF1ZXN0UmV2aWV3Q29tbWVudDIxMjI2NTY3OQ==","diff_hunk":"@@ -1,24 +1,546 @@\n ## Procedural Macros\n \n *Procedural macros* allow creating syntax extensions as execution of a function.\n-Procedural macros can be used to implement custom [derive] on your own\n-types. See [the book][procedural macros] for a tutorial.\n+Procedural macros currently come in one of three flavors:\n \n-Procedural macros involve a few different parts of the language and its\n-standard libraries. First is the `proc_macro` crate, included with Rust,\n-that defines an interface for building a procedural macro. The\n-`#[proc_macro_derive(Foo)]` attribute is used to mark the deriving\n-function. This function must have the type signature:\n+* Custom macros - `my_macro!(...)`\n+* Custom derive - `#[derive(MyTrait)]`\n+* Custom attributes - `#[my_attribute]`\n+\n+Procedural macros allow you to run code at compile time that operates over Rust\n+syntax, both consuming and producing Rust syntax. You can sort of think of\n+procedural macros as Rust functions from an AST to another AST.\n+\n+### Crates and procedural macros\n+\n+All procedural macros in Rust are compiled as a crate. Procedural macro crates\n+are defined with Cargo via the `proc-macro` key in your manfiest:\n+\n+```toml\n+[lib]\n+proc-macro = true\n+```\n+\n+Procedural macros are always compiled with the same target as the compiler\n+itself. For example if you execute `cargo build --target\n+arm-unknown-linux-gnueabi` then procedural macros will not be compiled for ARM,\n+but rather your build computer (for example `x86_64-unknown-linux-gnu`).\n+\n+Procedural macro crates are not currently allowed to export any items except\n+procedural macros (we'll see how to define these in a bit). For example this\n+crate is not allowed:\n+\n+```rust\n+pub fn foo() {}\n+```\n+\n+because the `foo` function is not a procedural macro. Procedural macros are\n+loaded dynamically by the compiler when they are needed during compilation.\n+Cargo will naturally make procedural macro crates available to crates which\n+depend on them, or you can use the `--extern` argument.\n+\n+### The `proc_macro` crate\n+\n+Procedural macro crates almost always will link to the in-tree `proc_macro`\n+crate. The `proc_macro` crate is a compiler-provided crate which provides\n+facilities to working with the types of each procedural macro function. You can\n+learn more about this crate by exploring [the documentation][pm-dox].\n+\n+[pm-dox]: https://doc.rust-lang.org/stable/proc_macro/\n+\n+Linking to the `proc_macro` crate can currently be done with:\n \n ```rust,ignore\n-use proc_macro::TokenStream;\n+extern crate proc_macro;\n+```\n+\n+In the 2018 edition, however, this statement will not be necessary.\n+\n+### The `TokenStream` Type\n+\n+One aspect you may notice about the `proc_macro` crate is that it doesn't\n+contain any AST items! Instead, it primarily contains a `TokenStream` type.\n+Procedural macros in Rust operate over *token streams* instead of AST nodes,\n+which is a far more stable interface over time for both the compiler and for\n+procedural macros to target.\n+\n+A *token stream* is roughly equivalent to `Vec<TokenTree>` where a `TokenTree`\n+can roughly be thought of as lexical token. For example `foo` is an `Ident`\n+token, `.` is a `Punct` token, and `1.2` is a `Literal` token.\n+\n+To learn more about token streams, let's first dive into writing our first\n+procedural macro.\n+\n+### Procedural Bang Macros\n \n-#[proc_macro_derive(Hello)]\n-pub fn hello_world(input: TokenStream) -> TokenStream\n+The first kind of procedural macro is the \"procedural bang macro\" macro. This\n+flavor of procedural macro is like writing `macro_rules!` only you get to\n+execute arbitrary code over the input tokens instead of being limited to\n+`macro_rules!` syntax.\n+\n+Procedural bang macros are defined with the `#[proc_macro]` attribute and have\n+the following signature:\n+\n+```rust,ignore\n+#[proc_macro]\n+pub fn foo(x: TokenStream) -> TokenStream {\n+    // ...\n+}\n+```\n+\n+This item is defining a procedural bang macro (`#[proc_macro]`) which is called\n+`foo`. The first argument is the input to the macro which explore in a second,\n+and the return value is the tokens that it should expand to. Let's fill in all\n+the pieces here with a noop macro.\n+\n+First up, let's generate a skeleton project:\n+\n+```sh\n+$ cargo new foo\n+$ cd foo\n+$ cargo new my-macro --lib\n+$ echo 'my-macro = { path = \"my-macro\" }' >> Cargo.toml\n+$ echo '[lib]' >> my-macro/Cargo.toml\n+$ echo 'proc-macro = true' >> my-macro/Cargo.toml\n+```\n+\n+This'll set up a main binary project called `foo` along with a subcrate called\n+`my-macro` which is declared as a procedural macro. Next up we'll fill in:\n+\n+```rust,ignore\n+// my-macro/src/lib.rs\n+extern crate proc_macro;\n+\n+use proc_macro::*;\n+\n+#[proc_macro]\n+pub fn foo(x: TokenStream) -> TokenStream {\n+    x\n+}\n+```\n+\n+And now let's invoke it:\n+\n+```rust,ignore\n+// src/main.rs\n+extern crate my_macro;\n+\n+my_macro::foo!(fn answer() -> u32 { 3 });\n+\n+fn main() {\n+    println!(\"the answer was: {}\", answer());\n+}\n ```\n \n-Finally, procedural macros must be in their own crate, with the `proc-macro`\n-crate type.\n+and finally, build it!\n+\n+```sh\n+$ cargo run\n+   Compiling my-macro v0.1.0 (file://.../foo/my-macro)\n+   Compiling foo v0.1.0 (file://.../foo)\n+    Finished dev [unoptimized + debuginfo] target(s) in 0.37s\n+     Running `target/debug/foo`\n+the answer was: 3\n+```\n+\n+Alright! This end-to-end example shows how we can create a macro that doesn't\n+do anything, so let's do something a bit more useful.\n+\n+First up, let's see what the input to our macro looks like by modifying our\n+macro:\n+\n+```rust,ignore\n+// my-macro/src/lib.rs\n+#[proc_macro]\n+pub fn foo(x: TokenStream) -> TokenStream {\n+    println!(\"{:#?}\", x);\n+    x\n+}\n+```\n+\n+and reexecute (output edited slightly here):\n+\n+```sh\n+$ cargo run\n+   Compiling my-macro v0.1.0 (file://.../foo/my-macro)\n+   Compiling foo v0.1.0 (file://.../foo)\n+TokenStream [\n+    Ident { ident: \"fn\", span: #0 bytes(39..41) },\n+    Ident { ident: \"answer\", span: #0 bytes(42..48) },\n+    Group { delimiter: Parenthesis, stream: TokenStream [], span: #0 bytes(48..50) },\n+    Punct { ch: '-', spacing: Joint, span: #0 bytes(51..53) },\n+    Punct { ch: '>', spacing: Alone, span: #0 bytes(51..53) },\n+    Ident { ident: \"u32\", span: #0 bytes(54..57) },\n+    Group {\n+        delimiter: Brace,\n+        stream: TokenStream [\n+            Literal { lit: Integer(3), suffix: None, span: #0 bytes(60..61) }\n+        ],\n+        span: #0 bytes(58..63)\n+    }\n+]\n+    Finished dev [unoptimized + debuginfo] target(s) in 0.37s\n+     Running `target/debug/foo`\n+the answer was: 3\n+```\n+\n+Here we can see how a procedural bang macro's input is a token stream (list) of\n+all the tokens provided as input to the macro itself, excluding the delimiters\n+used to invoke the macro. Notice how the braces and parentheses are using the\n+`Group` token tree which is used to enforce that macros always have balanced\n+delimiters.\n+\n+As you may have guessed by now the macro invocation is effectively replaced by\n+the return value of the macro, creating the function that we provided as input.\n+We can see another example of this where we simply ignore the input:\n+\n+```rust,ignore\n+// my-macro/src/lib.rs\n+#[proc_macro]\n+pub fn foo(_x: TokenStream) -> TokenStream {\n+    \"fn answer() -> u32 { 4 }\".parse().unwrap()\n+}\n+```\n+\n+and recompiling shows:\n+\n+```sh\n+$ cargo run\n+   Compiling my-macro v0.1.0 (file://.../foo/my-macro)\n+   Compiling foo v0.1.0 (file://.../foo)\n+    Finished dev [unoptimized + debuginfo] target(s) in 0.37s\n+     Running `target/debug/foo`\n+the answer was: 4\n+```\n+\n+showing us how the input was ignored and the macro's output was used instead.\n+\n+### Custom Derive\n+\n+[The book][procedural macros] has a tutorial on creating custom derives and here\n+we'll go into some of the nitty-gritty of how this works. The custom derive\n+feature allows you to define a custom `#[derive(Foo)]` mode which often makes it\n+much easier to systematically implement traits, removing quite a lot of\n+boilerplate.\n+\n+Custom derives are defined like so:\n+\n+```rust,ignore\n+#[proc_macro_derive(MyTrait)]\n+pub fn foo(item: TokenStream) -> TokenStream {\n+    // ...\n+}\n+```\n+\n+Here the argument to the `proc_macro_derive` attribute, `MyTrait`, is the name\n+of the custom derive mode. The name of the function here, `foo`, is not\n+currently used (but it may one day be used).\n+\n+Like procedural bang macros the input to the macro here is the item that the\n+attribute was applied to. Unlike bang macros, however, the output is *appended*\n+to the program rather than replacing the item its attached to. We can see this\n+behavior by defining a macro like:\n+\n+```rust,ignore\n+extern crate proc_macro;\n+use proc_macro::*;\n+\n+#[proc_macro_derive(MyTrait)]\n+pub fn foo(item: TokenStream) -> TokenStream {\n+    println!(\"{:#?}\", item);\n+    \"fn answer() -> u32 { 2 }\".parse().unwrap()\n+}\n+```\n+\n+using it liek:\n+\n+```rust,ignore\n+extern crate my_macro;\n+\n+use my_macro::MyTrait;\n+\n+#[derive(MyTrait)]\n+struct Foo;\n+\n+fn main() {\n+    drop(Foo);\n+    println!(\"the answer was: {}\", answer());\n+}\n+```\n+\n+and compiling it:\n+\n+```sh\n+$ cargo run\n+   Compiling my-macro v0.1.0 (file://.../foo/my-macro)\n+   Compiling foo v0.1.0 (file://.../foo)\n+TokenStream [\n+    Ident { ident: \"struct\", span: #0 bytes(67..73) },\n+    Ident { ident: \"Foo\", span: #0 bytes(74..77) },\n+    Punct { ch: ';', spacing: Alone, span: #0 bytes(77..78) }\n+]\n+    Finished dev [unoptimized + debuginfo] target(s) in 0.34s\n+     Running `target/debug/foo`\n+the answer was: 2\n+```\n+\n+Here we can see how the input to the macro was a `TokenStream` representing\n+the three input tokens `struct Foo;`. While our output only contained the\n+`answer` function, we were still able to use `Foo` in the main program because\n+custom derives *append* items, they don't replace them.\n+\n+Now this is a pretty wonky custom derive, and would likely be confusing to\n+users! Custom derives are primarily geared towards implementing traits, like\n+`Serialize` and `Deserialize`. The `syn` crate also has a [number of\n+examples][synex] of defining custom derives.\n+\n+[procedural macros]: ../book/first-edition/procedural-macros.html\n+[synex]: https://github.com/dtolnay/syn/tree/master/examples\n+\n+#### Custom attributes on Custom derive\n+\n+An additional feature of custom derive macros is that they can whitelist names\n+of attributes which are considered not part of normal attribute macro expansion.\n+Taking our example from earlier we can define:\n+\n+```rust,ignore\n+#[proc_macro_derive(MyTrait, attributes(my_attribute))]\n+pub fn foo(item: TokenStream) -> TokenStream {\n+    // ...\n+}\n+```\n+\n+The extra `attributes` key in the `proc_macro_derive` attribute contains a\n+comma-separated list of identifiers. Each identifier is a whitelist of attributes\n+that can be attached to items which also have `#[derive(MyTrait)]`. The\n+attributes will not do anything but will be passed through to the `foo`\n+procedural macro defined above.\n+\n+If we change our invocation to look like:\n+\n+```rust,ignore\n+#[derive(MyTrait)]\n+#[my_attribute(hello)]\n+struct Foo;\n+```\n+\n+you'll see that the `#[my_attribute(hello)]` attribute is fed through to the\n+macro for processing.\n+\n+Custom attributes are often used to customize the behavior of custom derives,\n+such as the `#[serde]` attribute for the `serde` crate.\n+\n+### Custom attributes\n+\n+The third and final form of procedural macros is custom attributes. Custom\n+attributes allow you to define a custom `#[attr]`-style attribute which can be\n+attached to items and generate wrappers and such. These macros are defined like:\n+\n+```rust,ignore\n+#[proc_macro_attribute]\n+pub fn foo(attr: TokenStream, item: TokenStream) -> TokenStream {\n+    // ...\n+}\n+```\n+\n+The `#[proc_macro_attribute]` indicates that this macro is an attribute macro\n+and can only be invoked like `#[foo]`. The name of the function here will be the\n+name of the attribute as well.\n+\n+The first input, `attr`, is the arguments to the attribute provided, which\n+we'll see in a moment. The second argument, `item`, is the item that the\n+attribute is attached to.\n+\n+Like with procedural bang macros at the beginning (and unlike custom derive),\n+the return value here *replaces* the input `item`.\n+\n+Let's see this attribute in action:\n+\n+```rust,ignore\n+// my-macro/src/lib.rs\n+extern crate proc_macro;\n+use proc_macro::*;\n+\n+#[proc_macro_attribute]\n+pub fn foo(attr: TokenStream, item: TokenStream) -> TokenStream {\n+    println!(\"attr: {}\", attr.to_string());\n+    println!(\"item: {}\", item.to_string());\n+    item\n+}\n+```\n+\n+and invoke it as:\n+\n+```rust,ignore\n+// src/main.rs\n+extern crate my_macro;\n+\n+use my_macro::foo;\n+\n+#[foo]\n+fn invoke1() {}\n+\n+#[foo(bar)]\n+fn invoke2() {}\n+\n+#[foo(crazy custom syntax)]\n+fn invoke3() {}\n+\n+#[foo { delimiters }]\n+fn invoke4() {}\n+\n+fn main() {\n+    // ...\n+}\n+```\n+\n+compiled as:\n+\n+```sh\n+$ cargo run\n+   Compiling foo v0.1.0 (file://.../foo)\n+attr:\n+item: fn invoke1() { }\n+attr: bar\n+item: fn invoke2() { }\n+attr: crazy custom syntax\n+item: fn invoke3() { }\n+attr: delimiters\n+item: fn invoke4() { }\n+    Finished dev [unoptimized + debuginfo] target(s) in 0.12s\n+     Running `target/debug/foo`\n+```\n+\n+Here we can see how the arguments to the attribute show up in the `attr`\n+argument. Notably these arguments do not include the delimiters used to enclose\n+the arguments (like procedural bang macros. Furthermore we can see the item\n+continue to operate on it, either replacing it or augmenting it.\n+\n+### Spans\n+\n+All tokens have an associated `Span`. A `Span` is currently an opaque value you\n+cannot modify (but you can manufacture). `Span`s represent an extent of source\n+code within a program and are primarily used for error reporting currently. You\n+can modify the `Span` of any token, and by doing so if the compiler would like\n+to print an error for the token in question it'll use the `Span` that you\n+manufactured.\n+\n+For example let's create a wonky procedural macro which swaps the spans of the\n+first two tokens:\n+\n+```rust,ignore\n+// my-macro/src/lib.rs\n+extern crate proc_macro;\n+\n+use proc_macro::*;\n+\n+#[proc_macro]\n+pub fn swap_spans(x: TokenStream) -> TokenStream {\n+    let mut iter = x.into_iter();\n+    let mut a = iter.next().unwrap();\n+    let mut b = iter.next().unwrap();\n+    let a_span = a.span();\n+    a.set_span(b.span());\n+    b.set_span(a_span);\n+    return vec![a, b].into_iter().chain(iter).collect()\n+}\n+```\n+\n+We can see what's going on here by feeding invalid syntax into the macro and\n+seeing what the compiler reports. Let's start off by seeing what the compiler\n+does normally:\n+\n+```rust,ignore\n+// src/main.rs\n+fn _() {}\n+```\n+\n+is compiled as:\n+\n+```sh\n+$ cargo run\n+   Compiling foo v0.1.0 (file://.../foo)\n+error: expected identifier, found reserved identifier `_`\n+ --> src/main.rs:1:4\n+  |\n+1 | fn _() {}\n+  |    ^ expected identifier, found reserved identifier\n+\n+error: aborting due to previous error\n+```\n+\n+but when we feed it through our macro:\n+\n+```rust,ignore\n+extern crate my_macro;\n+\n+my_macro::swap_spans! {\n+    fn _() {}\n+}\n+\n+fn main() {}\n+```\n+\n+and compile it:\n+\n+```sh\n+$ cargo run\n+   Compiling foo v0.1.0 (file://.../foo)\n+error: expected identifier, found reserved identifier `_`\n+ --> src/main.rs:4:5\n+  |\n+4 |     fn _() {}\n+  |     ^^ expected identifier, found reserved identifier\n+\n+error: aborting due to previous error\n+```\n+\n+notice how the error message is pointing to the wrong span! This is because we\n+swapped the spans of the first two tokens, giving the compiler false information\n+about where the tokens came from.\n+\n+Controlling spans is quite a powerful feature and needs to be used with care,\n+misuse can lead to some excessively confusing error messages!\n+\n+### Procedural macros and hygiene\n+\n+Currently all procedural macros are \"unhygienic\". This means that all procedural\n+macros behave as if the output token stream was simply written inline to the\n+code it's next to. This means that it's affected by external items and also\n+affected by external imports and such.\n+\n+Macro authors need to be careful to ensure their macros work in as many contexts\n+as possible given this limitation. This often includes using absolute paths to\n+items in libraries (`::std::option::Option` instead of `Option`) or\n+by ensuring that generated functions have names that are unlikely to clash with\n+other functions (like `__internal_foo` instead of `foo`).\n+\n+Eventually more support for hygiene will be added to make it easier to write a\n+robust macro.\n+\n+### Limitations of procedural macros\n+\n+Procedural macros are not currently quite as powerful as `macro_rules!`-defined\n+macros in some respects. These limitations include:\n+\n+* Procedural bang macros can only be invoked in *item* contexts. For example you\n+  can't define your own `format!` yet because that's only ever invoked in an\n+  expression context. Put another way, procedural bang macros can only expand to\n+  items (things like functions, impls, etc), not expressions.\n+\n+  This is primarily due to the lack of hygiene with procedural macros. Once a\n+  better hygiene story is stabilized this restriction will likely be lifted.\n+\n+* Procedural macros cannot expand to definitions of `macro_rules!` macros (none","path":"src/procedural-macros.md","position":546,"original_position":546,"commit_id":"1156a3da44104d911e6b78a024b1a6402e0e0f45","original_commit_id":"1156a3da44104d911e6b78a024b1a6402e0e0f45","user":{"login":"petrochenkov","id":5751617,"node_id":"MDQ6VXNlcjU3NTE2MTc=","avatar_url":"https://avatars2.githubusercontent.com/u/5751617?v=4","gravatar_id":"","url":"https://api.github.com/users/petrochenkov","html_url":"https://github.com/petrochenkov","followers_url":"https://api.github.com/users/petrochenkov/followers","following_url":"https://api.github.com/users/petrochenkov/following{/other_user}","gists_url":"https://api.github.com/users/petrochenkov/gists{/gist_id}","starred_url":"https://api.github.com/users/petrochenkov/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/petrochenkov/subscriptions","organizations_url":"https://api.github.com/users/petrochenkov/orgs","repos_url":"https://api.github.com/users/petrochenkov/repos","events_url":"https://api.github.com/users/petrochenkov/events{/privacy}","received_events_url":"https://api.github.com/users/petrochenkov/received_events","type":"User","site_admin":false},"body":"The restriction was implemented much later than derives were stabilized (https://github.com/rust-lang/rust/pull/50820), so it was applied to fn-like macros and attribute macros to avoid breakage.\r\n\r\nSo macro_rules generated from derives do not produce immediate errors, but they can still be buggy and perhaps go through some breakage later with hygiene changes.","created_at":"2018-08-23T10:54:39Z","updated_at":"2018-08-23T10:54:39Z","html_url":"https://github.com/rust-lang-nursery/reference/pull/405#discussion_r212265679","pull_request_url":"https://api.github.com/repos/rust-lang-nursery/reference/pulls/405","author_association":"CONTRIBUTOR","_links":{"self":{"href":"https://api.github.com/repos/rust-lang-nursery/reference/pulls/comments/212265679"},"html":{"href":"https://github.com/rust-lang-nursery/reference/pull/405#discussion_r212265679"},"pull_request":{"href":"https://api.github.com/repos/rust-lang-nursery/reference/pulls/405"}},"in_reply_to_id":212160426},"pull_request":{"url":"https://api.github.com/repos/rust-lang-nursery/reference/pulls/405","id":210304536,"node_id":"MDExOlB1bGxSZXF1ZXN0MjEwMzA0NTM2","html_url":"https://github.com/rust-lang-nursery/reference/pull/405","diff_url":"https://github.com/rust-lang-nursery/reference/pull/405.diff","patch_url":"https://github.com/rust-lang-nursery/reference/pull/405.patch","issue_url":"https://api.github.com/repos/rust-lang-nursery/reference/issues/405","number":405,"state":"open","locked":false,"title":"Expand documentation on procedural macros","user":{"login":"alexcrichton","id":64996,"node_id":"MDQ6VXNlcjY0OTk2","avatar_url":"https://avatars1.githubusercontent.com/u/64996?v=4","gravatar_id":"","url":"https://api.github.com/users/alexcrichton","html_url":"https://github.com/alexcrichton","followers_url":"https://api.github.com/users/alexcrichton/followers","following_url":"https://api.github.com/users/alexcrichton/following{/other_user}","gists_url":"https://api.github.com/users/alexcrichton/gists{/gist_id}","starred_url":"https://api.github.com/users/alexcrichton/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/alexcrichton/subscriptions","organizations_url":"https://api.github.com/users/alexcrichton/orgs","repos_url":"https://api.github.com/users/alexcrichton/repos","events_url":"https://api.github.com/users/alexcrichton/events{/privacy}","received_events_url":"https://api.github.com/users/alexcrichton/received_events","type":"User","site_admin":false},"body":"In preparation for the 1.30 stabilization I figured I'd get started and help\r\nwrite some documentation!","created_at":"2018-08-23T01:10:29Z","updated_at":"2018-08-23T10:54:39Z","closed_at":null,"merged_at":null,"merge_commit_sha":"1bf36b4cfe1307a0309cbb0225821600b2468df9","assignee":null,"assignees":[],"requested_reviewers":[],"requested_teams":[],"labels":[],"milestone":null,"commits_url":"https://api.github.com/repos/rust-lang-nursery/reference/pulls/405/commits","review_comments_url":"https://api.github.com/repos/rust-lang-nursery/reference/pulls/405/comments","review_comment_url":"https://api.github.com/repos/rust-lang-nursery/reference/pulls/comments{/number}","comments_url":"https://api.github.com/repos/rust-lang-nursery/reference/issues/405/comments","statuses_url":"https://api.github.com/repos/rust-lang-nursery/reference/statuses/1156a3da44104d911e6b78a024b1a6402e0e0f45","head":{"label":"alexcrichton:macros","ref":"macros","sha":"1156a3da44104d911e6b78a024b1a6402e0e0f45","user":{"login":"alexcrichton","id":64996,"node_id":"MDQ6VXNlcjY0OTk2","avatar_url":"https://avatars1.githubusercontent.com/u/64996?v=4","gravatar_id":"","url":"https://api.github.com/users/alexcrichton","html_url":"https://github.com/alexcrichton","followers_url":"https://api.github.com/users/alexcrichton/followers","following_url":"https://api.github.com/users/alexcrichton/following{/other_user}","gists_url":"https://api.github.com/users/alexcrichton/gists{/gist_id}","starred_url":"https://api.github.com/users/alexcrichton/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/alexcrichton/subscriptions","organizations_url":"https://api.github.com/users/alexcrichton/orgs","repos_url":"https://api.github.com/users/alexcrichton/repos","events_url":"https://api.github.com/users/alexcrichton/events{/privacy}","received_events_url":"https://api.github.com/users/alexcrichton/received_events","type":"User","site_admin":false},"repo":{"id":85619607,"node_id":"MDEwOlJlcG9zaXRvcnk4NTYxOTYwNw==","name":"reference","full_name":"alexcrichton/reference","owner":{"login":"alexcrichton","id":64996,"node_id":"MDQ6VXNlcjY0OTk2","avatar_url":"https://avatars1.githubusercontent.com/u/64996?v=4","gravatar_id":"","url":"https://api.github.com/users/alexcrichton","html_url":"https://github.com/alexcrichton","followers_url":"https://api.github.com/users/alexcrichton/followers","following_url":"https://api.github.com/users/alexcrichton/following{/other_user}","gists_url":"https://api.github.com/users/alexcrichton/gists{/gist_id}","starred_url":"https://api.github.com/users/alexcrichton/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/alexcrichton/subscriptions","organizations_url":"https://api.github.com/users/alexcrichton/orgs","repos_url":"https://api.github.com/users/alexcrichton/repos","events_url":"https://api.github.com/users/alexcrichton/events{/privacy}","received_events_url":"https://api.github.com/users/alexcrichton/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/alexcrichton/reference","description":"The Rust Reference","fork":true,"url":"https://api.github.com/repos/alexcrichton/reference","forks_url":"https://api.github.com/repos/alexcrichton/reference/forks","keys_url":"https://api.github.com/repos/alexcrichton/reference/keys{/key_id}","collaborators_url":"https://api.github.com/repos/alexcrichton/reference/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/alexcrichton/reference/teams","hooks_url":"https://api.github.com/repos/alexcrichton/reference/hooks","issue_events_url":"https://api.github.com/repos/alexcrichton/reference/issues/events{/number}","events_url":"https://api.github.com/repos/alexcrichton/reference/events","assignees_url":"https://api.github.com/repos/alexcrichton/reference/assignees{/user}","branches_url":"https://api.github.com/repos/alexcrichton/reference/branches{/branch}","tags_url":"https://api.github.com/repos/alexcrichton/reference/tags","blobs_url":"https://api.github.com/repos/alexcrichton/reference/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/alexcrichton/reference/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/alexcrichton/reference/git/refs{/sha}","trees_url":"https://api.github.com/repos/alexcrichton/reference/git/trees{/sha}","statuses_url":"https://api.github.com/repos/alexcrichton/reference/statuses/{sha}","languages_url":"https://api.github.com/repos/alexcrichton/reference/languages","stargazers_url":"https://api.github.com/repos/alexcrichton/reference/stargazers","contributors_url":"https://api.github.com/repos/alexcrichton/reference/contributors","subscribers_url":"https://api.github.com/repos/alexcrichton/reference/subscribers","subscription_url":"https://api.github.com/repos/alexcrichton/reference/subscription","commits_url":"https://api.github.com/repos/alexcrichton/reference/commits{/sha}","git_commits_url":"https://api.github.com/repos/alexcrichton/reference/git/commits{/sha}","comments_url":"https://api.github.com/repos/alexcrichton/reference/comments{/number}","issue_comment_url":"https://api.github.com/repos/alexcrichton/reference/issues/comments{/number}","contents_url":"https://api.github.com/repos/alexcrichton/reference/contents/{+path}","compare_url":"https://api.github.com/repos/alexcrichton/reference/compare/{base}...{head}","merges_url":"https://api.github.com/repos/alexcrichton/reference/merges","archive_url":"https://api.github.com/repos/alexcrichton/reference/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/alexcrichton/reference/downloads","issues_url":"https://api.github.com/repos/alexcrichton/reference/issues{/number}","pulls_url":"https://api.github.com/repos/alexcrichton/reference/pulls{/number}","milestones_url":"https://api.github.com/repos/alexcrichton/reference/milestones{/number}","notifications_url":"https://api.github.com/repos/alexcrichton/reference/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/alexcrichton/reference/labels{/name}","releases_url":"https://api.github.com/repos/alexcrichton/reference/releases{/id}","deployments_url":"https://api.github.com/repos/alexcrichton/reference/deployments","created_at":"2017-03-20T19:52:15Z","updated_at":"2018-08-23T01:10:27Z","pushed_at":"2018-08-23T01:09:51Z","git_url":"git://github.com/alexcrichton/reference.git","ssh_url":"git@github.com:alexcrichton/reference.git","clone_url":"https://github.com/alexcrichton/reference.git","svn_url":"https://github.com/alexcrichton/reference","homepage":null,"size":2316,"stargazers_count":0,"watchers_count":0,"language":"CSS","has_issues":false,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"archived":false,"open_issues_count":0,"license":{"key":"other","name":"Other","spdx_id":null,"url":null,"node_id":"MDc6TGljZW5zZTA="},"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"rust-lang-nursery:master","ref":"master","sha":"c04a1d93e411e3fd00393f1936169a6b0e0c1f5b","user":{"login":"rust-lang-nursery","id":14631425,"node_id":"MDEyOk9yZ2FuaXphdGlvbjE0NjMxNDI1","avatar_url":"https://avatars1.githubusercontent.com/u/14631425?v=4","gravatar_id":"","url":"https://api.github.com/users/rust-lang-nursery","html_url":"https://github.com/rust-lang-nursery","followers_url":"https://api.github.com/users/rust-lang-nursery/followers","following_url":"https://api.github.com/users/rust-lang-nursery/following{/other_user}","gists_url":"https://api.github.com/users/rust-lang-nursery/gists{/gist_id}","starred_url":"https://api.github.com/users/rust-lang-nursery/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/rust-lang-nursery/subscriptions","organizations_url":"https://api.github.com/users/rust-lang-nursery/orgs","repos_url":"https://api.github.com/users/rust-lang-nursery/repos","events_url":"https://api.github.com/users/rust-lang-nursery/events{/privacy}","received_events_url":"https://api.github.com/users/rust-lang-nursery/received_events","type":"Organization","site_admin":false},"repo":{"id":83575374,"node_id":"MDEwOlJlcG9zaXRvcnk4MzU3NTM3NA==","name":"reference","full_name":"rust-lang-nursery/reference","owner":{"login":"rust-lang-nursery","id":14631425,"node_id":"MDEyOk9yZ2FuaXphdGlvbjE0NjMxNDI1","avatar_url":"https://avatars1.githubusercontent.com/u/14631425?v=4","gravatar_id":"","url":"https://api.github.com/users/rust-lang-nursery","html_url":"https://github.com/rust-lang-nursery","followers_url":"https://api.github.com/users/rust-lang-nursery/followers","following_url":"https://api.github.com/users/rust-lang-nursery/following{/other_user}","gists_url":"https://api.github.com/users/rust-lang-nursery/gists{/gist_id}","starred_url":"https://api.github.com/users/rust-lang-nursery/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/rust-lang-nursery/subscriptions","organizations_url":"https://api.github.com/users/rust-lang-nursery/orgs","repos_url":"https://api.github.com/users/rust-lang-nursery/repos","events_url":"https://api.github.com/users/rust-lang-nursery/events{/privacy}","received_events_url":"https://api.github.com/users/rust-lang-nursery/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/rust-lang-nursery/reference","description":"The Rust Reference","fork":false,"url":"https://api.github.com/repos/rust-lang-nursery/reference","forks_url":"https://api.github.com/repos/rust-lang-nursery/reference/forks","keys_url":"https://api.github.com/repos/rust-lang-nursery/reference/keys{/key_id}","collaborators_url":"https://api.github.com/repos/rust-lang-nursery/reference/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/rust-lang-nursery/reference/teams","hooks_url":"https://api.github.com/repos/rust-lang-nursery/reference/hooks","issue_events_url":"https://api.github.com/repos/rust-lang-nursery/reference/issues/events{/number}","events_url":"https://api.github.com/repos/rust-lang-nursery/reference/events","assignees_url":"https://api.github.com/repos/rust-lang-nursery/reference/assignees{/user}","branches_url":"https://api.github.com/repos/rust-lang-nursery/reference/branches{/branch}","tags_url":"https://api.github.com/repos/rust-lang-nursery/reference/tags","blobs_url":"https://api.github.com/repos/rust-lang-nursery/reference/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/rust-lang-nursery/reference/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/rust-lang-nursery/reference/git/refs{/sha}","trees_url":"https://api.github.com/repos/rust-lang-nursery/reference/git/trees{/sha}","statuses_url":"https://api.github.com/repos/rust-lang-nursery/reference/statuses/{sha}","languages_url":"https://api.github.com/repos/rust-lang-nursery/reference/languages","stargazers_url":"https://api.github.com/repos/rust-lang-nursery/reference/stargazers","contributors_url":"https://api.github.com/repos/rust-lang-nursery/reference/contributors","subscribers_url":"https://api.github.com/repos/rust-lang-nursery/reference/subscribers","subscription_url":"https://api.github.com/repos/rust-lang-nursery/reference/subscription","commits_url":"https://api.github.com/repos/rust-lang-nursery/reference/commits{/sha}","git_commits_url":"https://api.github.com/repos/rust-lang-nursery/reference/git/commits{/sha}","comments_url":"https://api.github.com/repos/rust-lang-nursery/reference/comments{/number}","issue_comment_url":"https://api.github.com/repos/rust-lang-nursery/reference/issues/comments{/number}","contents_url":"https://api.github.com/repos/rust-lang-nursery/reference/contents/{+path}","compare_url":"https://api.github.com/repos/rust-lang-nursery/reference/compare/{base}...{head}","merges_url":"https://api.github.com/repos/rust-lang-nursery/reference/merges","archive_url":"https://api.github.com/repos/rust-lang-nursery/reference/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/rust-lang-nursery/reference/downloads","issues_url":"https://api.github.com/repos/rust-lang-nursery/reference/issues{/number}","pulls_url":"https://api.github.com/repos/rust-lang-nursery/reference/pulls{/number}","milestones_url":"https://api.github.com/repos/rust-lang-nursery/reference/milestones{/number}","notifications_url":"https://api.github.com/repos/rust-lang-nursery/reference/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/rust-lang-nursery/reference/labels{/name}","releases_url":"https://api.github.com/repos/rust-lang-nursery/reference/releases{/id}","deployments_url":"https://api.github.com/repos/rust-lang-nursery/reference/deployments","created_at":"2017-03-01T16:21:06Z","updated_at":"2018-08-22T02:13:33Z","pushed_at":"2018-08-23T01:10:29Z","git_url":"git://github.com/rust-lang-nursery/reference.git","ssh_url":"git@github.com:rust-lang-nursery/reference.git","clone_url":"https://github.com/rust-lang-nursery/reference.git","svn_url":"https://github.com/rust-lang-nursery/reference","homepage":"https://doc.rust-lang.org/nightly/reference/","size":2310,"stargazers_count":75,"watchers_count":75,"language":"CSS","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":78,"mirror_url":null,"archived":false,"open_issues_count":81,"license":{"key":"other","name":"Other","spdx_id":null,"url":null,"node_id":"MDc6TGljZW5zZTA="},"forks":78,"open_issues":81,"watchers":75,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/rust-lang-nursery/reference/pulls/405"},"html":{"href":"https://github.com/rust-lang-nursery/reference/pull/405"},"issue":{"href":"https://api.github.com/repos/rust-lang-nursery/reference/issues/405"},"comments":{"href":"https://api.github.com/repos/rust-lang-nursery/reference/issues/405/comments"},"review_comments":{"href":"https://api.github.com/repos/rust-lang-nursery/reference/pulls/405/comments"},"review_comment":{"href":"https://api.github.com/repos/rust-lang-nursery/reference/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/rust-lang-nursery/reference/pulls/405/commits"},"statuses":{"href":"https://api.github.com/repos/rust-lang-nursery/reference/statuses/1156a3da44104d911e6b78a024b1a6402e0e0f45"}},"author_association":"MEMBER"}}
{"actor":{"display_login":"petrochenkov"}}