78 lines
2.2 KiB
Ruby
78 lines
2.2 KiB
Ruby
|
require 'bit-struct/vector'
|
||
|
|
||
|
class BitStruct
|
||
|
# Class for embedding a BitStruct::Vector as a field within a BitStruct.
|
||
|
# Declared with BitStruct.vector.
|
||
|
class VectorField < Field
|
||
|
# Used in describe.
|
||
|
def self.class_name
|
||
|
@class_name ||= "vector"
|
||
|
end
|
||
|
|
||
|
# Used in describe.
|
||
|
def class_name
|
||
|
@class_name ||= vector_class.name[/\w+$/]
|
||
|
end
|
||
|
|
||
|
# Returns the subclass of Vector that is used to manage the value of this
|
||
|
# field. If the class was specified in the BitStruct.vector declaration,
|
||
|
# #vector_class will return it, otherwise it will be an anonymous class
|
||
|
# (which you can assign to a constant to make nonymous ;).
|
||
|
def vector_class
|
||
|
@vector_class ||= options[:vector_class] || options["vector_class"]
|
||
|
end
|
||
|
|
||
|
def describe opts # :nodoc:
|
||
|
if opts[:expand]
|
||
|
opts = opts.dup
|
||
|
opts[:byte_offset] = offset / 8
|
||
|
opts[:omit_header] = opts[:omit_footer] = true
|
||
|
vector_class.describe(nil, opts) {|desc| yield desc}
|
||
|
else
|
||
|
super
|
||
|
end
|
||
|
end
|
||
|
|
||
|
def add_accessors_to(cl, attr = name) # :nodoc:
|
||
|
unless offset % 8 == 0
|
||
|
raise ArgumentError,
|
||
|
"Bad offset, #{offset}, for vector field #{name}." +
|
||
|
" Must be multiple of 8."
|
||
|
end
|
||
|
|
||
|
unless length % 8 == 0
|
||
|
raise ArgumentError,
|
||
|
"Bad length, #{length}, for vector field #{name}." +
|
||
|
" Must be multiple of 8."
|
||
|
end
|
||
|
|
||
|
offset_byte = offset / 8
|
||
|
length_byte = length / 8
|
||
|
last_byte = offset_byte + length_byte - 1
|
||
|
byte_range = offset_byte..last_byte
|
||
|
|
||
|
vc = vector_class
|
||
|
|
||
|
cl.class_eval do
|
||
|
define_method attr do ||
|
||
|
vc.new(self[byte_range])
|
||
|
end
|
||
|
|
||
|
define_method "#{attr}=" do |val|
|
||
|
if val.length != length_byte
|
||
|
raise ArgumentError, "Size mismatch in vector field assignment " +
|
||
|
"to #{attr} with value #{val.inspect}"
|
||
|
end
|
||
|
|
||
|
if val.class != vc
|
||
|
warn "Type mismatch in vector field assignment " +
|
||
|
"to #{attr} with value #{val.inspect}"
|
||
|
end
|
||
|
|
||
|
self[byte_range] = val
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
end
|