vigilem-support 0.0.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. checksums.yaml +7 -0
  2. data/lib/vigilem/ffi.rb +19 -0
  3. data/lib/vigilem/ffi/array_pointer_sync.rb +382 -0
  4. data/lib/vigilem/ffi/struct.rb +54 -0
  5. data/lib/vigilem/ffi/utils.rb +240 -0
  6. data/lib/vigilem/ffi/utils/struct.rb +93 -0
  7. data/lib/vigilem/support.rb +31 -0
  8. data/lib/vigilem/support/core_ext.rb +13 -0
  9. data/lib/vigilem/support/core_ext/debug_puts.rb +5 -0
  10. data/lib/vigilem/support/core_ext/enumerable.rb +25 -0
  11. data/lib/vigilem/support/key_map.rb +323 -0
  12. data/lib/vigilem/support/key_map_info.rb +85 -0
  13. data/lib/vigilem/support/lazy_simple_delegator.rb +81 -0
  14. data/lib/vigilem/support/max_size_error.rb +17 -0
  15. data/lib/vigilem/support/metadata.rb +13 -0
  16. data/lib/vigilem/support/obj_space.rb +28 -0
  17. data/lib/vigilem/support/patch/cucumber/c_lexer.rb +30 -0
  18. data/lib/vigilem/support/patch/ffi/pointer.rb +19 -0
  19. data/lib/vigilem/support/size_error.rb +6 -0
  20. data/lib/vigilem/support/sys.rb +5 -0
  21. data/lib/vigilem/support/system.rb +92 -0
  22. data/lib/vigilem/support/transmutable_hash.rb +206 -0
  23. data/lib/vigilem/support/utils.rb +224 -0
  24. data/lib/vigilem/support/version.rb +5 -0
  25. data/spec/spec_helper.rb +9 -0
  26. data/spec/vigilem/ffi/array_pointer_sync_spec.rb +728 -0
  27. data/spec/vigilem/ffi/struct_spec.rb +22 -0
  28. data/spec/vigilem/ffi/utils/struct_spec.rb +79 -0
  29. data/spec/vigilem/ffi/utils_spec.rb +240 -0
  30. data/spec/vigilem/support/core_ext/enumerable_spec.rb +38 -0
  31. data/spec/vigilem/support/data/cached.kmap +130 -0
  32. data/spec/vigilem/support/data/cached_UTF-8_del.kmap +142 -0
  33. data/spec/vigilem/support/data/cached_short.kmap +38 -0
  34. data/spec/vigilem/support/data/dump_keys_short.kmap +128 -0
  35. data/spec/vigilem/support/key_map_spec.rb +767 -0
  36. data/spec/vigilem/support/lazy_simple_delegator_spec.rb +77 -0
  37. data/spec/vigilem/support/obj_space_spec.rb +47 -0
  38. data/spec/vigilem/support/sys_spec.rb +21 -0
  39. data/spec/vigilem/support/system_spec.rb +31 -0
  40. data/spec/vigilem/support/transmutable_hash_spec.rb +175 -0
  41. data/spec/vigilem/support/utils_spec.rb +214 -0
  42. metadata +240 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: ca7c5b14a32d34b7a9160a7eb60b96bc0654b3a5
4
+ data.tar.gz: 612804d8a3aef4f01e8587d595ecf1044147df9c
5
+ SHA512:
6
+ metadata.gz: 6d99905696f122267df2d1ff04eaa1b62e65d7c7c678d353272ccc639a93592ac840ca4bce74daecef07510f75d9b79bf533a734b3477cfb07ce18e8087d327a
7
+ data.tar.gz: 9cd01bad9a80179757b155212f3cf60e2c3407813b060b465c76f3962846bbbfdb0aef33bf5242fec47afc03f82b40f5437e627077824d91e757b150e9f6ad93
@@ -0,0 +1,19 @@
1
+ require 'ffi'
2
+
3
+ module Vigilem
4
+ module FFI
5
+ end
6
+ end
7
+
8
+ require 'vigilem/support'
9
+
10
+ require 'vigilem/ffi/utils'
11
+ FFIUtils = ::Vigilem::FFI::Utils
12
+
13
+ require 'vigilem/ffi/utils/struct'
14
+ FFIStructUtils = FFIUtils::Struct
15
+
16
+ require 'vigilem/ffi/struct'
17
+ VFFIStruct = ::Vigilem::FFI::Struct
18
+
19
+ require 'vigilem/ffi/array_pointer_sync'
@@ -0,0 +1,382 @@
1
+ module Vigilem::FFI
2
+ # creates an ary of fixed size that is synched with
3
+ # an underlying FFI::Pointer, kind of reinventing the wheel here
4
+ # if you think about it
5
+ # this can be split further for a more dynamic ary that can increase in
6
+ # size, but thats for the future
7
+ # @note ary is used to match ptr used by struct
8
+ module ArrayPointerSync
9
+
10
+ require 'vigilem/support/max_size_error'
11
+
12
+ attr_accessor :cache_hash, :max_size
13
+
14
+ #
15
+ # @raise [TypeError] '@max_size is nil'
16
+ # @return
17
+ def max_size!
18
+ @max_size || raise(TypeError, '@max_size is nil')
19
+ end
20
+
21
+ alias_method :max_len, :max_size
22
+ alias_method :max_len=, :max_size=
23
+
24
+ private :cache_hash=, :max_size=, :max_len=
25
+
26
+ #
27
+ # @return [FFI::Pointer]
28
+ def ptr
29
+ @ptr ||= FFI::MemoryPointer.new(self.class.ary_type, self.max_size!)
30
+ end
31
+
32
+ #
33
+ # @param base
34
+ # @return
35
+ def self.included(base)
36
+ base.extend ClassMethods
37
+ base.class_eval do
38
+ native_type FFI::Type::POINTER
39
+ end
40
+ end
41
+
42
+ @point_cuts = (Array.instance_methods -
43
+ [*Array.instance_methods.grep(/method|taint|trust|instance_variable|send|class|respond/),
44
+ :__id__, :object_id, :extend, :freeze, :kind_of?, :instance_of?, :is_a?, :replace, :eql?, :equal?
45
+ ]).sort
46
+
47
+ #
48
+ # @param [Symbol] method_name
49
+ # @param [Array] args
50
+ # @param [Proc] block
51
+ # @raise [RuntimeException]
52
+ # @see #out_of_bounds_check
53
+ # @return
54
+ def after_ary_method(method_name, return_value, *args, &block)
55
+ out_of_bounds_check
56
+ update
57
+ return_value
58
+ end
59
+
60
+ @point_cuts.each do |point_cut|
61
+ define_method(point_cut) do |*args, &block|
62
+ begin
63
+ update
64
+ ret = ary().__send__(point_cut, *args, &block)
65
+ method_name = __method__
66
+ if not [:size, :length].include? method_name
67
+ after_ary_method(method_name, ret, *args, &block)
68
+ else
69
+ ret
70
+ end
71
+ rescue StandardError => e
72
+ e.set_backtrace([__method__.to_s] + e.backtrace)
73
+ raise e
74
+ end
75
+ end
76
+ end
77
+
78
+ # @todo change max_len_or_ptr_or_first_item, and default max_size to init_values.length
79
+ # @param [Integer || FFI::Pointer] max_len_or_ptr
80
+ # @param [Array] init_values
81
+ # @return [ArrayPointerSync] self
82
+ def initialize_ary_ptr_sync(max_len_or_ptr, *init_values)
83
+ if max_len_or_ptr.is_a? FFI::Pointer
84
+ if not (max_len_or_ptr and init_values.empty?)
85
+ raise ArgumentError, "Cannot have both a pointer and *init_values:`#{max_len_or_ptr.inspect}' `#{init_values.inspect}'"
86
+ end
87
+ @ptr = max_len_or_ptr
88
+ update_ary
89
+ @max_size = ary().size
90
+ else
91
+ raise TypeError, "max_len_or_ptr, doesn't respond_to? :to_i" unless max_len_or_ptr.respond_to? :to_i
92
+ @max_size = max_len_or_ptr.to_i
93
+ @ary = init_values
94
+ @ptr = ::FFI::MemoryPointer.new(self.class.ary_type, @max_size)
95
+ update_ptr if not init_values.empty?
96
+ end
97
+ update_cache
98
+ self
99
+ end
100
+
101
+ #
102
+ #
103
+ module ClassMethods
104
+ include FFI::DataConverter
105
+
106
+ # @todo create and ary_type_wrapper for symbols so an if stmnt
107
+ # isn;t always needed
108
+ # @raise [RuntimeError]
109
+ # @return [Class || Symbol]
110
+ def ary_type
111
+ raise NotImplementedError, "No ary_type configured for this class #{self}"
112
+ end
113
+
114
+ #
115
+ # @return [Class]
116
+ def ary_type_object
117
+ if ary_type.is_a? Symbol
118
+ ::FFI.find_type(ary_type)
119
+ else
120
+ ary_type
121
+ end
122
+ end
123
+
124
+ #
125
+ # @return [Integer] the size
126
+ def ary_type_size
127
+ ary_type_object.size
128
+ end
129
+
130
+ #
131
+ # @param [Pointer] pointer
132
+ # @return [Integer]
133
+ def ptr_capacity(pointer)
134
+ pointer.size/ary_type_size
135
+ end
136
+
137
+ #
138
+ # @return [Array<#ary_type>]
139
+ def ary_of_type(pointer)
140
+ Utils.ary_of_type(ary_type, ary_type_size, pointer)
141
+ end
142
+ end
143
+
144
+ # @see Array#replace
145
+ # @param [Array] other
146
+ # @return [ArrayPointerSync]
147
+ def replace(other)
148
+ ary.replace(other)
149
+ update
150
+ self
151
+ end
152
+ #
153
+ # @return [String]
154
+ def bytes
155
+ update
156
+ ptr.read_bytes(ptr.size)
157
+ end
158
+
159
+ # bytes of the idtem referenced by index
160
+ # @param [Integer] idx
161
+ # @return [String]
162
+ def bytes_of(idx)
163
+ update
164
+ ptr.get_bytes(idx * (type_size = self.class.ary_type_size), type_size)
165
+ end
166
+
167
+ #
168
+ # @return [Array<Integer>]
169
+ def offsets
170
+ if update or @ptr_offsets.nil?
171
+ _ptr_offsets
172
+ else
173
+ @ptr_offsets
174
+ end
175
+ end
176
+
177
+ #
178
+ # @raise [RuntimeError] when both ptr and ary changed
179
+ # @return [Hash] what item changed
180
+ def what_changed?
181
+ results = {ary: ary_changed?, ptr: ptr_changed? }
182
+ raise 'both ary and pointer changed' if results.values.all?
183
+ results
184
+ end
185
+
186
+ # checks to see if the the ptr contents
187
+ # or ary conents have changed
188
+ #
189
+ # @return [TrueClass || FalseClass]
190
+ def changed?
191
+ what_changed?.values.any?
192
+ end
193
+
194
+ #
195
+ # @return [TrueClass || FalseClass]
196
+ def ptr_changed?
197
+ ptr_cache_hash() != ptr_hash()
198
+ end
199
+
200
+ #
201
+ # @return [TrueClass || FalseClass]
202
+ def ary_changed?
203
+ self.cache_hash != ary().hash
204
+ end
205
+
206
+ # checks whether or not ary.size > max_size
207
+ # @return [TrueClass || FalseClass]
208
+ def out_of_bounds?
209
+ _size > max_size!
210
+ end
211
+
212
+ #
213
+ # @raises RuntimeException
214
+ # @return [NilClass]
215
+ def out_of_bounds_check
216
+ _raise_size_error if out_of_bounds?
217
+ end
218
+
219
+ #
220
+ # @param [Array] other
221
+ # @return [ArrayPointerSync]
222
+ def replace(other)
223
+ ary.replace(other)
224
+ update
225
+ self
226
+ end
227
+
228
+ #
229
+ #
230
+ # @return [Array]
231
+ def to_a
232
+ update
233
+ ary
234
+ end
235
+
236
+ # @todo
237
+ #def to_ary
238
+ #
239
+ #end
240
+
241
+ #
242
+ # @return [ArrayPointerSync]
243
+ def dup
244
+ self.class.new(ptr.dup)
245
+ end
246
+
247
+ # dup copies everything to a new pointer, is this needed? does it copy
248
+ # @return [ArrayPointerSync]
249
+ def deep_dup
250
+ pointer = FFI::MemoryPointer.new(self.class.ary_type, max_size)
251
+ pointer.write_bytes(self.bytes)
252
+ self.class.new(pointer)
253
+ end
254
+
255
+ # @return [String] just like that of an array
256
+ def to_s
257
+ update
258
+ ary.to_s
259
+ end
260
+
261
+ #
262
+ # @see Object#inspect
263
+ # @return [String]
264
+ def inspect
265
+ update
266
+ vars = instance_variables.except(:@ary).map {|var| "#{var}=#{instance_variable_get(var)}" }.join(' ')
267
+ "#{_to_s.chomp('>')} #{vars}>"
268
+ end
269
+
270
+ # the basic inspect structure without the vars
271
+ # @return [String]
272
+ def _to_s
273
+ "#<#{self.class}:0x#{object_id << 1} #{ary}>"
274
+ end
275
+
276
+ private
277
+ attr_accessor :ptr_cache_hash
278
+
279
+ #
280
+ # @return [Array]
281
+ def ary
282
+ @ary ||= []
283
+ end
284
+
285
+ #
286
+ # @return [Array<Integer>]
287
+ def _ptr_offsets
288
+ @ptr_offsets = 0.upto((ary.size - 1)).map {|n| self.class.ary_type_size * n }
289
+ end
290
+
291
+ # @see String#hash
292
+ # @return [Integer]
293
+ def ptr_hash
294
+ ptr.read_bytes(ptr.size).hash
295
+ end
296
+
297
+ # detects what changed and updates as needed
298
+ # @return [TrueClass || FalseClass] updated?
299
+ def update
300
+ if (results = what_changed?)[:ary]
301
+ update_ptr
302
+ update_ary_cache
303
+ true
304
+ elsif results[:ptr]
305
+ update_ary
306
+ update_ptr_cache
307
+ true
308
+ else
309
+ false
310
+ end
311
+ end
312
+
313
+ #
314
+ # this is slightly dangerous, if anything was still pointing to old pointer location
315
+ # now its being reclaimed, this will change it
316
+ # @return [Integer] hash
317
+ def update_ptr
318
+ ptr.clear
319
+ if (not (arry_type = self.class.ary_type).is_a?(Symbol))
320
+ if arry_type.respond_to? :to_native
321
+ ary.each {|item| ptr.write_pointer(arry_type.to_native(item, nil)) }
322
+ elsif arry_type.method_defined? :bytes
323
+ ptr.write_bytes(ary.map {|item| item.respond.bytes }.join)
324
+ elsif arry_type.method_defined? :pointer
325
+ ary.each do |item|
326
+ if item.size == item.pointer.size
327
+ ptr.write_bytes((itm_ptr = item.pointer).read_bytes(itm_ptr.size))
328
+ else
329
+ raise ArgumentError, "Cannot reliably convert `#{item}' to a native_type"
330
+ end
331
+ end
332
+ else
333
+ raise ArgumentError, "Cannot reliably convert `#{arry_type}' to a native_type"
334
+ end
335
+ else
336
+ Utils.put_array_typedef(ptr, arry_type, ary)
337
+ end
338
+ update_ptr_cache
339
+ #self.ptr_cache_hash = @bytes.hash # @FIXME ptr_hash() and @bytes.hash should be the same...
340
+ end
341
+
342
+ #
343
+ # @return [Array<self.class.ary_type>]
344
+ def update_ary
345
+ arry = ary.replace(self.class.ary_of_type(ptr))
346
+ _ptr_offsets
347
+ update_ary_cache
348
+ arry
349
+ end
350
+
351
+ # size method on ary without update
352
+ # @return [Integer] size
353
+ def _size
354
+ ary.size
355
+ end
356
+
357
+ #
358
+ # @return [Array<Integer>]
359
+ def update_cache
360
+ [update_ary_cache, update_ptr_cache]
361
+ end
362
+
363
+ #
364
+ # @return [Integer] hash
365
+ def update_ptr_cache
366
+ self.ptr_cache_hash = ptr_hash()
367
+ end
368
+
369
+ #
370
+ # @return [Integer] hash
371
+ def update_ary_cache
372
+ self.cache_hash = ary().hash
373
+ end
374
+
375
+ #
376
+ # @raise [RuntimeError]
377
+ # @return
378
+ def _raise_size_error
379
+ raise Vigilem::Support::MaxSizeError, [_to_s, self.max_size!]
380
+ end
381
+ end
382
+ end
@@ -0,0 +1,54 @@
1
+ module Vigilem
2
+ module FFI
3
+ # ::FFI::Struct with some sugar
4
+ class Struct < ::FFI::Struct
5
+
6
+ include Utils::Struct
7
+
8
+ # should make assign private, but since FFI::Struct.rb
9
+ # doesn;t know it's memory location
10
+ # this may have to be updated from the outside
11
+ attr_accessor :ptr_offset
12
+
13
+ #
14
+ # @param [FFI::Pointer || Integer] ptr_or_offset
15
+ # @param [Integer] offset
16
+ def initialize(ptr_or_offset=nil, offset=0)
17
+ if ptr_or_offset.is_a? Integer
18
+ super()
19
+ @ptr_offset = ptr_or_offset
20
+ else
21
+ super(*ptr_or_offset)
22
+ @ptr_offset = offset
23
+ end
24
+ end
25
+
26
+ # allows initial values in a new object like Hash::[]
27
+ # @todo move to utils/struct::ClassMethods
28
+ # @param [Array<Hash||Array>] *vals
29
+ # @return [Struct]
30
+ def self.[](*vals)
31
+ frst = vals.first
32
+ vals = frst if frst.is_a? Hash and vals.size == 1
33
+ new.bulk_assign(vals)
34
+ end
35
+
36
+ # converts struct to a String bytes "\x00" or "\u0000"
37
+ # the struct needs to know where in the pointer it is...
38
+ # @param [FFI::Struct] struct
39
+ # @return [String]
40
+ def bytes
41
+ ptr = self.to_ptr
42
+ ptr.get_bytes(self.ptr_offset, self.size)
43
+ end
44
+
45
+ # shows the members and thier values in addition to the traditional inspect
46
+ # @see Object#inspect
47
+ # @return [String]
48
+ def inspect
49
+ "#{super.chop} #{members.map {|mem| "#{mem}=#{self[mem]}" }.join(' ')}>"
50
+ end
51
+
52
+ end
53
+ end
54
+ end