ffi-msgpack 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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