|
| 1 | +This package is a copy-paste of protobuf v1.0.11 (https://github.com/dedis/protobuf/tree/v1.0.11). The package is |
| 2 | +copy-pasted here to remove dependency on the library since it will soon be deprecated. Below is the original README. |
| 3 | + |
| 4 | +# Reflection-based Protocol Buffers |
| 5 | + |
| 6 | +Package protobuf implements Protocol Buffers reflectively using Go types to |
| 7 | +define message formats. This approach provides convenience similar to Gob |
| 8 | +encoding, but with a widely-used and language-neutral wire format. |
| 9 | +For detailed API documentation see https://godoc.org/go.dedis.ch/protobuf. |
| 10 | +For general information on Protocol buffers see |
| 11 | +https://developers.google.com/protocol-buffers. |
| 12 | + |
| 13 | +## Features |
| 14 | + |
| 15 | +- Reflection-based encoding and decoding to/from protocol buffer wire format. |
| 16 | +- Use Go struct field tags to control protobuf fields (ID, optional/required, names). |
| 17 | +- Generate `.proto` files from Go structures. |
| 18 | +- Encode `time.Time` as an `sfixed64` UnixNano. |
| 19 | +- Support for enums. |
| 20 | + |
| 21 | +## Details |
| 22 | + |
| 23 | +In contrast with goprotobuf, this package does not require users to write or |
| 24 | +compile .proto files; you just define the message formats you want as Go |
| 25 | +struct types. Consider for example this example message format definition from |
| 26 | +the Protocol Buffers overview: |
| 27 | + |
| 28 | +```protobuf |
| 29 | +message Person { |
| 30 | + required string name = 1; |
| 31 | + required int32 id = 2; |
| 32 | + optional string email = 3; |
| 33 | +
|
| 34 | + enum PhoneType { |
| 35 | + MOBILE = 0; |
| 36 | + HOME = 1; |
| 37 | + WORK = 2; |
| 38 | + } |
| 39 | +
|
| 40 | + message PhoneNumber { |
| 41 | + required string number = 1; |
| 42 | + optional PhoneType type = 2; |
| 43 | + } |
| 44 | +
|
| 45 | + repeated PhoneNumber phone = 4; |
| 46 | +} |
| 47 | +``` |
| 48 | + |
| 49 | +The following Go type and const definitions express exactly the same format, |
| 50 | +for purposes of encoding and decoding with this protobuf package: |
| 51 | + |
| 52 | +```go |
| 53 | +type Person struct { |
| 54 | + Name string |
| 55 | + Id int32 |
| 56 | + Email *string |
| 57 | + Phone []PhoneNumber |
| 58 | +} |
| 59 | + |
| 60 | +type PhoneType uint32 |
| 61 | +const ( |
| 62 | + MobilePhone PhoneType = iota |
| 63 | + HomePhone |
| 64 | + WorkPhone |
| 65 | +) |
| 66 | + |
| 67 | +type PhoneNumber struct { |
| 68 | + Number string |
| 69 | + Type *PhoneType |
| 70 | +} |
| 71 | +``` |
| 72 | + |
| 73 | +To encode a message, you simply call the Encode() function |
| 74 | +with a pointer to the struct you wish to encode, and |
| 75 | +Encode() returns a []byte slice containing the protobuf-encoded struct: |
| 76 | + |
| 77 | +```go |
| 78 | +person := Person{...} |
| 79 | +buf := Encode(&person) |
| 80 | +output.Write(buf) |
| 81 | +``` |
| 82 | + |
| 83 | +To decode an encoded message, simply call Decode() on the byte-slice: |
| 84 | + |
| 85 | +```go |
| 86 | +err := Decode(buf,&person) |
| 87 | +if err != nil { |
| 88 | + panic("Decode failed: "+err.Error()) |
| 89 | +} |
| 90 | +``` |
| 91 | + |
| 92 | +If you want to interoperate with code in other languages |
| 93 | +using the same message formats, you may of course still end up writing |
| 94 | +.proto files for the code in those other languages. |
| 95 | + |
| 96 | +However, defining message formats with native Go types enables these types |
| 97 | +to be tailored to the code using them without affecting wire compatibility, |
| 98 | +such as by attaching useful methods to these struct types. |
| 99 | + |
| 100 | +## Translation Rules |
| 101 | + |
| 102 | +The translation between a Go struct definition and a basic Protocol Buffers |
| 103 | +message format definition is straightforward; the rules are as follows. |
| 104 | + |
| 105 | +Go [field tags](https://golang.org/ref/spec#Struct_types) with the key |
| 106 | +"protobuf" may be used to control naming, IDs, and optional/required state. |
| 107 | +The options are comma-separated like so: |
| 108 | + |
| 109 | +```go |
| 110 | +type Tags struct { |
| 111 | + Field1 string `protobuf:"10,req,field_1"` |
| 112 | + Field2 int32 `protobuf:"20,opt,field_2"` |
| 113 | +} |
| 114 | +``` |
| 115 | + |
| 116 | +A message definition in a .proto file translates to a Go struct, whose fields |
| 117 | +are implicitly assigned consecutive numbers starting from 1. |
| 118 | + |
| 119 | +```go |
| 120 | +type Padded struct { |
| 121 | + Field1 string // = 1 |
| 122 | + Field2 int32 `protobuf:"3"` // = 3 |
| 123 | +} |
| 124 | +``` |
| 125 | + |
| 126 | +A 'required' protobuf field translates to a plain field of a corresponding |
| 127 | +type in the Go struct. The following table summarizes the correspondence |
| 128 | +between .proto definition types and Go field types: |
| 129 | + |
| 130 | +Protobuf | Go |
| 131 | +----------|--------- |
| 132 | +bool | bool |
| 133 | +enum | Enum |
| 134 | +int32 | uint32 |
| 135 | +int64 | uint64 |
| 136 | +uint32 | uint32 |
| 137 | +uint64 | uint64 |
| 138 | +sint32 | int32 |
| 139 | +sint64 | int64 |
| 140 | +fixed32 | Ufixed32 |
| 141 | +fixed64 | Ufixed64 |
| 142 | +sfixed32 | Sfixed32 |
| 143 | +sfixed64 | Sfixed64 |
| 144 | +float | float32 |
| 145 | +double | float64 |
| 146 | +string | string |
| 147 | +bytes | []byte |
| 148 | +message | struct |
| 149 | + |
| 150 | +An 'optional' protobuf field is expressed as a pointer field in Go. |
| 151 | +Encode() will transmit the field only if the pointer is non-nil. |
| 152 | +Decode() will instantiate the pointed-to type and fill in the pointer |
| 153 | +if the field is present in the message being decoded, |
| 154 | +leaving the pointer unmodified (usually nil) if the field is not present. |
| 155 | + |
| 156 | +A 'repeated' protobuf field translates to a slice field in Go. |
| 157 | +Slices of primitive bool, integer, and float types are encoded |
| 158 | +and decoded in packed format, as if the [packed=true] option |
| 159 | +was declared for the field in the .proto file. |
| 160 | + |
| 161 | +For flexibility and convenience, struct fields may have interface types, |
| 162 | +which this package interprets as having dynamic types to be bound at runtime. |
| 163 | +Encode() follows the interface's implicit pointer and uses reflection |
| 164 | +to determine the referred-to object's actual type for encoding |
| 165 | +Decode() takes an optional map of interface types to constructor functions, |
| 166 | +which it uses to instantiate concrete types for interfaces while decoding. |
| 167 | +Furthermore, if the instantiated types support the Encoding interface, |
| 168 | +Encode() and Decode() will invoke the methods of that interface, |
| 169 | +allowing objects to implement their own custom encoding/decoding methods. |
| 170 | + |
| 171 | +This package does not try to support all possible protobuf formats. It |
| 172 | +currently does not support nonzero default value declarations for enums, the |
| 173 | +legacy unpacked formats for repeated numeric fields, messages with extremely |
| 174 | +sparse field numbering, or other more exotic features like extensions or |
| 175 | +oneof. If you need to interoperate with existing protobuf code using these |
| 176 | +features, then you should probably use goprotobuf, at least for those |
| 177 | +particular message formats. |
| 178 | +Many of these limitations could be fixed by creative use of |
| 179 | +struct tag metadata (see https://golang.org/ref/spec#Struct_types). |
| 180 | + |
| 181 | +Another downside of this reflective approach to protobuf implementation is |
| 182 | +that reflective code is generally less efficient than statically generated |
| 183 | +code, as gogoprotobuf produces for example. If we decide we want the |
| 184 | +convenience of format definitions in Go with the runtime performance of static |
| 185 | +code generation, we could in principle achieve that by adding a "Go-format" |
| 186 | +message format compiler frontend to goprotobuf or gogoprotobuf - but we leave |
| 187 | +this as an exercise for the reader. |
| 188 | + |
| 189 | + |
| 190 | +## Generating .proto files |
| 191 | + |
| 192 | +`.proto` files can be generated from Go structs using the |
| 193 | +`GenerateProtobufDefinition()` function. The following: |
| 194 | + |
| 195 | +```go |
| 196 | +types := []interface{}{ |
| 197 | + Person{}, |
| 198 | + PhoneNumber{}, |
| 199 | +} |
| 200 | +enums := EnumMap{ |
| 201 | + "MobilePhone": MobilePhone, |
| 202 | + "HomePhone": HomePhone, |
| 203 | + "WorkPhone": WorkPhone, |
| 204 | +} |
| 205 | +GenerateProtobufDefinition(w, types, enums, nil) |
| 206 | +``` |
| 207 | + |
| 208 | +Will generate: |
| 209 | + |
| 210 | +```protobuf |
| 211 | +message Person { |
| 212 | + required string name = 1; |
| 213 | + required sint32 id = 2; |
| 214 | + optional string email = 3; |
| 215 | + repeated PhoneNumber phone = 4; |
| 216 | +} |
| 217 | +
|
| 218 | +message PhoneNumber { |
| 219 | + required string number = 1; |
| 220 | + optional uint32 type = 2; |
| 221 | +} |
| 222 | +``` |
| 223 | + |
| 224 | +Note: It can be quite tedious to manually synchronise the type and enum maps with the types in your package. I've found [pkgreflect](https://github.com/ungerik/pkgreflect) very useful for automating this. |
0 commit comments