Class: BinaryCodec::Uint

Inherits:
ComparableSerializedType show all
Defined in:
lib/binary-codec/types/uint.rb,
lib/binary-codec/types/uint.rb

Constant Summary collapse

BASE10_UINT64_FIELDS =

UInt64 fields that rippled renders in base 10 rather than as hex. They hold MPToken amounts, where a hex string would be a needless surprise.

%w[
  MaximumAmount
  OutstandingAmount
  MPTAmount
  LockedAmount
  ConfidentialOutstandingAmount
].freeze
NAMED_VALUES =

Which name tables a width accepts on the way in ...

{
  Uint16 => %i[transaction_types ledger_entry_types],
  Uint8 => %i[transaction_results],
  Uint32 => %i[delegatable_permissions]
}.freeze
NAMED_FIELDS =

... and which field renders its value by name on the way out.

{
  'TransactionType' => :transaction_types,
  'LedgerEntryType' => :ledger_entry_types,
  'TransactionResult' => :transaction_results,
  'PermissionValue' => :delegatable_permissions
}.freeze

Instance Attribute Summary

Attributes inherited from SerializedType

#bytes

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from ComparableSerializedType

#eq, #gt, #gte, #lt, #lte

Methods inherited from SerializedType

from_bytes, from_hex, from_json, get_type_by_name, #to_byte_sink, #to_bytes, #to_hex

Constructor Details

#initialize(byte_buf = nil) ⇒ Uint

Returns a new instance of Uint.



22
23
24
# File 'lib/binary-codec/types/uint.rb', line 22

def initialize(byte_buf = nil)
  super(byte_buf || Array.new(self.class.width, 0))
end

Class Method Details

.from(value) ⇒ Uint

Creates a new Uint instance from a value.

Parameters:

  • value (Uint, String, Integer) —

    The value to convert.

Returns:

  • (Uint) —

    The created instance.

Raises:

  • (StandardError)


29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
# File 'lib/binary-codec/types/uint.rb', line 29

def self.from(value)
  return value if value.is_a?(self)

  if value.is_a?(String)
    # Names for the fields that carry one: TransactionType and
    # LedgerEntryType (UInt16), TransactionResult (UInt8) and the
    # PermissionValue of a DelegateSet (UInt32). A name is never a valid
    # number, so the lookup cannot capture a numeric string.
    code = NAMED_VALUES.fetch(self, [])
                       .filter_map { |table| Definitions.instance.public_send(table)[value] }
                       .first
    return new(int_to_bytes(code, width)) if code

    # Handle hex strings or numeric strings
    if valid_hex?(value) && value.length == self.width * 2
      return new(hex_to_bytes(value))
    end
    return new(int_to_bytes(value.to_i, width))
  end

  if value.is_a?(Integer)
    return new(int_to_bytes(value, width))
  end

  raise StandardError, "Cannot construct #{self} from the value given"
end

.from_parser(parser, _hint = nil) ⇒ Uint

Creates a Uint instance from a parser.

Parameters:

  • parser (BinaryParser) —

    The parser to read from.

  • _hint (Integer, nil) (defaults to: nil) —

    Unused hint.

Returns:

  • (Uint) —

    The created instance.



60
61
62
# File 'lib/binary-codec/types/uint.rb', line 60

def self.from_parser(parser, _hint = nil)
  new(parser.read(width))
end

.width ⇒ Integer

Returns the width of the Uint type in bytes.

Returns:

  • (Integer) —

    The width.



18
19
20
# File 'lib/binary-codec/types/uint.rb', line 18

def self.width
  @width
end

Instance Method Details

#compare_to(other) ⇒ Integer

Returns Comparison result (-1, 0, or 1).

Parameters:

  • other (Uint) —

    The other Uint to compare to.

Returns:

  • (Integer) —

    Comparison result (-1, 0, or 1).



98
99
100
# File 'lib/binary-codec/types/uint.rb', line 98

def compare_to(other)
  value_of <=> other.value_of
end

#to_json(_definitions = nil, _field_name = nil) ⇒ Integer, String

Returns the JSON representation of the Uint.

Returns:

  • (Integer, String) —

    The value.



72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
# File 'lib/binary-codec/types/uint.rb', line 72

def to_json(_definitions = nil, _field_name = nil)
  # The fields that carry a name render it, the way rippled does. A code
  # without a name falls through and renders as the number.
  table = NAMED_FIELDS[_field_name]
  if table
    name = Definitions.instance.public_send(table).key(value_of)
    return name if name
  end

  # rippled renders the narrow unsigned integers as JSON numbers and UInt64
  # as a 16 digit hex string, because a UInt64 does not survive a round trip
  # through a JSON number. The MPToken amount fields are the exception to
  # that exception: they are UInt64 but carry a base 10 string.
  #
  # Everything wider than 8 bytes (Uint96 and up) is hash-like and stays
  # hex. Do not widen the numeric branch to cover it.
  val = value_of
  return val if self.class.width < 8
  return val.to_s if self.class.width == 8 && BASE10_UINT64_FIELDS.include?(_field_name)

  # Hex is unsigned, so a negative signed value has to wrap first.
  val += (1 << (self.class.width * 8)) if val < 0
  val.to_s(16).upcase.rjust(self.class.width * 2, '0')
end

#value_of ⇒ Integer

Returns the numeric value of the Uint.

Returns:

  • (Integer) —

    The numeric value.



66
67
68
# File 'lib/binary-codec/types/uint.rb', line 66

def value_of
  @bytes.reduce(0) { |acc, byte| (acc << 8) + byte }
end