github.com/nspcc-dev/neo-go@v0.105.2-0.20240517133400-6be757af3eba/pkg/util/uint160.go (about)

     1  package util
     2  
     3  import (
     4  	"encoding/hex"
     5  	"encoding/json"
     6  	"fmt"
     7  	"strings"
     8  
     9  	"github.com/nspcc-dev/neo-go/pkg/io"
    10  	"github.com/nspcc-dev/neo-go/pkg/util/slice"
    11  )
    12  
    13  // Uint160Size is the size of Uint160 in bytes.
    14  const Uint160Size = 20
    15  
    16  // Uint160 is a 20 byte long unsigned integer.
    17  type Uint160 [Uint160Size]uint8
    18  
    19  // Uint160DecodeStringBE attempts to decode the given string into a Uint160.
    20  func Uint160DecodeStringBE(s string) (Uint160, error) {
    21  	var u Uint160
    22  	if len(s) != Uint160Size*2 {
    23  		return u, fmt.Errorf("expected string size of %d got %d", Uint160Size*2, len(s))
    24  	}
    25  	b, err := hex.DecodeString(s)
    26  	if err != nil {
    27  		return u, err
    28  	}
    29  	return Uint160DecodeBytesBE(b)
    30  }
    31  
    32  // Uint160DecodeStringLE attempts to decode the given string
    33  // in little-endian hex encoding into a Uint160.
    34  func Uint160DecodeStringLE(s string) (Uint160, error) {
    35  	var u Uint160
    36  	if len(s) != Uint160Size*2 {
    37  		return u, fmt.Errorf("expected string size of %d got %d", Uint160Size*2, len(s))
    38  	}
    39  
    40  	b, err := hex.DecodeString(s)
    41  	if err != nil {
    42  		return u, err
    43  	}
    44  
    45  	return Uint160DecodeBytesLE(b)
    46  }
    47  
    48  // Uint160DecodeBytesBE attempts to decode the given bytes into a Uint160.
    49  func Uint160DecodeBytesBE(b []byte) (u Uint160, err error) {
    50  	if len(b) != Uint160Size {
    51  		return u, fmt.Errorf("expected byte size of %d got %d", Uint160Size, len(b))
    52  	}
    53  	copy(u[:], b)
    54  	return
    55  }
    56  
    57  // Uint160DecodeBytesLE attempts to decode the given bytes in little-endian
    58  // into a Uint160.
    59  func Uint160DecodeBytesLE(b []byte) (u Uint160, err error) {
    60  	if len(b) != Uint160Size {
    61  		return u, fmt.Errorf("expected byte size of %d got %d", Uint160Size, len(b))
    62  	}
    63  
    64  	for i := range b {
    65  		u[Uint160Size-i-1] = b[i]
    66  	}
    67  
    68  	return
    69  }
    70  
    71  // BytesBE returns a big-endian byte representation of u.
    72  func (u Uint160) BytesBE() []byte {
    73  	return u[:]
    74  }
    75  
    76  // BytesLE returns a little-endian byte representation of u.
    77  func (u Uint160) BytesLE() []byte {
    78  	return slice.CopyReverse(u.BytesBE())
    79  }
    80  
    81  // String implements the stringer interface.
    82  func (u Uint160) String() string {
    83  	return u.StringBE()
    84  }
    85  
    86  // StringBE returns string representations of u with big-endian byte order.
    87  func (u Uint160) StringBE() string {
    88  	return hex.EncodeToString(u.BytesBE())
    89  }
    90  
    91  // StringLE returns string representations of u with little-endian byte order.
    92  func (u Uint160) StringLE() string {
    93  	return hex.EncodeToString(u.BytesLE())
    94  }
    95  
    96  // Reverse returns a reversed representation of u.
    97  func (u Uint160) Reverse() (r Uint160) {
    98  	for i := 0; i < Uint160Size; i++ {
    99  		r[i] = u[Uint160Size-i-1]
   100  	}
   101  
   102  	return
   103  }
   104  
   105  // Equals returns true if both Uint160 values are the same.
   106  func (u Uint160) Equals(other Uint160) bool {
   107  	return u == other
   108  }
   109  
   110  // Less returns true if this value is less than the given Uint160 value. It's
   111  // primarily intended to be used for sorting purposes.
   112  func (u Uint160) Less(other Uint160) bool {
   113  	for k := range u {
   114  		if u[k] == other[k] {
   115  			continue
   116  		}
   117  		return u[k] < other[k]
   118  	}
   119  	return false
   120  }
   121  
   122  // UnmarshalJSON implements the json unmarshaller interface.
   123  func (u *Uint160) UnmarshalJSON(data []byte) (err error) {
   124  	var js string
   125  	if err = json.Unmarshal(data, &js); err != nil {
   126  		return err
   127  	}
   128  	js = strings.TrimPrefix(js, "0x")
   129  	*u, err = Uint160DecodeStringLE(js)
   130  	return err
   131  }
   132  
   133  // MarshalJSON implements the json marshaller interface.
   134  func (u Uint160) MarshalJSON() ([]byte, error) {
   135  	r := make([]byte, 3+Uint160Size*2+1)
   136  	copy(r, `"0x`)
   137  	r[len(r)-1] = '"'
   138  	slice.Reverse(u[:]) // u is a copy, so we can mangle it in any way.
   139  	hex.Encode(r[3:], u[:])
   140  	return r, nil
   141  }
   142  
   143  // UnmarshalYAML implements the YAML Unmarshaler interface.
   144  func (u *Uint160) UnmarshalYAML(unmarshal func(any) error) error {
   145  	var s string
   146  
   147  	err := unmarshal(&s)
   148  	if err != nil {
   149  		return err
   150  	}
   151  
   152  	s = strings.TrimPrefix(s, "0x")
   153  	*u, err = Uint160DecodeStringLE(s)
   154  	return err
   155  }
   156  
   157  // MarshalYAML implements the YAML marshaller interface.
   158  func (u Uint160) MarshalYAML() (any, error) {
   159  	return "0x" + u.StringLE(), nil
   160  }
   161  
   162  // EncodeBinary implements the Serializable interface.
   163  func (u *Uint160) EncodeBinary(bw *io.BinWriter) {
   164  	bw.WriteBytes(u[:])
   165  }
   166  
   167  // DecodeBinary implements the Serializable interface.
   168  func (u *Uint160) DecodeBinary(br *io.BinReader) {
   169  	br.ReadBytes(u[:])
   170  }