github.com/ledgerwatch/erigon-lib@v1.0.0/common/bytes4.go (about)

     1  package common
     2  
     3  import (
     4  	"bytes"
     5  	"database/sql/driver"
     6  	"encoding/hex"
     7  	"fmt"
     8  	"math/rand"
     9  	"reflect"
    10  
    11  	"github.com/ledgerwatch/erigon-lib/common/hexutility"
    12  	"github.com/ledgerwatch/erigon-lib/common/length"
    13  )
    14  
    15  var (
    16  	bytes4T = reflect.TypeOf(Bytes4{})
    17  )
    18  
    19  type Bytes4 [length.Bytes4]byte
    20  
    21  // Hex converts a hash to a hex string.
    22  func (b Bytes4) Hex() string { return hexutility.Encode(b[:]) }
    23  
    24  // UnmarshalJSON parses a hash in hex syntax.
    25  func (b *Bytes4) UnmarshalJSON(input []byte) error {
    26  	return hexutility.UnmarshalFixedJSON(bytes4T, input, b[:])
    27  }
    28  
    29  // UnmarshalText parses a hash in hex syntax.
    30  func (b *Bytes4) UnmarshalText(input []byte) error {
    31  	return hexutility.UnmarshalFixedText("Bytes4", input, b[:])
    32  }
    33  
    34  // MarshalText returns the hex representation of a.
    35  func (b Bytes4) MarshalText() ([]byte, error) {
    36  	bl := b[:]
    37  	result := make([]byte, len(b)*2+2)
    38  	copy(result, hexPrefix)
    39  	hex.Encode(result[2:], bl)
    40  	return result, nil
    41  }
    42  
    43  // Format implements fmt.Formatter.
    44  // Hash supports the %v, %s, %v, %x, %X and %d format verbs.
    45  func (b Bytes4) Format(s fmt.State, c rune) {
    46  	hexb := make([]byte, 2+len(b)*2)
    47  	copy(hexb, "0x")
    48  	hex.Encode(hexb[2:], b[:])
    49  
    50  	switch c {
    51  	case 'x', 'X':
    52  		if !s.Flag('#') {
    53  			hexb = hexb[2:]
    54  		}
    55  		if c == 'X' {
    56  			hexb = bytes.ToUpper(hexb)
    57  		}
    58  		fallthrough
    59  	case 'v', 's':
    60  		s.Write(hexb)
    61  	case 'q':
    62  		q := []byte{'"'}
    63  		s.Write(q)
    64  		s.Write(hexb)
    65  		s.Write(q)
    66  	case 'd':
    67  		fmt.Fprint(s, ([len(b)]byte)(b))
    68  	default:
    69  		fmt.Fprintf(s, "%%!%c(hash=%x)", c, b)
    70  	}
    71  }
    72  
    73  // String implements the stringer interface and is used also by the logger when
    74  // doing full logging into a file.
    75  func (b Bytes4) String() string {
    76  	return b.Hex()
    77  }
    78  
    79  // SetBytes sets the hash to the value of i.
    80  // If b is larger than len(h), b will be cropped from the left.
    81  func (b *Bytes4) SetBytes(i []byte) {
    82  	if len(i) > len(b) {
    83  		i = i[len(i)-length.Hash:]
    84  	}
    85  
    86  	copy(b[length.Hash-len(i):], i)
    87  }
    88  
    89  // Generate implements testing/quick.Generator.
    90  func (b Bytes4) Generate(rand *rand.Rand, size int) reflect.Value {
    91  	m := rand.Intn(len(b))
    92  	for i := len(b) - 1; i > m; i-- {
    93  		b[i] = byte(rand.Uint32())
    94  	}
    95  	return reflect.ValueOf(b)
    96  }
    97  
    98  // Value implements valuer for database/sql.
    99  func (b Bytes4) Value() (driver.Value, error) {
   100  	return b[:], nil
   101  }
   102  
   103  // TerminalString implements log.TerminalStringer, formatting a string for console
   104  // output during logging.
   105  func (b Bytes4) TerminalString() string {
   106  	return fmt.Sprintf("%x", b)
   107  }