msgpack 1.4.2 → 1.4.3

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.
@@ -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