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