|
- package dynamic
-
- // Binary serialization and de-serialization for dynamic messages
-
- import (
- "fmt"
- "github.com/golang/protobuf/proto"
- "github.com/jhump/protoreflect/codec"
- "io"
- )
-
- // defaultDeterminism, if true, will mean that calls to Marshal will produce
- // deterministic output. This is used to make the output of proto.Marshal(...)
- // deterministic (since there is no way to have that convey determinism intent).
- // **This is only used from tests.**
- var defaultDeterminism = false
-
- // Marshal serializes this message to bytes, returning an error if the operation
- // fails. The resulting bytes are in the standard protocol buffer binary format.
- func (m *Message) Marshal() ([]byte, error) {
- var b codec.Buffer
- b.SetDeterministic(defaultDeterminism)
- if err := m.marshal(&b); err != nil {
- return nil, err
- }
- return b.Bytes(), nil
- }
-
- // MarshalAppend behaves exactly the same as Marshal, except instead of allocating a
- // new byte slice to marshal into, it uses the provided byte slice. The backing array
- // for the returned byte slice *may* be the same as the one that was passed in, but
- // it's not guaranteed as a new backing array will automatically be allocated if
- // more bytes need to be written than the provided buffer has capacity for.
- func (m *Message) MarshalAppend(b []byte) ([]byte, error) {
- codedBuf := codec.NewBuffer(b)
- codedBuf.SetDeterministic(defaultDeterminism)
- if err := m.marshal(codedBuf); err != nil {
- return nil, err
- }
- return codedBuf.Bytes(), nil
- }
-
- // MarshalDeterministic serializes this message to bytes in a deterministic way,
- // returning an error if the operation fails. This differs from Marshal in that
- // map keys will be sorted before serializing to bytes. The protobuf spec does
- // not define ordering for map entries, so Marshal will use standard Go map
- // iteration order (which will be random). But for cases where determinism is
- // more important than performance, use this method instead.
- func (m *Message) MarshalDeterministic() ([]byte, error) {
- var b codec.Buffer
- b.SetDeterministic(true)
- if err := m.marshal(&b); err != nil {
- return nil, err
- }
- return b.Bytes(), nil
- }
-
- // MarshalAppendDeterministic behaves exactly the same as MarshalDeterministic,
- // except instead of allocating a new byte slice to marshal into, it uses the
- // provided byte slice. The backing array for the returned byte slice *may* be
- // the same as the one that was passed in, but it's not guaranteed as a new
- // backing array will automatically be allocated if more bytes need to be written
- // than the provided buffer has capacity for.
- func (m *Message) MarshalAppendDeterministic(b []byte) ([]byte, error) {
- codedBuf := codec.NewBuffer(b)
- codedBuf.SetDeterministic(true)
- if err := m.marshal(codedBuf); err != nil {
- return nil, err
- }
- return codedBuf.Bytes(), nil
- }
-
- func (m *Message) marshal(b *codec.Buffer) error {
- if err := m.marshalKnownFields(b); err != nil {
- return err
- }
- return m.marshalUnknownFields(b)
- }
-
- func (m *Message) marshalKnownFields(b *codec.Buffer) error {
- for _, tag := range m.knownFieldTags() {
- itag := int32(tag)
- val := m.values[itag]
- fd := m.FindFieldDescriptor(itag)
- if fd == nil {
- panic(fmt.Sprintf("Couldn't find field for tag %d", itag))
- }
- if err := b.EncodeFieldValue(fd, val); err != nil {
- return err
- }
- }
- return nil
- }
-
- func (m *Message) marshalUnknownFields(b *codec.Buffer) error {
- for _, tag := range m.unknownFieldTags() {
- itag := int32(tag)
- sl := m.unknownFields[itag]
- for _, u := range sl {
- if err := b.EncodeTagAndWireType(itag, u.Encoding); err != nil {
- return err
- }
- switch u.Encoding {
- case proto.WireBytes:
- if err := b.EncodeRawBytes(u.Contents); err != nil {
- return err
- }
- case proto.WireStartGroup:
- _, _ = b.Write(u.Contents)
- if err := b.EncodeTagAndWireType(itag, proto.WireEndGroup); err != nil {
- return err
- }
- case proto.WireFixed32:
- if err := b.EncodeFixed32(u.Value); err != nil {
- return err
- }
- case proto.WireFixed64:
- if err := b.EncodeFixed64(u.Value); err != nil {
- return err
- }
- case proto.WireVarint:
- if err := b.EncodeVarint(u.Value); err != nil {
- return err
- }
- default:
- return codec.ErrBadWireType
- }
- }
- }
- return nil
- }
-
- // Unmarshal de-serializes the message that is present in the given bytes into
- // this message. It first resets the current message. It returns an error if the
- // given bytes do not contain a valid encoding of this message type.
- func (m *Message) Unmarshal(b []byte) error {
- m.Reset()
- if err := m.UnmarshalMerge(b); err != nil {
- return err
- }
- return m.Validate()
- }
-
- // UnmarshalMerge de-serializes the message that is present in the given bytes
- // into this message. Unlike Unmarshal, it does not first reset the message,
- // instead merging the data in the given bytes into the existing data in this
- // message.
- func (m *Message) UnmarshalMerge(b []byte) error {
- return m.unmarshal(codec.NewBuffer(b), false)
- }
-
- func (m *Message) unmarshal(buf *codec.Buffer, isGroup bool) error {
- for !buf.EOF() {
- fd, val, err := buf.DecodeFieldValue(m.FindFieldDescriptor, m.mf)
- if err != nil {
- if err == codec.ErrWireTypeEndGroup {
- if isGroup {
- // finished parsing group
- return nil
- }
- return codec.ErrBadWireType
- }
- return err
- }
-
- if fd == nil {
- if m.unknownFields == nil {
- m.unknownFields = map[int32][]UnknownField{}
- }
- uv := val.(codec.UnknownField)
- u := UnknownField{
- Encoding: uv.Encoding,
- Value: uv.Value,
- Contents: uv.Contents,
- }
- m.unknownFields[uv.Tag] = append(m.unknownFields[uv.Tag], u)
- } else if err := mergeField(m, fd, val); err != nil {
- return err
- }
- }
- if isGroup {
- return io.ErrUnexpectedEOF
- }
- return nil
- }
|