ffi-struct_ex 0.0.3 → 0.1.0
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 +4 -4
- data/README.md +9 -7
- data/lib/ffi/struct_ex/struct_ex.rb +108 -58
- data/lib/ffi/struct_ex/version.rb +1 -1
- data/test/test_struct_ex.rb +185 -15
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f351f025099f8a13f3c2aeba992b7fd67d8dd90b
|
4
|
+
data.tar.gz: 198834f90618214c7ffb3a811d3de12c114dd4db
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 31828f46959ae2d4a4686b787f0555b3f320c12bfb80d7375920d1a45e8e620a27dc1f75cf13a19233ea157ac208e22f7e1909305cf156ca0b66894e256e22c5
|
7
|
+
data.tar.gz: daf79112bfa648f3aa9343319cf5e21d2cae9668ef1df5a98544e4af347279408032267184325fa080c7bd031446fcc8583327de83bf6b259cbd84d3b3281b39
|
data/README.md
CHANGED
@@ -18,22 +18,24 @@ Or install it yourself as:
|
|
18
18
|
|
19
19
|
## Usage
|
20
20
|
|
21
|
-
* Struct (
|
21
|
+
* Struct (default type is "unsigned char/short/int" depending on bits size)
|
22
22
|
|
23
23
|
```ruby
|
24
24
|
require 'ffi/struct_ex'
|
25
25
|
|
26
26
|
class Subject < FFI::StructEx
|
27
|
-
layout :bits_0_2, 3,
|
28
|
-
:bit_3, 1,
|
27
|
+
layout :bits_0_2, 'uint8: 3',
|
28
|
+
:bit_3, 'char: 1',
|
29
29
|
:bit_4, 1,
|
30
|
-
:bits_5_7, 3
|
30
|
+
:bits_5_7, 'char: 3'
|
31
31
|
end
|
32
32
|
|
33
|
-
|
33
|
+
Subject.size #=> 1
|
34
34
|
|
35
|
-
subject
|
36
|
-
|
35
|
+
subject = Subject.new(bits_0_2: 0b001, bit_3: 0b1, bit_4: 0b1, bits_5_7: 0b100)
|
36
|
+
|
37
|
+
subject[:bits_0_2] #=> 1
|
38
|
+
subject[:bits_5_7] #=> -4
|
37
39
|
```
|
38
40
|
|
39
41
|
* Struct (embedded bit fields)
|
@@ -9,6 +9,10 @@ class Integer
|
|
9
9
|
|
10
10
|
bytes
|
11
11
|
end
|
12
|
+
|
13
|
+
def to_signed(bits_size)
|
14
|
+
self & (1 << bits_size - 1) != 0 ? self - (1 << bits_size) : self
|
15
|
+
end
|
12
16
|
end
|
13
17
|
|
14
18
|
class String
|
@@ -26,67 +30,140 @@ end
|
|
26
30
|
|
27
31
|
module FFI
|
28
32
|
class StructEx < FFI::Struct
|
33
|
+
SIGNED_NUMBER_TYPES = [FFI::Type::INT8, FFI::Type::INT16, FFI::Type::INT32, FFI::Type::INT64]
|
34
|
+
UNSIGNED_NUMBER_TYPES = [FFI::Type::UINT8, FFI::Type::UINT16, FFI::Type::UINT32, FFI::Type::UINT64]
|
35
|
+
|
29
36
|
class << self
|
30
37
|
def bit_fields(*field_specs)
|
31
|
-
|
32
|
-
|
33
|
-
|
38
|
+
Class.new(FFI::StructLayout::Field) do
|
39
|
+
class << self
|
40
|
+
attr_accessor :struct_class
|
41
|
+
|
42
|
+
def alignment; struct_class.alignment; end
|
43
|
+
def size; struct_class.size; end
|
44
|
+
end
|
45
|
+
|
46
|
+
self.struct_class = Class.new(StructEx) do
|
47
|
+
layout(*field_specs)
|
48
|
+
end
|
34
49
|
|
35
|
-
bit_fields_class = Class.new(FFI::StructLayout::Field) do
|
36
50
|
def initialize(name, offset, type)
|
37
51
|
super(name, offset, FFI::Type::Struct.new(self.class.struct_class))
|
38
52
|
end
|
39
53
|
|
40
54
|
def get(ptr)
|
41
|
-
|
42
|
-
self.class.struct_class.new(ptr.slice(self.offset, self.size))
|
55
|
+
type.struct_class.new(ptr.slice(offset, size))
|
43
56
|
end
|
44
57
|
|
45
58
|
def put(ptr, value)
|
46
|
-
|
59
|
+
type.struct_class.new(ptr.slice(offset, size)).write(value)
|
47
60
|
end
|
61
|
+
end
|
62
|
+
end
|
48
63
|
|
64
|
+
def bit_field(type, bits_size, bits_offset)
|
65
|
+
Class.new(FFI::StructLayout::Field) do
|
49
66
|
class << self
|
50
|
-
attr_accessor :struct_class
|
67
|
+
attr_accessor :type, :bits_size, :bits_offset, :struct_class
|
68
|
+
#no need to implement alignment b/c we always provide offset when adding this field to struct_layout_builder
|
69
|
+
end
|
51
70
|
|
52
|
-
|
53
|
-
|
54
|
-
|
71
|
+
self.struct_class = Class.new(Struct) do
|
72
|
+
layout('', type)
|
73
|
+
end
|
55
74
|
|
56
|
-
|
57
|
-
|
58
|
-
|
75
|
+
self.type, self.bits_size, self.bits_offset = type, bits_size, bits_offset
|
76
|
+
|
77
|
+
def initialize(name, offset, type)
|
78
|
+
super(name, offset, FFI::Type::Struct.new(self.class.struct_class))
|
59
79
|
end
|
60
80
|
|
61
|
-
|
81
|
+
def read(ptr)
|
82
|
+
ptr.slice(offset, size).send("read_uint#{size * 8}".to_sym)
|
83
|
+
end
|
84
|
+
|
85
|
+
def write(ptr, value)
|
86
|
+
ptr.slice(offset, size).send("write_uint#{size * 8}".to_sym, value)
|
87
|
+
end
|
88
|
+
|
89
|
+
def get(ptr)
|
90
|
+
mask = (1 << self.class.bits_size) - 1
|
91
|
+
value = (read(ptr) >> self.class.bits_offset) & mask
|
92
|
+
|
93
|
+
SIGNED_NUMBER_TYPES.include?(self.class.type) ? value.to_signed(self.class.bits_size) : value
|
94
|
+
end
|
95
|
+
|
96
|
+
def put(ptr, value)
|
97
|
+
mask = ((1 << self.class.bits_size) - 1) << self.class.bits_offset
|
98
|
+
write(ptr, (read(ptr) & ~mask) | ((value << self.class.bits_offset) & mask))
|
99
|
+
end
|
62
100
|
end
|
63
101
|
end
|
64
102
|
|
65
|
-
attr_reader :
|
103
|
+
attr_reader :field_specs
|
66
104
|
|
67
|
-
|
68
|
-
|
105
|
+
private
|
106
|
+
def array_layout(builder, field_specs)
|
107
|
+
@field_specs = {}
|
69
108
|
|
70
|
-
field_spec_class = ::Struct.new(:name, :type, :
|
109
|
+
field_spec_class = ::Struct.new(:name, :type, :descriptors)
|
71
110
|
|
72
|
-
|
111
|
+
current_allocation_unit = nil
|
73
112
|
|
74
|
-
|
113
|
+
offset = i = 0
|
75
114
|
|
76
115
|
while i < field_specs.size
|
77
|
-
|
116
|
+
name, type = field_specs[i, 2]
|
78
117
|
i += 2
|
79
118
|
|
80
|
-
unless type.is_a?(Integer)
|
81
|
-
|
82
|
-
bits_size = type.size * 8
|
83
|
-
|
119
|
+
unless type.is_a?(Integer) || type.is_a?(String)
|
120
|
+
# If the next param is a Integer, it specifies the offset
|
84
121
|
if field_specs[i].is_a?(Integer)
|
85
|
-
|
122
|
+
offset = field_specs[i]
|
86
123
|
i += 1
|
124
|
+
else
|
125
|
+
offset = nil
|
87
126
|
end
|
127
|
+
|
128
|
+
type = find_field_type(type)
|
129
|
+
builder.add name, type, offset
|
130
|
+
|
131
|
+
current_allocation_unit = nil
|
88
132
|
else
|
89
|
-
|
133
|
+
if type.is_a?(Integer)
|
134
|
+
ffi_type, bits_size = UNSIGNED_NUMBER_TYPES.find {|ffi_type| type <= ffi_type.size * 8}, type
|
135
|
+
raise "Unrecognized format #{type}" unless ffi_type
|
136
|
+
elsif type.is_a?(String)
|
137
|
+
m = /^(?<ffi_type>[\w_]+)\s*:\s*(?<bits_size>\d+)$/.match(type.strip)
|
138
|
+
raise "Unrecognized format #{type}" unless m
|
139
|
+
|
140
|
+
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)
|
142
|
+
end
|
143
|
+
|
144
|
+
raise "Illegal format #{type}" if bits_size > ffi_type.size * 8
|
145
|
+
|
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)
|
149
|
+
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
|
164
|
+
end
|
165
|
+
|
166
|
+
builder.add name, find_field_type(bit_field(ffi_type, bits_size, current_allocation_unit[:bits_size] - bits_size)), offset
|
90
167
|
end
|
91
168
|
|
92
169
|
if field_specs[i].is_a?(Hash)
|
@@ -96,18 +173,7 @@ module FFI
|
|
96
173
|
descriptors = {}
|
97
174
|
end
|
98
175
|
|
99
|
-
@field_specs[
|
100
|
-
bits_offset += bits_size
|
101
|
-
end
|
102
|
-
|
103
|
-
@has_bit_field = @field_specs.any? {|field_name, field_spec| field_spec.type.is_a?(Integer)}
|
104
|
-
|
105
|
-
if @has_bit_field
|
106
|
-
#FIXME consider 24 bits situation or larger than 32 bits
|
107
|
-
#FIXME remove dummy field or have a better name for this field
|
108
|
-
super(:dummy, "uint#{(bits_offset + 7) & (-1 << 3)}".to_sym)
|
109
|
-
else
|
110
|
-
super(*field_specs.reject {|field_spec| field_spec.is_a?(Hash)})
|
176
|
+
@field_specs[name] = field_spec_class.new(name, type, descriptors)
|
111
177
|
end
|
112
178
|
end
|
113
179
|
end
|
@@ -121,25 +187,9 @@ module FFI
|
|
121
187
|
end
|
122
188
|
end
|
123
189
|
|
124
|
-
def [](field_name)
|
125
|
-
return super unless self.class.has_bit_field
|
126
|
-
|
127
|
-
field_spec = self.class.field_specs[field_name]
|
128
|
-
mask = ((1 << field_spec.type) - 1) << field_spec.bits_offset
|
129
|
-
|
130
|
-
(self.read & mask) >> field_spec.bits_offset
|
131
|
-
end
|
132
|
-
|
133
190
|
# Set field value
|
134
191
|
def []=(field_name, value)
|
135
|
-
|
136
|
-
|
137
|
-
return super(field_name, value) unless self.class.has_bit_field
|
138
|
-
|
139
|
-
field_spec = self.class.field_specs[field_name]
|
140
|
-
mask = ((1 << field_spec.type) - 1) << field_spec.bits_offset
|
141
|
-
|
142
|
-
self.write((self.read & (-1 - mask)) | ((value << field_spec.bits_offset) & mask))
|
192
|
+
super(field_name, map_field_value(field_name, value))
|
143
193
|
end
|
144
194
|
|
145
195
|
def write(value)
|
@@ -185,7 +235,7 @@ module FFI
|
|
185
235
|
return field_spec.descriptors[descriptor_key] if field_spec.descriptors.has_key?(descriptor_key)
|
186
236
|
|
187
237
|
type = field_spec.type
|
188
|
-
return value.to_dec if (type.is_a?(Integer) || FFI::StructLayoutBuilder::NUMBER_TYPES.include?(type)) && value.is_a?(String)
|
238
|
+
return value.to_dec if (type.is_a?(Integer) || type.is_a?(String) || FFI::StructLayoutBuilder::NUMBER_TYPES.include?(type)) && value.is_a?(String)
|
189
239
|
|
190
240
|
value
|
191
241
|
end
|
data/test/test_struct_ex.rb
CHANGED
@@ -5,11 +5,11 @@ require 'ffi/struct_ex'
|
|
5
5
|
class TestStructEx < Test::Unit::TestCase
|
6
6
|
def test_bit_fields
|
7
7
|
subject_class = Class.new(FFI::StructEx) do
|
8
|
-
layout :field_0, bit_fields(:bits_0_2, 3,
|
9
|
-
:bit_3, 1,
|
10
|
-
:bit_4, 1,
|
11
|
-
:bits_5_7, 3,
|
12
|
-
:bits_8_15, 8),
|
8
|
+
layout :field_0, bit_fields(:bits_0_2, 'uint16: 3',
|
9
|
+
:bit_3, 'uint16: 1',
|
10
|
+
:bit_4, 'uint16: 1',
|
11
|
+
:bits_5_7, 'uint16: 3',
|
12
|
+
:bits_8_15, 'uint16: 8'),
|
13
13
|
:field_1, :uint8,
|
14
14
|
:field_2, :uint8,
|
15
15
|
:field_3, :uint8
|
@@ -23,6 +23,7 @@ class TestStructEx < Test::Unit::TestCase
|
|
23
23
|
|
24
24
|
assert_equal(FFI::StructEx, subject[:field_0].class.superclass)
|
25
25
|
assert_equal(2, subject[:field_0].size)
|
26
|
+
assert_equal(2, subject[:field_0].alignment)
|
26
27
|
|
27
28
|
subject[:field_0] = 0b0110_1001
|
28
29
|
assert_equal(0b0110_1001, subject[:field_0].read)
|
@@ -122,8 +123,8 @@ class TestStructEx < Test::Unit::TestCase
|
|
122
123
|
|
123
124
|
assert_equal(FFI::StructEx, subject[:field_0].class.superclass)
|
124
125
|
assert_equal(1, subject[:field_0].size)
|
125
|
-
|
126
|
-
|
126
|
+
assert_equal(0b0110_1001, subject[:field_0])
|
127
|
+
assert_equal(subject[:field_1], subject.map_field_value(:field_1, '0x1'))
|
127
128
|
end
|
128
129
|
|
129
130
|
def test_descriptors
|
@@ -166,12 +167,181 @@ class TestStructEx < Test::Unit::TestCase
|
|
166
167
|
assert_equal(0x00, subject[:field_1])
|
167
168
|
end
|
168
169
|
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
170
|
+
def test_sizeof
|
171
|
+
assert_equal(4, Class.new(FFI::StructEx) do
|
172
|
+
layout :field_0, :short,
|
173
|
+
:field_1, :char,
|
174
|
+
:field_2, :char
|
175
|
+
end.size)
|
176
|
+
|
177
|
+
assert_equal(8, Class.new(FFI::StructEx) do
|
178
|
+
layout :field_0, 31,
|
179
|
+
:field_1, 31
|
180
|
+
end.size)
|
181
|
+
|
182
|
+
assert_equal(8, Class.new(FFI::StructEx) do
|
183
|
+
layout :field_0, 31,
|
184
|
+
:field_1, :uint8
|
185
|
+
end.size)
|
186
|
+
|
187
|
+
assert_equal(8, Class.new(FFI::StructEx) do
|
188
|
+
layout :field_0, 1,
|
189
|
+
:field_1, :uint32
|
190
|
+
end.size)
|
191
|
+
|
192
|
+
assert_equal(3, Class.new(FFI::StructEx) do
|
193
|
+
layout :field_0, 4,
|
194
|
+
:field_1, 4,
|
195
|
+
:field_2, 8,
|
196
|
+
:field_3, :uint8
|
197
|
+
end.size)
|
198
|
+
|
199
|
+
assert_equal(2, Class.new(FFI::StructEx) do
|
200
|
+
layout :field_0, 1,
|
201
|
+
:field_1, 1,
|
202
|
+
:field_2, :uint8
|
203
|
+
end.size)
|
204
|
+
|
205
|
+
assert_equal(3, Class.new(FFI::StructEx) do
|
206
|
+
layout :field_0, 1,
|
207
|
+
:field_1, 1,
|
208
|
+
:field_2, :uint8,
|
209
|
+
:field_3, 1,
|
210
|
+
:field_4, 1
|
211
|
+
end.size)
|
212
|
+
|
213
|
+
assert_equal(6, Class.new(FFI::StructEx) do
|
214
|
+
layout :field_0, 1,
|
215
|
+
:field_1, 1,
|
216
|
+
:field_2, :uint16,
|
217
|
+
:field_3, 1,
|
218
|
+
:field_4, 1
|
219
|
+
end.size)
|
220
|
+
|
221
|
+
assert_equal(6, Class.new(FFI::StructEx) do
|
222
|
+
layout :field_0, 1,
|
223
|
+
:field_1, 1,
|
224
|
+
:field_2, :uint16,
|
225
|
+
:field_3, 1,
|
226
|
+
:field_4, 8
|
227
|
+
end.size)
|
228
|
+
|
229
|
+
assert_equal(4, Class.new(FFI::StructEx) do
|
230
|
+
layout :field_0, 8,
|
231
|
+
:field_1, 16
|
232
|
+
end.size)
|
233
|
+
|
234
|
+
assert_equal(4, Class.new(FFI::StructEx) do
|
235
|
+
layout :field_0, 16,
|
236
|
+
:field_1, 8
|
237
|
+
end.size)
|
238
|
+
|
239
|
+
assert_equal(6, Class.new(FFI::StructEx) do
|
240
|
+
layout :field_0, 1,
|
241
|
+
:field_1, 16,
|
242
|
+
:field_2, 1
|
243
|
+
end.size)
|
244
|
+
|
245
|
+
assert_equal(1, Class.new(FFI::StructEx) do
|
246
|
+
layout :field_0, 'uint8: 1'
|
247
|
+
end.size)
|
248
|
+
|
249
|
+
assert_equal(2, Class.new(FFI::StructEx) do
|
250
|
+
layout :field_0, 'uint16: 1'
|
251
|
+
end.size)
|
252
|
+
|
253
|
+
assert_equal(4, Class.new(FFI::StructEx) do
|
254
|
+
layout :field_0, 'uint32: 1'
|
255
|
+
end.size)
|
256
|
+
|
257
|
+
assert_equal(2, Class.new(FFI::StructEx) do
|
258
|
+
layout :bits_0_2, 'uint16: 3',
|
259
|
+
:bit_3, 'uint16: 1',
|
260
|
+
:bit_4, 'uint16: 1',
|
261
|
+
:bits_5_7, 'uint16: 3',
|
262
|
+
:bits_8_15, 'uint16: 8'
|
263
|
+
end.size)
|
264
|
+
|
265
|
+
assert_equal(1, Class.new(FFI::StructEx) do
|
266
|
+
layout :field_0, 'uint8: 1',
|
267
|
+
:field_1, 'uint8: 1'
|
268
|
+
end.size)
|
269
|
+
|
270
|
+
assert_equal(1, Class.new(FFI::StructEx) do
|
271
|
+
layout :field_0, 'uint8: 1',
|
272
|
+
:field_1, 'int8: 1'
|
273
|
+
end.size)
|
274
|
+
|
275
|
+
assert_equal(8, Class.new(FFI::StructEx) do
|
276
|
+
layout :field_0, 'uint32: 1',
|
277
|
+
:field_1, :uint16
|
278
|
+
end.size)
|
279
|
+
|
280
|
+
assert_equal(8, Class.new(FFI::StructEx) do
|
281
|
+
layout :field_0, 'uint8: 1',
|
282
|
+
:field_1, :uint32
|
283
|
+
end.size)
|
284
|
+
|
285
|
+
assert_equal(8, Class.new(FFI::StructEx) do
|
286
|
+
layout :field_0, 'uint8: 1',
|
287
|
+
:field_1, 'uint32: 1'
|
288
|
+
end.size)
|
289
|
+
|
290
|
+
assert_equal(4, Class.new(FFI::StructEx) do
|
291
|
+
layout :field_0, :short,
|
292
|
+
:field_1, :char
|
293
|
+
end.size)
|
294
|
+
|
295
|
+
assert_equal(4, Class.new(FFI::StructEx) do
|
296
|
+
layout :field_0, :short,
|
297
|
+
:field_1, 'char: 1'
|
298
|
+
end.size)
|
299
|
+
|
300
|
+
subject_class = Class.new(FFI::StructEx) do
|
301
|
+
layout :field_0, :char,
|
302
|
+
:field_1, 'short: 1'
|
303
|
+
end
|
304
|
+
assert_equal(4, subject_class.size)
|
305
|
+
|
306
|
+
subject_class = Class.new(FFI::StructEx) do
|
307
|
+
layout :field_0, 'uint: 8',
|
308
|
+
:field_1, 'int: 1'
|
309
|
+
end
|
310
|
+
assert_equal(4, subject_class.size)
|
311
|
+
subject = subject_class.new
|
312
|
+
subject[:field_0] = 0b0110_1001
|
313
|
+
assert_equal(0b0110_1001, subject[:field_0])
|
314
|
+
subject[:field_0] = 0b1111_1111
|
315
|
+
assert_equal(0b1111_1111, subject[:field_0])
|
316
|
+
|
317
|
+
subject[:field_1] = 1
|
318
|
+
assert_equal(-1, subject[:field_1])
|
319
|
+
subject[:field_1] = 0
|
320
|
+
assert_equal(0, subject[:field_1])
|
321
|
+
subject[:field_1] = -1
|
322
|
+
assert_equal(-1, subject[:field_1])
|
323
|
+
|
324
|
+
#Check no impact for typedef type
|
325
|
+
FFI.typedef :uint8, :UINT8
|
326
|
+
subject_class = Class.new(FFI::StructEx) do
|
327
|
+
layout :field_0, 'UINT8: 8',
|
328
|
+
:field_1, 'int: 1'
|
329
|
+
end
|
330
|
+
|
331
|
+
subject_class = Class.new(FFI::StructEx) do
|
332
|
+
layout :bits_0_2, 'uint8: 3',
|
333
|
+
:bit_3, 'char: 1',
|
334
|
+
:bit_4, 'uint8: 1',
|
335
|
+
:bits_5_7, 'char: 3'
|
336
|
+
end
|
337
|
+
|
338
|
+
assert_equal(1, subject_class.size)
|
339
|
+
|
340
|
+
subject = subject_class.new(bits_0_2: 0b001, bit_3: 0b1, bit_4: 0b1, bits_5_7: 0b100)
|
341
|
+
assert_equal(1, subject[:bits_0_2])
|
342
|
+
assert_equal(-1, subject[:bit_3])
|
343
|
+
assert_equal(1, subject[:bit_4])
|
344
|
+
assert_equal(-4, subject[:bits_5_7])
|
345
|
+
|
346
|
+
end
|
177
347
|
end
|
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.0
|
4
|
+
version: 0.1.0
|
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-
|
11
|
+
date: 2014-05-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: ffi
|