ffi-msgpack 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.
Files changed (41) hide show
  1. data/.gitignore +4 -0
  2. data/.specopts +1 -0
  3. data/.yardopts +1 -0
  4. data/ChangeLog.md +8 -0
  5. data/Gemfile +24 -0
  6. data/LICENSE.txt +23 -0
  7. data/README.md +91 -0
  8. data/Rakefile +39 -0
  9. data/VERSION +1 -0
  10. data/ffi-msgpack.gemspec +101 -0
  11. data/lib/ffi/msgpack.rb +3 -0
  12. data/lib/ffi/msgpack/exceptions/parse_error.rb +6 -0
  13. data/lib/ffi/msgpack/extensions.rb +8 -0
  14. data/lib/ffi/msgpack/extensions/array.rb +7 -0
  15. data/lib/ffi/msgpack/extensions/false_class.rb +7 -0
  16. data/lib/ffi/msgpack/extensions/float.rb +7 -0
  17. data/lib/ffi/msgpack/extensions/hash.rb +7 -0
  18. data/lib/ffi/msgpack/extensions/integer.rb +7 -0
  19. data/lib/ffi/msgpack/extensions/nil_class.rb +7 -0
  20. data/lib/ffi/msgpack/extensions/string.rb +7 -0
  21. data/lib/ffi/msgpack/extensions/true_class.rb +7 -0
  22. data/lib/ffi/msgpack/msg_array.rb +35 -0
  23. data/lib/ffi/msgpack/msg_key_value.rb +33 -0
  24. data/lib/ffi/msgpack/msg_map.rb +41 -0
  25. data/lib/ffi/msgpack/msg_object.rb +276 -0
  26. data/lib/ffi/msgpack/msg_object_union.rb +20 -0
  27. data/lib/ffi/msgpack/msg_raw.rb +42 -0
  28. data/lib/ffi/msgpack/msgpack.rb +127 -0
  29. data/lib/ffi/msgpack/packable.rb +20 -0
  30. data/lib/ffi/msgpack/packer.rb +153 -0
  31. data/lib/ffi/msgpack/types.rb +30 -0
  32. data/lib/ffi/msgpack/unpacker.rb +248 -0
  33. data/lib/ffi/msgpack/zone.rb +18 -0
  34. data/lib/ffi/msgpack/zone_chunk_list.rb +13 -0
  35. data/lib/ffi/msgpack/zone_finalizer.rb +14 -0
  36. data/lib/ffi/msgpack/zone_finalizer_array.rb +13 -0
  37. data/spec/msg_object_spec.rb +193 -0
  38. data/spec/packer_spec.rb +62 -0
  39. data/spec/spec_helper.rb +15 -0
  40. data/spec/unpacker_spec.rb +69 -0
  41. metadata +190 -0
@@ -0,0 +1,33 @@
1
+ require 'ffi/msgpack/types'
2
+ require 'ffi/msgpack/msg_object'
3
+
4
+ module FFI
5
+ module MsgPack
6
+ class MsgKeyValue < FFI::Struct
7
+
8
+ layout :key, :pointer,
9
+ :value, :pointer
10
+
11
+ #
12
+ # The key.
13
+ #
14
+ # @return [MsgObject]
15
+ # The key Msg Object.
16
+ #
17
+ def key
18
+ MsgObject.new(self[:key])
19
+ end
20
+
21
+ #
22
+ # The value.
23
+ #
24
+ # @return [MsgObject]
25
+ # The value Msg Object.
26
+ #
27
+ def value
28
+ MsgObject.new(self[:value])
29
+ end
30
+
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,41 @@
1
+ require 'ffi/msgpack/types'
2
+ require 'ffi/msgpack/msg_key_value'
3
+
4
+ module FFI
5
+ module MsgPack
6
+ class MsgMap < FFI::Struct
7
+
8
+ layout :size, :uint32,
9
+ :ptr, :pointer
10
+
11
+ #
12
+ # The length of the MsgPack Array.
13
+ #
14
+ # @return [Integer]
15
+ # The length of the Array.
16
+ #
17
+ def length
18
+ self[:size]
19
+ end
20
+
21
+ #
22
+ # The Hash of the Msg Maps keys and values.
23
+ #
24
+ # @return [Hash]
25
+ # The Hash of the key->value values.
26
+ #
27
+ def to_hash
28
+ hash = {}
29
+
30
+ (0...self.length).each do |index|
31
+ pair = MsgKeyValue.new(self[:ptr][index * MsgKeyValue.size])
32
+
33
+ hash[pair.key.to_ruby] = pair.value.to_ruby
34
+ end
35
+
36
+ return hash
37
+ end
38
+
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,276 @@
1
+ require 'ffi/msgpack/types'
2
+ require 'ffi/msgpack/msg_object_union'
3
+
4
+ module FFI
5
+ module MsgPack
6
+ class MsgObject < FFI::Struct
7
+
8
+ layout :type, :msgpack_object_type,
9
+ :values, MsgObjectUnion
10
+
11
+ #
12
+ # Creates a new `nil` Msg Object.
13
+ #
14
+ # @param [FFI::Pointer] ptr
15
+ # Optional pointer to create the Msg Object at.
16
+ #
17
+ # @return [MsgObject]
18
+ # A new Msg Object that represents the `nil` value.
19
+ #
20
+ def MsgObject.new_nil(ptr=nil)
21
+ obj = MsgObject.new(ptr)
22
+ obj[:type] = :nil
23
+
24
+ return obj
25
+ end
26
+
27
+ #
28
+ # Creates a new boolean Msg Object.
29
+ #
30
+ # @param [Boolean] value
31
+ # The boolean value.
32
+ #
33
+ # @param [FFI::Pointer] ptr
34
+ # Optional pointer to create the Msg Object at.
35
+ #
36
+ # @return [MsgObject]
37
+ # The new boolean Msg Object.
38
+ #
39
+ def MsgObject.new_boolean(value,ptr=nil)
40
+ obj = MsgObject.new(ptr)
41
+ obj[:type] = :boolean
42
+ obj[:values][:boolean] = if value
43
+ 1
44
+ else
45
+ 0
46
+ end
47
+
48
+ return obj
49
+ end
50
+
51
+ #
52
+ # Creates a new integer Msg Object.
53
+ #
54
+ # @param [Integer] value
55
+ # The integer value.
56
+ #
57
+ # @param [FFI::Pointer] ptr
58
+ # Optional pointer to create the Msg Object at.
59
+ #
60
+ # @return [MsgObject]
61
+ # The new integer Msg Object.
62
+ #
63
+ def MsgObject.new_integer(value,ptr=nil)
64
+ obj = MsgObject.new(ptr)
65
+
66
+ if value < 0
67
+ obj[:type] = :negative_integer
68
+ obj[:values][:i64] = value
69
+ else
70
+ obj[:type] = :positive_integer
71
+ obj[:values][:u64] = value
72
+ end
73
+
74
+ return obj
75
+ end
76
+
77
+ #
78
+ # Creates a new floating-point Msg Object.
79
+ #
80
+ # @param [Double, Float] value
81
+ # The floating-point value.
82
+ #
83
+ # @param [FFI::Pointer] ptr
84
+ # Optional pointer to create the Msg Object at.
85
+ #
86
+ # @return [MsgObject]
87
+ # The floating-point Msg Object.
88
+ #
89
+ def MsgObject.new_double(value,ptr=nil)
90
+ obj = MsgObject.new(ptr)
91
+ obj[:type] = :double
92
+ obj[:values][:dec] = value
93
+
94
+ return obj
95
+ end
96
+
97
+ #
98
+ # @see MsgObject.new_double
99
+ #
100
+ def MsgObject.new_float(value,ptr=nil)
101
+ MsgObject.new_double(value,ptr)
102
+ end
103
+
104
+ #
105
+ # Creates a new raw Msg Object.
106
+ #
107
+ # @param [String] data
108
+ # The raw data.
109
+ #
110
+ # @param [FFI::Pointer] ptr
111
+ # Optional pointer to create the Msg Object at.
112
+ #
113
+ # @return [MsgObject]
114
+ # The raw Msg Object.
115
+ #
116
+ def MsgObject.new_raw(data,ptr=nil)
117
+ buffer = FFI::MemoryPointer.new(:uchar, data.length)
118
+ buffer.put_bytes(0,data)
119
+
120
+ obj = MsgObject.new(ptr)
121
+ obj[:type] = :raw
122
+ obj[:values][:raw][:size] = data.length
123
+ obj[:values][:raw][:ptr] = buffer
124
+
125
+ return obj
126
+ end
127
+
128
+ #
129
+ # Creates a new array Msg Object.
130
+ #
131
+ # @param [Array] values
132
+ # The values for the array.
133
+ #
134
+ # @param [FFI::Pointer] ptr
135
+ # Optional pointer to create the Msg Object at.
136
+ #
137
+ # @return [MsgObject]
138
+ # The array Msg Object.
139
+ #
140
+ def MsgObject.new_array(values,ptr=nil)
141
+ entries = FFI::MemoryPointer.new(MsgObject,values.length)
142
+
143
+ values.each_with_index do |value,index|
144
+ MsgObject.new_object(value,entries[index])
145
+ end
146
+
147
+ obj = MsgObject.new(ptr)
148
+ obj[:type] = :array
149
+ obj[:values][:array][:size] = values.length
150
+ obj[:values][:array][:ptr] = entries
151
+
152
+ return obj
153
+ end
154
+
155
+ #
156
+ # Creates a new map Msg Object.
157
+ #
158
+ # @param [Hash] values
159
+ # The values for the map.
160
+ #
161
+ # @param [FFI::Pointer] ptr
162
+ # Optional pointer to create the Msg Object at.
163
+ #
164
+ # @return [MsgObject]
165
+ # The map Msg Object.
166
+ #
167
+ def MsgObject.new_map(values,ptr=nil)
168
+ entries = FFI::MemoryPointer.new(MsgKeyValue,values.length)
169
+
170
+ values.each_with_index do |(key,value),index|
171
+ pair = MsgKeyValue.new(entries[index])
172
+
173
+ pair[:key] = MsgObject.new_object(key)
174
+ pair[:value] = MsgObject.new_object(value)
175
+ end
176
+
177
+ obj = MsgObject.new
178
+ obj[:type] = :map
179
+ obj[:values][:map][:size] = values.length
180
+ obj[:values][:map][:ptr] = entries
181
+
182
+ return obj
183
+ end
184
+
185
+ #
186
+ # Creates a Msg Object from a given Ruby object.
187
+ #
188
+ # @param [Object] value
189
+ # The Ruby object.
190
+ #
191
+ # @param [FFI::Pointer] ptr
192
+ # Optional pointer to create the Msg Object at.
193
+ #
194
+ # @return [MsgObject]
195
+ # The new Msg Object.
196
+ #
197
+ def MsgObject.new_object(value,ptr=nil)
198
+ case value
199
+ when Hash
200
+ MsgObject.new_map(value,ptr)
201
+ when Array
202
+ MsgObject.new_array(value,ptr)
203
+ when String, Symbol
204
+ MsgObject.new_raw(value.to_s,ptr)
205
+ when Float
206
+ MsgObject.new_double(value,ptr)
207
+ when Integer
208
+ MsgObject.new_integer(value,ptr)
209
+ when TrueClass, FalseClass
210
+ MsgObject.new_boolean(value,ptr)
211
+ when NilClass
212
+ MsgObject.new_nil(ptr)
213
+ else
214
+ raise(ArgumentError,"ambigious object to create MsgObject from: #{value.inspect}",caller)
215
+ end
216
+ end
217
+
218
+ #
219
+ # The type of the Msg Object.
220
+ #
221
+ # @return [Symbol]
222
+ # The type of the Msg Object.
223
+ #
224
+ def type
225
+ self[:type]
226
+ end
227
+
228
+ #
229
+ # The union of values for the Msg Object.
230
+ #
231
+ # @return [MsgObjectUnion]
232
+ # The union of values.
233
+ #
234
+ def values
235
+ self[:values]
236
+ end
237
+
238
+ #
239
+ # The value of the Msg Object.
240
+ #
241
+ # @return [Object]
242
+ # The value of the Msg Object, expressed as a Ruby primitive.
243
+ #
244
+ # @raise [RuntimeError]
245
+ # The type of the Msg Object was unknown.
246
+ #
247
+ def to_ruby
248
+ case self[:type]
249
+ when :nil
250
+ nil
251
+ when :boolean
252
+ if self[:values][:boolean] == 0
253
+ false
254
+ else
255
+ true
256
+ end
257
+ when :positive_integer
258
+ self[:values][:u64]
259
+ when :negative_integer
260
+ self[:values][:i64]
261
+ when :double
262
+ self[:values][:dec]
263
+ when :raw
264
+ self[:values][:raw].to_s
265
+ when :array
266
+ self[:values][:array].to_a
267
+ when :map
268
+ self[:values][:map].to_hash
269
+ else
270
+ raise(RuntimeError,"unknown msgpack object type",caller)
271
+ end
272
+ end
273
+
274
+ end
275
+ end
276
+ end
@@ -0,0 +1,20 @@
1
+ require 'ffi/msgpack/types'
2
+ require 'ffi/msgpack/msg_array'
3
+ require 'ffi/msgpack/msg_map'
4
+ require 'ffi/msgpack/msg_raw'
5
+
6
+ module FFI
7
+ module MsgPack
8
+ class MsgObjectUnion < FFI::Union
9
+
10
+ layout :boolean, :uint8,
11
+ :u64, :uint64,
12
+ :i64, :int64,
13
+ :dec, :double,
14
+ :array, MsgArray,
15
+ :map, MsgMap,
16
+ :raw, MsgRaw
17
+
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,42 @@
1
+ require 'ffi/msgpack/types'
2
+
3
+ module FFI
4
+ module MsgPack
5
+ class MsgRaw < FFI::Struct
6
+
7
+ layout :size, :uint32,
8
+ :ptr, :pointer
9
+
10
+ #
11
+ # The length of the raw data.
12
+ #
13
+ # @return [Integer]
14
+ # The length of the raw data.
15
+ #
16
+ def length
17
+ self[:size]
18
+ end
19
+
20
+ #
21
+ # The pointer to the raw data.
22
+ #
23
+ # @return [FFI::Pointer]
24
+ # The pointer to the raw data.
25
+ #
26
+ def raw
27
+ self[:ptr]
28
+ end
29
+
30
+ #
31
+ # The raw data.
32
+ #
33
+ # @return [String]
34
+ # The raw data.
35
+ #
36
+ def to_s
37
+ self[:ptr].get_bytes(0,self[:size])
38
+ end
39
+
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,127 @@
1
+ require 'ffi/msgpack/types'
2
+ require 'ffi/msgpack/msg_object'
3
+
4
+ require 'ffi'
5
+ require 'enumerator'
6
+
7
+ module FFI
8
+ module MsgPack
9
+ extend FFI::Library
10
+
11
+ ffi_lib 'msgpack'
12
+
13
+ attach_function :msgpack_object_print, [:pointer, MsgObject.by_value], :void
14
+ #attach_function :msgpack_object_equal, [MsgObject, MsgObject.by_value], :bool
15
+
16
+ attach_function :msgpack_zone_init, [:pointer, :size_t], :bool
17
+ attach_function :msgpack_zone_destroy, [:pointer], :void
18
+ attach_function :msgpack_zone_new, [:size_t], :pointer
19
+ attach_function :msgpack_zone_free, [:pointer], :void
20
+ attach_function :msgpack_zone_is_empty, [:pointer], :bool
21
+ attach_function :msgpack_zone_clear, [:pointer], :void
22
+
23
+ attach_function :msgpack_unpacker_init, [:pointer, :size_t], :bool
24
+ attach_function :msgpack_unpacker_destroy, [:pointer], :void
25
+
26
+ attach_function :msgpack_unpacker_new, [:size_t], :pointer
27
+ attach_function :msgpack_unpacker_free, [:pointer], :void
28
+
29
+ #attach_function :msgpack_unpacker_reserve_buffer, [:pointer, :size_t], :bool
30
+ #attach_function :msgpack_unpacker_buffer, [:pointer], :pointer
31
+ #attach_function :msgpack_unpacker_buffer_capacity, [:pointer], :size_t
32
+ #attach_function :msgpack_unpacker_buffer_consumed, [:pointer, :size_t], :void
33
+
34
+ attach_function :msgpack_unpacker_execute, [:pointer], :int
35
+
36
+ attach_function :msgpack_unpacker_data, [:pointer], MsgObject.by_value
37
+
38
+ attach_function :msgpack_unpacker_release_zone, [:pointer], :pointer
39
+
40
+ attach_function :msgpack_unpacker_reset_zone, [:pointer], :void
41
+
42
+ attach_function :msgpack_unpacker_reset, [:pointer], :void
43
+
44
+ #attach_function :msgpack_unpacker_message_size, [:pointer], :size_t
45
+
46
+ attach_function :msgpack_unpack, [:pointer, :size_t, :pointer, :pointer, :pointer], :msgpack_unpack_return
47
+
48
+ #attach_function :msgpack_unpacker_parsed_size, [:pointer], :size_t
49
+
50
+ attach_function :msgpack_unpacker_flush_zone, [:pointer], :bool
51
+
52
+ attach_function :msgpack_unpacker_expand_buffer, [:pointer, :size_t], :bool
53
+
54
+ #attach_function :msgpack_packer_init, [:pointer, :pointer, :msgpack_packer_write], :void
55
+
56
+ #attach_function :msgpack_packer_new, [:pointer, :msgpack_packer_write], :pointer
57
+ #attach_function :msgpack_packer_free, [:pointer], :void
58
+
59
+ #attach_function :msgpack_pack_short, [:pointer, :short], :int
60
+ #attach_function :msgpack_pack_int, [:pointer, :int], :int
61
+ #attach_function :msgpack_pack_long, [:pointer, :long], :int
62
+ #attach_function :msgpack_pack_long_long, [:pointer, :int64], :int
63
+ #attach_function :msgpack_pack_unsigned_short, [:pointer, :ushort], :int
64
+ #attach_function :msgpack_pack_unsigned_int, [:pointer, :uint], :int
65
+ #attach_function :msgpack_pack_unsigned_long, [:pointer, :ulong], :int
66
+ #attach_function :msgpack_pack_unsigned_long_long, [:pointer, :uint64], :int
67
+
68
+ #attach_function :msgpack_pack_uint8, [:pointer, :uint8], :int
69
+ #attach_function :msgpack_pack_uint16, [:pointer, :uint16], :int
70
+ #attach_function :msgpack_pack_uint32, [:pointer, :uint32], :int
71
+ #attach_function :msgpack_pack_uint64, [:pointer, :uint64], :int
72
+ #attach_function :msgpack_pack_int8, [:pointer, :int8], :int
73
+ #attach_function :msgpack_pack_int16, [:pointer, :int16], :int
74
+ #attach_function :msgpack_pack_int32, [:pointer, :int32], :int
75
+ #attach_function :msgpack_pack_int64, [:pointer, :int64], :int
76
+
77
+ #attach_function :msgpack_pack_float, [:pointer, :float], :int
78
+ #attach_function :msgpack_pack_double, [:pointer, :double], :int
79
+
80
+ #attach_function :msgpack_pack_nil, [:pointer], :int
81
+ #attach_function :msgpack_pack_true, [:pointer], :int
82
+ #attach_function :msgpack_pack_false, [:pointer], :int
83
+
84
+ #attach_function :msgpack_pack_array, [:pointer, :uint], :int
85
+
86
+ #attach_function :msgpack_pack_map, [:pointer, :uint], :int
87
+
88
+ #attach_function :msgpack_pack_raw, [:pointer, :size_t], :int
89
+
90
+ #attach_function :msgpack_pack_raw_body, [:pointer, :pointer, :size_t], :int
91
+
92
+ attach_function :msgpack_pack_object, [:pointer, MsgObject.by_value], :int
93
+
94
+ #
95
+ # Packs a Ruby object.
96
+ #
97
+ # @param [Hash, Array, String, Symbol, Integer, Float, true, false, nil] obj
98
+ # The Ruby object to pack.
99
+ #
100
+ # @return [String]
101
+ # The packed Ruby object.
102
+ #
103
+ def MsgPack.pack(obj)
104
+ packer = Packer.create
105
+ packer << obj
106
+
107
+ return packer.to_s
108
+ end
109
+
110
+ #
111
+ # Unpacks a packed object.
112
+ #
113
+ # @param [String] packed
114
+ # The packed object.
115
+ #
116
+ # @return [Hash, Array, String, Symbol, Integer, Float, true, false, nil]
117
+ # The first unpacked Ruby object.
118
+ #
119
+ def MsgPack.unpack(packed)
120
+ unpacker = Unpacker.create(packed.length)
121
+ unpacker << packed
122
+
123
+ return unpacker.first
124
+ end
125
+
126
+ end
127
+ end