msgpack 1.4.2 → 1.4.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -27,6 +27,7 @@ import static org.jruby.runtime.Visibility.PRIVATE;
27
27
 
28
28
  @JRubyClass(name="MessagePack::Unpacker")
29
29
  public class Unpacker extends RubyObject {
30
+ private static final long serialVersionUID = 8451264671199362492L;
30
31
  private final ExtensionRegistry registry;
31
32
 
32
33
  private IRubyObject stream;
@@ -59,22 +60,23 @@ public class Unpacker extends RubyObject {
59
60
  allowUnknownExt = false;
60
61
  freeze = false;
61
62
  if (args.length > 0) {
63
+ Ruby runtime = ctx.runtime;
62
64
  if (args[args.length - 1] instanceof RubyHash) {
63
65
  RubyHash options = (RubyHash) args[args.length - 1];
64
- IRubyObject sk = options.fastARef(ctx.getRuntime().newSymbol("symbolize_keys"));
66
+ IRubyObject sk = options.fastARef(runtime.newSymbol("symbolize_keys"));
65
67
  if (sk != null) {
66
68
  symbolizeKeys = sk.isTrue();
67
69
  }
68
- IRubyObject f = options.fastARef(ctx.getRuntime().newSymbol("freeze"));
70
+ IRubyObject f = options.fastARef(runtime.newSymbol("freeze"));
69
71
  if (f != null) {
70
72
  freeze = f.isTrue();
71
73
  }
72
- IRubyObject au = options.fastARef(ctx.getRuntime().newSymbol("allow_unknown_ext"));
74
+ IRubyObject au = options.fastARef(runtime.newSymbol("allow_unknown_ext"));
73
75
  if (au != null) {
74
76
  allowUnknownExt = au.isTrue();
75
77
  }
76
78
  }
77
- if (args[0] != ctx.getRuntime().getNil() && !(args[0] instanceof RubyHash)) {
79
+ if (args[0] != runtime.getNil() && !(args[0] instanceof RubyHash)) {
78
80
  setStream(ctx, args[0]);
79
81
  }
80
82
  }
@@ -82,24 +84,24 @@ public class Unpacker extends RubyObject {
82
84
  }
83
85
 
84
86
  public static Unpacker newUnpacker(ThreadContext ctx, ExtensionRegistry extRegistry, IRubyObject[] args) {
85
- Unpacker unpacker = new Unpacker(ctx.getRuntime(), ctx.getRuntime().getModule("MessagePack").getClass("Unpacker"), extRegistry);
87
+ Unpacker unpacker = new Unpacker(ctx.runtime, ctx.runtime.getModule("MessagePack").getClass("Unpacker"), extRegistry);
86
88
  unpacker.initialize(ctx, args);
87
89
  return unpacker;
88
90
  }
89
91
 
90
92
  @JRubyMethod(name = "symbolize_keys?")
91
93
  public IRubyObject isSymbolizeKeys(ThreadContext ctx) {
92
- return symbolizeKeys ? ctx.getRuntime().getTrue() : ctx.getRuntime().getFalse();
94
+ return symbolizeKeys ? ctx.runtime.getTrue() : ctx.runtime.getFalse();
93
95
  }
94
96
 
95
97
  @JRubyMethod(name = "freeze?")
96
98
  public IRubyObject isFreeze(ThreadContext ctx) {
97
- return freeze ? ctx.getRuntime().getTrue() : ctx.getRuntime().getFalse();
99
+ return freeze ? ctx.runtime.getTrue() : ctx.runtime.getFalse();
98
100
  }
99
101
 
100
102
  @JRubyMethod(name = "allow_unknown_ext?")
101
103
  public IRubyObject isAllowUnknownExt(ThreadContext ctx) {
102
- return allowUnknownExt ? ctx.getRuntime().getTrue() : ctx.getRuntime().getFalse();
104
+ return allowUnknownExt ? ctx.runtime.getTrue() : ctx.runtime.getFalse();
103
105
  }
104
106
 
105
107
  @JRubyMethod(name = "registered_types_internal", visibility = PRIVATE)
@@ -109,7 +111,7 @@ public class Unpacker extends RubyObject {
109
111
 
110
112
  @JRubyMethod(name = "register_type", required = 1, optional = 2)
111
113
  public IRubyObject registerType(ThreadContext ctx, IRubyObject[] args, final Block block) {
112
- Ruby runtime = ctx.getRuntime();
114
+ Ruby runtime = ctx.runtime;
113
115
  IRubyObject type = args[0];
114
116
 
115
117
  RubyModule extModule;
@@ -155,7 +157,7 @@ public class Unpacker extends RubyObject {
155
157
  if (limit == -1) {
156
158
  limit = byteList.length() - offset;
157
159
  }
158
- Decoder decoder = new Decoder(ctx.getRuntime(), registry, byteList.unsafeBytes(), byteList.begin() + offset, limit, symbolizeKeys, freeze, allowUnknownExt);
160
+ Decoder decoder = new Decoder(ctx.runtime, registry, byteList.unsafeBytes(), byteList.begin() + offset, limit, symbolizeKeys, freeze, allowUnknownExt);
159
161
  try {
160
162
  data = null;
161
163
  data = decoder.next();
@@ -164,13 +166,13 @@ public class Unpacker extends RubyObject {
164
166
  throw re;
165
167
  }
166
168
  }
167
- return ctx.getRuntime().newFixnum(decoder.offset());
169
+ return ctx.runtime.newFixnum(decoder.offset());
168
170
  }
169
171
 
170
172
  @JRubyMethod(name = "data")
171
173
  public IRubyObject getData(ThreadContext ctx) {
172
174
  if (data == null) {
173
- return ctx.getRuntime().getNil();
175
+ return ctx.runtime.getNil();
174
176
  } else {
175
177
  return data;
176
178
  }
@@ -178,14 +180,14 @@ public class Unpacker extends RubyObject {
178
180
 
179
181
  @JRubyMethod(name = "finished?")
180
182
  public IRubyObject finished_p(ThreadContext ctx) {
181
- return data == null ? ctx.getRuntime().getFalse() : ctx.getRuntime().getTrue();
183
+ return data == null ? ctx.runtime.getFalse() : ctx.runtime.getTrue();
182
184
  }
183
185
 
184
186
  @JRubyMethod(required = 1, name = "feed", alias = { "feed_reference" })
185
187
  public IRubyObject feed(ThreadContext ctx, IRubyObject data) {
186
188
  ByteList byteList = data.asString().getByteList();
187
189
  if (decoder == null) {
188
- decoder = new Decoder(ctx.getRuntime(), registry, byteList.unsafeBytes(), byteList.begin(), byteList.length(), symbolizeKeys, freeze, allowUnknownExt);
190
+ decoder = new Decoder(ctx.runtime, registry, byteList.unsafeBytes(), byteList.begin(), byteList.length(), symbolizeKeys, freeze, allowUnknownExt);
189
191
  } else {
190
192
  decoder.feed(byteList.unsafeBytes(), byteList.begin(), byteList.length());
191
193
  }
@@ -202,7 +204,7 @@ public class Unpacker extends RubyObject {
202
204
  feed(ctx, data);
203
205
  if (block.isGiven()) {
204
206
  each(ctx, block);
205
- return ctx.getRuntime().getNil();
207
+ return ctx.runtime.getNil();
206
208
  } else {
207
209
  return callMethod(ctx, "to_enum");
208
210
  }
@@ -230,7 +232,7 @@ public class Unpacker extends RubyObject {
230
232
 
231
233
  @JRubyMethod
232
234
  public IRubyObject fill(ThreadContext ctx) {
233
- return ctx.getRuntime().getNil();
235
+ return ctx.runtime.getNil();
234
236
  }
235
237
 
236
238
  @JRubyMethod
@@ -238,13 +240,13 @@ public class Unpacker extends RubyObject {
238
240
  if (decoder != null) {
239
241
  decoder.reset();
240
242
  }
241
- return ctx.getRuntime().getNil();
243
+ return ctx.runtime.getNil();
242
244
  }
243
245
 
244
246
  @JRubyMethod(name = "read", alias = { "unpack" })
245
247
  public IRubyObject read(ThreadContext ctx) {
246
248
  if (decoder == null) {
247
- throw ctx.getRuntime().newEOFError();
249
+ throw ctx.runtime.newEOFError();
248
250
  }
249
251
  try {
250
252
  return decoder.next();
@@ -252,19 +254,19 @@ public class Unpacker extends RubyObject {
252
254
  if (re.getException().getType() != underflowErrorClass) {
253
255
  throw re;
254
256
  } else {
255
- throw ctx.getRuntime().newEOFError();
257
+ throw ctx.runtime.newEOFError();
256
258
  }
257
259
  }
258
260
  }
259
261
 
260
262
  @JRubyMethod(name = "skip")
261
263
  public IRubyObject skip(ThreadContext ctx) {
262
- throw ctx.getRuntime().newNotImplementedError("Not supported yet in JRuby implementation");
264
+ throw ctx.runtime.newNotImplementedError("Not supported yet in JRuby implementation");
263
265
  }
264
266
 
265
267
  @JRubyMethod(name = "skip_nil")
266
268
  public IRubyObject skipNil(ThreadContext ctx) {
267
- throw ctx.getRuntime().newNotImplementedError("Not supported yet in JRuby implementation");
269
+ throw ctx.runtime.newNotImplementedError("Not supported yet in JRuby implementation");
268
270
  }
269
271
 
270
272
  @JRubyMethod
@@ -276,11 +278,11 @@ public class Unpacker extends RubyObject {
276
278
  if (re.getException().getType() != underflowErrorClass) {
277
279
  throw re;
278
280
  } else {
279
- throw ctx.getRuntime().newEOFError();
281
+ throw ctx.runtime.newEOFError();
280
282
  }
281
283
  }
282
284
  }
283
- return ctx.getRuntime().getNil();
285
+ return ctx.runtime.getNil();
284
286
  }
285
287
 
286
288
  @JRubyMethod
@@ -292,17 +294,17 @@ public class Unpacker extends RubyObject {
292
294
  if (re.getException().getType() != underflowErrorClass) {
293
295
  throw re;
294
296
  } else {
295
- throw ctx.getRuntime().newEOFError();
297
+ throw ctx.runtime.newEOFError();
296
298
  }
297
299
  }
298
300
  }
299
- return ctx.getRuntime().getNil();
301
+ return ctx.runtime.getNil();
300
302
  }
301
303
 
302
304
  @JRubyMethod(name = "stream")
303
305
  public IRubyObject getStream(ThreadContext ctx) {
304
306
  if (stream == null) {
305
- return ctx.getRuntime().getNil();
307
+ return ctx.runtime.getNil();
306
308
  } else {
307
309
  return stream;
308
310
  }
@@ -318,12 +320,12 @@ public class Unpacker extends RubyObject {
318
320
  } else if (stream.respondsTo("read")) {
319
321
  str = stream.callMethod(ctx, "read").asString();
320
322
  } else {
321
- throw ctx.getRuntime().newTypeError(stream, "IO");
323
+ throw ctx.runtime.newTypeError(stream, "IO");
322
324
  }
323
325
  ByteList byteList = str.getByteList();
324
326
  this.stream = stream;
325
327
  this.decoder = null;
326
- this.decoder = new Decoder(ctx.getRuntime(), registry, byteList.unsafeBytes(), byteList.begin(), byteList.length(), symbolizeKeys, freeze, allowUnknownExt);
328
+ this.decoder = new Decoder(ctx.runtime, registry, byteList.unsafeBytes(), byteList.begin(), byteList.length(), symbolizeKeys, freeze, allowUnknownExt);
327
329
  return getStream(ctx);
328
330
  }
329
331
  }
data/ext/msgpack/buffer.c CHANGED
@@ -164,12 +164,7 @@ size_t msgpack_buffer_read_to_string_nonblock(msgpack_buffer_t* b, VALUE string,
164
164
  b->head->mapped_string != NO_MAPPED_STRING &&
165
165
  length >= b->read_reference_threshold) {
166
166
  VALUE s = _msgpack_buffer_refer_head_mapped_string(b, length);
167
- #ifndef HAVE_RB_STR_REPLACE
168
- /* TODO MRI 1.8 */
169
- rb_funcall(string, s_replace, 1, s);
170
- #else
171
167
  rb_str_replace(string, s);
172
- #endif
173
168
  /* here doesn't have to call ENCODING_SET because
174
169
  * encoding of s is always ASCII-8BIT */
175
170
  _msgpack_buffer_consumed(b, length);
data/ext/msgpack/buffer.h CHANGED
@@ -494,4 +494,9 @@ static inline VALUE msgpack_buffer_read_top_as_string(msgpack_buffer_t* b, size_
494
494
  #endif // HAVE_RB_ENC_INTERNED_STR
495
495
  }
496
496
 
497
+ static inline VALUE msgpack_buffer_read_top_as_symbol(msgpack_buffer_t* b, size_t length)
498
+ {
499
+ return rb_str_intern(msgpack_buffer_read_top_as_string(b, length, true, false));
500
+ }
501
+
497
502
  #endif
@@ -2,14 +2,7 @@ require 'mkmf'
2
2
 
3
3
  have_header("ruby/st.h")
4
4
  have_header("st.h")
5
- have_func("rb_str_replace", ["ruby.h"])
6
- have_func("rb_intern_str", ["ruby.h"])
7
5
  have_func("rb_enc_interned_str", "ruby.h")
8
- have_func("rb_sym2str", ["ruby.h"])
9
- have_func("rb_str_intern", ["ruby.h"])
10
- have_func("rb_block_lambda", ["ruby.h"])
11
- have_func("rb_hash_dup", ["ruby.h"])
12
- have_func("rb_hash_clear", ["ruby.h"])
13
6
 
14
7
  unless RUBY_PLATFORM.include? 'mswin'
15
8
  $CFLAGS << %[ -I.. -Wall -O3 -g -std=gnu99]
@@ -32,6 +32,8 @@ struct msgpack_factory_t {
32
32
  msgpack_packer_ext_registry_t pkrg;
33
33
  msgpack_unpacker_ext_registry_t ukrg;
34
34
  bool has_symbol_ext_type;
35
+ bool optimized_symbol_ext_type;
36
+ int symbol_ext_type;
35
37
  };
36
38
 
37
39
  #define FACTORY(from, name) \
@@ -114,6 +116,8 @@ VALUE MessagePack_Factory_unpacker(int argc, VALUE* argv, VALUE self)
114
116
 
115
117
  msgpack_unpacker_ext_registry_destroy(&uk->ext_registry);
116
118
  msgpack_unpacker_ext_registry_dup(&fc->ukrg, &uk->ext_registry);
119
+ uk->optimized_symbol_ext_type = fc->optimized_symbol_ext_type;
120
+ uk->symbol_ext_type = fc->symbol_ext_type;
117
121
 
118
122
  return unpacker;
119
123
  }
@@ -128,11 +132,7 @@ static VALUE Factory_registered_types_internal(VALUE self)
128
132
  rb_hash_aset(uk_mapping, INT2FIX(i - 128), fc->ukrg.array[i]);
129
133
  }
130
134
  }
131
- #ifdef HAVE_RB_HASH_DUP
132
135
  return rb_ary_new3(2, rb_hash_dup(fc->pkrg.hash), uk_mapping);
133
- #else
134
- return rb_ary_new3(2, rb_funcall(fc->pkrg.hash, rb_intern("dup"), 0), uk_mapping);
135
- #endif
136
136
  }
137
137
 
138
138
  static VALUE Factory_register_type(int argc, VALUE* argv, VALUE self)
@@ -141,7 +141,7 @@ static VALUE Factory_register_type(int argc, VALUE* argv, VALUE self)
141
141
 
142
142
  int ext_type;
143
143
  VALUE ext_module;
144
- VALUE options;
144
+ VALUE options = Qnil;
145
145
  VALUE packer_arg, unpacker_arg;
146
146
  VALUE packer_proc, unpacker_proc;
147
147
 
@@ -188,6 +188,8 @@ static VALUE Factory_register_type(int argc, VALUE* argv, VALUE self)
188
188
  if(unpacker_arg != Qnil) {
189
189
  if(rb_type(unpacker_arg) == T_SYMBOL || rb_type(unpacker_arg) == T_STRING) {
190
190
  unpacker_proc = rb_obj_method(ext_module, unpacker_arg);
191
+ } else if (rb_respond_to(unpacker_arg, rb_intern("call"))) {
192
+ unpacker_proc = unpacker_arg;
191
193
  } else {
192
194
  unpacker_proc = rb_funcall(unpacker_arg, rb_intern("method"), 1, ID2SYM(rb_intern("call")));
193
195
  }
@@ -197,6 +199,9 @@ static VALUE Factory_register_type(int argc, VALUE* argv, VALUE self)
197
199
 
198
200
  if (ext_module == rb_cSymbol) {
199
201
  fc->has_symbol_ext_type = true;
202
+ if(RB_TEST(options) && RB_TEST(rb_hash_aref(options, ID2SYM(rb_intern("optimized_symbols_parsing"))))) {
203
+ fc->optimized_symbol_ext_type = true;
204
+ }
200
205
  }
201
206
 
202
207
  msgpack_unpacker_ext_registry_put(&fc->ukrg, ext_module, ext_type, unpacker_proc, unpacker_arg);
data/ext/msgpack/packer.c CHANGED
@@ -121,7 +121,7 @@ void msgpack_packer_write_hash_value(msgpack_packer_t* pk, VALUE v)
121
121
  #endif
122
122
  }
123
123
 
124
- void msgpack_packer_write_other_value(msgpack_packer_t* pk, VALUE v)
124
+ bool msgpack_packer_try_write_with_ext_type_lookup(msgpack_packer_t* pk, VALUE v)
125
125
  {
126
126
  int ext_type;
127
127
 
@@ -131,7 +131,14 @@ void msgpack_packer_write_other_value(msgpack_packer_t* pk, VALUE v)
131
131
  VALUE payload = rb_funcall(proc, s_call, 1, v);
132
132
  StringValue(payload);
133
133
  msgpack_packer_write_ext(pk, ext_type, payload);
134
- } else {
134
+ return true;
135
+ }
136
+ return false;
137
+ }
138
+
139
+ void msgpack_packer_write_other_value(msgpack_packer_t* pk, VALUE v)
140
+ {
141
+ if(!(msgpack_packer_try_write_with_ext_type_lookup(pk, v))) {
135
142
  rb_funcall(v, pk->to_msgpack_method, 1, pk->to_msgpack_arg);
136
143
  }
137
144
  }
@@ -155,13 +162,19 @@ void msgpack_packer_write_value(msgpack_packer_t* pk, VALUE v)
155
162
  msgpack_packer_write_symbol_value(pk, v);
156
163
  break;
157
164
  case T_STRING:
158
- msgpack_packer_write_string_value(pk, v);
165
+ if(rb_class_of(v) == rb_cString || !msgpack_packer_try_write_with_ext_type_lookup(pk, v)) {
166
+ msgpack_packer_write_string_value(pk, v);
167
+ }
159
168
  break;
160
169
  case T_ARRAY:
161
- msgpack_packer_write_array_value(pk, v);
170
+ if(rb_class_of(v) == rb_cArray || !msgpack_packer_try_write_with_ext_type_lookup(pk, v)) {
171
+ msgpack_packer_write_array_value(pk, v);
172
+ }
162
173
  break;
163
174
  case T_HASH:
164
- msgpack_packer_write_hash_value(pk, v);
175
+ if(rb_class_of(v) == rb_cHash || !msgpack_packer_try_write_with_ext_type_lookup(pk, v)) {
176
+ msgpack_packer_write_hash_value(pk, v);
177
+ }
165
178
  break;
166
179
  case T_BIGNUM:
167
180
  msgpack_packer_write_bignum_value(pk, v);
data/ext/msgpack/packer.h CHANGED
@@ -444,16 +444,7 @@ static inline void msgpack_packer_write_string_value(msgpack_packer_t* pk, VALUE
444
444
 
445
445
  static inline void msgpack_packer_write_symbol_string_value(msgpack_packer_t* pk, VALUE v)
446
446
  {
447
- #ifdef HAVE_RB_SYM2STR
448
- /* rb_sym2str is added since MRI 2.2.0 */
449
447
  msgpack_packer_write_string_value(pk, rb_sym2str(v));
450
- #else
451
- VALUE str = rb_id2str(SYM2ID(v));
452
- if (!str) {
453
- rb_raise(rb_eRuntimeError, "could not convert a symbol to string");
454
- }
455
- msgpack_packer_write_string_value(pk, str);
456
- #endif
457
448
  }
458
449
 
459
450
  void msgpack_packer_write_other_value(msgpack_packer_t* pk, VALUE v);
@@ -339,11 +339,7 @@ static VALUE Packer_write_to(VALUE self, VALUE io)
339
339
  static VALUE Packer_registered_types_internal(VALUE self)
340
340
  {
341
341
  PACKER(self, pk);
342
- #ifdef HAVE_RB_HASH_DUP
343
342
  return rb_hash_dup(pk->ext_registry.hash);
344
- #else
345
- return rb_funcall(pk->ext_registry.hash, rb_intern("dup"), 0);
346
- #endif
347
343
  }
348
344
 
349
345
  static VALUE Packer_register_type(int argc, VALUE* argv, VALUE self)
@@ -359,12 +355,7 @@ static VALUE Packer_register_type(int argc, VALUE* argv, VALUE self)
359
355
  case 2:
360
356
  /* register_type(0x7f, Time) {|obj| block... } */
361
357
  rb_need_block();
362
- #ifdef HAVE_RB_BLOCK_LAMBDA
363
358
  proc = rb_block_lambda();
364
- #else
365
- /* MRI 1.8 */
366
- proc = rb_block_proc();
367
- #endif
368
359
  arg = proc;
369
360
  break;
370
361
  case 3:
@@ -43,37 +43,15 @@ void msgpack_packer_ext_registry_mark(msgpack_packer_ext_registry_t* pkrg)
43
43
  void msgpack_packer_ext_registry_dup(msgpack_packer_ext_registry_t* src,
44
44
  msgpack_packer_ext_registry_t* dst)
45
45
  {
46
- #ifdef HAVE_RB_HASH_DUP
47
46
  dst->hash = rb_hash_dup(src->hash);
48
47
  dst->cache = rb_hash_dup(src->cache);
49
- #else
50
- dst->hash = rb_funcall(src->hash, rb_intern("dup"), 0);
51
- dst->cache = rb_funcall(src->cache, rb_intern("dup"), 0);
52
- #endif
53
48
  }
54
49
 
55
- #ifndef HAVE_RB_HASH_CLEAR
56
-
57
- static int
58
- __rb_hash_clear_clear_i(key, value, dummy)
59
- VALUE key, value, dummy;
60
- {
61
- return ST_DELETE;
62
- }
63
-
64
- #endif
65
-
66
50
  VALUE msgpack_packer_ext_registry_put(msgpack_packer_ext_registry_t* pkrg,
67
51
  VALUE ext_module, int ext_type, VALUE proc, VALUE arg)
68
52
  {
69
53
  VALUE e = rb_ary_new3(3, INT2FIX(ext_type), proc, arg);
70
54
  /* clear lookup cache not to miss added type */
71
- #ifdef HAVE_RB_HASH_CLEAR
72
55
  rb_hash_clear(pkrg->cache);
73
- #else
74
- if(FIX2INT(rb_funcall(pkrg->cache, rb_intern("size"), 0)) > 0) {
75
- rb_hash_foreach(pkrg->cache, __rb_hash_clear_clear_i, 0);
76
- }
77
- #endif
78
56
  return rb_hash_aset(pkrg->hash, ext_module, e);
79
57
  }
@@ -151,8 +151,19 @@ static inline int object_complete(msgpack_unpacker_t* uk, VALUE object)
151
151
  return PRIMITIVE_OBJECT_COMPLETE;
152
152
  }
153
153
 
154
+ static inline int object_complete_symbol(msgpack_unpacker_t* uk, VALUE object)
155
+ {
156
+ uk->last_object = object;
157
+ reset_head_byte(uk);
158
+ return PRIMITIVE_OBJECT_COMPLETE;
159
+ }
160
+
154
161
  static inline int object_complete_ext(msgpack_unpacker_t* uk, int ext_type, VALUE str)
155
162
  {
163
+ if (uk->optimized_symbol_ext_type && ext_type == uk->symbol_ext_type) {
164
+ return object_complete_symbol(uk, rb_str_intern(str));
165
+ }
166
+
156
167
  VALUE proc = msgpack_unpacker_ext_registry_lookup(&uk->ext_registry, ext_type);
157
168
  if(proc != Qnil) {
158
169
  VALUE obj = rb_funcall(proc, s_call, 1, str);
@@ -273,22 +284,27 @@ static inline int read_raw_body_begin(msgpack_unpacker_t* uk, int raw_type)
273
284
  /* try optimized read */
274
285
  size_t length = uk->reading_raw_remaining;
275
286
  if(length <= msgpack_buffer_top_readable_size(UNPACKER_BUFFER_(uk))) {
276
- /* don't use zerocopy for hash keys but get a frozen string directly
277
- * because rb_hash_aset freezes keys and it causes copying */
278
- bool will_freeze = uk->freeze || is_reading_map_key(uk);
279
- VALUE string = msgpack_buffer_read_top_as_string(UNPACKER_BUFFER_(uk), length, will_freeze, raw_type == RAW_TYPE_STRING);
280
287
  int ret;
281
- if(raw_type == RAW_TYPE_STRING || raw_type == RAW_TYPE_BINARY) {
282
- ret = object_complete(uk, string);
288
+ if ((uk->optimized_symbol_ext_type && uk->symbol_ext_type == raw_type) || (uk->symbolize_keys && is_reading_map_key(uk))) {
289
+ VALUE symbol = msgpack_buffer_read_top_as_symbol(UNPACKER_BUFFER_(uk), length);
290
+ ret = object_complete_symbol(uk, symbol);
283
291
  } else {
284
- ret = object_complete_ext(uk, raw_type, string);
285
- }
292
+ /* don't use zerocopy for hash keys but get a frozen string directly
293
+ * because rb_hash_aset freezes keys and it causes copying */
294
+ bool will_freeze = uk->freeze || is_reading_map_key(uk);
295
+ VALUE string = msgpack_buffer_read_top_as_string(UNPACKER_BUFFER_(uk), length, will_freeze, raw_type == RAW_TYPE_STRING);
296
+ if(raw_type == RAW_TYPE_STRING || raw_type == RAW_TYPE_BINARY) {
297
+ ret = object_complete(uk, string);
298
+ } else {
299
+ ret = object_complete_ext(uk, raw_type, string);
300
+ }
286
301
 
287
302
  # if !HASH_ASET_DEDUPE
288
- if(will_freeze) {
289
- rb_obj_freeze(string);
290
- }
303
+ if(will_freeze) {
304
+ rb_obj_freeze(string);
305
+ }
291
306
  # endif
307
+ }
292
308
  uk->reading_raw_remaining = 0;
293
309
  return ret;
294
310
  }
@@ -705,18 +721,8 @@ int msgpack_unpacker_read(msgpack_unpacker_t* uk, size_t target_stack_depth)
705
721
  break;
706
722
  case STACK_TYPE_MAP_VALUE:
707
723
  if(uk->symbolize_keys && rb_type(top->key) == T_STRING) {
708
- /* here uses rb_intern_str instead of rb_intern so that Ruby VM can GC unused symbols */
709
- #ifdef HAVE_RB_STR_INTERN
710
- /* rb_str_intern is added since MRI 2.2.0 */
724
+ /* here uses rb_str_intern instead of rb_intern so that Ruby VM can GC unused symbols */
711
725
  rb_hash_aset(top->object, rb_str_intern(top->key), uk->last_object);
712
- #else
713
- #ifndef HAVE_RB_INTERN_STR
714
- /* MRI 1.8 doesn't have rb_intern_str or rb_intern2 */
715
- rb_hash_aset(top->object, ID2SYM(rb_intern(RSTRING_PTR(top->key))), uk->last_object);
716
- #else
717
- rb_hash_aset(top->object, ID2SYM(rb_intern_str(top->key)), uk->last_object);
718
- #endif
719
- #endif
720
726
  } else {
721
727
  rb_hash_aset(top->object, top->key, uk->last_object);
722
728
  }
@@ -66,6 +66,8 @@ struct msgpack_unpacker_t {
66
66
  bool symbolize_keys;
67
67
  bool freeze;
68
68
  bool allow_unknown_ext;
69
+ bool optimized_symbol_ext_type;
70
+ int symbol_ext_type;
69
71
  };
70
72
 
71
73
  #define UNPACKER_BUFFER_(uk) (&(uk)->buffer)
@@ -369,12 +369,7 @@ static VALUE Unpacker_register_type(int argc, VALUE* argv, VALUE self)
369
369
  case 1:
370
370
  /* register_type(0x7f) {|data| block... } */
371
371
  rb_need_block();
372
- #ifdef HAVE_RB_BLOCK_LAMBDA
373
372
  proc = rb_block_lambda();
374
- #else
375
- /* MRI 1.8 */
376
- proc = rb_block_proc();
377
- #endif
378
373
  arg = proc;
379
374
  ext_module = Qnil;
380
375
  break;
@@ -1,9 +1,19 @@
1
1
  class Symbol
2
- def to_msgpack_ext
3
- [to_s].pack('A*')
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
4
10
  end
5
11
 
6
12
  def self.from_msgpack_ext(data)
7
- data.unpack('A*').first.to_sym
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
+ data.to_sym
8
18
  end
9
- end
19
+ end
data/lib/msgpack/time.rb CHANGED
@@ -18,7 +18,7 @@ module MessagePack
18
18
  else
19
19
  lambda do |payload|
20
20
  tv = MessagePack::Timestamp.from_msgpack_ext(payload)
21
- ::Time.at(tv.sec, tv.nsec / 1000.0)
21
+ ::Time.at(tv.sec, tv.nsec / 1000.0r)
22
22
  end
23
23
  end
24
24
 
@@ -1,5 +1,5 @@
1
1
  module MessagePack
2
- VERSION = "1.4.2"
2
+ VERSION = "1.4.3"
3
3
  # Note for maintainers:
4
4
  # Don't miss building/releasing the JRuby version (rake buld:java)
5
5
  # See "How to build -java rubygems" in README for more details.
data/lib/msgpack.rb CHANGED
@@ -1,9 +1,8 @@
1
1
  require "msgpack/version"
2
2
 
3
3
  if defined?(RUBY_ENGINE) && RUBY_ENGINE == "jruby" # This is same with `/java/ =~ RUBY_VERSION`
4
- require "java"
5
4
  require "msgpack/msgpack.jar"
6
- org.msgpack.jruby.MessagePackLibrary.new.load(JRuby.runtime, false)
5
+ JRuby::Util.load_ext("org.msgpack.jruby.MessagePackLibrary")
7
6
  else
8
7
  require "msgpack/msgpack"
9
8
  end
data/spec/factory_spec.rb CHANGED
@@ -280,6 +280,23 @@ describe MessagePack::Factory do
280
280
  unpacker.feed(packed_symbol).unpack
281
281
  end
282
282
 
283
+ context 'using the optimized symbol unpacker' do
284
+ before do
285
+ skip if IS_JRUBY # JRuby implementation doesn't support the optimized symbols unpacker for now
286
+ subject.register_type(
287
+ 0x00,
288
+ ::Symbol,
289
+ packer: :to_msgpack_ext,
290
+ unpacker: :from_msgpack_ext,
291
+ optimized_symbols_parsing: true,
292
+ )
293
+ end
294
+
295
+ it 'lets symbols survive a roundtrip' do
296
+ expect(symbol_after_roundtrip).to be :symbol
297
+ end
298
+ end
299
+
283
300
  context 'if no ext type is registered for symbols' do
284
301
  it 'converts symbols to string' do
285
302
  expect(symbol_after_roundtrip).to eq 'symbol'
data/spec/msgpack_spec.rb CHANGED
@@ -115,7 +115,7 @@ describe MessagePack do
115
115
  expect { MessagePack.pack(self) }.to raise_error(NoMethodError, /^undefined method `to_msgpack'/)
116
116
  end
117
117
 
118
- it 'rasies an error on #unpack with garbage' do
118
+ it 'raises an error on #unpack with garbage' do
119
119
  skip "but nothing was raised. why?"
120
120
  expect { MessagePack.unpack('asdka;sd') }.to raise_error(MessagePack::UnpackError)
121
121
  end
data/spec/packer_spec.rb CHANGED
@@ -488,6 +488,24 @@ describe MessagePack::Packer do
488
488
  it { is_expected.to eq "\xC7\x0F\x01value_msgpacked" }
489
489
  end
490
490
 
491
+ shared_examples_for 'extension subclasses core type' do |klass|
492
+ before { stub_const('Value', Class.new(klass)) }
493
+ let(:object) { Value.new }
494
+ subject { packer.pack(object).to_s }
495
+
496
+ it "defaults to #{klass.name} packer if no extension is present" do
497
+ expect(subject).to eq(MessagePack.dump(klass.new))
498
+ end
499
+
500
+ it "uses core type extension for #{klass.name}" do
501
+ packer.register_type(0x01, Value, ->(_) { 'value_msgpacked' })
502
+ expect(subject).to eq("\xC7\x0F\x01value_msgpacked")
503
+ end
504
+ end
505
+ it_behaves_like 'extension subclasses core type', Hash
506
+ it_behaves_like 'extension subclasses core type', Array
507
+ it_behaves_like 'extension subclasses core type', String
508
+
491
509
  context 'when registering a type for symbols' do
492
510
  before { packer.register_type(0x00, ::Symbol, :to_msgpack_ext) }
493
511