github.com/onflow/flow-go@v0.35.7-crescendo-preview.23-atree-inlining/ledger/common/utils/utils.go (about) 1 package utils 2 3 import ( 4 "encoding/binary" 5 "fmt" 6 "io" 7 "math" 8 ) 9 10 // MaxUint16 returns the max value of two uint16 11 func MaxUint16(a, b uint16) uint16 { 12 if a > b { 13 return a 14 } 15 return b 16 } 17 18 // Uint16ToBinary converst a uint16 to a byte slice (big endian) 19 func Uint16ToBinary(integer uint16) []byte { 20 b := make([]byte, 2) 21 binary.BigEndian.PutUint16(b, integer) 22 return b 23 } 24 25 // Uint64ToBinary converst a uint64 to a byte slice (big endian) 26 func Uint64ToBinary(integer uint64) []byte { 27 b := make([]byte, 8) 28 binary.BigEndian.PutUint64(b, integer) 29 return b 30 } 31 32 // AppendUint8 appends the value byte to the input slice 33 func AppendUint8(input []byte, value uint8) []byte { 34 return append(input, value) 35 } 36 37 // AppendUint16 appends the value bytes to the input slice (big endian) 38 func AppendUint16(input []byte, value uint16) []byte { 39 buffer := make([]byte, 2) 40 binary.BigEndian.PutUint16(buffer, value) 41 return append(input, buffer...) 42 } 43 44 // AppendUint32 appends the value bytes to the input slice (big endian) 45 func AppendUint32(input []byte, value uint32) []byte { 46 buffer := make([]byte, 4) 47 binary.BigEndian.PutUint32(buffer, value) 48 return append(input, buffer...) 49 } 50 51 // AppendUint64 appends the value bytes to the input slice (big endian) 52 func AppendUint64(input []byte, value uint64) []byte { 53 buffer := make([]byte, 8) 54 binary.BigEndian.PutUint64(buffer, value) 55 return append(input, buffer...) 56 } 57 58 // AppendShortData appends data shorter than 16kB 59 func AppendShortData(input []byte, data []byte) []byte { 60 if len(data) > math.MaxUint16 { 61 panic(fmt.Sprintf("short data too long! %d", len(data))) 62 } 63 input = AppendUint16(input, uint16(len(data))) 64 input = append(input, data...) 65 return input 66 } 67 68 // AppendLongData appends data shorter than 32MB 69 func AppendLongData(input []byte, data []byte) []byte { 70 if len(data) > math.MaxUint32 { 71 panic(fmt.Sprintf("long data too long! %d", len(data))) 72 } 73 input = AppendUint32(input, uint32(len(data))) 74 input = append(input, data...) 75 return input 76 } 77 78 // ReadSlice reads `size` bytes from the input 79 func ReadSlice(input []byte, size int) (value []byte, rest []byte, err error) { 80 if len(input) < size { 81 return nil, input, fmt.Errorf("input size is too small to be splited %d < %d ", len(input), size) 82 } 83 return input[:size], input[size:], nil 84 } 85 86 // ReadUint8 reads a uint8 from the input and returns the rest 87 func ReadUint8(input []byte) (value uint8, rest []byte, err error) { 88 if len(input) < 1 { 89 return 0, input, fmt.Errorf("input size (%d) is too small to read a uint8", len(input)) 90 } 91 return input[0], input[1:], nil 92 } 93 94 // ReadUint16 reads a uint16 from the input and returns the rest 95 func ReadUint16(input []byte) (value uint16, rest []byte, err error) { 96 if len(input) < 2 { 97 return 0, input, fmt.Errorf("input size (%d) is too small to read a uint16", len(input)) 98 } 99 return binary.BigEndian.Uint16(input[:2]), input[2:], nil 100 } 101 102 // ReadUint32 reads a uint32 from the input and returns the rest 103 func ReadUint32(input []byte) (value uint32, rest []byte, err error) { 104 if len(input) < 4 { 105 return 0, input, fmt.Errorf("input size (%d) is too small to read a uint32", len(input)) 106 } 107 return binary.BigEndian.Uint32(input[:4]), input[4:], nil 108 } 109 110 // ReadUint64 reads a uint64 from the input and returns the rest 111 func ReadUint64(input []byte) (value uint64, rest []byte, err error) { 112 if len(input) < 8 { 113 return 0, input, fmt.Errorf("input size (%d) is too small to read a uint64", len(input)) 114 } 115 return binary.BigEndian.Uint64(input[:8]), input[8:], nil 116 } 117 118 // ReadShortData read data shorter than 16kB and return the rest of bytes 119 func ReadShortData(input []byte) (data []byte, rest []byte, err error) { 120 var size uint16 121 size, rest, err = ReadUint16(input) 122 if err != nil { 123 return nil, rest, err 124 } 125 data = rest[:size] 126 rest = rest[size:] 127 return 128 } 129 130 // ReadShortDataFromReader reads data shorter than 16kB from reader 131 func ReadShortDataFromReader(reader io.Reader) ([]byte, error) { 132 buf, err := ReadFromBuffer(reader, 2) 133 if err != nil { 134 return nil, fmt.Errorf("cannot read short data length: %w", err) 135 } 136 137 size, _, err := ReadUint16(buf) 138 if err != nil { 139 return nil, fmt.Errorf("cannot read short data length: %w", err) 140 } 141 142 buf, err = ReadFromBuffer(reader, int(size)) 143 if err != nil { 144 return nil, fmt.Errorf("cannot read short data: %w", err) 145 } 146 147 return buf, nil 148 } 149 150 // ReadLongDataFromReader reads data shorter than 16kB from reader 151 func ReadLongDataFromReader(reader io.Reader) ([]byte, error) { 152 buf, err := ReadFromBuffer(reader, 4) 153 if err != nil { 154 return nil, fmt.Errorf("cannot read long data length: %w", err) 155 } 156 size, _, err := ReadUint32(buf) 157 if err != nil { 158 return nil, fmt.Errorf("cannot read long data length: %w", err) 159 } 160 buf, err = ReadFromBuffer(reader, int(size)) 161 if err != nil { 162 return nil, fmt.Errorf("cannot read long data: %w", err) 163 } 164 165 return buf, nil 166 } 167 168 // ReadFromBuffer reads 'length' bytes from the input 169 func ReadFromBuffer(reader io.Reader, length int) ([]byte, error) { 170 if length == 0 { 171 return nil, nil 172 } 173 buf := make([]byte, length) 174 _, err := io.ReadFull(reader, buf) 175 if err != nil { 176 return nil, fmt.Errorf("cannot read data: %w", err) 177 } 178 return buf, nil 179 }