Class: BinaryCodec::STArray

Inherits:
SerializedType show all
Defined in:
lib/binary-codec/types/st_array.rb

Constant Summary collapse

ARRAY_END_MARKER =
0xF1

Instance Attribute Summary

Attributes inherited from SerializedType

#bytes

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from SerializedType

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

Constructor Details

#initialize(byte_buf = nil) ⇒ STArray

Returns a new instance of STArray.



7
8
9
# File 'lib/binary-codec/types/st_array.rb', line 7

def initialize(byte_buf = nil)
  super(byte_buf || [])
end

Class Method Details

.from(value, definitions = nil) ⇒ STArray

Creates a new STArray instance from a value.

Parameters:

  • value (STArray, String, Array<Hash>)

    The value to convert.

  • definitions (Definitions, nil) (defaults to: nil)

    Optional definitions.

Returns:

  • (STArray)

    The created instance.

Raises:

  • (StandardError)


15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
# File 'lib/binary-codec/types/st_array.rb', line 15

def self.from(value, definitions = nil)
  return value if value.is_a?(STArray)
  definitions ||= Definitions.instance

  if value.is_a?(String)
    return STArray.new(hex_to_bytes(value))
  end

  if value.is_a?(Array)
    bytes = []
    value.each do |item|
      # item should be a hash with one key (the field name)
      # e.g., {"Signer" => { ... }}
      if item.is_a?(::Hash)
        # Use keys.first and unwrap directly
        field_name = item.keys.first.to_s
        field_value = item[item.keys.first]
        
        field = definitions.get_field_instance(field_name)
        bytes.concat(field.header.to_bytes)
        
        obj = STObject.from(field_value, nil, definitions)
        bytes.concat(obj.to_bytes)
        bytes.concat([0xE1]) unless bytes.last == 0xE1
      else
        raise StandardError, "STArray item must be a Hash, got #{item.class}"
      end
    end
    bytes.concat([ARRAY_END_MARKER])
    return STArray.new(bytes)
  end

  raise StandardError, "Cannot construct STArray from #{value.class}"
end

.from_parser(parser, _hint = nil) ⇒ STArray

Creates an STArray instance from a parser.

Parameters:

  • parser (BinaryParser)

    The parser to read from.

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

    Unused.

Returns:

  • (STArray)

    The created instance.



54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
# File 'lib/binary-codec/types/st_array.rb', line 54

def self.from_parser(parser, _hint = nil)
  bytes = []
  until parser.end?
    # Check if we reached the ArrayEndMarker (0xF1)
    if parser.peek == ARRAY_END_MARKER
      parser.read(1) # Consume 0xF1
      break
    end

    # In STArray, each item is an STObject with its field header.
    # So we read the field header first.
    field_header = parser.read_field_header
    
    # Then we read the STObject
    obj = STObject.from_parser(parser)
    
    # Reconstruct the serialized item: [FieldHeader][STObject][ObjectEndMarker]
    bytes.concat(field_header.to_bytes)
    bytes.concat(obj.to_bytes)
    bytes.concat([0xE1]) unless bytes.last == 0xE1
  end

  # The ArrayEndMarker has to go back in. Without it the reconstructed
  # bytes have no terminator, so re-parsing them - which is what to_json
  # does - runs the array on into whatever field follows it.
  bytes.concat([ARRAY_END_MARKER])
  STArray.new(bytes)
end

Instance Method Details

#to_json(definitions = nil, _field_name = nil) ⇒ Array<Hash>

Returns the JSON representation of the STArray.

Parameters:

  • definitions (Definitions, nil) (defaults to: nil)

    Definitions for lookup.

  • _field_name (String, nil) (defaults to: nil)

    Unused.

Returns:

  • (Array<Hash>)

    The JSON representation.



87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
# File 'lib/binary-codec/types/st_array.rb', line 87

def to_json(definitions = nil, _field_name = nil)
  definitions ||= Definitions.instance
  parser = BinaryParser.new(to_hex)
  result = []
  until parser.end?
    break if parser.peek == ARRAY_END_MARKER

    # Each item is an STObject behind its own field header, e.g. "Signer".
    field_header = parser.read_field_header
    field_name = definitions.get_field_name_from_header(field_header)
    obj = STObject.from_parser(parser)

    result << { field_name => obj.to_json(definitions) }
  end
  result
end