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  }