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 }