github.com/Mrs4s/MiraiGo@v0.0.0-20240226124653-54bdd873e3fe/internal/proto/dynamic.go (about)

     1  package proto
     2  
     3  import (
     4  	"encoding/binary"
     5  	"math"
     6  	"sort"
     7  )
     8  
     9  type DynamicMessage map[uint64]any
    10  
    11  // zigzag encoding types
    12  type (
    13  	SInt   int
    14  	SInt32 int32
    15  	SInt64 int64
    16  )
    17  
    18  type encoder struct {
    19  	buf []byte
    20  }
    21  
    22  func (msg DynamicMessage) Encode() []byte {
    23  	en := encoder{}
    24  
    25  	// sort all items
    26  	type pair struct {
    27  		key   uint64
    28  		value any
    29  	}
    30  	all := make([]pair, len(msg))
    31  	for k, v := range msg {
    32  		all = append(all, pair{key: k, value: v})
    33  	}
    34  	sort.Slice(all, func(i, j int) bool {
    35  		return all[i].key < all[j].key
    36  	})
    37  
    38  	//nolint:staticcheck
    39  	for _, item := range all {
    40  		key := item.key << 3
    41  		switch v := item.value.(type) {
    42  		case bool:
    43  			en.uvarint(key | 0)
    44  			vi := uint64(0)
    45  			if v {
    46  				vi = 1
    47  			}
    48  			en.uvarint(vi)
    49  		case int:
    50  			en.uvarint(key | 0)
    51  			en.uvarint(uint64(v))
    52  		case uint:
    53  			en.uvarint(key | 0)
    54  			en.uvarint(uint64(v))
    55  		case int32:
    56  			en.uvarint(key | 0)
    57  			en.uvarint(uint64(v))
    58  		case int64:
    59  			en.uvarint(key | 0)
    60  			en.uvarint(uint64(v))
    61  		case uint32:
    62  			en.uvarint(key | 0)
    63  			en.uvarint(uint64(v))
    64  		case uint64:
    65  			en.uvarint(key | 0)
    66  			en.uvarint(v)
    67  		case SInt:
    68  			en.uvarint(key | 0)
    69  			en.svarint(int64(v))
    70  		case SInt32:
    71  			en.uvarint(key | 0)
    72  			en.svarint(int64(v))
    73  		case SInt64:
    74  			en.uvarint(key | 0)
    75  			en.svarint(int64(v))
    76  		case float32:
    77  			en.uvarint(key | 5)
    78  			en.u32(math.Float32bits(v))
    79  		case float64:
    80  			en.uvarint(key | 1)
    81  			en.u64(math.Float64bits(v))
    82  		case string:
    83  			en.uvarint(key | 2)
    84  			en.uvarint(uint64(len(v)))
    85  			en.buf = append(en.buf, v...)
    86  		case []uint64:
    87  			for i := 0; i < len(v); i++ {
    88  				en.uvarint(key | 0)
    89  				en.uvarint(v[i])
    90  			}
    91  		case []byte:
    92  			en.uvarint(key | 2)
    93  			en.uvarint(uint64(len(v)))
    94  			en.buf = append(en.buf, v...)
    95  		case DynamicMessage:
    96  			en.uvarint(key | 2)
    97  			b := v.Encode()
    98  			en.uvarint(uint64(len(b)))
    99  			en.buf = append(en.buf, b...)
   100  		}
   101  	}
   102  	return en.buf
   103  }
   104  
   105  func (en *encoder) uvarint(v uint64) {
   106  	en.buf = binary.AppendUvarint(en.buf, v)
   107  }
   108  
   109  func (en *encoder) svarint(v int64) {
   110  	en.buf = binary.AppendVarint(en.buf, v)
   111  }
   112  
   113  func (en *encoder) u32(v uint32) {
   114  	en.buf = binary.LittleEndian.AppendUint32(en.buf, v)
   115  }
   116  
   117  func (en *encoder) u64(v uint64) {
   118  	en.buf = binary.LittleEndian.AppendUint64(en.buf, v)
   119  }