github.com/jhump/protoreflect@v1.16.0/internal/codec/encode.go (about) 1 package codec 2 3 import ( 4 "github.com/golang/protobuf/proto" 5 ) 6 7 // EncodeVarint writes a varint-encoded integer to the Buffer. 8 // This is the format for the 9 // int32, int64, uint32, uint64, bool, and enum 10 // protocol buffer types. 11 func (cb *Buffer) EncodeVarint(x uint64) error { 12 for x >= 1<<7 { 13 cb.buf = append(cb.buf, uint8(x&0x7f|0x80)) 14 x >>= 7 15 } 16 cb.buf = append(cb.buf, uint8(x)) 17 return nil 18 } 19 20 // EncodeTagAndWireType encodes the given field tag and wire type to the 21 // buffer. This combines the two values and then writes them as a varint. 22 func (cb *Buffer) EncodeTagAndWireType(tag int32, wireType int8) error { 23 v := uint64((int64(tag) << 3) | int64(wireType)) 24 return cb.EncodeVarint(v) 25 } 26 27 // EncodeFixed64 writes a 64-bit integer to the Buffer. 28 // This is the format for the 29 // fixed64, sfixed64, and double protocol buffer types. 30 func (cb *Buffer) EncodeFixed64(x uint64) error { 31 cb.buf = append(cb.buf, 32 uint8(x), 33 uint8(x>>8), 34 uint8(x>>16), 35 uint8(x>>24), 36 uint8(x>>32), 37 uint8(x>>40), 38 uint8(x>>48), 39 uint8(x>>56)) 40 return nil 41 } 42 43 // EncodeFixed32 writes a 32-bit integer to the Buffer. 44 // This is the format for the 45 // fixed32, sfixed32, and float protocol buffer types. 46 func (cb *Buffer) EncodeFixed32(x uint64) error { 47 cb.buf = append(cb.buf, 48 uint8(x), 49 uint8(x>>8), 50 uint8(x>>16), 51 uint8(x>>24)) 52 return nil 53 } 54 55 // EncodeRawBytes writes a count-delimited byte buffer to the Buffer. 56 // This is the format used for the bytes protocol buffer 57 // type and for embedded messages. 58 func (cb *Buffer) EncodeRawBytes(b []byte) error { 59 if err := cb.EncodeVarint(uint64(len(b))); err != nil { 60 return err 61 } 62 cb.buf = append(cb.buf, b...) 63 return nil 64 } 65 66 // EncodeMessage writes the given message to the buffer. 67 func (cb *Buffer) EncodeMessage(pm proto.Message) error { 68 bytes, err := marshalMessage(cb.buf, pm, cb.deterministic) 69 if err != nil { 70 return err 71 } 72 cb.buf = bytes 73 return nil 74 } 75 76 // EncodeDelimitedMessage writes the given message to the buffer with a 77 // varint-encoded length prefix (the delimiter). 78 func (cb *Buffer) EncodeDelimitedMessage(pm proto.Message) error { 79 bytes, err := marshalMessage(cb.tmp, pm, cb.deterministic) 80 if err != nil { 81 return err 82 } 83 // save truncated buffer if it was grown (so we can re-use it and 84 // curtail future allocations) 85 if cap(bytes) > cap(cb.tmp) { 86 cb.tmp = bytes[:0] 87 } 88 return cb.EncodeRawBytes(bytes) 89 } 90 91 func marshalMessage(b []byte, pm proto.Message, deterministic bool) ([]byte, error) { 92 // We try to use the most efficient way to marshal to existing slice. 93 94 if deterministic { 95 // see if the message has custom deterministic methods, preferring an 96 // "append" method over one that must always re-allocate 97 madm, ok := pm.(interface { 98 MarshalAppendDeterministic(b []byte) ([]byte, error) 99 }) 100 if ok { 101 return madm.MarshalAppendDeterministic(b) 102 } 103 104 mdm, ok := pm.(interface { 105 MarshalDeterministic() ([]byte, error) 106 }) 107 if ok { 108 bytes, err := mdm.MarshalDeterministic() 109 if err != nil { 110 return nil, err 111 } 112 if len(b) == 0 { 113 return bytes, nil 114 } 115 return append(b, bytes...), nil 116 } 117 118 var buf proto.Buffer 119 buf.SetDeterministic(true) 120 if err := buf.Marshal(pm); err != nil { 121 return nil, err 122 } 123 bytes := buf.Bytes() 124 if len(b) == 0 { 125 return bytes, nil 126 } 127 return append(b, bytes...), nil 128 } 129 130 mam, ok := pm.(interface { 131 // see if we can append the message, vs. having to re-allocate 132 MarshalAppend(b []byte) ([]byte, error) 133 }) 134 if ok { 135 return mam.MarshalAppend(b) 136 } 137 138 // lowest common denominator 139 bytes, err := proto.Marshal(pm) 140 if err != nil { 141 return nil, err 142 } 143 if len(b) == 0 { 144 return bytes, nil 145 } 146 return append(b, bytes...), nil 147 }