ffi-struct_ex 0.1.0 → 0.1.1

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: f351f025099f8a13f3c2aeba992b7fd67d8dd90b
4
- data.tar.gz: 198834f90618214c7ffb3a811d3de12c114dd4db
3
+ metadata.gz: 4092e8230ac37c9885fe7fa0103252632d8aff4c
4
+ data.tar.gz: b7585d0ea88c05cec20c3cac0939fbecf54fd114
5
5
  SHA512:
6
- metadata.gz: 31828f46959ae2d4a4686b787f0555b3f320c12bfb80d7375920d1a45e8e620a27dc1f75cf13a19233ea157ac208e22f7e1909305cf156ca0b66894e256e22c5
7
- data.tar.gz: daf79112bfa648f3aa9343319cf5e21d2cae9668ef1df5a98544e4af347279408032267184325fa080c7bd031446fcc8583327de83bf6b259cbd84d3b3281b39
6
+ metadata.gz: b90c7ec9a5a6e5d2fdcb84346a19c9882de73a601d9cb35d6e18c05455648f6e700c92a61ea2ca2007659c3fe830b031a3a4408111fd1c7a26e79c8c75c1f1b4
7
+ data.tar.gz: b2077caf64d8b31265a2b30ec2c72690181ac5cb1f5be710a56888a7f75a546eaa853be20be7cce7c5c8b7fd2e2edc60eda30e6b78c867dd7f436f728fb6d905
@@ -1,15 +1,6 @@
1
1
  require 'ffi'
2
2
 
3
3
  class Integer
4
- def to_bytes(size)
5
- bytes = [0] * size
6
- bytes.each_index do |i|
7
- bytes[i] = (self >> (i * 8)) & 0xff
8
- end
9
-
10
- bytes
11
- end
12
-
13
4
  def to_signed(bits_size)
14
5
  self & (1 << bits_size - 1) != 0 ? self - (1 << bits_size) : self
15
6
  end
@@ -32,9 +23,10 @@ module FFI
32
23
  class StructEx < FFI::Struct
33
24
  SIGNED_NUMBER_TYPES = [FFI::Type::INT8, FFI::Type::INT16, FFI::Type::INT32, FFI::Type::INT64]
34
25
  UNSIGNED_NUMBER_TYPES = [FFI::Type::UINT8, FFI::Type::UINT16, FFI::Type::UINT32, FFI::Type::UINT64]
26
+ NUMBER_TYPES = SIGNED_NUMBER_TYPES + UNSIGNED_NUMBER_TYPES
35
27
 
36
28
  class << self
37
- def bit_fields(*field_specs)
29
+ def struct_ex(*field_specs)
38
30
  Class.new(FFI::StructLayout::Field) do
39
31
  class << self
40
32
  attr_accessor :struct_class
@@ -104,13 +96,13 @@ module FFI
104
96
 
105
97
  private
106
98
  def array_layout(builder, field_specs)
107
- @field_specs = {}
108
-
109
99
  field_spec_class = ::Struct.new(:name, :type, :descriptors)
110
100
 
111
- current_allocation_unit = nil
101
+ @field_specs = {}
102
+
103
+ bits_unit = nil
112
104
 
113
- offset = i = 0
105
+ i = 0
114
106
 
115
107
  while i < field_specs.size
116
108
  name, type = field_specs[i, 2]
@@ -128,7 +120,7 @@ module FFI
128
120
  type = find_field_type(type)
129
121
  builder.add name, type, offset
130
122
 
131
- current_allocation_unit = nil
123
+ bits_unit = nil
132
124
  else
133
125
  if type.is_a?(Integer)
134
126
  ffi_type, bits_size = UNSIGNED_NUMBER_TYPES.find {|ffi_type| type <= ffi_type.size * 8}, type
@@ -138,32 +130,22 @@ module FFI
138
130
  raise "Unrecognized format #{type}" unless m
139
131
 
140
132
  ffi_type, bits_size = find_field_type(m[:ffi_type].to_sym), m[:bits_size].to_i
141
- raise "Unrecognized type #{type}" unless UNSIGNED_NUMBER_TYPES.include?(ffi_type) || SIGNED_NUMBER_TYPES.include?(ffi_type)
133
+ raise "Unrecognized type #{type}" unless NUMBER_TYPES.include?(ffi_type)
142
134
  end
143
135
 
144
136
  raise "Illegal format #{type}" if bits_size > ffi_type.size * 8
145
137
 
146
- unless current_allocation_unit
147
- current_allocation_unit = {ffi_type: ffi_type, bits_size: bits_size}
148
- offset = builder.send(:align, builder.size, [@min_alignment || 1, ffi_type.alignment].max)
138
+ # Adjacent bit fields are packed into the same 1-, 2-, or 4-byte allocation unit if the integral types are the same size
139
+ # and if the next bit field fits into the current allocation unit without crossing the boundary
140
+ # imposed by the common alignment requirements of the bit fields.
141
+ if bits_unit && bits_unit[:ffi_type].size == ffi_type.size && bits_unit[:bits_size] + bits_size <= bits_unit[:ffi_type].size * 8
142
+ bits_unit[:bits_size] += bits_size
149
143
  else
150
- # Adjacent bit fields are packed into the same 1-, 2-, or 4-byte allocation unit if the integral types are the same size
151
- # and if the next bit field fits into the current allocation unit without crossing the boundary
152
- # imposed by the common alignment requirements of the bit fields.
153
- if ffi_type.size == current_allocation_unit[:ffi_type].size
154
- if current_allocation_unit[:bits_size] + bits_size <= ffi_type.size * 8
155
- current_allocation_unit[:bits_size] += bits_size
156
- else
157
- offset = builder.send(:align, builder.size, [@min_alignment || 1, ffi_type.alignment].max)
158
- current_allocation_unit[:bits_size] = bits_size
159
- end
160
- else
161
- offset = builder.send(:align, builder.size, [@min_alignment || 1, ffi_type.alignment].max)
162
- current_allocation_unit = {ffi_type: ffi_type, bits_size: bits_size}
163
- end
144
+ offset = builder.send(:align, builder.size, [@min_alignment || 1, ffi_type.alignment].max)
145
+ bits_unit = {ffi_type: ffi_type, bits_size: bits_size}
164
146
  end
165
147
 
166
- builder.add name, find_field_type(bit_field(ffi_type, bits_size, current_allocation_unit[:bits_size] - bits_size)), offset
148
+ builder.add name, find_field_type(bit_field(ffi_type, bits_size, bits_unit[:bits_size] - bits_size)), offset
167
149
  end
168
150
 
169
151
  if field_specs[i].is_a?(Hash)
@@ -193,26 +175,17 @@ module FFI
193
175
  end
194
176
 
195
177
  def write(value)
196
- if value.is_a?(Integer)
197
- to_ptr.write_array_of_uint8(value.to_bytes(self.class.size))
198
- elsif value.is_a?(Hash)
178
+ if value.is_a?(Hash)
199
179
  value.each do |field_name, v|
200
180
  self[field_name] = v
201
181
  end
182
+ elsif value.is_a?(self.class)
183
+ self.pointer.__copy_from__(value.pointer, self.size)
202
184
  end
203
185
  end
204
186
 
205
- def read
206
- bytes = to_ptr.read_array_of_uint8(self.class.size)
207
- bytes.reverse.inject(0) {|value, n| (value << 8) | n}
208
- end
209
-
210
187
  def ==(other)
211
- if other.is_a?(Integer)
212
- self.read == other
213
- elsif other.is_a?(String)
214
- self.==(other.to_dec)
215
- elsif other.is_a?(Hash)
188
+ if other.is_a?(Hash)
216
189
  other.all? {|k, v| self[k] == self.map_field_value(k, v)}
217
190
  else
218
191
  super
@@ -1,5 +1,5 @@
1
1
  module Ffi
2
2
  module StructEx
3
- VERSION = "0.1.0"
3
+ VERSION = "0.1.1"
4
4
  end
5
5
  end
@@ -3,53 +3,53 @@ require 'test/unit'
3
3
  require 'ffi/struct_ex'
4
4
 
5
5
  class TestStructEx < Test::Unit::TestCase
6
- def test_bit_fields
6
+ def test_struct_ex
7
7
  subject_class = Class.new(FFI::StructEx) do
8
- layout :field_0, bit_fields(:bits_0_2, 'uint16: 3',
8
+ layout :field_0, struct_ex(:bits_0_2, 'uint16: 3',
9
9
  :bit_3, 'uint16: 1',
10
10
  :bit_4, 'uint16: 1',
11
11
  :bits_5_7, 'uint16: 3',
12
- :bits_8_15, 'uint16: 8'),
12
+ :bits_8_15, :uint8),
13
13
  :field_1, :uint8,
14
14
  :field_2, :uint8,
15
15
  :field_3, :uint8
16
16
  end
17
17
 
18
- assert_equal(6, subject_class.size)
18
+ assert_equal(8, subject_class.size)
19
19
  assert_equal(2, subject_class.alignment)
20
- assert_equal(2, subject_class.offset_of(:field_1))
20
+ assert_equal(4, subject_class.offset_of(:field_1))
21
21
 
22
22
  subject = subject_class.new
23
23
 
24
24
  assert_equal(FFI::StructEx, subject[:field_0].class.superclass)
25
- assert_equal(2, subject[:field_0].size)
25
+ assert_equal(4, subject[:field_0].size)
26
26
  assert_equal(2, subject[:field_0].alignment)
27
27
 
28
- subject[:field_0] = 0b0110_1001
29
- assert_equal(0b0110_1001, subject[:field_0].read)
28
+ subject[:field_0].to_ptr.write_uint16(0b0110_1001)
29
+ assert_equal(0b0110_1001, subject[:field_0].to_ptr.read_uint16)
30
30
  assert_equal(0b001, subject[:field_0][:bits_0_2])
31
31
 
32
32
  subject[:field_0][:bits_0_2] = 0b101
33
33
  assert_equal(0b101, subject[:field_0][:bits_0_2])
34
- assert_equal(0b0110_1101, subject[:field_0].read)
34
+ assert_equal(0b0110_1101, subject[:field_0].to_ptr.read_uint16)
35
35
 
36
36
  subject[:field_0] = {bits_0_2: 0b001, bit_3: 0b1, bit_4: 0b0, bits_5_7: 0b011}
37
- assert_equal(0b0110_1001, subject[:field_0].read)
37
+ assert_equal(0b0110_1001, subject[:field_0].to_ptr.read_uint16)
38
38
  assert_equal(0b001, subject[:field_0][:bits_0_2])
39
39
 
40
- assert(subject[:field_0] == {bits_0_2: 0b001, bit_3: 0b1, bit_4: 0b0, bits_5_7: 0b011, bits_8_15: 0b0})
41
- assert(subject[:field_0] == 0b0110_1001)
42
- assert(subject[:field_0] == '0b0110_1001')
40
+ assert_equal(subject[:field_0], {bits_0_2: 0b001, bit_3: 0b1, bit_4: 0b0, bits_5_7: 0b011, bits_8_15: 0b0})
41
+ assert_equal(subject[:field_0].to_ptr.read_uint16, 0b0110_1001)
43
42
 
44
43
  subject[:field_1] = 1
45
44
  subject[:field_2] = 2
46
45
  subject[:field_3] = 3
47
- assert(subject == {field_0: {bits_0_2: 0b001, bit_3: 0b1, bit_4: 0b0, bits_5_7: 0b011, bits_8_15: 0b0}, field_1: 1, field_2: 2, field_3: 3})
48
- assert(subject == 0x0302010069)
49
- assert(subject == '0x0302010069')
46
+ assert_equal(subject, {field_0: {bits_0_2: 0b001, bit_3: 0b1, bit_4: 0b0, bits_5_7: 0b011, bits_8_15: 0b0}, field_1: 1, field_2: 2, field_3: 3})
47
+
48
+ subject[:field_0] = subject[:field_0].class.new(bits_0_2: 0b111, bit_3: 0b0, bit_4: 0b0, bits_5_7: 0b101, bits_8_15: 0b10011100)
49
+ assert_equal(subject[:field_0].to_ptr.read_uint32, 0b10011100_00000000_10100111)
50
50
  end
51
51
 
52
- def test_pure_bit_fields
52
+ def test_pure_struct_ex
53
53
  subject_class = Class.new(FFI::StructEx) do
54
54
  layout :bits_0_2, 3,
55
55
  :bit_3, 1,
@@ -69,7 +69,8 @@ class TestStructEx < Test::Unit::TestCase
69
69
  assert_equal(0b1, subject[:bit_3])
70
70
  assert_equal(0b101, subject[:bits_0_2])
71
71
 
72
- subject = subject_class.new(0b0110_1001)
72
+ subject = subject_class.new
73
+ subject.to_ptr.write_uint8(0b0110_1001)
73
74
  assert_equal(0b001, subject[:bits_0_2])
74
75
  assert_equal(0b1, subject[:bit_3])
75
76
  assert_equal(0b0, subject[:bit_4])
@@ -80,10 +81,10 @@ class TestStructEx < Test::Unit::TestCase
80
81
  assert_equal(0b1, subject[:bit_3])
81
82
  assert_equal(0b0, subject[:bit_4])
82
83
  assert_equal(0b011, subject[:bits_5_7])
83
- assert_equal(0b0110_1001, subject.read)
84
+ assert_equal(0b0110_1001, subject.to_ptr.read_uint8)
84
85
  end
85
86
 
86
- def test_interpreted_bit_fields
87
+ def test_interpreted_struct_ex
87
88
  subject_class = Class.new(FFI::StructEx) do
88
89
  layout :bits_0_2, 3, {'all_1' => 0b111, 'all_0' => 0b000},
89
90
  :bit_3, 1, {'yes' => 0b1, 'no' => 0b0},
@@ -112,18 +113,18 @@ class TestStructEx < Test::Unit::TestCase
112
113
 
113
114
  def test_equality
114
115
  subject_class = Class.new(FFI::StructEx) do
115
- layout :field_0, bit_fields(:bits_0_2, 3,
116
+ layout :field_0, struct_ex(:bits_0_2, 3,
116
117
  :bit_3, 1,
117
118
  :bit_4, 1,
118
119
  :bits_5_7, 3),
119
120
  :field_1, :uint8
120
121
  end
121
122
 
122
- subject = subject_class.new({field_0: {bits_0_2: 0b001, bit_3: 0b1, bit_4: 0b0, bits_5_7: 0b011}, field_1: 0x1})
123
+ subject = subject_class.new(field_0: {bits_0_2: 0b001, bit_3: 0b1, bit_4: 0b0, bits_5_7: 0b011}, field_1: 0x1)
123
124
 
124
125
  assert_equal(FFI::StructEx, subject[:field_0].class.superclass)
125
126
  assert_equal(1, subject[:field_0].size)
126
- assert_equal(0b0110_1001, subject[:field_0])
127
+ assert_equal(0b0110_1001, subject[:field_0].to_ptr.read_uint8)
127
128
  assert_equal(subject[:field_1], subject.map_field_value(:field_1, '0x1'))
128
129
  end
129
130
 
@@ -154,7 +155,7 @@ class TestStructEx < Test::Unit::TestCase
154
155
 
155
156
  def test_initialized_memory_should_be_zero
156
157
  subject_class = Class.new(FFI::StructEx) do
157
- layout :field_0, bit_fields(:bits_0_2, 3,
158
+ layout :field_0, struct_ex(:bits_0_2, 3,
158
159
  :bit_3, 1,
159
160
  :bit_4, 1,
160
161
  :bits_5_7, 3),
@@ -163,7 +164,7 @@ class TestStructEx < Test::Unit::TestCase
163
164
 
164
165
  subject = subject_class.new
165
166
 
166
- assert_equal(0x00, subject[:field_0])
167
+ assert_equal(0x00, subject[:field_0].to_ptr.read_uint8)
167
168
  assert_equal(0x00, subject[:field_1])
168
169
  end
169
170
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ffi-struct_ex
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ruijia Li
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-05-23 00:00:00.000000000 Z
11
+ date: 2014-05-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ffi