ed-precompiled_msgpack 1.8.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 +7 -0
- data/ChangeLog +368 -0
- data/LICENSE +177 -0
- data/README.md +302 -0
- data/ext/java/org/msgpack/jruby/Buffer.java +233 -0
- data/ext/java/org/msgpack/jruby/Decoder.java +307 -0
- data/ext/java/org/msgpack/jruby/Encoder.java +456 -0
- data/ext/java/org/msgpack/jruby/ExtensionRegistry.java +167 -0
- data/ext/java/org/msgpack/jruby/ExtensionValue.java +128 -0
- data/ext/java/org/msgpack/jruby/Factory.java +130 -0
- data/ext/java/org/msgpack/jruby/MessagePackLibrary.java +45 -0
- data/ext/java/org/msgpack/jruby/Packer.java +266 -0
- data/ext/java/org/msgpack/jruby/Types.java +37 -0
- data/ext/java/org/msgpack/jruby/Unpacker.java +336 -0
- data/ext/msgpack/buffer.c +669 -0
- data/ext/msgpack/buffer.h +604 -0
- data/ext/msgpack/buffer_class.c +616 -0
- data/ext/msgpack/buffer_class.h +33 -0
- data/ext/msgpack/compat.h +26 -0
- data/ext/msgpack/extconf.rb +53 -0
- data/ext/msgpack/extension_value_class.c +34 -0
- data/ext/msgpack/extension_value_class.h +31 -0
- data/ext/msgpack/factory_class.c +276 -0
- data/ext/msgpack/factory_class.h +33 -0
- data/ext/msgpack/packer.c +199 -0
- data/ext/msgpack/packer.h +513 -0
- data/ext/msgpack/packer_class.c +442 -0
- data/ext/msgpack/packer_class.h +43 -0
- data/ext/msgpack/packer_ext_registry.c +74 -0
- data/ext/msgpack/packer_ext_registry.h +140 -0
- data/ext/msgpack/rbinit.c +35 -0
- data/ext/msgpack/rmem.c +93 -0
- data/ext/msgpack/rmem.h +109 -0
- data/ext/msgpack/sysdep.h +118 -0
- data/ext/msgpack/sysdep_endian.h +50 -0
- data/ext/msgpack/sysdep_types.h +46 -0
- data/ext/msgpack/unpacker.c +986 -0
- data/ext/msgpack/unpacker.h +152 -0
- data/ext/msgpack/unpacker_class.c +447 -0
- data/ext/msgpack/unpacker_class.h +43 -0
- data/ext/msgpack/unpacker_ext_registry.c +74 -0
- data/ext/msgpack/unpacker_ext_registry.h +62 -0
- data/lib/msgpack/bigint.rb +69 -0
- data/lib/msgpack/buffer.rb +9 -0
- data/lib/msgpack/core_ext.rb +139 -0
- data/lib/msgpack/factory.rb +211 -0
- data/lib/msgpack/packer.rb +37 -0
- data/lib/msgpack/symbol.rb +26 -0
- data/lib/msgpack/time.rb +29 -0
- data/lib/msgpack/timestamp.rb +76 -0
- data/lib/msgpack/unpacker.rb +41 -0
- data/lib/msgpack/version.rb +6 -0
- data/lib/msgpack.rb +53 -0
- data/msgpack.gemspec +41 -0
- metadata +216 -0
@@ -0,0 +1,62 @@
|
|
1
|
+
/*
|
2
|
+
* MessagePack for Ruby
|
3
|
+
*
|
4
|
+
* Copyright (C) 2008-2015 Sadayuki Furuhashi
|
5
|
+
*
|
6
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
7
|
+
* you may not use this file except in compliance with the License.
|
8
|
+
* You may obtain a copy of the License at
|
9
|
+
*
|
10
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
*
|
12
|
+
* Unless required by applicable law or agreed to in writing, software
|
13
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
14
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
15
|
+
* See the License for the specific language governing permissions and
|
16
|
+
* limitations under the License.
|
17
|
+
*/
|
18
|
+
#ifndef MSGPACK_RUBY_UNPACKER_EXT_REGISTRY_H__
|
19
|
+
#define MSGPACK_RUBY_UNPACKER_EXT_REGISTRY_H__
|
20
|
+
|
21
|
+
#include "compat.h"
|
22
|
+
#include "ruby.h"
|
23
|
+
|
24
|
+
#define MSGPACK_EXT_RECURSIVE 0b0001
|
25
|
+
|
26
|
+
struct msgpack_unpacker_ext_registry_t;
|
27
|
+
typedef struct msgpack_unpacker_ext_registry_t msgpack_unpacker_ext_registry_t;
|
28
|
+
|
29
|
+
struct msgpack_unpacker_ext_registry_t {
|
30
|
+
unsigned int borrow_count;
|
31
|
+
VALUE array[256];
|
32
|
+
};
|
33
|
+
|
34
|
+
void msgpack_unpacker_ext_registry_release(msgpack_unpacker_ext_registry_t* ukrg);
|
35
|
+
|
36
|
+
static inline void msgpack_unpacker_ext_registry_borrow(msgpack_unpacker_ext_registry_t* src, msgpack_unpacker_ext_registry_t** dst)
|
37
|
+
{
|
38
|
+
if (src) {
|
39
|
+
src->borrow_count++;
|
40
|
+
*dst = src;
|
41
|
+
}
|
42
|
+
}
|
43
|
+
|
44
|
+
void msgpack_unpacker_ext_registry_mark(msgpack_unpacker_ext_registry_t* ukrg);
|
45
|
+
|
46
|
+
void msgpack_unpacker_ext_registry_put(VALUE owner, msgpack_unpacker_ext_registry_t** ukrg,
|
47
|
+
VALUE ext_module, int ext_type, int flags, VALUE proc);
|
48
|
+
|
49
|
+
static inline VALUE msgpack_unpacker_ext_registry_lookup(msgpack_unpacker_ext_registry_t* ukrg,
|
50
|
+
int ext_type, int* ext_flags_result)
|
51
|
+
{
|
52
|
+
if (ukrg) {
|
53
|
+
VALUE entry = ukrg->array[ext_type + 128];
|
54
|
+
if (entry != Qnil) {
|
55
|
+
*ext_flags_result = FIX2INT(rb_ary_entry(entry, 2));
|
56
|
+
return rb_ary_entry(entry, 1);
|
57
|
+
}
|
58
|
+
}
|
59
|
+
return Qnil;
|
60
|
+
}
|
61
|
+
|
62
|
+
#endif
|
@@ -0,0 +1,69 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module MessagePack
|
4
|
+
module Bigint
|
5
|
+
# We split the bigint in 32bits chunks so that individual part fits into
|
6
|
+
# a MRI immediate Integer.
|
7
|
+
CHUNK_BITLENGTH = 32
|
8
|
+
FORMAT = 'CL>*'
|
9
|
+
|
10
|
+
if Integer.instance_method(:[]).arity != 1 # Ruby 2.7 and newer
|
11
|
+
# Starting from Ruby 2.7 we can address arbitrary bitranges inside an Integer with Integer#[]
|
12
|
+
# This allows to not allocate any Integer.
|
13
|
+
def self.to_msgpack_ext(bigint)
|
14
|
+
members = []
|
15
|
+
|
16
|
+
if bigint < 0
|
17
|
+
bigint = -bigint
|
18
|
+
members << 1
|
19
|
+
else
|
20
|
+
members << 0
|
21
|
+
end
|
22
|
+
|
23
|
+
offset = 0
|
24
|
+
length = bigint.bit_length
|
25
|
+
while offset < length
|
26
|
+
members << bigint[offset, CHUNK_BITLENGTH]
|
27
|
+
offset += CHUNK_BITLENGTH
|
28
|
+
end
|
29
|
+
|
30
|
+
members.pack(FORMAT)
|
31
|
+
end
|
32
|
+
else
|
33
|
+
# On 2.6 and older since we can't address arbitrary bitranges, so we fallback to shifting the bigint.
|
34
|
+
# This means that after each shift, we may allocate another Integer instance.
|
35
|
+
BASE = (2**CHUNK_BITLENGTH) - 1
|
36
|
+
def self.to_msgpack_ext(bigint)
|
37
|
+
members = []
|
38
|
+
|
39
|
+
if bigint < 0
|
40
|
+
bigint = -bigint
|
41
|
+
members << 1
|
42
|
+
else
|
43
|
+
members << 0
|
44
|
+
end
|
45
|
+
|
46
|
+
while bigint > 0
|
47
|
+
members << (bigint & BASE)
|
48
|
+
bigint = bigint >> CHUNK_BITLENGTH
|
49
|
+
end
|
50
|
+
|
51
|
+
members.pack(FORMAT)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def self.from_msgpack_ext(data)
|
56
|
+
parts = data.unpack(FORMAT)
|
57
|
+
|
58
|
+
sign = parts.shift
|
59
|
+
sum = parts.pop.to_i
|
60
|
+
|
61
|
+
parts.reverse_each do |part|
|
62
|
+
sum = sum << CHUNK_BITLENGTH
|
63
|
+
sum += part
|
64
|
+
end
|
65
|
+
|
66
|
+
sign == 0 ? sum : -sum
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,139 @@
|
|
1
|
+
module MessagePack
|
2
|
+
module CoreExt
|
3
|
+
def to_msgpack(packer_or_io = nil)
|
4
|
+
if packer_or_io
|
5
|
+
if packer_or_io.is_a?(MessagePack::Packer)
|
6
|
+
to_msgpack_with_packer packer_or_io
|
7
|
+
else
|
8
|
+
MessagePack.pack(self, packer_or_io)
|
9
|
+
end
|
10
|
+
else
|
11
|
+
MessagePack.pack(self)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
class NilClass
|
18
|
+
include MessagePack::CoreExt
|
19
|
+
|
20
|
+
private
|
21
|
+
def to_msgpack_with_packer(packer)
|
22
|
+
packer.write_nil
|
23
|
+
packer
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
class TrueClass
|
28
|
+
include MessagePack::CoreExt
|
29
|
+
|
30
|
+
private
|
31
|
+
def to_msgpack_with_packer(packer)
|
32
|
+
packer.write_true
|
33
|
+
packer
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
class FalseClass
|
38
|
+
include MessagePack::CoreExt
|
39
|
+
|
40
|
+
private
|
41
|
+
def to_msgpack_with_packer(packer)
|
42
|
+
packer.write_false
|
43
|
+
packer
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
class Float
|
48
|
+
include MessagePack::CoreExt
|
49
|
+
|
50
|
+
private
|
51
|
+
def to_msgpack_with_packer(packer)
|
52
|
+
packer.write_float self
|
53
|
+
packer
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
class String
|
58
|
+
include MessagePack::CoreExt
|
59
|
+
|
60
|
+
private
|
61
|
+
def to_msgpack_with_packer(packer)
|
62
|
+
packer.write_string self
|
63
|
+
packer
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
class Array
|
68
|
+
include MessagePack::CoreExt
|
69
|
+
|
70
|
+
private
|
71
|
+
def to_msgpack_with_packer(packer)
|
72
|
+
packer.write_array self
|
73
|
+
packer
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
class Hash
|
78
|
+
include MessagePack::CoreExt
|
79
|
+
|
80
|
+
private
|
81
|
+
def to_msgpack_with_packer(packer)
|
82
|
+
packer.write_hash self
|
83
|
+
packer
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
class Symbol
|
88
|
+
include MessagePack::CoreExt
|
89
|
+
|
90
|
+
private
|
91
|
+
def to_msgpack_with_packer(packer)
|
92
|
+
packer.write_symbol self
|
93
|
+
packer
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
if 1.class.name == "Integer"
|
98
|
+
class Integer
|
99
|
+
include MessagePack::CoreExt
|
100
|
+
|
101
|
+
private
|
102
|
+
def to_msgpack_with_packer(packer)
|
103
|
+
packer.write_int self
|
104
|
+
packer
|
105
|
+
end
|
106
|
+
end
|
107
|
+
else
|
108
|
+
class Fixnum
|
109
|
+
include MessagePack::CoreExt
|
110
|
+
|
111
|
+
private
|
112
|
+
def to_msgpack_with_packer(packer)
|
113
|
+
packer.write_int self
|
114
|
+
packer
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
class Bignum
|
119
|
+
include MessagePack::CoreExt
|
120
|
+
|
121
|
+
private
|
122
|
+
def to_msgpack_with_packer(packer)
|
123
|
+
packer.write_int self
|
124
|
+
packer
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
module MessagePack
|
130
|
+
class ExtensionValue
|
131
|
+
include CoreExt
|
132
|
+
|
133
|
+
private
|
134
|
+
def to_msgpack_with_packer(packer)
|
135
|
+
packer.write_extension self
|
136
|
+
packer
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
@@ -0,0 +1,211 @@
|
|
1
|
+
module MessagePack
|
2
|
+
class Factory
|
3
|
+
# see ext for other methods
|
4
|
+
|
5
|
+
def register_type(type, klass, options = { packer: :to_msgpack_ext, unpacker: :from_msgpack_ext })
|
6
|
+
raise FrozenError, "can't modify frozen MessagePack::Factory" if frozen?
|
7
|
+
|
8
|
+
if options
|
9
|
+
options = options.dup
|
10
|
+
case packer = options[:packer]
|
11
|
+
when nil, Proc
|
12
|
+
# all good
|
13
|
+
when String, Symbol
|
14
|
+
options[:packer] = packer.to_sym.to_proc
|
15
|
+
when Method
|
16
|
+
options[:packer] = packer.to_proc
|
17
|
+
when packer.respond_to?(:call)
|
18
|
+
options[:packer] = packer.method(:call).to_proc
|
19
|
+
else
|
20
|
+
raise ::TypeError, "expected :packer argument to be a callable object, got: #{packer.inspect}"
|
21
|
+
end
|
22
|
+
|
23
|
+
case unpacker = options[:unpacker]
|
24
|
+
when nil, Proc
|
25
|
+
# all good
|
26
|
+
when String, Symbol
|
27
|
+
options[:unpacker] = klass.method(unpacker).to_proc
|
28
|
+
when Method
|
29
|
+
options[:unpacker] = unpacker.to_proc
|
30
|
+
when packer.respond_to?(:call)
|
31
|
+
options[:unpacker] = unpacker.method(:call).to_proc
|
32
|
+
else
|
33
|
+
raise ::TypeError, "expected :unpacker argument to be a callable object, got: #{unpacker.inspect}"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
register_type_internal(type, klass, options)
|
38
|
+
end
|
39
|
+
|
40
|
+
# [ {type: id, class: Class(or nil), packer: arg, unpacker: arg}, ... ]
|
41
|
+
def registered_types(selector=:both)
|
42
|
+
packer, unpacker = registered_types_internal
|
43
|
+
# packer: Class -> [tid, proc, _flags]
|
44
|
+
# unpacker: tid -> [klass, proc, _flags]
|
45
|
+
|
46
|
+
list = []
|
47
|
+
|
48
|
+
case selector
|
49
|
+
when :both
|
50
|
+
packer.each_pair do |klass, ary|
|
51
|
+
type = ary[0]
|
52
|
+
packer_proc = ary[1]
|
53
|
+
unpacker_proc = nil
|
54
|
+
if unpacker.has_key?(type)
|
55
|
+
unpacker_proc = unpacker.delete(type)[1]
|
56
|
+
end
|
57
|
+
list << {type: type, class: klass, packer: packer_proc, unpacker: unpacker_proc}
|
58
|
+
end
|
59
|
+
|
60
|
+
# unpacker definition only
|
61
|
+
unpacker.each_pair do |type, ary|
|
62
|
+
list << {type: type, class: ary[0], packer: nil, unpacker: ary[1]}
|
63
|
+
end
|
64
|
+
|
65
|
+
when :packer
|
66
|
+
packer.each_pair do |klass, ary|
|
67
|
+
if ary[1]
|
68
|
+
list << {type: ary[0], class: klass, packer: ary[1]}
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
when :unpacker
|
73
|
+
unpacker.each_pair do |type, ary|
|
74
|
+
if ary[1]
|
75
|
+
list << {type: type, class: ary[0], unpacker: ary[1]}
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
else
|
80
|
+
raise ArgumentError, "invalid selector #{selector}"
|
81
|
+
end
|
82
|
+
|
83
|
+
list.sort{|a, b| a[:type] <=> b[:type] }
|
84
|
+
end
|
85
|
+
|
86
|
+
def type_registered?(klass_or_type, selector=:both)
|
87
|
+
case klass_or_type
|
88
|
+
when Class
|
89
|
+
klass = klass_or_type
|
90
|
+
registered_types(selector).any?{|entry| klass <= entry[:class] }
|
91
|
+
when Integer
|
92
|
+
type = klass_or_type
|
93
|
+
registered_types(selector).any?{|entry| type == entry[:type] }
|
94
|
+
else
|
95
|
+
raise ArgumentError, "class or type id"
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def load(src, param = nil)
|
100
|
+
unpacker = nil
|
101
|
+
|
102
|
+
if src.is_a? String
|
103
|
+
unpacker = unpacker(param)
|
104
|
+
unpacker.feed(src)
|
105
|
+
else
|
106
|
+
unpacker = unpacker(src, param)
|
107
|
+
end
|
108
|
+
|
109
|
+
unpacker.full_unpack
|
110
|
+
end
|
111
|
+
alias :unpack :load
|
112
|
+
|
113
|
+
def dump(v, *rest)
|
114
|
+
packer = packer(*rest)
|
115
|
+
packer.write(v)
|
116
|
+
packer.full_pack
|
117
|
+
end
|
118
|
+
alias :pack :dump
|
119
|
+
|
120
|
+
def pool(size = 1, **options)
|
121
|
+
Pool.new(
|
122
|
+
frozen? ? self : dup.freeze,
|
123
|
+
size,
|
124
|
+
options.empty? ? nil : options,
|
125
|
+
)
|
126
|
+
end
|
127
|
+
|
128
|
+
class Pool
|
129
|
+
if RUBY_ENGINE == "ruby"
|
130
|
+
class MemberPool
|
131
|
+
def initialize(size, &block)
|
132
|
+
@size = size
|
133
|
+
@new_member = block
|
134
|
+
@members = []
|
135
|
+
end
|
136
|
+
|
137
|
+
def with
|
138
|
+
member = @members.pop || @new_member.call
|
139
|
+
begin
|
140
|
+
yield member
|
141
|
+
ensure
|
142
|
+
# If the pool is already full, we simply drop the extra member.
|
143
|
+
# This is because contrary to a connection pool, creating an extra instance
|
144
|
+
# is extremely unlikely to cause some kind of resource exhaustion.
|
145
|
+
#
|
146
|
+
# We could cycle the members (keep the newer one) but first It's more work and second
|
147
|
+
# the older member might have been created pre-fork, so it might be at least partially
|
148
|
+
# in shared memory.
|
149
|
+
if member && @members.size < @size
|
150
|
+
member.reset
|
151
|
+
@members << member
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
156
|
+
else
|
157
|
+
class MemberPool
|
158
|
+
def initialize(size, &block)
|
159
|
+
@size = size
|
160
|
+
@new_member = block
|
161
|
+
@members = []
|
162
|
+
@mutex = Mutex.new
|
163
|
+
end
|
164
|
+
|
165
|
+
def with
|
166
|
+
member = @mutex.synchronize { @members.pop } || @new_member.call
|
167
|
+
begin
|
168
|
+
yield member
|
169
|
+
ensure
|
170
|
+
member.reset
|
171
|
+
@mutex.synchronize do
|
172
|
+
if member && @members.size < @size
|
173
|
+
@members << member
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
def initialize(factory, size, options = nil)
|
182
|
+
options = nil if !options || options.empty?
|
183
|
+
@factory = factory
|
184
|
+
@packers = MemberPool.new(size) { factory.packer(options).freeze }
|
185
|
+
@unpackers = MemberPool.new(size) { factory.unpacker(options).freeze }
|
186
|
+
end
|
187
|
+
|
188
|
+
def load(data)
|
189
|
+
@unpackers.with do |unpacker|
|
190
|
+
unpacker.feed(data)
|
191
|
+
unpacker.full_unpack
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
def dump(object)
|
196
|
+
@packers.with do |packer|
|
197
|
+
packer.write(object)
|
198
|
+
packer.full_pack
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
def unpacker(&block)
|
203
|
+
@unpackers.with(&block)
|
204
|
+
end
|
205
|
+
|
206
|
+
def packer(&block)
|
207
|
+
@packers.with(&block)
|
208
|
+
end
|
209
|
+
end
|
210
|
+
end
|
211
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module MessagePack
|
2
|
+
class Packer
|
3
|
+
# see ext for other methods
|
4
|
+
|
5
|
+
# The semantic of duping a packer is just too weird.
|
6
|
+
undef_method :dup
|
7
|
+
undef_method :clone
|
8
|
+
|
9
|
+
def register_type(type, klass, method_name = nil, &block)
|
10
|
+
raise ArgumentError, "expected Module/Class got: #{klass.inspect}" unless klass.is_a?(Module)
|
11
|
+
register_type_internal(type, klass, block || method_name.to_proc)
|
12
|
+
end
|
13
|
+
|
14
|
+
def registered_types
|
15
|
+
list = []
|
16
|
+
|
17
|
+
registered_types_internal.each_pair do |klass, ary|
|
18
|
+
list << {type: ary[0], class: klass, packer: ary[1]}
|
19
|
+
end
|
20
|
+
|
21
|
+
list.sort{|a, b| a[:type] <=> b[:type] }
|
22
|
+
end
|
23
|
+
|
24
|
+
def type_registered?(klass_or_type)
|
25
|
+
case klass_or_type
|
26
|
+
when Class
|
27
|
+
klass = klass_or_type
|
28
|
+
registered_types.any?{|entry| klass <= entry[:class] }
|
29
|
+
when Integer
|
30
|
+
type = klass_or_type
|
31
|
+
registered_types.any?{|entry| type == entry[:type] }
|
32
|
+
else
|
33
|
+
raise ArgumentError, "class or type id"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
class Symbol
|
2
|
+
# to_msgpack_ext is supposed to return a binary string.
|
3
|
+
# The canonical way to do it for symbols would be:
|
4
|
+
# [to_s].pack('A*')
|
5
|
+
# However in this instance we can take a shortcut
|
6
|
+
if method_defined?(:name)
|
7
|
+
alias_method :to_msgpack_ext, :name
|
8
|
+
else
|
9
|
+
alias_method :to_msgpack_ext, :to_s
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.from_msgpack_ext(data)
|
13
|
+
# from_msgpack_ext is supposed to parse a binary string.
|
14
|
+
# The canonical way to do it for symbols would be:
|
15
|
+
# data.unpack1('A*').to_sym
|
16
|
+
# However in this instance we can take a shortcut
|
17
|
+
|
18
|
+
# We assume the string encoding is UTF-8, and let Ruby create either
|
19
|
+
# an ASCII symbol or UTF-8 symbol.
|
20
|
+
data.force_encoding(Encoding::UTF_8).to_sym
|
21
|
+
rescue EncodingError
|
22
|
+
# If somehow the string wasn't valid UTF-8 not valid ASCII, we fallback
|
23
|
+
# to what has been the historical behavior of creating a binary symbol
|
24
|
+
data.force_encoding(Encoding::BINARY).to_sym
|
25
|
+
end
|
26
|
+
end
|
data/lib/msgpack/time.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# MessagePack extention packer and unpacker for built-in Time class
|
4
|
+
module MessagePack
|
5
|
+
module Time
|
6
|
+
# 3-arg Time.at is available Ruby >= 2.5
|
7
|
+
TIME_AT_3_AVAILABLE = begin
|
8
|
+
!!::Time.at(0, 0, :nanosecond)
|
9
|
+
rescue ArgumentError
|
10
|
+
false
|
11
|
+
end
|
12
|
+
|
13
|
+
Unpacker = if TIME_AT_3_AVAILABLE
|
14
|
+
lambda do |payload|
|
15
|
+
tv = MessagePack::Timestamp.from_msgpack_ext(payload)
|
16
|
+
::Time.at(tv.sec, tv.nsec, :nanosecond)
|
17
|
+
end
|
18
|
+
else
|
19
|
+
lambda do |payload|
|
20
|
+
tv = MessagePack::Timestamp.from_msgpack_ext(payload)
|
21
|
+
::Time.at(tv.sec, tv.nsec / 1000.0r)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
Packer = lambda { |time|
|
26
|
+
MessagePack::Timestamp.to_msgpack_ext(time.tv_sec, time.tv_nsec)
|
27
|
+
}
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module MessagePack
|
4
|
+
class Timestamp # a.k.a. "TimeSpec"
|
5
|
+
# Because the byte-order of MessagePack is big-endian in,
|
6
|
+
# pack() and unpack() specifies ">".
|
7
|
+
# See https://docs.ruby-lang.org/en/trunk/Array.html#method-i-pack for details.
|
8
|
+
|
9
|
+
# The timestamp extension type defined in the MessagePack spec.
|
10
|
+
# See https://github.com/msgpack/msgpack/blob/master/spec.md#timestamp-extension-type for details.
|
11
|
+
TYPE = -1
|
12
|
+
|
13
|
+
TIMESTAMP32_MAX_SEC = (1 << 32) - 1
|
14
|
+
TIMESTAMP64_MAX_SEC = (1 << 34) - 1
|
15
|
+
|
16
|
+
# @return [Integer]
|
17
|
+
attr_reader :sec
|
18
|
+
|
19
|
+
# @return [Integer]
|
20
|
+
attr_reader :nsec
|
21
|
+
|
22
|
+
# @param [Integer] sec
|
23
|
+
# @param [Integer] nsec
|
24
|
+
def initialize(sec, nsec)
|
25
|
+
@sec = sec
|
26
|
+
@nsec = nsec
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.from_msgpack_ext(data)
|
30
|
+
case data.length
|
31
|
+
when 4
|
32
|
+
# timestamp32 (sec: uint32be)
|
33
|
+
sec, = data.unpack('L>')
|
34
|
+
new(sec, 0)
|
35
|
+
when 8
|
36
|
+
# timestamp64 (nsec: uint30be, sec: uint34be)
|
37
|
+
n, s = data.unpack('L>2')
|
38
|
+
sec = ((n & 0b11) << 32) | s
|
39
|
+
nsec = n >> 2
|
40
|
+
new(sec, nsec)
|
41
|
+
when 12
|
42
|
+
# timestam96 (nsec: uint32be, sec: int64be)
|
43
|
+
nsec, sec = data.unpack('L>q>')
|
44
|
+
new(sec, nsec)
|
45
|
+
else
|
46
|
+
raise MalformedFormatError, "Invalid timestamp data size: #{data.length}"
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def self.to_msgpack_ext(sec, nsec)
|
51
|
+
if sec >= 0 && nsec >= 0 && sec <= TIMESTAMP64_MAX_SEC
|
52
|
+
if nsec === 0 && sec <= TIMESTAMP32_MAX_SEC
|
53
|
+
# timestamp32 = (sec: uint32be)
|
54
|
+
[sec].pack('L>')
|
55
|
+
else
|
56
|
+
# timestamp64 (nsec: uint30be, sec: uint34be)
|
57
|
+
nsec30 = nsec << 2
|
58
|
+
sec_high2 = sec >> 32 # high 2 bits (`x & 0b11` is redandunt)
|
59
|
+
sec_low32 = sec & 0xffffffff # low 32 bits
|
60
|
+
[nsec30 | sec_high2, sec_low32].pack('L>2')
|
61
|
+
end
|
62
|
+
else
|
63
|
+
# timestamp96 (nsec: uint32be, sec: int64be)
|
64
|
+
[nsec, sec].pack('L>q>')
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def to_msgpack_ext
|
69
|
+
self.class.to_msgpack_ext(sec, nsec)
|
70
|
+
end
|
71
|
+
|
72
|
+
def ==(other)
|
73
|
+
other.class == self.class && sec == other.sec && nsec == other.nsec
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module MessagePack
|
2
|
+
class Unpacker
|
3
|
+
# see ext for other methods
|
4
|
+
|
5
|
+
# The semantic of duping an unpacker is just too weird.
|
6
|
+
undef_method :dup
|
7
|
+
undef_method :clone
|
8
|
+
|
9
|
+
def register_type(type, klass = nil, method_name = nil, &block)
|
10
|
+
if klass && method_name
|
11
|
+
block = klass.method(method_name).to_proc
|
12
|
+
elsif !block_given?
|
13
|
+
raise ArgumentError, "register_type takes either 3 arguments or a block"
|
14
|
+
end
|
15
|
+
register_type_internal(type, klass, block)
|
16
|
+
end
|
17
|
+
|
18
|
+
def registered_types
|
19
|
+
list = []
|
20
|
+
|
21
|
+
registered_types_internal.each_pair do |type, ary|
|
22
|
+
list << {type: type, class: ary[0], unpacker: ary[1]}
|
23
|
+
end
|
24
|
+
|
25
|
+
list.sort{|a, b| a[:type] <=> b[:type] }
|
26
|
+
end
|
27
|
+
|
28
|
+
def type_registered?(klass_or_type)
|
29
|
+
case klass_or_type
|
30
|
+
when Class
|
31
|
+
klass = klass_or_type
|
32
|
+
registered_types.any?{|entry| klass == entry[:class] }
|
33
|
+
when Integer
|
34
|
+
type = klass_or_type
|
35
|
+
registered_types.any?{|entry| type == entry[:type] }
|
36
|
+
else
|
37
|
+
raise ArgumentError, "class or type id"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|