lib/gogyou/accessor.rb in gogyou-0.2.4 vs lib/gogyou/accessor.rb in gogyou-0.2.5

- old
+ new

@@ -175,10 +175,16 @@ subarray.name # すでに名前が定義されてる場合はこれで固定される Accessor.const_set("UserArray_%08X" % subarray.__id__, subarray) subarray end + def self.define_subpointer(typeobj, constant = false) + newtype = Accessor::Pointer.define(typeobj) + Accessor.const_set("AnonymousPointer_%08X" % newtype.__id__, newtype) + newtype + end + def self.define_accessors(accessorclass, model) accessorclass.class_eval do namecheck = {} fieldsize = model.fields.size define_method(:size__GOGYOU__, -> { fieldsize }) @@ -248,9 +254,117 @@ # # 型情報オブジェクトとしてのメソッドです。 # def self.extensible? self::EXTENSIBLE + end + + class Pointer < Accessor + BYTESIZE = Primitives::SIZE_T.bytesize + BYTEALIGN = Primitives::SIZE_T.bytealign + EXTENSIBLE = false + + def self.aref(buf, off) + new(buf, off) + end + + def self.aset(buf, off, val) + if val.kind_of?(Fixnum) + buf.store_sizet(off, val) + else + raise PointerError, "wrong address (#{val.class} for Fixnum)" + end + + buf + end + + def self.define(type) + require_relative "fiddle" # for Fiddle::Pointer and extend + + Class.new(Pointer) do |t| + define_singleton_method(:aset, ->(buf, off, val) { + if val.kind_of?(self) + addr = val.buffer.load_sizet(val.offset) + buf.store_sizet(off, addr) + else + super + end + + buf + }) + + define_method(:pointer_address, -> { + @buffer__GOGYOU__.load_sizet(@offset__GOGYOU__) + }) + + define_method(:[], ->(*args) { + case args.size + when 0 + elem = 0 + when 1 + elem = args[0].to_i + else + raise ArgumentError, "wrong argument size (#{args.size} for 0 .. 1)" + end + addr = @buffer__GOGYOU__.load_sizet(@offset__GOGYOU__) + if addr == 0 + raise NullPointerError, "nullpo - #<%s:0x%08X>" % [self.class, __id__ << 1] + end + buf = ::Fiddle::Pointer.new(addr + elem * type.bytesize, type.bytesize) + type.aref(buf, 0) + }) + + define_method(:[]=, ->(*args) { + case args.size + when 1 + elem = 0 + v = args[0] + when 2 + elem = args[0].to_i + v = args[1] + else + raise ArgumentError, "wrong argument size (#{args.size} for 1 .. 2)" + end + + addr = @buffer__GOGYOU__.load_sizet(@offset__GOGYOU__) + if addr == 0 + raise NullPointerError, "nullpo - #<%s:0x%08X>" % [self.class, __id__ << 1] + end + buf = ::Fiddle::Pointer.new(addr + elem * type.bytesize, type.bytesize) + type.aset(buf, 0, v) + v + }) + + define_method(:+, ->(elem) { + addr = @buffer__GOGYOU__.load_sizet(@offset__GOGYOU__) + buf = String.alloc(Primitives::SIZE_T.bytesize) + buf.store_sizet(0, addr + elem * type.bytesize) + self.class.new(buf, 0) + }) + + typename = String(type.respond_to?(:name) ? type.name : type) rescue String(type) + define_method(:inspect, -> { + addr = @buffer__GOGYOU__.load_sizet(@offset__GOGYOU__) + "#<*%s:0x%08X>" % [typename, addr] + }) + end + end + + # + # call-seq: + # self + elem_num -> new pointer object + # + def +(elem_num) + raise NotImplementedError, "this method is shall be defined in sub-class" + end + + def -(off) + send(:+, -off.to_i) + end + + def pretty_print(q) + q.text inspect + end end class BasicStruct < Accessor end