{"action":"created","comment":{"url":"https://api.github.com/repos/google/protobuf/pulls/comments/72088345","id":72088345,"diff_hunk":"@@ -0,0 +1,674 @@\n+# Protocol Buffers in Swift\n+\n+## Objective\n+\n+This document describes the user-facing API and internal implementation of\n+proto2 and proto3 messages in Apple’s Swift programming language.\n+\n+One of the key goals of protobufs is to provide idiomatic APIs for each\n+language. In that vein, **interoperability with Objective-C is a non-goal of\n+this proposal.** Protobuf users who need to pass messages between Objective-C\n+and Swift code in the same application should use the existing Objective-C proto\n+library. The goal of the effort described here is to provide an API for protobuf\n+messages that uses features specific to Swift—optional types, algebraic\n+enumerated types, value types, and so forth—in a natural way that will delight,\n+rather than surprise, users of the language.\n+\n+## Naming\n+\n+*   By convention, both typical protobuf message names and Swift structs/classes\n+    are `UpperCamelCase`, so for most messages, the name of a message can be the\n+    same as the name of its generated type. (However, see the discussion below\n+    about prefixes under [Packages](#packages).)\n+\n+*   Enum cases in protobufs typically are `UPPERCASE_WITH_UNDERSCORES`, whereas\n+    in Swift they are `lowerCamelCase` (as of the Swift 3 API design\n+    guidelines). We will transform the names to match Swift convention, using\n+    a whitelist similar to the Objective-C compiler plugin to handle commonly\n+    used acronyms.\n+\n+*   Typical fields in proto messages are `lowercase_with_underscores`, while in\n+    Swift they are `lowerCamelCase`. We will transform the names to match\n+    Swift convention by removing the underscores and uppercasing the subsequent\n+    letter.\n+\n+## Swift reserved words\n+\n+Swift has a large set of reserved words—some always reserved and some\n+contextually reserved (that is, they can be used as identifiers in contexts\n+where they would not be confused). As of Swift 2.2, the set of always-reserved\n+words is:\n+\n+```\n+_, #available, #column, #else, #elseif, #endif, #file, #function, #if, #line,\n+#selector, as, associatedtype, break, case, catch, class, continue, default,\n+defer, deinit, do, dynamicType, else, enum, extension, fallthrough, false, for,\n+func, guard, if, import, in, init, inout, internal, is, let, nil, operator,\n+private, protocol, public, repeat, rethrows, return, self, Self, static,\n+struct, subscript, super, switch, throw, throws, true, try, typealias, var,\n+where, while\n+```\n+\n+The set of contextually reserved words is:\n+\n+```\n+associativity, convenience, dynamic, didSet, final, get, infix, indirect,\n+lazy, left, mutating, none, nonmutating, optional, override, postfix,\n+precedence, prefix, Protocol, required, right, set, Type, unowned, weak,\n+willSet\n+```\n+\n+It is possible to use any reserved word as an identifier by escaping it with\n+backticks (for example, ``let `class` = 5``). Other name-mangling schemes would\n+require us to transform the names themselves (for example, by appending an\n+underscore), which requires us to then ensure that the new name does not collide\n+with something else in the same namespace.\n+\n+While the backtick feature may not be widely known by all Swift developers, a\n+small amount of user education can address this and it seems like the best\n+approach. We can unconditionally surround all property names with backticks to\n+simplify generation.\n+\n+Some remapping will still be required, though, to avoid collisions between\n+generated properties and the names of methods and properties defined in the base\n+protocol/implementation of messages.\n+\n+# Features of Protocol Buffers\n+\n+This section describes how the features of the protocol buffer syntaxes (proto2\n+and proto3) map to features in Swift—what the code generated from a proto will\n+look like, and how it will be implemented in the underlying library.\n+\n+## Packages\n+\n+Modules are the main form of namespacing in Swift, but they are not declared\n+using syntactic constructs like namespaces in C++ or packages in Java. Instead,\n+they are tied to build targets in Xcode (or, in the future with open-source\n+Swift, declarations in a Swift Package Manager manifest). They also do not\n+easily support nesting submodules (Clang module maps support this, but pure\n+Swift does not yet provide a way to define submodules).\n+\n+We will generate types with fully-qualified underscore-delimited names. For\n+example, a message `Baz` in package `foo.bar` would generate a struct named\n+`Foo_Bar_Baz`. For each fully-qualified proto message, there will be exactly one\n+unique type symbol emitted in the generated binary.\n+\n+Users are likely to balk at the ugliness of underscore-delimited names for every\n+generated type. To improve upon this situation, we will add a new string file\n+level option, `swift_package_typealias`, that can be added to `.proto` files.\n+When present, this will cause `typealias`es to be added to the generated Swift\n+messages that replace the package name prefix with the provided string. For\n+example, the following `.proto` file:\n+\n+```protobuf\n+option swift_package_typealias = \"FBP\";\n+package foo.bar;\n+\n+message Baz {\n+  // Message fields\n+}\n+```\n+\n+would generate the following Swift source:\n+\n+```swift\n+public struct Foo_Bar_Baz {\n+  // Message fields and other methods\n+}\n+\n+typealias FBPBaz = Foo_Bar_Baz\n+```\n+\n+It should be noted that this type alias is recorded in the generated\n+`.swiftmodule` so that code importing the module can refer to it, but it does\n+not cause a new symbol to be generated in the compiled binary (i.e., we do not\n+risk compiled size bloat by adding `typealias`es for every type).\n+\n+Other strategies to handle packages that were considered and rejected can be\n+found in [Appendix A](#appendix-a-rejected-strategies-to-handle-packages).\n+\n+## Messages\n+\n+Proto messages are natural value types and we will generate messages as structs\n+instead of classes. Users will benefit from Swift’s built-in behavior with\n+regard to mutability. We will define a `ProtoMessage` protocol that defines the\n+common methods and properties for all messages (such as serialization) and also\n+lets users treat messages polymorphically. Any shared method implementations\n+that do not differ between individual messages can be implemented in a protocol\n+extension.\n+\n+The backing storage itself for fields of a message will be managed by a\n+`ProtoFieldStorage` type that uses an internal dictionary keyed by field number,\n+and whose values are the value of the field with that number (up-cast to Swift’s\n+`Any` type). This class will provide type-safe getters and setters so that\n+generated messages can manipulate this storage, and core serialization logic\n+will live here as well. Furthermore, factoring the storage out into a separate\n+type, rather than inlining the fields as stored properties in the message\n+itself, lets us implement copy-on-write efficiently to support passing around\n+large messages. (Furthermore, because the messages themselves are value types,\n+inlining fields is not possible if the fields are submessages of the same type,\n+or a type that eventually includes a submessage of the same type.)\n+\n+### Required fields (proto2 only)\n+\n+Required fields in proto2 messages seem like they could be naturally represented\n+by non-optional properties in Swift, but this presents some problems/concerns.\n+\n+Serialization APIs permit partial serialization, which allows required fields to\n+remain unset. Furthermore, other language APIs still provide `has*` and `clear*`\n+methods for required fields, and knowing whether a property has a value when the\n+message is in memory is still useful.\n+\n+For example, an e-mail draft message may have the “to” address required on the\n+wire, but when the user constructs it in memory, it doesn’t make sense to force\n+a value until they provide one. We only want to force a value to be present when\n+the message is serialized to the wire. Using non-optional properties prevents\n+this use case, and makes client usage awkward because the user would be forced\n+to select a sentinel or placeholder value for any required fields at the time\n+the message was created.\n+\n+### Default values\n+\n+In proto2, fields can have a default value specified that may be a value other\n+than the default value for its corresponding language type (for example, a\n+default value of 5 instead of 0 for an integer). When reading a field that is\n+not explicitly set, the user expects to get that value. This makes Swift\n+optionals (i.e., `Foo?`) unsuitable for fields in general. Unfortunately, we\n+cannot implement our own “enhanced optional” type without severely complicating\n+usage (Swift’s use of type inference and its lack of implicit conversions would\n+require manual unwrapping of every property value).\n+\n+Instead, we can use **implicitly unwrapped optionals.** For example, a property\n+generated for a field of type `int32` would have Swift type `Int32!`. These\n+properties would behave with the following characteristics, which mirror the\n+nil-resettable properties used elsewhere in Apple’s SDKs (for example,\n+`UIView.tintColor`):\n+\n+*   Assigning a non-nil value to a property sets the field to that value.\n+*   Assigning nil to a property clears the field (its internal representation is\n+    nilled out).\n+*   Reading the value of a property returns its value if it is set, or returns\n+    its default value if it is not set. Reading a property never returns nil.\n+\n+The final point in the list above implies that the optional cannot be checked to\n+determine if the field is set to a value other than its default: it will never\n+be nil. Instead, we must provide `has*` methods for each field to allow the user\n+to check this. These methods will be public in proto2. In proto3, these methods\n+will be private (if generated at all), since the user can test the returned\n+value against the zero value for that type.\n+\n+### Autocreation of nested messages\n+\n+For convenience, dotting into an unset field representing a nested message will\n+return an instance of that message with default values. As in the Objective-C\n+implementation, this does not actually cause the field to be set until the\n+returned message is mutated. Fortunately, thanks to the way mutability of value\n+types is implemented in Swift, the language automatically handles the\n+reassignment-on-mutation for us. A static singleton instance containing default\n+values can be associated with each message that can be returned when reading, so\n+copies are only made by the Swift runtime when mutation occurs. For example,\n+given the following proto:\n+\n+```protobuf\n+message Node {\n+  Node child = 1;\n+  string value = 2 [default = \"foo\"];\n+}\n+```\n+\n+The following Swift code would act as commented, where setting deeply nested\n+properties causes the copies and mutations to occur as the assignment statement\n+is unwound:\n+\n+```swift\n+var node = Node()\n+\n+let s = node.child.child.value\n+// 1. node.child returns the \"default Node\".\n+// 2. Reading .child on the result of (1) returns the same default Node.\n+// 3. Reading .value on the result of (2) returns the default value \"foo\".\n+\n+node.child.child.value = \"bar\"\n+// 4. Setting .value on the default Node causes a copy to be made and sets\n+//    the property on that copy. Subsequently, the language updates the\n+//    value of \"node.child.child\" to point to that copy.\n+// 5. Updating \"node.child.child\" in (4) requires another copy, because\n+//    \"node.child\" was also the instance of the default node. The copy is\n+//    assigned back to \"node.child\".\n+// 6. Setting \"node.child\" in (5) is a simple value reassignment, since\n+//    \"node\" is a mutable var.\n+```\n+\n+In other words, the generated messages do not internally have to manage parental\n+relationships to backfill the appropriate properties on mutation. Swift provides\n+this for free.\n+\n+## Scalar value fields\n+\n+Proto scalar value fields will map to Swift types in the following way:\n+\n+.proto Type | Swift Type\n+----------- | -------------------\n+`double`    | `Double`\n+`float`     | `Float`\n+`int32`     | `Int32`\n+`int64`     | `Int64`\n+`uint32`    | `UInt32`\n+`uint64`    | `UInt64`\n+`sint32`    | `Int32`\n+`sint64`    | `Int64`\n+`fixed32`   | `UInt32`\n+`fixed64`   | `UInt64`\n+`sfixed32`  | `Int32`\n+`sfixed64`  | `Int64`\n+`bool`      | `Bool`\n+`string`    | `String`\n+`bytes`     | `Foundation.NSData`\n+\n+The proto spec defines a number of integral types that map to the same Swift\n+type; for example, `intXX`, `sintXX`, and `sfixedXX` are all signed integers,\n+and `uintXX` and `fixedXX` are both unsigned integers. No other language\n+implementation distinguishes these further, so we do not do so either. The\n+rationale is that the various types only serve to distinguish how the value is\n+**encoded on the wire**; once loaded in memory, the user is not concerned about\n+these variations.\n+\n+Swift’s lack of implicit conversions among types will make it slightly annoying\n+to use these types in a context expecting an `Int`, or vice-versa, but since\n+this is a data-interchange format with explicitly-sized fields, we should not\n+hide that information from the user. Users will have to explicitly write\n+`Int(message.myField)`, for example.\n+\n+## Embedded message fields\n+\n+Embedded message fields can be represented using an optional variable of the\n+generated message type. Thus, the message\n+\n+```protobuf\n+message Foo {\n+  Bar bar = 1;\n+}\n+```\n+\n+would be represented in Swift as\n+\n+```swift\n+public struct Foo: ProtoMessage {\n+  public var bar: Bar! {\n+    get { ... }\n+    set { ... }\n+  }\n+}\n+```\n+\n+If the user explicitly sets `bar` to nil, or if it was never set when read from\n+the wire, retrieving the value of `bar` would return a default, statically\n+allocated instance of `Bar` containing default values for its fields. This\n+achieves the desired behavior for default values in the same way that scalar\n+fields are designed, and also allows users to deep-drill into complex object\n+graphs to get or set fields without checking for nil at each step.\n+\n+## Enum fields\n+\n+The design and implementation of enum fields will differ somewhat drastically\n+depending on whether the message being generated is a proto2 or proto3 message.\n+\n+### proto2 enums\n+\n+For proto2, we do not need to be concerned about unknown enum values, so we can\n+use the simple raw-value enum syntax provided by Swift. So the following enum in\n+proto2:\n+\n+```protobuf\n+enum ContentType {\n+  TEXT = 0;\n+  IMAGE = 1;\n+}\n+```\n+\n+would become this Swift enum:\n+\n+```swift\n+public enum ContentType: Int32, NilLiteralConvertible {\n+  case text = 0\n+  case image = 1\n+\n+  public init(nilLiteral: ()) {\n+    self = .text\n+  }\n+}\n+```\n+\n+See below for the discussion about `NilLiteralConvertible`.\n+\n+### proto3 enums\n+\n+For proto3, we need to be able to preserve unknown enum values that may come\n+across the wire so that they can be written back if unmodified. We can\n+accomplish this in Swift by using a case with an associated value for unknowns.\n+So the following enum in proto3:\n+\n+```protobuf\n+enum ContentType {\n+  TEXT = 0;\n+  IMAGE = 1;\n+}\n+```\n+\n+would become this Swift enum:\n+\n+```swift\n+public enum ContentType: RawRepresentable, NilLiteralConvertible {\n+  case text\n+  case image\n+  case UNKNOWN_VALUE(Int32)\n+\n+  public typealias RawValue = Int32\n+\n+  public init(nilLiteral: ()) {\n+    self = .text\n+  }\n+\n+  public init(rawValue: RawValue) {\n+    switch rawValue {\n+      case 0: self = .text\n+      case 1: self = .image\n+      default: self = .UNKNOWN_VALUE(rawValue)\n+  }\n+\n+  public var rawValue: RawValue {\n+    switch self {\n+      case .text: return 0\n+      case .image: return 1\n+      case .UNKNOWN_VALUE(let value): return value\n+    }\n+  }\n+}\n+```\n+\n+Note that the use of a parameterized case prevents us from inheriting from the\n+raw `Int32` type; Swift does not allow an enum with a raw type to have cases\n+with arguments. Instead, we must implement the raw value initializer and\n+computed property manually. The `UNKNOWN_VALUE` case is explicitly chosen to be\n+\"ugly\" so that it stands out and does not conflict with other possible case\n+names.\n+\n+Using this approach, proto3 consumers must always have a default case or handle\n+the `.UNKNOWN_VALUE` case to satisfy case exhaustion in a switch statement; the\n+Swift compiler considers it an error if switch statements are not exhaustive.\n+\n+### NilLiteralConvertible conformance\n+\n+This is required to clean up the usage of enum-typed properties in switch\n+statements. Unlike other field types, enum properties cannot be\n+implicitly-unwrapped optionals without requiring that uses in switch statements\n+be explicitly unwrapped. For example, if we consider a message with the enum\n+above, this usage will fail to compile:\n+\n+```swift\n+// Without NilLiteralConvertible conformance on ContentType\n+public struct SomeMessage: ProtoMessage {\n+  public var contentType: ContentType! { ... }\n+}\n+\n+// ERROR: no case named text or image\n+switch someMessage.contentType {\n+  case .text: { ... }\n+  case .image: { ... }\n+}\n+```\n+\n+Even though our implementation guarantees that `contentType` will never be nil,\n+if it is an optional type, its cases would be `some` and `none`, not the cases\n+of the underlying enum type. In order to use it in this context, the user must\n+write `someMessage.contentType!` in their switch statement.\n+\n+Making the enum itself `NilLiteralConvertible` permits us to make the property\n+non-optional, so the user can still set it to nil to clear it (i.e., reset it to\n+its default value), while eliminating the need to explicitly unwrap it in a\n+switch statement.\n+\n+```swift\n+// With NilLiteralConvertible conformance on ContentType\n+public struct SomeMessage: ProtoMessage {\n+  // Note that the property type is no longer optional\n+  public var contentType: ContentType { ... }\n+}\n+\n+// OK: Compiles and runs as expected\n+switch someMessage.contentType {\n+  case .text: { ... }\n+  case .image: { ... }\n+}\n+\n+// The enum can be reset to its default value this way\n+someMessage.contentType = nil\n+```\n+\n+One minor oddity with this approach is that nil will be auto-converted to the\n+default value of the enum in any context, not just field assignment. In other\n+words, this is valid:\n+\n+```swift\n+func foo(contentType: ContentType) { ... }\n+foo(nil) // Inside foo, contentType == .text\n+```\n+\n+That being said, the advantage of being able to simultaneously support\n+nil-resettability and switch-without-unwrapping outweighs this side effect,\n+especially if appropriately documented. It is our hope that a new form of\n+resettable properties will be added to Swift that eliminates this inconsistency.\n+Some community members have already drafted or sent proposals for review that\n+would benefit our designs:\n+\n+*   [SE-0030: Property Behaviors]\n+    (https://github.com/apple/swift-evolution/blob/master/proposals/0030-property-behavior-decls.md)\n+*   [Drafted: Resettable Properties]\n+    (https://github.com/patters/swift-evolution/blob/master/proposals/0000-resettable-properties.md)\n+\n+### Enum aliases\n+\n+The `allow_alias` option in protobuf slightly complicates the use of Swift enums\n+to represent that type, because raw values of cases in an enum must be unique.\n+Swift lets us define static variables in an enum that alias actual cases. For\n+example, the following protobuf enum:\n+\n+```protobuf\n+enum Foo {\n+  option allow_alias = true;\n+  BAR = 0;\n+  BAZ = 0;\n+}\n+```\n+\n+will be represented in Swift as:\n+\n+```swift\n+public enum Foo: Int32, NilLiteralConvertible {\n+  case bar = 0\n+  static public let baz = bar\n+\n+  // ... etc.\n+}\n+\n+// Can still use .baz shorthand to reference the alias in contexts\n+// where the type is inferred\n+```\n+\n+That is, we use the first name as the actual case and use static variables for\n+the other aliases. One drawback to this approach is that the static aliases\n+cannot be used as cases in a switch statement (the compiler emits the error\n+*“Enum case ‘baz’ not found in type ‘Foo’”*). However, in our own code bases,\n+there are only a few places where enum aliases are not mere renamings of an\n+older value, but they also don’t appear to be the type of value that one would\n+expect to switch on (for example, a group of named constants representing\n+metrics rather than a set of options), so this restriction is not significant.\n+\n+This strategy also implies that changing the name of an enum and adding the old\n+name as an alias below the new name will be a breaking change in the generated\n+Swift code.\n+\n+## Oneof types\n+\n+The `oneof` feature represents a “variant/union” data type that maps nicely to\n+Swift enums with associated values (algebraic types). These fields can also be\n+accessed independently though, and, specifically in the case of proto2, it’s\n+reasonable to expect access to default values when accessing a field that is not\n+explicitly set.\n+\n+Taking all this into account, we can represent a `oneof` in Swift with two sets\n+of constructs:\n+\n+*   Properties in the message that correspond to the `oneof` fields.\n+*   A nested enum named after the `oneof` and which provides the corresponding\n+    field values as case arguments.\n+\n+This approach fulfills the needs of proto consumers by providing a\n+Swift-idiomatic way of simultaneously checking which field is set and accessing\n+its value, providing individual properties to access the default values\n+(important for proto2), and safely allows a field to be moved into a `oneof`\n+without breaking clients.\n+\n+Consider the following proto:\n+\n+```protobuf\n+message MyMessage {\n+  oneof record {\n+    string name = 1 [default = \"unnamed\"];\n+    int32 id_number = 2 [default = 0];\n+  }\n+}\n+```\n+\n+In Swift, we would generate an enum, a property for that enum, and properties\n+for the fields themselves:\n+\n+```swift\n+public struct MyMessage: ProtoMessage {\n+  public enum Record: NilLiteralConvertible {\n+    case name(String)\n+    case idNumber(Int32)\n+    case NOT_SET\n+\n+    public init(nilLiteral: ()) { self = .NOT_SET }\n+  }\n+\n+  // This is the \"Swifty\" way of accessing the value\n+  public var record: Record { ... }\n+\n+  // Direct access to the underlying fields\n+  public var name: String! { ... }\n+  public var idNumber: Int32! { ... }\n+}\n+```\n+\n+This makes both usage patterns possible:\n+\n+```swift\n+// Usage 1: Case-based dispatch\n+switch message.record {\n+  case .name(let name):\n+    // Do something with name if it was explicitly set\n+  case .idNumber(let id):\n+    // Do something with id_number if it was explicitly set\n+  case .NOT_SET:\n+    // Do something if it’s not set\n+}\n+\n+// Usage 2: Direct access for default value fallback\n+// Sets the label text to the name if it was explicitly set, or to\n+// \"unnamed\" (the default value for the field) if id_number was set\n+// instead\n+let myLabel = UILabel()\n+myLabel.text = message.name\n+```\n+\n+As with proto enums, the generated `oneof` enum conforms to\n+`NilLiteralConvertible` to avoid switch statement issues. Setting the property\n+to nil will clear it (i.e., reset it to `NOT_SET`).\n+\n+## Unknown Fields (proto2 only)\n+\n+To be written.\n+\n+## Extensions (proto2 only)\n+\n+To be written.\n+\n+## Reflection and Descriptors\n+\n+We will not include reflection or descriptors in the first version of the Swift\n+library. The use cases for reflection on mobile are not as strong and the static\n+data to represent the descriptors would add bloat when we wish to keep the code\n+size small.","path":"docs/swift/DesignDoc.md","position":603,"original_position":603,"commit_id":"466916fe70e7d9e3b50045cafccd1c5ea4535b8a","original_commit_id":"466916fe70e7d9e3b50045cafccd1c5ea4535b8a","user":{"login":"allevato","id":1062427,"avatar_url":"https://avatars.githubusercontent.com/u/1062427?v=3","gravatar_id":"","url":"https://api.github.com/users/allevato","html_url":"https://github.com/allevato","followers_url":"https://api.github.com/users/allevato/followers","following_url":"https://api.github.com/users/allevato/following{/other_user}","gists_url":"https://api.github.com/users/allevato/gists{/gist_id}","starred_url":"https://api.github.com/users/allevato/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/allevato/subscriptions","organizations_url":"https://api.github.com/users/allevato/orgs","repos_url":"https://api.github.com/users/allevato/repos","events_url":"https://api.github.com/users/allevato/events{/privacy}","received_events_url":"https://api.github.com/users/allevato/received_events","type":"User","site_admin":false},"body":"I hadn't thought of using mirrors in this fashion, but now that you bring it up, it sounds compelling. Thanks—it's definitely something I'll explore.","created_at":"2016-07-25T15:41:33Z","updated_at":"2016-07-25T15:41:33Z","html_url":"https://github.com/google/protobuf/pull/1442#discussion_r72088345","pull_request_url":"https://api.github.com/repos/google/protobuf/pulls/1442","_links":{"self":{"href":"https://api.github.com/repos/google/protobuf/pulls/comments/72088345"},"html":{"href":"https://github.com/google/protobuf/pull/1442#discussion_r72088345"},"pull_request":{"href":"https://api.github.com/repos/google/protobuf/pulls/1442"}}},"pull_request":{"url":"https://api.github.com/repos/google/protobuf/pulls/1442","id":67428080,"html_url":"https://github.com/google/protobuf/pull/1442","diff_url":"https://github.com/google/protobuf/pull/1442.diff","patch_url":"https://github.com/google/protobuf/pull/1442.patch","issue_url":"https://api.github.com/repos/google/protobuf/issues/1442","number":1442,"state":"closed","locked":false,"title":"Add initial design document for Swift protocol buffers.","user":{"login":"allevato","id":1062427,"avatar_url":"https://avatars.githubusercontent.com/u/1062427?v=3","gravatar_id":"","url":"https://api.github.com/users/allevato","html_url":"https://github.com/allevato","followers_url":"https://api.github.com/users/allevato/followers","following_url":"https://api.github.com/users/allevato/following{/other_user}","gists_url":"https://api.github.com/users/allevato/gists{/gist_id}","starred_url":"https://api.github.com/users/allevato/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/allevato/subscriptions","organizations_url":"https://api.github.com/users/allevato/orgs","repos_url":"https://api.github.com/users/allevato/repos","events_url":"https://api.github.com/users/allevato/events{/privacy}","received_events_url":"https://api.github.com/users/allevato/received_events","type":"User","site_admin":false},"body":"","created_at":"2016-04-21T21:49:52Z","updated_at":"2016-07-25T15:41:33Z","closed_at":"2016-04-22T16:15:14Z","merged_at":"2016-04-22T16:15:14Z","merge_commit_sha":"385755e13bd1574c5ff7e00a0546547ba4546d41","assignee":{"login":"thomasvl","id":5279928,"avatar_url":"https://avatars.githubusercontent.com/u/5279928?v=3","gravatar_id":"","url":"https://api.github.com/users/thomasvl","html_url":"https://github.com/thomasvl","followers_url":"https://api.github.com/users/thomasvl/followers","following_url":"https://api.github.com/users/thomasvl/following{/other_user}","gists_url":"https://api.github.com/users/thomasvl/gists{/gist_id}","starred_url":"https://api.github.com/users/thomasvl/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/thomasvl/subscriptions","organizations_url":"https://api.github.com/users/thomasvl/orgs","repos_url":"https://api.github.com/users/thomasvl/repos","events_url":"https://api.github.com/users/thomasvl/events{/privacy}","received_events_url":"https://api.github.com/users/thomasvl/received_events","type":"User","site_admin":false},"assignees":[{"login":"thomasvl","id":5279928,"avatar_url":"https://avatars.githubusercontent.com/u/5279928?v=3","gravatar_id":"","url":"https://api.github.com/users/thomasvl","html_url":"https://github.com/thomasvl","followers_url":"https://api.github.com/users/thomasvl/followers","following_url":"https://api.github.com/users/thomasvl/following{/other_user}","gists_url":"https://api.github.com/users/thomasvl/gists{/gist_id}","starred_url":"https://api.github.com/users/thomasvl/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/thomasvl/subscriptions","organizations_url":"https://api.github.com/users/thomasvl/orgs","repos_url":"https://api.github.com/users/thomasvl/repos","events_url":"https://api.github.com/users/thomasvl/events{/privacy}","received_events_url":"https://api.github.com/users/thomasvl/received_events","type":"User","site_admin":false}],"milestone":null,"commits_url":"https://api.github.com/repos/google/protobuf/pulls/1442/commits","review_comments_url":"https://api.github.com/repos/google/protobuf/pulls/1442/comments","review_comment_url":"https://api.github.com/repos/google/protobuf/pulls/comments{/number}","comments_url":"https://api.github.com/repos/google/protobuf/issues/1442/comments","statuses_url":"https://api.github.com/repos/google/protobuf/statuses/466916fe70e7d9e3b50045cafccd1c5ea4535b8a","head":{"label":"allevato:master","ref":"master","sha":"466916fe70e7d9e3b50045cafccd1c5ea4535b8a","user":{"login":"allevato","id":1062427,"avatar_url":"https://avatars.githubusercontent.com/u/1062427?v=3","gravatar_id":"","url":"https://api.github.com/users/allevato","html_url":"https://github.com/allevato","followers_url":"https://api.github.com/users/allevato/followers","following_url":"https://api.github.com/users/allevato/following{/other_user}","gists_url":"https://api.github.com/users/allevato/gists{/gist_id}","starred_url":"https://api.github.com/users/allevato/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/allevato/subscriptions","organizations_url":"https://api.github.com/users/allevato/orgs","repos_url":"https://api.github.com/users/allevato/repos","events_url":"https://api.github.com/users/allevato/events{/privacy}","received_events_url":"https://api.github.com/users/allevato/received_events","type":"User","site_admin":false},"repo":{"id":56795235,"name":"protobuf","full_name":"allevato/protobuf","owner":{"login":"allevato","id":1062427,"avatar_url":"https://avatars.githubusercontent.com/u/1062427?v=3","gravatar_id":"","url":"https://api.github.com/users/allevato","html_url":"https://github.com/allevato","followers_url":"https://api.github.com/users/allevato/followers","following_url":"https://api.github.com/users/allevato/following{/other_user}","gists_url":"https://api.github.com/users/allevato/gists{/gist_id}","starred_url":"https://api.github.com/users/allevato/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/allevato/subscriptions","organizations_url":"https://api.github.com/users/allevato/orgs","repos_url":"https://api.github.com/users/allevato/repos","events_url":"https://api.github.com/users/allevato/events{/privacy}","received_events_url":"https://api.github.com/users/allevato/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/allevato/protobuf","description":"Protocol Buffers - Google's data interchange format","fork":true,"url":"https://api.github.com/repos/allevato/protobuf","forks_url":"https://api.github.com/repos/allevato/protobuf/forks","keys_url":"https://api.github.com/repos/allevato/protobuf/keys{/key_id}","collaborators_url":"https://api.github.com/repos/allevato/protobuf/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/allevato/protobuf/teams","hooks_url":"https://api.github.com/repos/allevato/protobuf/hooks","issue_events_url":"https://api.github.com/repos/allevato/protobuf/issues/events{/number}","events_url":"https://api.github.com/repos/allevato/protobuf/events","assignees_url":"https://api.github.com/repos/allevato/protobuf/assignees{/user}","branches_url":"https://api.github.com/repos/allevato/protobuf/branches{/branch}","tags_url":"https://api.github.com/repos/allevato/protobuf/tags","blobs_url":"https://api.github.com/repos/allevato/protobuf/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/allevato/protobuf/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/allevato/protobuf/git/refs{/sha}","trees_url":"https://api.github.com/repos/allevato/protobuf/git/trees{/sha}","statuses_url":"https://api.github.com/repos/allevato/protobuf/statuses/{sha}","languages_url":"https://api.github.com/repos/allevato/protobuf/languages","stargazers_url":"https://api.github.com/repos/allevato/protobuf/stargazers","contributors_url":"https://api.github.com/repos/allevato/protobuf/contributors","subscribers_url":"https://api.github.com/repos/allevato/protobuf/subscribers","subscription_url":"https://api.github.com/repos/allevato/protobuf/subscription","commits_url":"https://api.github.com/repos/allevato/protobuf/commits{/sha}","git_commits_url":"https://api.github.com/repos/allevato/protobuf/git/commits{/sha}","comments_url":"https://api.github.com/repos/allevato/protobuf/comments{/number}","issue_comment_url":"https://api.github.com/repos/allevato/protobuf/issues/comments{/number}","contents_url":"https://api.github.com/repos/allevato/protobuf/contents/{+path}","compare_url":"https://api.github.com/repos/allevato/protobuf/compare/{base}...{head}","merges_url":"https://api.github.com/repos/allevato/protobuf/merges","archive_url":"https://api.github.com/repos/allevato/protobuf/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/allevato/protobuf/downloads","issues_url":"https://api.github.com/repos/allevato/protobuf/issues{/number}","pulls_url":"https://api.github.com/repos/allevato/protobuf/pulls{/number}","milestones_url":"https://api.github.com/repos/allevato/protobuf/milestones{/number}","notifications_url":"https://api.github.com/repos/allevato/protobuf/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/allevato/protobuf/labels{/name}","releases_url":"https://api.github.com/repos/allevato/protobuf/releases{/id}","deployments_url":"https://api.github.com/repos/allevato/protobuf/deployments","created_at":"2016-04-21T18:04:14Z","updated_at":"2016-04-21T18:04:24Z","pushed_at":"2016-04-21T21:48:45Z","git_url":"git://github.com/allevato/protobuf.git","ssh_url":"git@github.com:allevato/protobuf.git","clone_url":"https://github.com/allevato/protobuf.git","svn_url":"https://github.com/allevato/protobuf","homepage":"https://developers.google.com/protocol-buffers/","size":31756,"stargazers_count":0,"watchers_count":0,"language":"C++","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":"google:master","ref":"master","sha":"034294bfb0e822e2f5dd09c016cc2beac6c31237","user":{"login":"google","id":1342004,"avatar_url":"https://avatars.githubusercontent.com/u/1342004?v=3","gravatar_id":"","url":"https://api.github.com/users/google","html_url":"https://github.com/google","followers_url":"https://api.github.com/users/google/followers","following_url":"https://api.github.com/users/google/following{/other_user}","gists_url":"https://api.github.com/users/google/gists{/gist_id}","starred_url":"https://api.github.com/users/google/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/google/subscriptions","organizations_url":"https://api.github.com/users/google/orgs","repos_url":"https://api.github.com/users/google/repos","events_url":"https://api.github.com/users/google/events{/privacy}","received_events_url":"https://api.github.com/users/google/received_events","type":"Organization","site_admin":false},"repo":{"id":23357588,"name":"protobuf","full_name":"google/protobuf","owner":{"login":"google","id":1342004,"avatar_url":"https://avatars.githubusercontent.com/u/1342004?v=3","gravatar_id":"","url":"https://api.github.com/users/google","html_url":"https://github.com/google","followers_url":"https://api.github.com/users/google/followers","following_url":"https://api.github.com/users/google/following{/other_user}","gists_url":"https://api.github.com/users/google/gists{/gist_id}","starred_url":"https://api.github.com/users/google/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/google/subscriptions","organizations_url":"https://api.github.com/users/google/orgs","repos_url":"https://api.github.com/users/google/repos","events_url":"https://api.github.com/users/google/events{/privacy}","received_events_url":"https://api.github.com/users/google/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/google/protobuf","description":"Protocol Buffers - Google's data interchange format","fork":false,"url":"https://api.github.com/repos/google/protobuf","forks_url":"https://api.github.com/repos/google/protobuf/forks","keys_url":"https://api.github.com/repos/google/protobuf/keys{/key_id}","collaborators_url":"https://api.github.com/repos/google/protobuf/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/google/protobuf/teams","hooks_url":"https://api.github.com/repos/google/protobuf/hooks","issue_events_url":"https://api.github.com/repos/google/protobuf/issues/events{/number}","events_url":"https://api.github.com/repos/google/protobuf/events","assignees_url":"https://api.github.com/repos/google/protobuf/assignees{/user}","branches_url":"https://api.github.com/repos/google/protobuf/branches{/branch}","tags_url":"https://api.github.com/repos/google/protobuf/tags","blobs_url":"https://api.github.com/repos/google/protobuf/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/google/protobuf/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/google/protobuf/git/refs{/sha}","trees_url":"https://api.github.com/repos/google/protobuf/git/trees{/sha}","statuses_url":"https://api.github.com/repos/google/protobuf/statuses/{sha}","languages_url":"https://api.github.com/repos/google/protobuf/languages","stargazers_url":"https://api.github.com/repos/google/protobuf/stargazers","contributors_url":"https://api.github.com/repos/google/protobuf/contributors","subscribers_url":"https://api.github.com/repos/google/protobuf/subscribers","subscription_url":"https://api.github.com/repos/google/protobuf/subscription","commits_url":"https://api.github.com/repos/google/protobuf/commits{/sha}","git_commits_url":"https://api.github.com/repos/google/protobuf/git/commits{/sha}","comments_url":"https://api.github.com/repos/google/protobuf/comments{/number}","issue_comment_url":"https://api.github.com/repos/google/protobuf/issues/comments{/number}","contents_url":"https://api.github.com/repos/google/protobuf/contents/{+path}","compare_url":"https://api.github.com/repos/google/protobuf/compare/{base}...{head}","merges_url":"https://api.github.com/repos/google/protobuf/merges","archive_url":"https://api.github.com/repos/google/protobuf/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/google/protobuf/downloads","issues_url":"https://api.github.com/repos/google/protobuf/issues{/number}","pulls_url":"https://api.github.com/repos/google/protobuf/pulls{/number}","milestones_url":"https://api.github.com/repos/google/protobuf/milestones{/number}","notifications_url":"https://api.github.com/repos/google/protobuf/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/google/protobuf/labels{/name}","releases_url":"https://api.github.com/repos/google/protobuf/releases{/id}","deployments_url":"https://api.github.com/repos/google/protobuf/deployments","created_at":"2014-08-26T15:52:15Z","updated_at":"2016-07-25T14:40:44Z","pushed_at":"2016-07-25T09:01:17Z","git_url":"git://github.com/google/protobuf.git","ssh_url":"git@github.com:google/protobuf.git","clone_url":"https://github.com/google/protobuf.git","svn_url":"https://github.com/google/protobuf","homepage":"https://developers.google.com/protocol-buffers/","size":61858,"stargazers_count":10357,"watchers_count":10357,"language":"C++","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":true,"forks_count":3126,"mirror_url":null,"open_issues_count":433,"forks":3126,"open_issues":433,"watchers":10357,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/google/protobuf/pulls/1442"},"html":{"href":"https://github.com/google/protobuf/pull/1442"},"issue":{"href":"https://api.github.com/repos/google/protobuf/issues/1442"},"comments":{"href":"https://api.github.com/repos/google/protobuf/issues/1442/comments"},"review_comments":{"href":"https://api.github.com/repos/google/protobuf/pulls/1442/comments"},"review_comment":{"href":"https://api.github.com/repos/google/protobuf/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/google/protobuf/pulls/1442/commits"},"statuses":{"href":"https://api.github.com/repos/google/protobuf/statuses/466916fe70e7d9e3b50045cafccd1c5ea4535b8a"}}}}
{"actor":{"display_login":"allevato"}}