{"action":"created","comment":{"url":"https://api.github.com/repos/rust-lang/rfcs/pulls/comments/100723872","pull_request_review_id":21435552,"id":100723872,"diff_hunk":"@@ -178,39 +190,489 @@ fn is_zero(v: Value) -> bool {\n }\n ```\n \n-Note that a pattern match on a union field that has a smaller size than the\n-entire union must not make any assumptions about the value of the union's\n-memory outside that field.  For example, if a union contains a `u8` and a\n-`u32`, matching on the `u8` may not perform a `u32`-sized comparison over the\n-entire union.\n+Since union fields share common storage, gaining write access to one\n+field of a union can give write access to all its remaining fields.\n+Borrow checking rules have to be adjusted to account for this fact.\n+As a result, if one field of a union is borrowed, all its remaining fields\n+are borrowed as well for the same lifetime.\n+\n+```rust\n+// ERROR: cannot borrow `u` (via `u.f2`) as mutable more than once at a time\n+fn test() {\n+    let mut u = MyUnion { f1: 1 };\n+    unsafe {\n+        let b1 = &mut u.f1;\n+                      ---- first mutable borrow occurs here (via `u.f1`)\n+        let b2 = &mut u.f2;\n+                      ^^^^ second mutable borrow occurs here (via `u.f2`)\n+        *b1 = 5;\n+    }\n+    - first borrow ends here\n+    assert_eq!(unsafe { u.f1 }, 5);\n+}\n+```\n+\n+As you could see, in many aspects (except for layouts, safety and ownership)\n+unions behave exactly like structs, largely as a consequence of inheriting their\n+syntactic shape from structs.  \n+This is also true for many unmentioned aspects of Rust language (such as\n+privacy, name resolution, type inference, generics, trait implementations,\n+inherent implementations, coherence, pattern checking, etc etc etc).\n+\n+>Unless some difference is explicitly mentioned in this or the next section,\n+behavior of a union should coincide with behavior of an equivalent struct.\n+\n+# Detailed design\n+\n+## Definitions\n+\n+### Union variant\n+\n+Same as union field. These two terms are further used interchangeably.\n+\n+### Trivially destructible type\n+\n+Either of the following:\n+\n+- primitive scalar type (including references) or `str`, or\n+- aggregate (including arrays and closures) having trivially destructible\n+component types and not implementing `Drop`, or\n+- union not implementing `Drop`, or\n+- anonymous type with `Copy` bound.\n+\n+If the type is trivially destructible, then dropping its value is a no-op and\n+doesn't require running any code.\n+\n+### Structural fragments\n+\n+Consider a struct or union type having some fields that, in their turn, have\n+their own nested fields.  \n+For brevity this example uses anonymous structs and unions which don't currently\n+exist in the language.\n+\n+```rust\n+s: struct {\n+    a: union {\n+        b: u8,\n+        c: struct {\n+            d: enum {\n+                A { x: u8 }\n+            },\n+            e: u8,\n+        },\n+        f: u8,\n+    },\n+    g: struct {\n+        h: &'static u8,\n+        i: (u8, u8),\n+    }\n+}\n+```\n+\n+The top level aggregate represents a tree-like hierarchical structure with\n+primitive indivisible leaf nodes (we consider enums indivisible and ignore\n+arrays for simplicity). Let's call subtrees of this tree structural fragments\n+(or, for brevity, simply fragments). Let's also define direct fragments (1 level\n+of nestedness) and leaf fragments (the indivisible ones).\n+\n+Borrow checker uses more complex fragments (it recurses into enums and\n+references), but these simplified fragments are good enough for\n+move/initialization checking and talking about guarantees for unions.\n+\n+In the example above `s.a` and `s.g` are direct fragments of `s`.  \n+`s.a.b`, `s.a.c.d`, `s.a.c.e`, `s.a.f`, `s.g.h`, `s.g.i.0` and `s.g.i.1` are\n+leaf fragments.\n+\n+See also [Delayed and unresolved questions](#delayed-and-unresolved-questions).\n+\n+### Active fragment and active field\n+\n+Active fragment of a union is its most recently assigned fragment that wasn't\n+a nested fragment of the previous active fragment.\n+\n+Active field of a union is its direct active fragment, if it exists.\n+\n+Example:\n+```rust\n+u: union {\n+    a: struct {\n+        x: u8,\n+        y: u8,\n+    },\n+    b: u8,\n+}\n+\n+u.b = 0; // b is the active fragment and field\n+u.a.x = 0; // a.x is the active fragment\n+u.a = 0; // a is the active fragment and field\n+u.a.y = 0; // a is still the active fragment and field\n+```\n+\n+In general case the active fragment/field is not known statically.\n+\n+See also [Delayed and unresolved questions](#delayed-and-unresolved-questions).\n+\n+### Initialization state\n+\n+A fragment can be either in initialized or uninitialized state.\n+This state is known statically and move checker will allow accesses only to\n+initialized fragments.\n+(For simplicity we will consider conditionally initialized fragments with\n+dynamic drop flags to be uninitialized.)\n+\n+If fragment has both initialized and uninitialized nested fragments then it's\n+still uninitialized (we call it partially (un)initialized) and accesses to this\n+fragment as a whole are prevented by move checker.  \n+If fragment has only initialized nested fragments then it's initialized as a\n+whole and can be accessed.  \n+If fragment has only uninitialized nested fragments then it's is uninitialized\n+as a whole and cannot be accessed.\n+\n+A fragment becomes initialized when it's assigned to, or created using\n+initializer, or it's a union field and its sibling becomes initialized,\n+or all its nested fragments become initialized.  \n+A fragment becomes uninitialized when it doesn't implement `Copy` and is moved\n+out from, or it's a union field (possibly `Copy`) and its sibling becomes\n+uninitialized, or some of its nested fragments becomes uninitialized.\n+\n+Example:\n+```\n+struct S {\n+    x: String,\n+    y: String,\n+}\n+\n+let mut s: S; // s, s.x, s.y are uninitialized\n+s.x = String::new(); // s.x is initialized, s and s.y are uninitialized\n+s.y = String::new(); // s, s.x, s.y are initialized\n+let x = s.x; // s.y is initialized, s and s.x are uninitialized\n+```\n+\n+NOTE: The \"fragment becomes initialized when all its nested fragments become\n+initialized\" rule is not currently implemented and the compiler accepts less\n+code than it should.\n+\n+## Union declaration\n+\n+Unions are declared using the same syntax as structures\n+\n+```rust\n+#[repr(C)]\n+#[derive(Copy, Clone)]\n+pub union MyUnion<T: Copy> where T: Debug {\n+    pub f1: u32,\n+    pub f2: f32,\n+    f3: T,\n+}\n+```\n+\n+except that tuple unions (`union U(u8, u16);`) and unit unions (`union U;`)\n+are not permitted.\n+\n+Empty unions with zero fields (`union U {}`) are permitted and equivalent to\n+uninhabited empty enums (`enum E {}`) following the\n+[\"enum with unknown discriminant\"](#towards-better-guarantees-enum-with-unknown-discriminant)\n+interpretation of unions.\n \n-## Borrowing union fields\n+### Contextual keyword\n \n-Unsafe code may borrow a reference to a field of a union; doing so borrows the\n-entire union, such that any borrow conflicting with a borrow of the union\n-(including a borrow of another union field or a borrow of a structure\n-containing the union) will produce an error.\n+`union` is not a keyword and can be used as identifier in all positions where\n+identifiers are permitted. For example:\n \n ```rust\n+fn union() {\n+    let union = 10;\n+    union;\n+    union as u8;\n+}\n+```\n+\n+`union` is treated as a start of union declaration only if it's found in item\n+position (possibly after `pub` and/or attributes) and is followed by a\n+non-keyword identifier (union name).  \n+This way it doesn't cause any ambiguities in the Rust grammar and can\n+be introduced without breaking any existing code that uses `union` as an\n+identifier.\n+\n+### Representation attributes\n+\n+Attributes `#[repr(C)]` and `#[repr(packed)]` are permitted on unions.\n+Attribute `#[repr(simd)]` is permitted on structs, but not on unions.\n+\n+Layouts of unions using `#[repr(C)]` are usually defined by ABI documents\n+provided by C compilers, or hardware vendors, or some standardization\n+groups.\n+\n+Typically, alignment of a union with `#[repr(C)]` is equal to the alignment of\n+its most aligned field, and size of a union is equal to the size of its largest\n+field rounded up to union alignment (so unions can have trailing padding).  \n+Note that those maximums may come from different fields; for instance:\n+\n+```rust\n+#[repr(C)]\n union U {\n-    f1: u32,\n-    f2: f32,\n+    f1: u16,\n+    f2: [u8; 4],\n+}\n+\n+fn main() {\n+    assert_eq!(std::mem::size_of<U>(), 4);\n+    assert_eq!(std::mem::align_of<U>(), 2);\n }\n+```\n+\n+Alignment of a union with `#[repr(C, packed)]` is typically equal to 1, and its\n+size is equal to the size of its largest field (so packed unions do not have\n+trailing padding).\n+\n+By default, if `#[repr(C)]` is not used, layout of a union is *unspecified*.\n+\n+Regardless of representation attributes, all the union fields and the union\n+itself are located at the same address in memory (pointers to them are equal).  \n+For `#[repr(C)]` unions this property is guaranteed by ISO C standards.\n+\n+### Dynamically sized fields\n+\n+Unions cannot contain fields with dynamically sized types like `[u8]` or\n+`Trait`.\n \n-#[test]\n+### Unions and `#[derive]`\n+\n+Unions support deriving a few traits that do not require accessing their fields.\n+Supported traits are\n+\n+- `Copy`, supported only for unions with `Copy` fields\n+- `Clone`, supported only for unions implementing `Copy`, which can be cloned\n+trivially\n+- `Eq` (but not `PartialEq`), supported for unions with `Eq` fields.\n+\n+Since accessing union fields reliably requires extra knowledge, traits trying to\n+do it (e.g. `PartialEq`) cannot be derived automatically.\n+\n+## Constructing union values\n+\n+A value of a union type can be created using the same syntax that is used for\n+struct types, except that it must specify exactly one field:\n+\n+```rust\n+let u = MyUnion { f1: 1 };\n+```\n+\n+This expression will create a value of type `MyUnion` with active field `f1`.  \n+Union expressions, unlike struct expressions, do not support functional record\n+update (FRU) `MyUnion { f1: 1, ..v }`.  \n+Note that creating a union with union expression is safe (no potentially\n+unreliable data is accessed) and therefore doesn't require `unsafe` block.\n+\n+Alternatively, a union can be created in uninitialized state and filled in\n+later.\n+```rust\n+let u: MyUnion;\n+u.f1 = 1; // u becomes initialized, f1 is the active field\n+          // NB: this is not actually implemented right now, but it should be\n+```\n+\n+## Accessing union fields\n+\n+### Field access (`.`)\n+\n+Union fields can be accessed using the same dot syntax as struct fields\n+```rust\n+unsafe {\n+    let a = u.f1;\n+    u.f2 = 1.0;\n+    fn_call(&u.f2);\n+}\n+```\n+\n+All accesses to union fields (both reads and writes, and also borrows) require\n+`unsafe` blocks.\n+The active field/fragment of a union can always be accessed safely, but\n+reads of inactive fields/fragments can result in undefined behavior (see\n+[Guarantees and undefined behavior](#guarantees-and-undefined-behavior) for\n+more detail).\n+\n+Write to a union field can potentially overwrite contents of its other fields.  \n+Write to a union field should not modify any bits outside of the modified field\n+(except for possibly by running destructor of the old field value).\n+\n+When a new value is assigned to a union field, the old value of the field is\n+dropped normally. This matches the behavior of `struct` fields, but differs\n+from assignments to the whole union, which ignore field destructors by default\n+(see [Unions and drop](#unions-and-drop) for more detail). Example:\n+\n+```rust\n+struct NoisyDrop;\n+impl Drop for NoisyDrop {\n+    fn drop(&mut self) {\n+        println!(\"BOOM!\");\n+    }\n+}\n+\n+union U {\n+    a: NoisyDrop\n+}\n+\n+fn main() {\n+    unsafe {\n+        let mut u = U { a: NoisyDrop };\n+        u.a = NoisyDrop; // BOOM!\n+        u = U { a: NoisyDrop }; // Silence\n+    }\n+}\n+```","path":"text/1444-union.md","position":580,"original_position":580,"commit_id":"e5266bd105f592f7408b8592c5c3deaccba7f1ec","original_commit_id":"e5266bd105f592f7408b8592c5c3deaccba7f1ec","user":{"login":"kennytm","id":103023,"avatar_url":"https://avatars.githubusercontent.com/u/103023?v=3","gravatar_id":"","url":"https://api.github.com/users/kennytm","html_url":"https://github.com/kennytm","followers_url":"https://api.github.com/users/kennytm/followers","following_url":"https://api.github.com/users/kennytm/following{/other_user}","gists_url":"https://api.github.com/users/kennytm/gists{/gist_id}","starred_url":"https://api.github.com/users/kennytm/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/kennytm/subscriptions","organizations_url":"https://api.github.com/users/kennytm/orgs","repos_url":"https://api.github.com/users/kennytm/repos","events_url":"https://api.github.com/users/kennytm/events{/privacy}","received_events_url":"https://api.github.com/users/kennytm/received_events","type":"User","site_admin":false},"body":"What happens when we write to an inactive field with `Drop`, UB due to a read? Unresolved question?\r\n\r\n```rust\r\nunion U {\r\n    a: NoisyDrop1,\r\n    b: NoisyDrop2,\r\n}\r\nfn main() {\r\n    unsafe {\r\n        let mut u = U { a: NoisyDrop1 };\r\n        u.b = NoisyDrop2;  // calls `NoisyDrop2::drop(&mut u.b)` (UB)? or something else?\r\n    }\r\n}\r\n```","created_at":"2017-02-13T04:46:26Z","updated_at":"2017-02-13T04:50:04Z","html_url":"https://github.com/rust-lang/rfcs/pull/1897#discussion_r100723872","pull_request_url":"https://api.github.com/repos/rust-lang/rfcs/pulls/1897","_links":{"self":{"href":"https://api.github.com/repos/rust-lang/rfcs/pulls/comments/100723872"},"html":{"href":"https://github.com/rust-lang/rfcs/pull/1897#discussion_r100723872"},"pull_request":{"href":"https://api.github.com/repos/rust-lang/rfcs/pulls/1897"}}},"pull_request":{"url":"https://api.github.com/repos/rust-lang/rfcs/pulls/1897","id":105809364,"html_url":"https://github.com/rust-lang/rfcs/pull/1897","diff_url":"https://github.com/rust-lang/rfcs/pull/1897.diff","patch_url":"https://github.com/rust-lang/rfcs/pull/1897.patch","issue_url":"https://api.github.com/repos/rust-lang/rfcs/issues/1897","number":1897,"state":"open","locked":false,"title":"Unions 1.2","user":{"login":"petrochenkov","id":5751617,"avatar_url":"https://avatars.githubusercontent.com/u/5751617?v=3","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 existing implementation, guarantees and tradeoffs are described in more detail.\r\nFuture directions are outlined.\r\nFew corner cases are permitted (empty unions, union patterns with zero fields and `..`).\r\n\r\nThis RFC also provides documentation necessary for stabilization of the feature.\r\nThe \"Overview\" section can be copy-pasted into the book and \"Detailed design\" into the reference.\r\n\r\nThe section about guarantees may be written a bit hastily, I just wanted to submit this today to start stabilization process for `Copy` unions.\r\n\r\n[Rendered](https://github.com/petrochenkov/rfcs/blob/8f1a960844b6ae37ec19fd89d39355fa98b1bb2b/text/1444-union.md)","created_at":"2017-02-12T22:20:22Z","updated_at":"2017-02-13T04:50:04Z","closed_at":null,"merged_at":null,"merge_commit_sha":"524b4f298d318f6945031439518462b83a99033c","assignee":null,"assignees":[],"milestone":null,"commits_url":"https://api.github.com/repos/rust-lang/rfcs/pulls/1897/commits","review_comments_url":"https://api.github.com/repos/rust-lang/rfcs/pulls/1897/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/1897/comments","statuses_url":"https://api.github.com/repos/rust-lang/rfcs/statuses/e5266bd105f592f7408b8592c5c3deaccba7f1ec","head":{"label":"petrochenkov:union2","ref":"union2","sha":"e5266bd105f592f7408b8592c5c3deaccba7f1ec","user":{"login":"petrochenkov","id":5751617,"avatar_url":"https://avatars.githubusercontent.com/u/5751617?v=3","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},"repo":{"id":39134748,"name":"rfcs","full_name":"petrochenkov/rfcs","owner":{"login":"petrochenkov","id":5751617,"avatar_url":"https://avatars.githubusercontent.com/u/5751617?v=3","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},"private":false,"html_url":"https://github.com/petrochenkov/rfcs","description":"RFCs for changes to Rust","fork":true,"url":"https://api.github.com/repos/petrochenkov/rfcs","forks_url":"https://api.github.com/repos/petrochenkov/rfcs/forks","keys_url":"https://api.github.com/repos/petrochenkov/rfcs/keys{/key_id}","collaborators_url":"https://api.github.com/repos/petrochenkov/rfcs/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/petrochenkov/rfcs/teams","hooks_url":"https://api.github.com/repos/petrochenkov/rfcs/hooks","issue_events_url":"https://api.github.com/repos/petrochenkov/rfcs/issues/events{/number}","events_url":"https://api.github.com/repos/petrochenkov/rfcs/events","assignees_url":"https://api.github.com/repos/petrochenkov/rfcs/assignees{/user}","branches_url":"https://api.github.com/repos/petrochenkov/rfcs/branches{/branch}","tags_url":"https://api.github.com/repos/petrochenkov/rfcs/tags","blobs_url":"https://api.github.com/repos/petrochenkov/rfcs/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/petrochenkov/rfcs/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/petrochenkov/rfcs/git/refs{/sha}","trees_url":"https://api.github.com/repos/petrochenkov/rfcs/git/trees{/sha}","statuses_url":"https://api.github.com/repos/petrochenkov/rfcs/statuses/{sha}","languages_url":"https://api.github.com/repos/petrochenkov/rfcs/languages","stargazers_url":"https://api.github.com/repos/petrochenkov/rfcs/stargazers","contributors_url":"https://api.github.com/repos/petrochenkov/rfcs/contributors","subscribers_url":"https://api.github.com/repos/petrochenkov/rfcs/subscribers","subscription_url":"https://api.github.com/repos/petrochenkov/rfcs/subscription","commits_url":"https://api.github.com/repos/petrochenkov/rfcs/commits{/sha}","git_commits_url":"https://api.github.com/repos/petrochenkov/rfcs/git/commits{/sha}","comments_url":"https://api.github.com/repos/petrochenkov/rfcs/comments{/number}","issue_comment_url":"https://api.github.com/repos/petrochenkov/rfcs/issues/comments{/number}","contents_url":"https://api.github.com/repos/petrochenkov/rfcs/contents/{+path}","compare_url":"https://api.github.com/repos/petrochenkov/rfcs/compare/{base}...{head}","merges_url":"https://api.github.com/repos/petrochenkov/rfcs/merges","archive_url":"https://api.github.com/repos/petrochenkov/rfcs/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/petrochenkov/rfcs/downloads","issues_url":"https://api.github.com/repos/petrochenkov/rfcs/issues{/number}","pulls_url":"https://api.github.com/repos/petrochenkov/rfcs/pulls{/number}","milestones_url":"https://api.github.com/repos/petrochenkov/rfcs/milestones{/number}","notifications_url":"https://api.github.com/repos/petrochenkov/rfcs/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/petrochenkov/rfcs/labels{/name}","releases_url":"https://api.github.com/repos/petrochenkov/rfcs/releases{/id}","deployments_url":"https://api.github.com/repos/petrochenkov/rfcs/deployments","created_at":"2015-07-15T12:09:11Z","updated_at":"2016-02-06T13:29:26Z","pushed_at":"2017-02-12T23:07:38Z","git_url":"git://github.com/petrochenkov/rfcs.git","ssh_url":"git@github.com:petrochenkov/rfcs.git","clone_url":"https://github.com/petrochenkov/rfcs.git","svn_url":"https://github.com/petrochenkov/rfcs","homepage":"","size":3593,"stargazers_count":0,"watchers_count":0,"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":0,"default_branch":"master"}},"base":{"label":"rust-lang:master","ref":"master","sha":"ee6347ea059f8622a0d6141aefeb3fcba33895fd","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}","deployments_url":"https://api.github.com/repos/rust-lang/rfcs/deployments","created_at":"2014-03-07T21:29:00Z","updated_at":"2017-02-12T04:44:32Z","pushed_at":"2017-02-12T23:07:39Z","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":3552,"stargazers_count":888,"watchers_count":888,"language":null,"has_issues":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":394,"mirror_url":null,"open_issues_count":696,"forks":394,"open_issues":696,"watchers":888,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/rust-lang/rfcs/pulls/1897"},"html":{"href":"https://github.com/rust-lang/rfcs/pull/1897"},"issue":{"href":"https://api.github.com/repos/rust-lang/rfcs/issues/1897"},"comments":{"href":"https://api.github.com/repos/rust-lang/rfcs/issues/1897/comments"},"review_comments":{"href":"https://api.github.com/repos/rust-lang/rfcs/pulls/1897/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/1897/commits"},"statuses":{"href":"https://api.github.com/repos/rust-lang/rfcs/statuses/e5266bd105f592f7408b8592c5c3deaccba7f1ec"}}}}
{"actor":{"display_login":"kennytm"}}