github.com/TrueCloudLab/frostfs-api-go/v2@v2.0.0-20230228134343-196241c4e79a/util/proto/marshal.go (about) 1 /* 2 This package contains help functions for stable marshaller. Their usage is 3 totally optional. One can implement fast stable marshaller without these 4 runtime function calls. 5 */ 6 7 package proto 8 9 import ( 10 "encoding/binary" 11 "math" 12 "math/bits" 13 "reflect" 14 ) 15 16 type ( 17 stableMarshaller interface { 18 StableMarshal([]byte) []byte 19 StableSize() int 20 } 21 ) 22 23 func BytesMarshal(field int, buf, v []byte) int { 24 if len(v) == 0 { 25 return 0 26 } 27 return bytesMarshal(field, buf, v) 28 } 29 30 func bytesMarshal(field int, buf, v []byte) int { 31 prefix := field<<3 | 0x2 32 33 // buf length check can prevent panic at PutUvarint, but it will make 34 // marshaller a bit slower. 35 i := binary.PutUvarint(buf, uint64(prefix)) 36 i += binary.PutUvarint(buf[i:], uint64(len(v))) 37 i += copy(buf[i:], v) 38 39 return i 40 } 41 42 func BytesSize(field int, v []byte) int { 43 ln := len(v) 44 if ln == 0 { 45 return 0 46 } 47 return bytesSize(field, v) 48 } 49 50 func bytesSize(field int, v []byte) int { 51 prefix := field<<3 | 0x2 52 53 return VarUIntSize(uint64(prefix)) + VarUIntSize(uint64(len(v))) + len(v) 54 } 55 56 func StringMarshal(field int, buf []byte, v string) int { 57 return BytesMarshal(field, buf, []byte(v)) 58 } 59 60 func StringSize(field int, v string) int { 61 return BytesSize(field, []byte(v)) 62 } 63 64 func BoolMarshal(field int, buf []byte, v bool) int { 65 if !v { 66 return 0 67 } 68 69 prefix := field << 3 70 71 // buf length check can prevent panic at PutUvarint, but it will make 72 // marshaller a bit slower. 73 i := binary.PutUvarint(buf, uint64(prefix)) 74 buf[i] = 0x1 75 76 return i + 1 77 } 78 79 func BoolSize(field int, v bool) int { 80 if !v { 81 return 0 82 } 83 84 prefix := field << 3 85 86 return VarUIntSize(uint64(prefix)) + 1 // bool is always 1 byte long 87 } 88 89 func UInt64Marshal(field int, buf []byte, v uint64) int { 90 if v == 0 { 91 return 0 92 } 93 94 prefix := field << 3 95 96 // buf length check can prevent panic at PutUvarint, but it will make 97 // marshaller a bit slower. 98 i := binary.PutUvarint(buf, uint64(prefix)) 99 i += binary.PutUvarint(buf[i:], v) 100 101 return i 102 } 103 104 func UInt64Size(field int, v uint64) int { 105 if v == 0 { 106 return 0 107 } 108 109 prefix := field << 3 110 111 return VarUIntSize(uint64(prefix)) + VarUIntSize(v) 112 } 113 114 func Int64Marshal(field int, buf []byte, v int64) int { 115 return UInt64Marshal(field, buf, uint64(v)) 116 } 117 118 func Int64Size(field int, v int64) int { 119 return UInt64Size(field, uint64(v)) 120 } 121 122 func UInt32Marshal(field int, buf []byte, v uint32) int { 123 return UInt64Marshal(field, buf, uint64(v)) 124 } 125 126 func UInt32Size(field int, v uint32) int { 127 return UInt64Size(field, uint64(v)) 128 } 129 130 func Int32Marshal(field int, buf []byte, v int32) int { 131 return UInt64Marshal(field, buf, uint64(v)) 132 } 133 134 func Int32Size(field int, v int32) int { 135 return UInt64Size(field, uint64(v)) 136 } 137 138 func EnumMarshal(field int, buf []byte, v int32) int { 139 return UInt64Marshal(field, buf, uint64(v)) 140 } 141 142 func EnumSize(field int, v int32) int { 143 return UInt64Size(field, uint64(v)) 144 } 145 146 func RepeatedBytesMarshal(field int, buf []byte, v [][]byte) int { 147 var offset int 148 149 for i := range v { 150 offset += bytesMarshal(field, buf[offset:], v[i]) 151 } 152 153 return offset 154 } 155 156 func RepeatedBytesSize(field int, v [][]byte) (size int) { 157 for i := range v { 158 size += bytesSize(field, v[i]) 159 } 160 161 return size 162 } 163 164 func RepeatedStringMarshal(field int, buf []byte, v []string) int { 165 var offset int 166 167 for i := range v { 168 offset += bytesMarshal(field, buf[offset:], []byte(v[i])) 169 } 170 171 return offset 172 } 173 174 func RepeatedStringSize(field int, v []string) (size int) { 175 for i := range v { 176 size += bytesSize(field, []byte(v[i])) 177 } 178 179 return size 180 } 181 182 func RepeatedUInt64Marshal(field int, buf []byte, v []uint64) int { 183 if len(v) == 0 { 184 return 0 185 } 186 187 prefix := field<<3 | 0x02 188 offset := binary.PutUvarint(buf, uint64(prefix)) 189 190 _, arrSize := RepeatedUInt64Size(field, v) 191 offset += binary.PutUvarint(buf[offset:], uint64(arrSize)) 192 for i := range v { 193 offset += binary.PutUvarint(buf[offset:], v[i]) 194 } 195 196 return offset 197 } 198 199 func RepeatedUInt64Size(field int, v []uint64) (size, arraySize int) { 200 if len(v) == 0 { 201 return 0, 0 202 } 203 204 for i := range v { 205 size += VarUIntSize(v[i]) 206 } 207 arraySize = size 208 209 size += VarUIntSize(uint64(size)) 210 211 prefix := field<<3 | 0x2 212 size += VarUIntSize(uint64(prefix)) 213 214 return size, arraySize 215 } 216 217 func RepeatedInt64Marshal(field int, buf []byte, v []int64) int { 218 if len(v) == 0 { 219 return 0 220 } 221 222 convert := make([]uint64, len(v)) 223 for i := range v { 224 convert[i] = uint64(v[i]) 225 } 226 227 return RepeatedUInt64Marshal(field, buf, convert) 228 } 229 230 func RepeatedInt64Size(field int, v []int64) (size, arraySize int) { 231 if len(v) == 0 { 232 return 0, 0 233 } 234 235 convert := make([]uint64, len(v)) 236 for i := range v { 237 convert[i] = uint64(v[i]) 238 } 239 240 return RepeatedUInt64Size(field, convert) 241 } 242 243 func RepeatedUInt32Marshal(field int, buf []byte, v []uint32) int { 244 if len(v) == 0 { 245 return 0 246 } 247 248 convert := make([]uint64, len(v)) 249 for i := range v { 250 convert[i] = uint64(v[i]) 251 } 252 253 return RepeatedUInt64Marshal(field, buf, convert) 254 } 255 256 func RepeatedUInt32Size(field int, v []uint32) (size, arraySize int) { 257 if len(v) == 0 { 258 return 0, 0 259 } 260 261 convert := make([]uint64, len(v)) 262 for i := range v { 263 convert[i] = uint64(v[i]) 264 } 265 266 return RepeatedUInt64Size(field, convert) 267 } 268 269 func RepeatedInt32Marshal(field int, buf []byte, v []int32) int { 270 if len(v) == 0 { 271 return 0 272 } 273 274 convert := make([]uint64, len(v)) 275 for i := range v { 276 convert[i] = uint64(v[i]) 277 } 278 279 return RepeatedUInt64Marshal(field, buf, convert) 280 } 281 282 func RepeatedInt32Size(field int, v []int32) (size, arraySize int) { 283 if len(v) == 0 { 284 return 0, 0 285 } 286 287 convert := make([]uint64, len(v)) 288 for i := range v { 289 convert[i] = uint64(v[i]) 290 } 291 292 return RepeatedUInt64Size(field, convert) 293 } 294 295 // VarUIntSize returns length of varint byte sequence for uint64 value 'x'. 296 func VarUIntSize(x uint64) int { 297 return (bits.Len64(x|1) + 6) / 7 298 } 299 300 func NestedStructurePrefix(field int64) (prefix uint64, ln int) { 301 prefix = uint64(field<<3 | 0x02) 302 return prefix, VarUIntSize(prefix) 303 } 304 305 func NestedStructureMarshal(field int64, buf []byte, v stableMarshaller) int { 306 if v == nil || reflect.ValueOf(v).IsNil() { 307 return 0 308 } 309 310 prefix, _ := NestedStructurePrefix(field) 311 offset := binary.PutUvarint(buf, prefix) 312 313 n := v.StableSize() 314 offset += binary.PutUvarint(buf[offset:], uint64(n)) 315 v.StableMarshal(buf[offset:]) 316 317 return offset + n 318 } 319 320 func NestedStructureSize(field int64, v stableMarshaller) (size int) { 321 if v == nil || reflect.ValueOf(v).IsNil() { 322 return 0 323 } 324 325 _, ln := NestedStructurePrefix(field) 326 n := v.StableSize() 327 size = ln + VarUIntSize(uint64(n)) + n 328 329 return size 330 } 331 332 func Fixed64Marshal(field int, buf []byte, v uint64) int { 333 if v == 0 { 334 return 0 335 } 336 337 prefix := field<<3 | 1 338 339 // buf length check can prevent panic at PutUvarint, but it will make 340 // marshaller a bit slower. 341 i := binary.PutUvarint(buf, uint64(prefix)) 342 binary.LittleEndian.PutUint64(buf[i:], v) 343 344 return i + 8 345 } 346 347 func Fixed64Size(fNum int, v uint64) int { 348 if v == 0 { 349 return 0 350 } 351 352 prefix := fNum<<3 | 1 353 354 return VarUIntSize(uint64(prefix)) + 8 355 } 356 357 func Float64Marshal(field int, buf []byte, v float64) int { 358 if v == 0 { 359 return 0 360 } 361 362 prefix := field<<3 | 1 363 364 i := binary.PutUvarint(buf, uint64(prefix)) 365 binary.LittleEndian.PutUint64(buf[i:], math.Float64bits(v)) 366 367 return i + 8 368 } 369 370 func Float64Size(fNum int, v float64) int { 371 if v == 0 { 372 return 0 373 } 374 375 prefix := fNum<<3 | 1 376 377 return VarUIntSize(uint64(prefix)) + 8 378 } 379 380 // Fixed32Marshal encodes uint32 value to Protocol Buffers fixed32 field with specified number, 381 // and writes it to specified buffer. Returns number of bytes written. 382 // 383 // Panics if the buffer is undersized. 384 func Fixed32Marshal(field int, buf []byte, v uint32) int { 385 if v == 0 { 386 return 0 387 } 388 389 prefix := field<<3 | 5 390 391 // buf length check can prevent panic at PutUvarint, but it will make 392 // marshaller a bit slower. 393 i := binary.PutUvarint(buf, uint64(prefix)) 394 binary.LittleEndian.PutUint32(buf[i:], v) 395 396 return i + 4 397 } 398 399 // Fixed32Size returns number of bytes required to encode uint32 value to Protocol Buffers fixed32 field 400 // with specified number. 401 func Fixed32Size(fNum int, v uint32) int { 402 if v == 0 { 403 return 0 404 } 405 406 prefix := fNum<<3 | 5 407 408 return VarUIntSize(uint64(prefix)) + 4 409 }