ffi-struct_ex 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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