Scott Baker | 1fe7273 | 2019-10-21 10:58:51 -0700 | [diff] [blame] | 1 | // Package dynamic provides an implementation for a dynamic protobuf message. |
| 2 | // |
| 3 | // The dynamic message is essentially a message descriptor along with a map of |
| 4 | // tag numbers to values. It has a broad API for interacting with the message, |
| 5 | // including inspection and modification. Generally, most operations have two |
| 6 | // forms: a regular method that panics on bad input or error and a "Try" form |
| 7 | // of the method that will instead return an error. |
| 8 | // |
| 9 | // A dynamic message can optionally be constructed with a MessageFactory. The |
| 10 | // MessageFactory has various registries that may be used by the dynamic message, |
| 11 | // such as during de-serialization. The message factory is "inherited" by any |
| 12 | // other dynamic messages created, such as nested messages that are created |
| 13 | // during de-serialization. Similarly, any dynamic message created using |
| 14 | // MessageFactory.NewMessage will be associated with that factory, which in turn |
| 15 | // will be used to create other messages or parse extension fields during |
| 16 | // de-serialization. |
| 17 | // |
| 18 | // |
| 19 | // Field Types |
| 20 | // |
| 21 | // The types of values expected by setters and returned by getters are the |
| 22 | // same as protoc generates for scalar fields. For repeated fields, there are |
| 23 | // methods for getting and setting values at a particular index or for adding |
| 24 | // an element. Similarly, for map fields, there are methods for getting and |
| 25 | // setting values for a particular key. |
| 26 | // |
| 27 | // If you use GetField for a repeated field, it will return a copy of all |
| 28 | // elements as a slice []interface{}. Similarly, using GetField for a map field |
| 29 | // will return a copy of all mappings as a map[interface{}]interface{}. You can |
| 30 | // also use SetField to supply an entire slice or map for repeated or map fields. |
| 31 | // The slice need not be []interface{} but can actually be typed according to |
| 32 | // the field's expected type. For example, a repeated uint64 field can be set |
| 33 | // using a slice of type []uint64. |
| 34 | // |
| 35 | // Descriptors for map fields describe them as repeated fields with a nested |
| 36 | // message type. The nested message type is a special generated type that |
| 37 | // represents a single mapping: key and value pair. The dynamic message has some |
| 38 | // special affordances for this representation. For example, you can use |
| 39 | // SetField to set a map field using a slice of these entry messages. Internally, |
| 40 | // the slice of entries will be converted to an actual map. Similarly, you can |
| 41 | // use AddRepeatedField with an entry message to add (or overwrite) a mapping. |
| 42 | // However, you cannot use GetRepeatedField or SetRepeatedField to modify maps, |
| 43 | // since those take numeric index arguments which are not relevant to maps |
| 44 | // (since maps in Go have no defined ordering). |
| 45 | // |
| 46 | // When setting field values in dynamic messages, the type-checking is lenient |
| 47 | // in that it accepts any named type with the right kind. So a string field can |
| 48 | // be assigned to any type that is defined as a string. Enum fields require |
| 49 | // int32 values (or any type that is defined as an int32). |
| 50 | // |
| 51 | // Unlike normal use of numeric values in Go, values will be automatically |
| 52 | // widened when assigned. So, for example, an int64 field can be set using an |
| 53 | // int32 value since it can be safely widened without truncation or loss of |
| 54 | // precision. Similar goes for uint32 values being converted to uint64 and |
| 55 | // float32 being converted to float64. Narrowing conversions are not done, |
| 56 | // however. Also, unsigned values will never be automatically converted to |
| 57 | // signed (and vice versa), and floating point values will never be |
| 58 | // automatically converted to integral values (and vice versa). Since the bit |
| 59 | // width of int and uint fields is allowed to be platform dependent, but will |
| 60 | // always be less than or equal to 64, they can only be used as values for |
| 61 | // int64 and uint64 fields, respectively. They cannot be used to set int32 or |
| 62 | // uint32 fields, which includes enums fields. |
| 63 | // |
| 64 | // Fields whose type is a nested message can have values set to either other |
| 65 | // dynamic messages or generated messages (e.g. pointers to structs generated by |
| 66 | // protoc). Getting a value for such a field will return the actual type it is |
| 67 | // set to (e.g. either a dynamic message or a generated message). If the value |
| 68 | // is not set and the message uses proto2 syntax, the default message returned |
| 69 | // will be whatever is returned by the dynamic message's MessageFactory (if the |
| 70 | // dynamic message was not created with a factory, it will use the logic of the |
| 71 | // zero value factory). In most typical cases, it will return a dynamic message, |
| 72 | // but if the factory is configured with a KnownTypeRegistry, or if the field's |
| 73 | // type is a well-known type, it will return a zero value generated message. |
| 74 | // |
| 75 | // |
| 76 | // Unrecognized Fields |
| 77 | // |
| 78 | // Unrecognized fields are preserved by the dynamic message when unmarshaling |
| 79 | // from the standard binary format. If the message's MessageFactory was |
| 80 | // configured with an ExtensionRegistry, it will be used to identify and parse |
| 81 | // extension fields for the message. |
| 82 | // |
| 83 | // Unrecognized fields can dynamically become recognized fields if the |
| 84 | // application attempts to retrieve an unrecognized field's value using a |
| 85 | // FieldDescriptor. In this case, the given FieldDescriptor is used to parse the |
| 86 | // unknown field and move the parsed value into the message's set of known |
| 87 | // fields. This behavior is most suited to the use of extensions, where an |
| 88 | // ExtensionRegistry is not setup with all known extensions ahead of time. But |
| 89 | // it can even happen for non-extension fields! Here's an example scenario where |
| 90 | // a non-extension field can initially be unknown and become known: |
| 91 | // |
| 92 | // 1. A dynamic message is created with a descriptor, A, and then |
| 93 | // de-serialized from a stream of bytes. The stream includes an |
| 94 | // unrecognized tag T. The message will include tag T in its unrecognized |
| 95 | // field set. |
| 96 | // 2. Another call site retrieves a newer descriptor, A', which includes a |
| 97 | // newly added field with tag T. |
| 98 | // 3. That other call site then uses a FieldDescriptor to access the value of |
| 99 | // the new field. This will cause the dynamic message to parse the bytes |
| 100 | // for the unknown tag T and store them as a known field. |
| 101 | // 4. Subsequent operations for tag T, including setting the field using only |
| 102 | // tag number or de-serializing a stream that includes tag T, will operate |
| 103 | // as if that tag were part of the original descriptor, A. |
| 104 | // |
| 105 | // |
| 106 | // Compatibility |
| 107 | // |
| 108 | // In addition to implementing the proto.Message interface, the included |
| 109 | // Message type also provides an XXX_MessageName() method, so it can work with |
| 110 | // proto.MessageName. And it provides a Descriptor() method that behaves just |
| 111 | // like the method of the same signature in messages generated by protoc. |
| 112 | // Because of this, it is actually compatible with proto.Message in many (though |
| 113 | // not all) contexts. In particular, it is compatible with proto.Marshal and |
| 114 | // proto.Unmarshal for serializing and de-serializing messages. |
| 115 | // |
| 116 | // The dynamic message supports binary and text marshaling, using protobuf's |
| 117 | // well-defined binary format and the same text format that protoc-generated |
| 118 | // types use. It also supports JSON serialization/de-serialization by |
| 119 | // implementing the json.Marshaler and json.Unmarshaler interfaces. And dynamic |
| 120 | // messages can safely be used with the jsonpb package for JSON serialization |
| 121 | // and de-serialization. |
| 122 | // |
| 123 | // In addition to implementing the proto.Message interface and numerous related |
| 124 | // methods, it also provides inter-op with generated messages via conversion. |
| 125 | // The ConvertTo, ConvertFrom, MergeInto, and MergeFrom methods copy message |
| 126 | // contents from a dynamic message to a generated message and vice versa. |
| 127 | // |
| 128 | // When copying from a generated message into a dynamic message, if the |
| 129 | // generated message contains fields unknown to the dynamic message (e.g. not |
| 130 | // present in the descriptor used to create the dynamic message), these fields |
| 131 | // become known to the dynamic message (as per behavior described above in |
| 132 | // "Unrecognized Fields"). If the generated message has unrecognized fields of |
| 133 | // its own, including unrecognized extensions, they are preserved in the dynamic |
| 134 | // message. It is possible that the dynamic message knows about fields that the |
| 135 | // generated message did not, like if it has a different version of the |
| 136 | // descriptor or its MessageFactory has an ExtensionRegistry that knows about |
| 137 | // different extensions than were linked into the program. In this case, these |
| 138 | // unrecognized fields in the generated message will be known fields in the |
| 139 | // dynamic message. |
| 140 | // |
| 141 | // Similarly, when copying from a dynamic message into a generated message, if |
| 142 | // the dynamic message has unrecognized fields they can be preserved in the |
| 143 | // generated message (currently only for syntax proto2 since proto3 generated |
| 144 | // messages do not preserve unrecognized fields). If the generated message knows |
| 145 | // about fields that the dynamic message does not, these unrecognized fields may |
| 146 | // become known fields in the generated message. |
| 147 | // |
| 148 | // |
| 149 | // Registries |
| 150 | // |
| 151 | // This package also contains a couple of registries, for managing known types |
| 152 | // and descriptors. |
| 153 | // |
| 154 | // The KnownTypeRegistry allows de-serialization of a dynamic message to use |
| 155 | // generated message types, instead of dynamic messages, for some kinds of |
| 156 | // nested message fields. This is particularly useful for working with proto |
| 157 | // messages that have special encodings as JSON (e.g. the well-known types), |
| 158 | // since the dynamic message does not try to handle these special cases in its |
| 159 | // JSON marshaling facilities. |
| 160 | // |
| 161 | // The ExtensionRegistry allows for recognizing and parsing extensions fields |
| 162 | // (for proto2 messages). |
| 163 | package dynamic |