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  }