lib/gogyou/model.rb in gogyou-0.2.2 vs lib/gogyou/model.rb in gogyou-0.2.3
- old
+ new
@@ -11,18 +11,28 @@
FIELDNAME_PATTERN = /\A[A-Za-z_][0-9A-Za-z_]*\Z/
undef :bytesize=, :bytealign=, :fields=
- def initialize(*args)
- case
- when args.size < 3
- raise ArgumentError, "wrong argument size (#{args.size} for 3+)"
- when args.size < 4 && args[2].kind_of?(::Array)
+ #
+ # call-seq:
+ # initialize(bytesize, bytealign, fields, ...)
+ #
+ # [bytesize]
+ # This is total model size in bytes.
+ #
+ # [bytealign]
+ # This is model alignment size in bytes.
+ #
+ # [fields ...]
+ # These are one or more field instance.
+ #
+ def initialize(bytesize, bytealign, field1, *fields)
+ if fields.empty? && field1.kind_of?(::Array)
super
else
- super(args[0], args[1], args.slice(2 .. -1))
+ super bytesize.to_i, bytealign.to_i, [field1, *fields]
end
end
def aset(buffer, offset, value)
raise NotImplementedError
@@ -83,10 +93,15 @@
else
type.extensible?
end
end
+ def bytesize
+ s = type.bytesize
+ vector ? vector.inject(&:*) * s : s
+ end
+
def const?
((flags & CONST_BITMASK) == CONST_BITMASK) ? true : false
end
def packed?
@@ -213,11 +228,11 @@
def maxalign(fields = self.fields)
fields.map { |f| f.packed? ? f.packsize : f.type.bytealign }.max
end
def maxsize(fields = self.fields)
- fields.map { |f| s = f.type.bytesize; f.vector ? f.vector.inject(&:*) * s : s }.max
+ fields.map { |f| f.bytesize }.max
end
def flatten_field(fields = self.fields)
#pp fields
fields2 = []
@@ -234,63 +249,19 @@
end
end
fields2
end
- # :nodoc: all
- class Proxy < Object
- #class Proxy < BasicObject
- def initialize(creator, packexp = Field::PACKSIZE_NOTDEFINE)
- #singleton_class = (class << proxy; self; end)
- singleton_class.class_eval do
- latest_fields = nil
- #define_method(:method_missing, ->(type, *args) { latest_fields = creator.addfield(type, args); nil })
- creator.typemap.each_key do |t|
- define_method(t, ->(*args) { latest_fields = creator.addfield(t, packexp, args); nil })
- end
- define_method(:struct, ->(*args, &block) { latest_fields = creator.struct(args, packexp, &block); nil })
- define_method(:union, ->(*args, &block) { latest_fields = creator.union(args, packexp, &block); nil })
- define_method(:const, ->(dummy_fields) { creator.const(latest_fields); latest_fields = nil; nil })
- define_method(:typedef, ->(*args, &block) { creator.typedef(args, &block) })
- packexp0 = nil
- define_method(:packed, ->(bytealign = 1, &block) {
- raise "wrong nested ``packed''" if packexp0
- exp = Math.log(bytealign, 2)
- # exp が Nan Infinity -Infinity の場合は例外が発生するので、それに対する処置も行う
- unless ((exp = exp.to_i) rescue nil) && (1 << exp) == bytealign
- raise ArgumentError, "shall be given power of two (but #{bytealign})"
- end
-
- begin
- packexp0 = packexp
- packexp = exp
- self.instance_exec(&block)
- ensure
- (packexp, packexp0) = packexp0, nil
- end
-
- nil
- })
- if creator.respond_to?(:bytealign)
- define_method(:bytealign, ->(bytesize, &block) { creator.bytealign(bytesize, &block); nil })
- end
- if creator.respond_to?(:padding)
- define_method(:padding, ->(bytesize, &block) { creator.padding(bytesize, &block); nil })
- end
- end
- end
- end
-
#
# call-seq:
# struct type, name, *vector
# struct proc, name, *vector
# struct { ... }
#
- # 最初の呼び出し方法は、既存の (typedef していない) 型情報を用いる、または構造体をその場で定義するために利用できます。
+ # 最初と二番目の呼び出し方法は、既存の (typedef していない) 型情報を用いる、または構造体をその場で定義するために利用できます。
#
- # 二番目の呼び出し方法は、無名構造体を定義するために利用できます。
+ # 三番目の呼び出し方法は、無名構造体を定義するために利用できます。
#
# === example (型情報を用いる)
#
# Type1 = struct {
# struct UserType, :a, :b, 2, 3, 4
@@ -359,10 +330,32 @@
def const(fields)
fields.each { |f| f.set_const }
end
#
+ # call-seq:
+ # packed { ... } -> nil
+ # packed(bytealign) { ... } -> nil
+ #
+ # ブロック内部のフィールドのバイトアライメントを調節します。
+ #
+ # packed を直接の入れ子にして呼び出すことは出来ません。struct や union を挟んで呼び出すことは出来ます。
+ #
+ # 引数無しで呼び出した場合は、bytealign に 1 を与えて呼び出すものと同義となります。
+ #
+ # [bytealign]
+ # 1 以上で2の冪乗となる整数値を指定します。
+ #
+ # nil を与えた場合、上位階層で指定したパックサイズを無効化して本来のバイトアライメントに配置するようにします。
+ #
+ def packed(bytealign = 1)
+ raise "This method is defined for documentaion. Real implemented is in Gogyou::Model::BasicCreator::Proxy#initialize"
+ yield
+ nil
+ end
+
+ #
# フィールド名の解析
#
def parse!(args)
raise ArgumentError, "nothing argument" if args.empty?
name = nil
@@ -426,9 +419,56 @@
self.offset += typesize * elements
end
end
tmpfields
+ end
+
+ class Proxy < Object # :nodoc: all
+ #class Proxy < BasicObject
+ def initialize(creator, packexp = Field::PACKSIZE_NOTDEFINE)
+ #singleton_class = (class << proxy; self; end)
+ singleton_class.class_eval do
+ latest_fields = nil
+ #define_method(:method_missing, ->(type, *args) { latest_fields = creator.addfield(type, args); nil })
+ creator.typemap.each_key do |t|
+ define_method(t, ->(*args) { latest_fields = creator.addfield(t, packexp, args); nil })
+ end
+ define_method(:struct, ->(*args, &block) { latest_fields = creator.struct(args, packexp, &block); nil })
+ define_method(:union, ->(*args, &block) { latest_fields = creator.union(args, packexp, &block); nil })
+ define_method(:const, ->(dummy_fields) { creator.const(latest_fields); latest_fields = nil; nil })
+ define_method(:typedef, ->(*args, &block) { creator.typedef(args, &block) })
+ packexp0 = nil
+ define_method(:packed, ->(bytealign = 1, &block) {
+ raise "wrong nested ``packed''" if packexp0
+ if bytealign.nil?
+ exp = Field::PACKSIZE_NOTDEFINE
+ else
+ exp = Math.log(bytealign, 2)
+ # exp が Nan Infinity -Infinity の場合は例外が発生するので、それに対する処置も行う
+ unless ((exp = exp.to_i) rescue nil) && (1 << exp) == bytealign
+ raise ArgumentError, "shall be given power of two (but #{bytealign})"
+ end
+ end
+
+ begin
+ packexp0 = packexp
+ packexp = exp
+ self.instance_exec(&block)
+ ensure
+ (packexp, packexp0) = packexp0, nil
+ end
+
+ nil
+ })
+ if creator.respond_to?(:bytealign)
+ define_method(:bytealign, ->(bytesize, &block) { creator.bytealign(bytesize, &block); nil })
+ end
+ if creator.respond_to?(:padding)
+ define_method(:padding, ->(bytesize, &block) { creator.padding(bytesize, &block); nil })
+ end
+ end
+ end
end
end
class Struct < Model
class Creator < Model::BasicCreator