gogyou 0.2.1 → 0.2.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: c1f4c10b0e249b1b9897b5b1c317e0ef5e535830
4
- data.tar.gz: c8ccad916b49f45e18d91bff8538cf1b7e5b6377
3
+ metadata.gz: ff192352d61629b6bcec6f1f4a3ce798c2cab5ff
4
+ data.tar.gz: 244710ba81429d85608ed708424971d5c1bcd843
5
5
  SHA512:
6
- metadata.gz: b73dba83766abfce2f63ba2daad894fdf3b7560ed20bfa613d9d388aa707f053dac67f8133f6fe76002eb0958824d8b6cec23fc1a05b58228244d1ab0cfdb503
7
- data.tar.gz: 93b5fb1d45270650ff47c10746ec94ddf0b44c59751b8f035af841902a0fc807f02e2c39820447ca9d055aeafa1abc4ee1ab78a9e2f72383e5d7db0a7e325fd1
6
+ metadata.gz: b575790ca4b409310f7418dcc4e12220a9dfaeb511f4449756ad9997e83abf1c77953efa2d3dcc33c28e8b5fe92e0f71b66bb65ba296603054ab2639b85904eb
7
+ data.tar.gz: 3cc09af86d7884cca95aa399c912d19963608399273d45dd96cfbedc239c136f718e87ce2d2a8c6918d5757a0e2ddded0d93ff94afe45840f894de9ded4f003c
@@ -77,7 +77,7 @@ end
77
77
  obj = MyRuby::RObject.new
78
78
  # or obj = MyRuby::RObject.new(File.read("sample.bin", MyRuby::RObject.size, mode: "rb"))
79
79
  obj.basic.flags = 0x12345678
80
- (obj.basic.klass = 0xaaaaaaaa) rescue $! # => exception! klass field is immutable type
80
+ (obj.basic.klass = 0xaaaaaaaa) rescue p $! # => exception! klass field is immutable type
81
81
  obj.basic.force_modify.klass = 0xaaaaaaaa
82
82
  obj.as.heap.numiv = 0x55555555
83
83
  p obj.as.ary[0] # => 0x55555555
@@ -97,37 +97,73 @@ p obj.to_buffer # => "xV4\x12\0\0\0\0\xaa\xaa\xaa\xaa\0\0\0\0UUUU\0\0\0\0DDDD\0
97
97
 
98
98
  C に似た構造体・共用体に対応 (入れ子構造も可能)
99
99
 
100
- struct {
101
- struct {
102
- ....
103
- union {
104
- ....
105
- struct {
106
- ....
107
- }
108
- }
109
- ....
110
- }
111
- }
100
+ ``` ruby:ruby
101
+ X = Gogyou.struct {
102
+ int :a
103
+ float :b
104
+ double :c
105
+ union {
106
+ struct -> {
107
+ float :x, y, z
108
+ }, :d
109
+ const struct -> {
110
+ int :x, :y, :z
111
+ }, :e
112
+ }
113
+ }
114
+ ```
112
115
 
113
116
  * Support multidimensional arrays
114
117
 
115
118
  多次元配列に対応
116
119
 
117
- struct {
118
- char :name, 64, 4 # => char name[64][4];
119
- }
120
+ ``` ruby:ruby
121
+ Gogyou.struct {
122
+ char :name, 64, 4 # => char name[64][4];
123
+ }
124
+ ```
120
125
 
121
126
  * Alias types by `typedef` (with array)
122
127
 
123
128
  `typedef` による型の別名定義 (配列も可能)
124
129
 
125
- typedef :float, :vector3f, 3 # => C: typedef float vector3f[3];
130
+ ``` ruby:ruby
131
+ module MyModule
132
+ extend Gogyou
133
+
134
+ typedef :float, :vector3f, 3 # => C: typedef float vector3f[3];
135
+
136
+ X = struct { # struct X {
137
+ vector3f :a # vector3f a;
138
+ vector3f :b, 4 # vector3f b[4];
139
+ } # };
140
+ end
141
+ ```
142
+
143
+ * Support packed struct liked GCC ``__attribute__((packed))``
144
+
145
+ GCC の ``__attribute__((packed))`` に似た、パックされた構造体に対応
146
+
147
+ C 言語での記述
148
+
149
+ ``` c:c
150
+ struct X
151
+ {
152
+ char a;
153
+ int b;
154
+ } __attribute__((packed));
155
+ ```
156
+
157
+ ruby による記述
126
158
 
127
- X = struct { # struct X {
128
- vector3f :a # vector3f a;
129
- vector3f :b, 4 # vector3f b[4];
130
- } # };
159
+ ``` ruby:ruby
160
+ X = Gogyou.struct {
161
+ packed {
162
+ char :a
163
+ int :b
164
+ }
165
+ }
166
+ ```
131
167
 
132
168
  * Appended bit operation for Integer
133
169
 
@@ -284,7 +320,7 @@ struct 内の struct の呼び出し方法を示します。union も同様に
284
320
 
285
321
  例として、MD5 を定義する場合の型情報は次のようになります。
286
322
 
287
- ```ruby:ruby
323
+ ``` ruby:ruby
288
324
  class MD5
289
325
  def self.bytesize
290
326
  16
@@ -308,6 +344,18 @@ class MD5
308
344
  end
309
345
  ```
310
346
 
347
+ これらのメソッドを一つ一つ定義する代わりに、任意のクラス・モジュールの中で ``Gogyou.define_typeinfo`` を用いることでまとめて定義することも出来ます。
348
+
349
+ ``` ruby:ruby
350
+ class MD5
351
+ Gogyou.define_typeinfo(16, # bytesize
352
+ 1, # bytealign
353
+ false, # extensible?
354
+ ->(buffer, offset) { ... snip ... }, # aref
355
+ ->(buffer, offset, data) { ... snip ... }) # aset
356
+ end
357
+ ```
358
+
311
359
  順を追って説明していきます。
312
360
 
313
361
  ### `.bytesize`
@@ -413,6 +461,60 @@ class MD5
413
461
  end
414
462
  ```
415
463
 
464
+ ## Define packed struct
465
+
466
+ GCC の ``__attribute__((packed))`` に似たパックされた構造体のフィールドを定義するには、そのフィールドを ``packed`` メソッドのブロックとして囲うことで行います。
467
+
468
+ 構造体自体をパックするには、その構造体のフィールド全体を ``packed`` することで行います。
469
+
470
+ また、``packed`` の中に ``struct`` や ``union`` を含めることも出来、その入れ子内部で ``packed`` を行うことも出来ます。
471
+
472
+ ただし ``packed`` を直接入れ子にして呼び出すことは出来ません。
473
+
474
+ 構造体全体を ``packed`` する場合:
475
+
476
+ ``` ruby:ruby
477
+ X = Gogyou.struct {
478
+ packed {
479
+ char :a
480
+ int :b
481
+ int :c
482
+ }
483
+ }
484
+
485
+ p X.bytesize # => 9
486
+ ```
487
+
488
+ ``packed`` された入れ子構造体の内部でさらに ``packed`` する場合:
489
+
490
+ ``` ruby:ruby
491
+ Y = Gogyou.struct {
492
+ char :a
493
+ packed {
494
+ struct {
495
+ int :b
496
+ }
497
+ }
498
+ char :c, 3
499
+ int :d
500
+ }
501
+
502
+ p Y.bytesize # => 12
503
+ ```
504
+
505
+ 直接入れ子にして ``packed`` して例外が発生する場合:
506
+
507
+ ``` ruby:ruby
508
+ Z = Gogyou.struct {
509
+ packed {
510
+ packed { ## => EXCEPTION!
511
+ char :a
512
+ int :b
513
+ }
514
+ }
515
+ }
516
+ ```
517
+
416
518
 
417
519
  ## Demerit (短所)
418
520
 
@@ -423,7 +525,3 @@ end
423
525
  * The cost is high for reference/asignment from/to fields
424
526
 
425
527
  フィールドに対する参照・代入のコストが高い
426
-
427
- * Can't be definition for packed struct
428
-
429
- パックされた構造体の定義が出来ない (常にフィールドは型によるバイト境界に強制配置される)
@@ -141,7 +141,7 @@
141
141
  #
142
142
  module Gogyou
143
143
  Gogyou = self
144
- VERSION = Gem::Version.new("0.2.1")
144
+ VERSION = Gem::Version.new("0.2.2")
145
145
 
146
146
  require_relative "gogyou/typespec"
147
147
  require_relative "gogyou/mixin"
@@ -196,6 +196,89 @@ module Gogyou
196
196
  end
197
197
  end
198
198
 
199
+ #
200
+ # call-seq:
201
+ # define_typeinfo(type, bytesize, bytealign, extensible, aref, aset) -> type
202
+ #
203
+ # ``type`` に対して、型情報子とするための特異メソッドである ``#bytesize`` ``#bytealign`` ``#extensible?`` ``#aref`` ``#aset`` を定義します。
204
+ #
205
+ # ``bytesize`` と ``bytealign`` には整数値、文字列、nil を与えます。
206
+ #
207
+ # ``extensible`` には真偽値、文字列、nil を与えます。
208
+ #
209
+ # ``aref`` には、引数として ``(buffer, offset)`` を受け取る Proc オブジェクト、文字列、nil を与えます。
210
+ #
211
+ # ``aset`` には、引数として ``(buffer, offset, value)`` を受け取る Proc オブジェクト、文字列、nil を与えます。
212
+ #
213
+ # これらの引数に文字列を与えた場合、メソッド定義コードとして直接埋め込まれます。
214
+ #
215
+ # ``bytesize`` と ``bytealign``、``extensible`` の引数はありません。
216
+ #
217
+ # ``aref`` の文字列内部で利用できる引数は ``buffer`` ``offset`` です。
218
+ #
219
+ # ``aset`` の文字列内部で利用できる引数は ``buffer`` ``offset`` ``value`` です。
220
+ #
221
+ # また nil を与えた場合は、対応するメソッドの定義を省略します。
222
+ #
223
+ # 常に ``type`` を返します。
224
+ #
225
+ def self.define_typeinfo(type, bytesize, bytealign, extensible, aref, aset)
226
+ type.instance_eval do
227
+ unless bytesize.nil?
228
+ bytesize = bytesize.to_i unless bytesize.kind_of?(String)
229
+ eval <<-EOM
230
+ def bytesize
231
+ #{bytesize}
232
+ end
233
+ EOM
234
+ end
235
+
236
+ unless bytealign.nil?
237
+ bytealign = bytealign.to_i unless bytealign.kind_of?(String)
238
+ eval <<-EOM
239
+ def bytealign
240
+ #{bytealign}
241
+ end
242
+ EOM
243
+ end
244
+
245
+ unless extensible.nil?
246
+ extensible = (!!extensible).inspect unless extensible.kind_of?(String)
247
+ eval <<-EOM
248
+ def extensible?
249
+ #{extensible}
250
+ end
251
+ EOM
252
+ end
253
+
254
+ unless aref.nil?
255
+ if aref.kind_of?(String)
256
+ eval <<-EOM
257
+ def aref(buffer, offset)
258
+ #{aref}
259
+ end
260
+ EOM
261
+ else
262
+ define_singleton_method(:aref, aref)
263
+ end
264
+ end
265
+
266
+ unless aset.nil?
267
+ if aset.kind_of?(String)
268
+ eval <<-EOM
269
+ def aset(buffer, offset, value)
270
+ #{aset}
271
+ end
272
+ EOM
273
+ else
274
+ define_singleton_method(:aset, aset)
275
+ end
276
+ end
277
+ end
278
+
279
+ type
280
+ end
281
+
199
282
  #
200
283
  # 構造体 (もどき) を定義します。
201
284
  #
@@ -90,7 +90,7 @@ module Gogyou
90
90
 
91
91
  def inspect
92
92
  "#<%s buffer=%p, offset=%p>" % [self.class,
93
- buffer__GOGYOU__,
93
+ buffer__GOGYOU__.inspect,
94
94
  offset__GOGYOU__]
95
95
  end
96
96
 
@@ -337,7 +337,7 @@ module Gogyou
337
337
  case value
338
338
  when ::String
339
339
  raise ArgumentError, "buffer size too small" unless value.bytesize < self::BYTESIZE
340
- buffer.setbinary(offset, value, self::BYTESIZE, 0)
340
+ buffer.setbinary(offset, value, 0, self::BYTESIZE)
341
341
  when ::Array
342
342
  raise NotImplementedError
343
343
  when self::SUBTYPE
@@ -231,7 +231,7 @@ module Gogyou
231
231
  self
232
232
  end
233
233
 
234
- def setbinary(index, str, bytesize = str.bytesize, offset = 0)
234
+ def setbinary(index, str, offset = 0, bytesize = str.bytesize)
235
235
  offset = offset.to_i
236
236
  bytesize = bytesize.to_i
237
237
  size1 = str.bytesize - offset
@@ -66,13 +66,14 @@ module Gogyou
66
66
  :name, # field name
67
67
  :vector, # 要素数。任意数配列の場合は 0。配列でないならば nil。
68
68
  :type, # type specification (or model object) of this field
69
- :flags) # 0x01: const / 0x02: packed (not aligned)
69
+ :flags) # LSB-0+8: packed size exponent (not aligned) / LSB-16: const
70
70
  BasicStruct = superclass
71
71
 
72
- FLAG_CONST = 0x01
73
- FLAG_PACKED = 0x02
72
+ CONST_BITMASK = 1 << 16
73
+ PACKSIZE_BITMASK = 0xff
74
+ PACKSIZE_NOTDEFINE = 20 # = (1 << 20) = 1 MiB # 事実上の無限
74
75
 
75
- def initialize(offset, name, vector, type, flags = 0)
76
+ def initialize(offset, name, vector, type, flags = 0 | PACKSIZE_NOTDEFINE)
76
77
  super(offset, name, vector, type, flags)
77
78
  end
78
79
 
@@ -85,25 +86,30 @@ module Gogyou
85
86
  end
86
87
 
87
88
  def const?
88
- ((flags & FLAG_CONST) == FLAG_CONST) ? true : false
89
+ ((flags & CONST_BITMASK) == CONST_BITMASK) ? true : false
89
90
  end
90
91
 
91
92
  def packed?
92
- ((flags & FLAG_PACKED) == FLAG_PACKED) ? true : false
93
+ ((flags & PACKSIZE_BITMASK) == PACKSIZE_NOTDEFINE) ? false : true
93
94
  end
94
95
 
95
- def mark_const
96
- self.flags |= FLAG_CONST
96
+ def set_const
97
+ self.flags |= CONST_BITMASK
97
98
  self
98
99
  end
99
100
 
100
- def mark_packed
101
- self.flags |= FLAGS_PACKED
101
+ def set_packsize(pack_exponent)
102
+ pack_exponent = PACKSIZE_NOTDEFINE if pack_exponent > PACKSIZE_NOTDEFINE
103
+ self.flags = flags.setbit(0, 8, pack_exponent)
102
104
  self
103
105
  end
104
106
 
107
+ def packsize
108
+ 1 << flags.getbit(0, 8)
109
+ end
110
+
105
111
  def strflags
106
- set = [const? ? "const" : nil, packed? ? "packed" : nil]
112
+ set = [const? ? "const" : nil, packed? ? "packed(#{packsize})" : nil]
107
113
  set.compact!
108
114
  return nil if set.empty?
109
115
  set.join(",")
@@ -145,12 +151,12 @@ module Gogyou
145
151
  end
146
152
  end
147
153
 
148
- def self.struct(typemap, &block)
149
- define_container(typemap, Model::Struct, &block)
154
+ def self.struct(typemap, packexp = Field::PACKSIZE_NOTDEFINE, &block)
155
+ define_container(typemap, packexp, Model::Struct, &block)
150
156
  end
151
157
 
152
- def self.union(typemap, &block)
153
- define_container(typemap, Model::Union, &block)
158
+ def self.union(typemap, packexp = Field::PACKSIZE_NOTDEFINE, &block)
159
+ define_container(typemap, packexp, Model::Union, &block)
154
160
  end
155
161
 
156
162
  def self.typedef(typemap, type, aliasname, *elements)
@@ -178,9 +184,9 @@ module Gogyou
178
184
  nil
179
185
  end
180
186
 
181
- def self.define_container(typemap, model_type, &block)
187
+ def self.define_container(typemap, packexp, model_type, &block)
182
188
  creator = model_type::Creator.new(typemap, 0, [])
183
- proxy = model_type::Creator::Proxy.new(creator)
189
+ proxy = model_type::Creator::Proxy.new(creator, packexp)
184
190
  proxy.instance_exec(&block)
185
191
  model = creator.to_model
186
192
  model
@@ -205,7 +211,7 @@ module Gogyou
205
211
 
206
212
  class BasicCreator
207
213
  def maxalign(fields = self.fields)
208
- fields.map { |f| f.type.bytealign }.max
214
+ fields.map { |f| f.packed? ? f.packsize : f.type.bytealign }.max
209
215
  end
210
216
 
211
217
  def maxsize(fields = self.fields)
@@ -223,7 +229,7 @@ module Gogyou
223
229
  else
224
230
  raise "BUG? : field.type is not a Model (%p)" % f.type unless f.type.kind_of?(Model)
225
231
  fs = flatten_field(f.type.fields)
226
- fs.each { |ff| ff.offset += f.offset; ff.mark_const if f.const? }
232
+ fs.each { |ff| ff.offset += f.offset; ff.set_const if f.const? }
227
233
  fields2.concat fs
228
234
  end
229
235
  end
@@ -233,23 +239,42 @@ module Gogyou
233
239
  # :nodoc: all
234
240
  class Proxy < Object
235
241
  #class Proxy < BasicObject
236
- def initialize(creator)
242
+ def initialize(creator, packexp = Field::PACKSIZE_NOTDEFINE)
237
243
  #singleton_class = (class << proxy; self; end)
238
244
  singleton_class.class_eval do
239
245
  latest_fields = nil
240
246
  #define_method(:method_missing, ->(type, *args) { latest_fields = creator.addfield(type, args); nil })
241
247
  creator.typemap.each_key do |t|
242
- define_method(t, ->(*args) { latest_fields = creator.addfield(t, args); nil })
248
+ define_method(t, ->(*args) { latest_fields = creator.addfield(t, packexp, args); nil })
243
249
  end
244
- define_method(:struct, ->(*args, &block) { latest_fields = creator.struct(args, &block); nil })
245
- define_method(:union, ->(*args, &block) { latest_fields = creator.union(args, &block); nil })
250
+ define_method(:struct, ->(*args, &block) { latest_fields = creator.struct(args, packexp, &block); nil })
251
+ define_method(:union, ->(*args, &block) { latest_fields = creator.union(args, packexp, &block); nil })
246
252
  define_method(:const, ->(dummy_fields) { creator.const(latest_fields); latest_fields = nil; nil })
247
253
  define_method(:typedef, ->(*args, &block) { creator.typedef(args, &block) })
254
+ packexp0 = nil
255
+ define_method(:packed, ->(bytealign = 1, &block) {
256
+ raise "wrong nested ``packed''" if packexp0
257
+ exp = Math.log(bytealign, 2)
258
+ # exp が Nan Infinity -Infinity の場合は例外が発生するので、それに対する処置も行う
259
+ unless ((exp = exp.to_i) rescue nil) && (1 << exp) == bytealign
260
+ raise ArgumentError, "shall be given power of two (but #{bytealign})"
261
+ end
262
+
263
+ begin
264
+ packexp0 = packexp
265
+ packexp = exp
266
+ self.instance_exec(&block)
267
+ ensure
268
+ (packexp, packexp0) = packexp0, nil
269
+ end
270
+
271
+ nil
272
+ })
248
273
  if creator.respond_to?(:bytealign)
249
- define_method(:bytealign, ->(bytesize, &block) { creator.bytealign(bytesize, &block) })
274
+ define_method(:bytealign, ->(bytesize, &block) { creator.bytealign(bytesize, &block); nil })
250
275
  end
251
276
  if creator.respond_to?(:padding)
252
- define_method(:padding, ->(bytesize, &block) { creator.padding(bytesize, &block) })
277
+ define_method(:padding, ->(bytesize, &block) { creator.padding(bytesize, &block); nil })
253
278
  end
254
279
  end
255
280
  end
@@ -287,8 +312,8 @@ module Gogyou
287
312
  # }
288
313
  # }
289
314
  #
290
- def struct(args, &block)
291
- define_container(args, block, Model.method(:struct))
315
+ def struct(args, packexp, &block)
316
+ define_container(args, packexp, block, Model.method(:struct))
292
317
  end
293
318
 
294
319
  #
@@ -306,24 +331,24 @@ module Gogyou
306
331
  # この記述ができる唯一の理由は、人間が見てわかりやすくすることを意図しています
307
332
  # (ただし、ミスリードを誘う手口にも利用されてしまうのが最大の欠点です)。
308
333
  #
309
- def union(args, &block)
310
- define_container(args, block, Model.method(:union))
334
+ def union(args, packexp, &block)
335
+ define_container(args, packexp, block, Model.method(:union))
311
336
  end
312
337
 
313
- def define_container(args, anonymblock, container)
338
+ def define_container(args, packexp, anonymblock, container)
314
339
  if anonymblock
315
340
  raise ArgumentError, "given block and arguments" unless args.empty?
316
- model = container.(typemap.dup, &anonymblock)
341
+ model = container.(typemap.dup, packexp, &anonymblock)
317
342
  raise "BUG - object is not a Model (#{model.class})" unless model.kind_of?(Model)
318
343
  #p model: model, superclass: model.superclass
319
344
  self.offset = offset.align_ceil(model.bytealign) unless kind_of?(Model::Union::Creator)
320
- fields << f = Field[offset, nil, nil, model, 0]
345
+ fields << f = Field[offset, nil, nil, model, packexp]
321
346
  self.offset += model.bytesize unless kind_of?(Model::Union::Creator)
322
347
  [f]
323
348
  else
324
349
  type = args.shift
325
- type = container.(typemap.dup, &type) if type.kind_of?(::Proc)
326
- addfield!(type, args)
350
+ type = container.(typemap.dup, packexp, &type) if type.kind_of?(::Proc)
351
+ addfield!(type, packexp, args)
327
352
  end
328
353
  end
329
354
 
@@ -332,7 +357,7 @@ module Gogyou
332
357
  end
333
358
 
334
359
  def const(fields)
335
- fields.each { |f| f.mark_const }
360
+ fields.each { |f| f.set_const }
336
361
  end
337
362
 
338
363
  #
@@ -371,16 +396,16 @@ module Gogyou
371
396
  nil
372
397
  end
373
398
 
374
- def addfield(type, args)
399
+ def addfield(type, packexp, args)
375
400
  typeobj = typemap[type.intern]
376
401
  unless typeobj
377
402
  raise NoMethodError, "typename or method is missing (#{type})"
378
403
  end
379
404
 
380
- addfield!(typeobj, args)
405
+ addfield!(typeobj, packexp, args)
381
406
  end
382
407
 
383
- def addfield!(typeobj, args)
408
+ def addfield!(typeobj, packexp, args)
384
409
  #p typeobj
385
410
  # check extensible field >>> creator.fields[-1].vector[-1]
386
411
  if (x = fields[-1]) && (x = x.vector) && x[-1] == 0
@@ -388,13 +413,13 @@ module Gogyou
388
413
  end
389
414
 
390
415
  typesize = typeobj.bytesize
391
- typealign = typeobj.bytealign
416
+ typealign = [typeobj.bytealign, 1 << packexp].min
392
417
 
393
418
  tmpfields = []
394
419
 
395
420
  parse!(args) do |name, vect|
396
421
  self.offset = offset.align_ceil(typealign) unless kind_of?(Model::Union::Creator)
397
- fields << f = Field[offset, name, vect, typeobj, 0]
422
+ fields << f = Field[offset, name, vect, typeobj, 0 | packexp]
398
423
  tmpfields << f
399
424
  unless kind_of?(Model::Union::Creator)
400
425
  elements = vect ? vect.inject(1, &:*) : 1
@@ -35,8 +35,8 @@ describe Gogyou::Model do
35
35
 
36
36
  reference = Gogyou::Model::Union[
37
37
  4, 4,
38
- Gogyou::Model::Field[0, :a, nil, Gogyou::Primitives::INT32_T, 0x00],
39
- Gogyou::Model::Field[0, :b, nil, Gogyou::Primitives::UINT32_T, 0x00]
38
+ Gogyou::Model::Field[0, :a, nil, Gogyou::Primitives::INT32_T],
39
+ Gogyou::Model::Field[0, :b, nil, Gogyou::Primitives::UINT32_T]
40
40
  ]
41
41
 
42
42
  expect(x::MODEL).to eq reference
@@ -57,11 +57,11 @@ describe Gogyou::Model do
57
57
 
58
58
  ref = Gogyou::Model::Struct[
59
59
  32, 8,
60
- Gogyou::Model::Field[0, :a, nil, Gogyou::Primitives::CHAR, 0],
61
- Gogyou::Model::Field[8, :b, nil, Gogyou::Primitives::INT, 0],
62
- Gogyou::Model::Field[8, :c, nil, Gogyou::Primitives::INT64_T, 0],
63
- Gogyou::Model::Field[16, :d, nil, Gogyou::Primitives::INT32_T, 0],
64
- Gogyou::Model::Field[24, :e, nil, Gogyou::Primitives::CHAR, 0]
60
+ Gogyou::Model::Field[0, :a, nil, Gogyou::Primitives::CHAR],
61
+ Gogyou::Model::Field[8, :b, nil, Gogyou::Primitives::INT],
62
+ Gogyou::Model::Field[8, :c, nil, Gogyou::Primitives::INT64_T],
63
+ Gogyou::Model::Field[16, :d, nil, Gogyou::Primitives::INT32_T],
64
+ Gogyou::Model::Field[24, :e, nil, Gogyou::Primitives::CHAR]
65
65
  ]
66
66
 
67
67
  expect(x::MODEL).to eq ref
@@ -81,12 +81,12 @@ describe Gogyou::Model do
81
81
 
82
82
  ref = Gogyou::Model::Struct[
83
83
  72, 8,
84
- Gogyou::Model::Field[0, :a, nil, Gogyou::Primitives::CHAR, 0x00],
85
- Gogyou::Model::Field[8, :b, nil, Gogyou::Primitives::INT, 0x00],
84
+ Gogyou::Model::Field[0, :a, nil, Gogyou::Primitives::CHAR],
85
+ Gogyou::Model::Field[8, :b, nil, Gogyou::Primitives::INT],
86
86
  Gogyou::Model::Field[8, :e, [4], Gogyou::Model::Struct[
87
87
  16, 8,
88
- Gogyou::Model::Field[0, :c, nil, Gogyou::Primitives::INT64_T, 0x00],
89
- Gogyou::Model::Field[8, :d, nil, Gogyou::Primitives::INT32_T, 0x00]], 0x00]]
88
+ Gogyou::Model::Field[0, :c, nil, Gogyou::Primitives::INT64_T],
89
+ Gogyou::Model::Field[8, :d, nil, Gogyou::Primitives::INT32_T]]]]
90
90
  expect(x::MODEL).to eq ref
91
91
  end
92
92
 
@@ -108,8 +108,8 @@ describe Gogyou::Model do
108
108
 
109
109
  ref = Gogyou::Model::Union[
110
110
  24, 8,
111
- Gogyou::Model::Field[0, :a, nil, x, 0x00],
112
- Gogyou::Model::Field[0, :b, nil, x, 0x00]]
111
+ Gogyou::Model::Field[0, :a, nil, x],
112
+ Gogyou::Model::Field[0, :b, nil, x]]
113
113
  expect(y::MODEL).to eq ref
114
114
  end
115
115
  end
@@ -163,4 +163,144 @@ describe Gogyou::Accessor do
163
163
  obj = type.new
164
164
  expect(obj.bytesize).to eq 20
165
165
  end
166
+
167
+ it "packed struct" do
168
+ type1 = Gogyou.struct {
169
+ packed(1) {
170
+ char :a
171
+ int32_t :b
172
+ }
173
+ }
174
+
175
+ expect(type1.bytesize).to eq 5
176
+ expect(type1.bytealign).to eq 1
177
+ expect(type1.extensible?).to eq false
178
+ expect(type1.new.bytesize).to eq 5
179
+
180
+ type2 = Gogyou.struct {
181
+ packed(2) {
182
+ char :a
183
+ int32_t :b
184
+ }
185
+ }
186
+
187
+ expect(type2.bytesize).to eq 6
188
+ expect(type2.bytealign).to eq 2
189
+ expect(type2.extensible?).to eq false
190
+ expect(type2.new.bytesize).to eq 6
191
+ end
192
+
193
+ it "packed and nested struct" do
194
+ type1 = Gogyou.struct {
195
+ struct {
196
+ packed(1) {
197
+ char :a
198
+ int32_t :b
199
+ }
200
+ }
201
+ }
202
+
203
+ expect(type1.bytesize).to eq 5
204
+ expect(type1.bytealign).to eq 1
205
+ expect(type1.extensible?).to eq false
206
+ expect(type1.new.bytesize).to eq 5
207
+
208
+ type2 = Gogyou.struct {
209
+ packed(1) {
210
+ struct {
211
+ char :a
212
+ int32_t :b
213
+ }
214
+ }
215
+ }
216
+
217
+ expect(type2.bytesize).to eq 5
218
+ expect(type2.bytealign).to eq 1
219
+ expect(type2.extensible?).to eq false
220
+ expect(type2.new.bytesize).to eq 5
221
+
222
+ type3 = Gogyou.struct {
223
+ packed(1) {
224
+ struct -> {
225
+ char :a
226
+ int32_t :b
227
+ }, :x
228
+ }
229
+ }
230
+
231
+ expect(type3.bytesize).to eq 5
232
+ expect(type3.bytealign).to eq 1
233
+ expect(type3.extensible?).to eq false
234
+ expect(type3.new.bytesize).to eq 5
235
+ end
236
+
237
+ it "packed and nested struct" do
238
+ type1 = Gogyou.struct {
239
+ packed(2) {
240
+ struct {
241
+ packed(1) {
242
+ char :a
243
+ int32_t :b
244
+ }
245
+ }
246
+ }
247
+ }
248
+
249
+ expect(type1.bytesize).to eq 6
250
+ expect(type1.bytealign).to eq 2
251
+ expect(type1.extensible?).to eq false
252
+ expect(type1.new.bytesize).to eq 6
253
+
254
+ expect {
255
+ Gogyou.struct {
256
+ packed(1) {
257
+ packed(2) {
258
+ struct {
259
+ char :a
260
+ int32_t :b
261
+ }
262
+ }
263
+ }
264
+ }
265
+ }.to raise_error RuntimeError
266
+ end
267
+ end
268
+
269
+ describe "user typeinfo" do
270
+ it "definition and use" do
271
+ x1 = Object.new
272
+ Gogyou.define_typeinfo(x1, 8.0, Rational(5, 2), false,
273
+ ->(buffer, offset) { buffer.byteslice(offset, 8) },
274
+ ->(buffer, offset, value) { buffer.setbinary(offset, value, 0, 16) })
275
+ expect(x1.bytesize).to eq 8
276
+ expect(x1.bytealign).to eq 2
277
+ expect(x1.extensible?).to eq false
278
+
279
+ x2 = Object.new
280
+ Gogyou.define_typeinfo(x2, "16", "4", "false",
281
+ "buffer.byteslice(offset, 16)",
282
+ "buffer.setbinary(offset, value.downcase, 0, 16)")
283
+ expect(x2.bytesize).to eq 16
284
+ expect(x2.bytealign).to eq 4
285
+ expect(x2.extensible?).to eq false
286
+
287
+ type = Gogyou.struct {
288
+ struct x1, :a
289
+ struct x2, :b
290
+ }
291
+
292
+ expect(type.bytesize).to eq 24
293
+ expect(type.bytealign).to eq 4
294
+ expect(type.extensible?).to eq false
295
+
296
+ v = type.bind("abcdefghijklmnopqrstuvwx")
297
+ expect(v.bytesize).to eq 24
298
+ expect(v.size).to eq 2
299
+ expect(v.a).to eq "abcdefgh"
300
+ v.a = "ABCDEFGH"
301
+ expect(v.buffer).to eq "ABCDEFGHijklmnopqrstuvwx"
302
+ expect(v.b).to eq "ijklmnopqrstuvwx"
303
+ v.b = "0ijklmnopqrstuv9wx"
304
+ expect(v.buffer).to eq "ABCDEFGH0ijklmnopqrstuv9"
305
+ end
166
306
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gogyou
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.2.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - dearblue
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-09-11 00:00:00.000000000 Z
11
+ date: 2014-09-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rspec
@@ -57,8 +57,8 @@ extra_rdoc_files:
57
57
  - lib/gogyou/accessor.rb
58
58
  - lib/gogyou/mixin.rb
59
59
  - lib/gogyou/model.rb
60
- - lib/gogyou/primitives.rb
61
60
  - lib/gogyou/typespec.rb
61
+ - lib/gogyou/primitives.rb
62
62
  files:
63
63
  - LICENSE.markdown
64
64
  - README.markdown