class BinData::Struct

calls to #read, #write, #num_bytes or #snapshot.
if false, this object will not be included in any
[:onlyif] Used to indicate a data object is optional.
Fields may have have extra parameters as listed below:
== Field Parameters
nested data objects.
endian of any numerics in this struct, or in any
:endian
Either :little or :big. This specifies the default
by name.
in #snapshot or #field_names but are still accessible
from the outside world. Hidden fields don’t appear
:hide
A list of the names of fields that are to be hidden
when instantiating it.
optional hash of parameters to pass to this field
type. Name is the name of this field. Params is an
params]. Type is a symbol representing a registered
Each element of the array is of the form [type, name,
:fields

An array specifying the fields for this struct.
an object. These params are:
Parameters may be provided at initialisation to control the behaviour of
== Parameters
obj.field_names =># [“b”, “s”]
[:tuple, :s] ])
[:int16le, :b],
:fields => [ [:int32le, :a],
obj = BinData::Struct.new(:hide => :a,
end
int8 :z
int8 :y
int8 :x
class Tuple < BinData::Record
require ‘bindata’
A Struct is an ordered collection of named data objects.

def _assign(val)

def _assign(val)
  clear
  assign_fields(as_snapshot(val))
end

def _do_num_bytes

def _do_num_bytes
  instantiate_all_objs
  sum_num_bytes_for_all_fields.ceil
end

def _do_read(io)

def _do_read(io)
  instantiate_all_objs
  @field_objs.each { |f| f.do_read(io) if include_obj(f) }
end

def _do_write(io)

def _do_write(io)
  instantiate_all_objs
  @field_objs.each { |f| f.do_write(io) if include_obj(f) }
end

def _done_read

def _done_read
  @field_objs.each { |f| f.done_read if include_obj(f) }
end

def _snapshot

def _snapshot
  snapshot = Snapshot.new
  field_names.each do |name|
    obj = find_obj_for_name(name)
    snapshot[name] = obj.snapshot if include_obj(obj)
  end
  snapshot
end

def as_snapshot(val)

def as_snapshot(val)
  if val.class == Hash
    snapshot = Snapshot.new
    val.each_pair { |k,v| snapshot[k.to_s] = v unless v.nil? }
    snapshot
  elsif val.nil?
    Snapshot.new
  else
    val
  end
end

def assign_fields(snapshot)

def assign_fields(snapshot)
  field_names(true).each do |name|
    obj = find_obj_for_name(name)
    if obj and snapshot.respond_to?(name)
      obj.assign(snapshot.__send__(name))
    end
  end
end

def clear #:nodoc:

:nodoc:
def clear #:nodoc:
  @field_objs.each { |f| f.clear unless f.nil? }
end

def clear? #:nodoc:

:nodoc:
def clear? #:nodoc:
  @field_objs.inject(true) { |all_clear, f| all_clear and (f.nil? or f.clear?) }
end

def debug_name_of(child) #:nodoc:

:nodoc:
def debug_name_of(child) #:nodoc:
  field_name = @field_names[find_index_of(child)]
  "#{debug_name}.#{field_name}"
end

def ensure_field_names_are_valid(field_names)

def ensure_field_names_are_valid(field_names)
  instance_methods = self.instance_methods.collect { |meth| meth.to_s }
  reserved_names = RESERVED
  field_names.each do |name|
    if instance_methods.include?(name)
      raise NameError.new("Rename field '#{name}' in #{self}, " +
                          "as it shadows an existing method.", name)
    end
    if reserved_names.include?(name)
      raise NameError.new("Rename field '#{name}' in #{self}, " +
                          "as it is a reserved name.", name)
    end
    if field_names.count(name) != 1
      raise NameError.new("field '#{name}' in #{self}, " +
                          "is defined multiple times.", name)
    end
  end
end

def field_names(include_hidden = false)

in the listing.
object. +include_hidden+ specifies whether to include hidden names
Returns a list of the names of all fields accessible through this
def field_names(include_hidden = false)
  if include_hidden
    @field_names.dup
  else
    hidden = get_parameter(:hide) || []
    @field_names - hidden
  end
end

def find_index_of(obj)

def find_index_of(obj)
  @field_objs.index { |el| el.equal?(obj) }
end

def find_obj_for_name(name)

def find_obj_for_name(name)
  field_name = name.to_s.chomp("=")
  index = @field_names.index(field_name)
  if index
    instantiate_obj_at(index)
    @field_objs[index]
  else
    nil
  end
end

def hidden_field_names(hidden)

def hidden_field_names(hidden)
  (hidden || []).collect { |h| h.to_s }
end

def include_obj(obj)

def include_obj(obj)
  not obj.has_parameter?(:onlyif) or obj.eval_parameter(:onlyif)
end

def initialize(params = {}, parent = nil)

def initialize(params = {}, parent = nil)
  super(params, parent)
  @field_names = get_parameter(:fields).field_names
  @field_objs  = []
end

def instantiate_all_objs

def instantiate_all_objs
  @field_names.each_index { |i| instantiate_obj_at(i) }
end

def instantiate_obj_at(index)

def instantiate_obj_at(index)
  if @field_objs[index].nil?
    field = get_parameter(:fields)[index]
    @field_objs[index] = field.instantiate(self)
  end
end

def invoke_field(obj, symbol, args)

def invoke_field(obj, symbol, args)
  name = symbol.to_s
  is_writer = (name[-1, 1] == "=")
  if is_writer
    obj.assign(*args)
  else
    obj
  end
end

def method_missing(symbol, *args, &block) #:nodoc:

:nodoc:
def method_missing(symbol, *args, &block) #:nodoc:
  obj = find_obj_for_name(symbol)
  if obj
    invoke_field(obj, symbol, args)
  else
    super
  end
end

def offset_of(child) #:nodoc:

:nodoc:
def offset_of(child) #:nodoc:
  instantiate_all_objs
  sum = sum_num_bytes_below_index(find_index_of(child))
  child.do_num_bytes.is_a?(Integer) ? sum.ceil : sum.floor
end

def respond_to?(symbol, include_private = false) #:nodoc:

:nodoc:
def respond_to?(symbol, include_private = false) #:nodoc:
  super(symbol, include_private) ||
    field_names(true).include?(symbol.to_s.chomp("="))
end

def sanitize_endian(params, sanitizer)

def sanitize_endian(params, sanitizer)
  if params.needs_sanitizing?(:endian)
    params[:endian] = sanitizer.create_sanitized_endian(params[:endian])
  end
end

def sanitize_fields(params, sanitizer)

def sanitize_fields(params, sanitizer)
  if params.needs_sanitizing?(:fields)
    fields = params[:fields]
    params[:fields] = sanitizer.create_sanitized_fields(params[:endian])
    fields.each do |ftype, fname, fparams|
      params[:fields].add_field(ftype, fname, fparams)
    end
    field_names = sanitized_field_names(params[:fields])
    ensure_field_names_are_valid(field_names)
  end
end

def sanitize_hide(params, sanitizer)

def sanitize_hide(params, sanitizer)
  if params.needs_sanitizing?(:hide) and params.has_parameter?(:fields)
    field_names = sanitized_field_names(params[:fields])
    hfield_names = hidden_field_names(params[:hide])
    params[:hide]   = (hfield_names & field_names)
  end
end

def sanitize_parameters!(params, sanitizer) #:nodoc:

:nodoc:
def sanitize_parameters!(params, sanitizer) #:nodoc:
  sanitize_endian(params, sanitizer)
  sanitize_fields(params, sanitizer)
  sanitize_hide(params, sanitizer)
end

def sanitized_field_names(sanitized_fields)

def sanitized_field_names(sanitized_fields)
  sanitized_fields.field_names
end

def sum_num_bytes_below_index(index)

def sum_num_bytes_below_index(index)
  sum = 0
  (0...index).each do |i|
    obj = @field_objs[i]
    if include_obj(obj)
      nbytes = obj.do_num_bytes
      sum = (nbytes.is_a?(Integer) ? sum.ceil : sum) + nbytes
    end
  end
  sum
end

def sum_num_bytes_for_all_fields

def sum_num_bytes_for_all_fields
  sum_num_bytes_below_index(@field_objs.length)
end