class BinData::BasePrimitive

the value just read in.
or failure. Any other return is compared to
parameter. A boolean return indicates success
available to any lambda assigned to this
this criteria. The variable value is made
[:check_value] Raise an error unless the value read in meets
IO, not the result of the :value param.
will return the value of the data read from the
calls to #do_read and #done_read, #value
using this param. In the interval between
Calls to #value= are ignored when
[:value] The object will always have this value.
either #read or explicitly set with #value=.
[:initial_value] This is the initial value to use before one is
an object. These params include those for BinData::Base as well as:
Parameters may be provided at initialisation to control the behaviour of
== Parameters
obj.read(“007”) #=> BinData::ValidityError: value not as expected
obj = BinData::Uint8.new(:check_value => lambda { value < 5 })
obj.read(“005”) #=> BinData::ValidityError: value is ‘5’ but expected ‘3’
obj = BinData::Uint8.new(:check_value => 3)
obj.value #=> 42
obj.value = 5
obj.value #=> 42
obj = BinData::Uint8.new(:value => 42)
obj.value #=> 42
obj.clear
obj.value #=> 5
obj.value = 5
obj.value #=> 42
obj = BinData::Uint8.new(:initial_value => 42)
require ‘bindata’
this object. This value can be read from or written to an IO stream.
such as as integer, float or string. Only one value can be contained by
particular binary representation. A value corresponds to a primitive type
A BinData::BasePrimitive object is a container for a value that has a

def _assign(val)

def _assign(val)
  raise ArgumentError, "can't set a nil value for #{debug_name}" if val.nil?
  unless has_parameter?(:value)
    raw_val = val.respond_to?(:snapshot) ? val.snapshot : val
    @value = begin
               raw_val.dup
             rescue TypeError
               # can't dup Fixnums
               raw_val
             end
  end
end

def _do_num_bytes(ignored)

def _do_num_bytes(ignored)
  value_to_binary_string(_value).length
end

def _do_read(io)

def _do_read(io)
  @in_read = true
  @value   = read_and_return_value(io)
  trace_value
  if has_parameter?(:check_value)
    check_value(value)
  end
end

def _do_write(io)

def _do_write(io)
  raise "can't write whilst reading #{debug_name}" if @in_read
  io.writebytes(value_to_binary_string(_value))
end

def _done_read

def _done_read
  @in_read = false
end

def _snapshot

def _snapshot
  _value
end

def _value

modify the value.
method. This is so that #value can be overridden in subclasses to
The unmodified value of this data object. Note that #value calls this
def _value
  # Table of possible preconditions and expected outcome
  #   1. :value and !in_read          ->   :value
  #   2. :value and in_read           ->   @value
  #   3. :initial_value and clear?    ->   :initial_value
  #   4. :initial_value and !clear?   ->   @value
  #   5. clear?                       ->   sensible_default
  #   6. !clear?                      ->   @value
  if not @in_read and has_parameter?(:value)
    # rule 1 above
    eval_parameter(:value)
  else
    # combining all other rules gives this simplified expression
    @value || eval_parameter(:value) ||
      eval_parameter(:initial_value) || sensible_default()
  end
end

def check_value(current_value)

def check_value(current_value)
  expected = eval_parameter(:check_value, :value => current_value)
  if not expected
    raise ValidityError,
          "value '#{current_value}' not as expected for #{debug_name}"
  elsif current_value != expected and expected != true
    raise ValidityError,
          "value is '#{current_value}' but " +
          "expected '#{expected}' for #{debug_name}"
  end
end

def clear

def clear
  @value = nil
  @in_read = false
end

def clear?

def clear?
  @value.nil?
end

def eql?(other)

def eql?(other)
  # double dispatch
  other.eql?(snapshot)
end

def hash

def hash
  snapshot.hash
end

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

def initialize(params = {}, parent = nil)
  super(params, parent)
  @value   = nil
  @in_read = false
end

def method_missing(symbol, *args, &block)

def method_missing(symbol, *args, &block)
  if value.respond_to?(symbol)
    value.__send__(symbol, *args, &block)
  else
    super
  end
end

def read_and_return_value(io)

Read a number of bytes from +io+ and return the value they represent.
def read_and_return_value(io)
  raise NotImplementedError
end

def respond_to?(symbol, include_private=false)

def respond_to?(symbol, include_private=false)
  super || value.respond_to?(symbol, include_private)
end

def sensible_default

Return a sensible default for this data.
def sensible_default
  raise NotImplementedError
end

def trace_value

def trace_value
  BinData::trace_message do |tracer|
    value_string = _value.inspect
    if value_string.length > 30
      value_string = value_string.slice(0 .. 30) + "..."
    end
    tracer.trace("#{debug_name} => #{value_string}")
  end
end

def value

def value
  # TODO: warn "#value is deprecated, use #snapshot instead"
  snapshot
end

def value=(val)

def value=(val)
  # TODO: warn "#value= is deprecated, use #assign instead"
  assign(val)
end

def value_to_binary_string(val)

Return the string representation that +val+ will take when written.
def value_to_binary_string(val)
  raise NotImplementedError
end