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