msgpack 1.2.6 → 1.4.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yaml +56 -0
  3. data/.gitignore +3 -1
  4. data/.rubocop.yml +4 -1
  5. data/ChangeLog +59 -0
  6. data/Gemfile +3 -0
  7. data/README.md +242 -0
  8. data/Rakefile +3 -8
  9. data/doclib/msgpack/factory.rb +1 -0
  10. data/doclib/msgpack/packer.rb +20 -0
  11. data/doclib/msgpack/time.rb +22 -0
  12. data/doclib/msgpack/timestamp.rb +44 -0
  13. data/doclib/msgpack.rb +2 -2
  14. data/ext/java/org/msgpack/jruby/Buffer.java +21 -16
  15. data/ext/java/org/msgpack/jruby/Decoder.java +29 -10
  16. data/ext/java/org/msgpack/jruby/Encoder.java +38 -19
  17. data/ext/java/org/msgpack/jruby/ExtensionRegistry.java +9 -9
  18. data/ext/java/org/msgpack/jruby/ExtensionValue.java +5 -8
  19. data/ext/java/org/msgpack/jruby/Factory.java +8 -3
  20. data/ext/java/org/msgpack/jruby/Packer.java +31 -8
  21. data/ext/java/org/msgpack/jruby/Unpacker.java +40 -27
  22. data/ext/msgpack/buffer.c +4 -16
  23. data/ext/msgpack/buffer.h +60 -5
  24. data/ext/msgpack/compat.h +1 -12
  25. data/ext/msgpack/extconf.rb +39 -7
  26. data/ext/msgpack/factory_class.c +10 -5
  27. data/ext/msgpack/packer.c +18 -5
  28. data/ext/msgpack/packer.h +0 -16
  29. data/ext/msgpack/packer_class.c +21 -9
  30. data/ext/msgpack/packer_ext_registry.c +0 -22
  31. data/ext/msgpack/unpacker.c +41 -49
  32. data/ext/msgpack/unpacker.h +8 -0
  33. data/ext/msgpack/unpacker_class.c +23 -13
  34. data/lib/msgpack/symbol.rb +14 -4
  35. data/lib/msgpack/time.rb +29 -0
  36. data/lib/msgpack/timestamp.rb +76 -0
  37. data/lib/msgpack/version.rb +4 -7
  38. data/lib/msgpack.rb +8 -10
  39. data/msgpack.gemspec +3 -7
  40. data/spec/cruby/buffer_spec.rb +6 -1
  41. data/spec/factory_spec.rb +17 -0
  42. data/spec/msgpack_spec.rb +44 -1
  43. data/spec/packer_spec.rb +54 -0
  44. data/spec/spec_helper.rb +27 -0
  45. data/spec/timestamp_spec.rb +161 -0
  46. data/spec/unpacker_spec.rb +113 -1
  47. metadata +19 -51
  48. data/.travis.yml +0 -41
  49. data/README.rdoc +0 -201
@@ -165,6 +165,18 @@ static VALUE Packer_write_string(VALUE self, VALUE obj)
165
165
  return self;
166
166
  }
167
167
 
168
+ static VALUE Packer_write_bin(VALUE self, VALUE obj)
169
+ {
170
+ PACKER(self, pk);
171
+ Check_Type(obj, T_STRING);
172
+
173
+ VALUE enc = rb_enc_from_encoding(rb_ascii8bit_encoding());
174
+ obj = rb_str_encode(obj, enc, 0, Qnil);
175
+
176
+ msgpack_packer_write_string_value(pk, obj);
177
+ return self;
178
+ }
179
+
168
180
  static VALUE Packer_write_array(VALUE self, VALUE obj)
169
181
  {
170
182
  PACKER(self, pk);
@@ -232,6 +244,13 @@ static VALUE Packer_write_map_header(VALUE self, VALUE n)
232
244
  return self;
233
245
  }
234
246
 
247
+ static VALUE Packer_write_bin_header(VALUE self, VALUE n)
248
+ {
249
+ PACKER(self, pk);
250
+ msgpack_packer_write_bin_header(pk, NUM2UINT(n));
251
+ return self;
252
+ }
253
+
235
254
  static VALUE Packer_write_float32(VALUE self, VALUE numeric)
236
255
  {
237
256
  if(!rb_obj_is_kind_of(numeric, rb_cNumeric)) {
@@ -320,11 +339,7 @@ static VALUE Packer_write_to(VALUE self, VALUE io)
320
339
  static VALUE Packer_registered_types_internal(VALUE self)
321
340
  {
322
341
  PACKER(self, pk);
323
- #ifdef HAVE_RB_HASH_DUP
324
342
  return rb_hash_dup(pk->ext_registry.hash);
325
- #else
326
- return rb_funcall(pk->ext_registry.hash, rb_intern("dup"), 0);
327
- #endif
328
343
  }
329
344
 
330
345
  static VALUE Packer_register_type(int argc, VALUE* argv, VALUE self)
@@ -340,12 +355,7 @@ static VALUE Packer_register_type(int argc, VALUE* argv, VALUE self)
340
355
  case 2:
341
356
  /* register_type(0x7f, Time) {|obj| block... } */
342
357
  rb_need_block();
343
- #ifdef HAVE_RB_BLOCK_LAMBDA
344
358
  proc = rb_block_lambda();
345
- #else
346
- /* MRI 1.8 */
347
- proc = rb_block_proc();
348
- #endif
349
359
  arg = proc;
350
360
  break;
351
361
  case 3:
@@ -416,6 +426,7 @@ void MessagePack_Packer_module_init(VALUE mMessagePack)
416
426
  rb_define_method(cMessagePack_Packer, "write_false", Packer_write_false, 0);
417
427
  rb_define_method(cMessagePack_Packer, "write_float", Packer_write_float, 1);
418
428
  rb_define_method(cMessagePack_Packer, "write_string", Packer_write_string, 1);
429
+ rb_define_method(cMessagePack_Packer, "write_bin", Packer_write_bin, 1);
419
430
  rb_define_method(cMessagePack_Packer, "write_array", Packer_write_array, 1);
420
431
  rb_define_method(cMessagePack_Packer, "write_hash", Packer_write_hash, 1);
421
432
  rb_define_method(cMessagePack_Packer, "write_symbol", Packer_write_symbol, 1);
@@ -423,6 +434,7 @@ void MessagePack_Packer_module_init(VALUE mMessagePack)
423
434
  rb_define_method(cMessagePack_Packer, "write_extension", Packer_write_extension, 1);
424
435
  rb_define_method(cMessagePack_Packer, "write_array_header", Packer_write_array_header, 1);
425
436
  rb_define_method(cMessagePack_Packer, "write_map_header", Packer_write_map_header, 1);
437
+ rb_define_method(cMessagePack_Packer, "write_bin_header", Packer_write_bin_header, 1);
426
438
  rb_define_method(cMessagePack_Packer, "write_ext", Packer_write_ext, 2);
427
439
  rb_define_method(cMessagePack_Packer, "write_float32", Packer_write_float32, 1);
428
440
  rb_define_method(cMessagePack_Packer, "flush", Packer_flush, 0);
@@ -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
  }
@@ -142,32 +142,27 @@ static inline void reset_head_byte(msgpack_unpacker_t* uk)
142
142
 
143
143
  static inline int object_complete(msgpack_unpacker_t* uk, VALUE object)
144
144
  {
145
+ if(uk->freeze) {
146
+ rb_obj_freeze(object);
147
+ }
148
+
145
149
  uk->last_object = object;
146
150
  reset_head_byte(uk);
147
151
  return PRIMITIVE_OBJECT_COMPLETE;
148
152
  }
149
153
 
150
- static inline int object_complete_string(msgpack_unpacker_t* uk, VALUE str)
151
- {
152
- #ifdef COMPAT_HAVE_ENCODING
153
- ENCODING_SET(str, msgpack_rb_encindex_utf8);
154
- #endif
155
- return object_complete(uk, str);
156
- }
157
-
158
- static inline int object_complete_binary(msgpack_unpacker_t* uk, VALUE str)
154
+ static inline int object_complete_symbol(msgpack_unpacker_t* uk, VALUE object)
159
155
  {
160
- #ifdef COMPAT_HAVE_ENCODING
161
- ENCODING_SET(str, msgpack_rb_encindex_ascii8bit);
162
- #endif
163
- return object_complete(uk, str);
156
+ uk->last_object = object;
157
+ reset_head_byte(uk);
158
+ return PRIMITIVE_OBJECT_COMPLETE;
164
159
  }
165
160
 
166
161
  static inline int object_complete_ext(msgpack_unpacker_t* uk, int ext_type, VALUE str)
167
162
  {
168
- #ifdef COMPAT_HAVE_ENCODING
169
- ENCODING_SET(str, msgpack_rb_encindex_ascii8bit);
170
- #endif
163
+ if (uk->optimized_symbol_ext_type && ext_type == uk->symbol_ext_type) {
164
+ return object_complete_symbol(uk, rb_str_intern(str));
165
+ }
171
166
 
172
167
  VALUE proc = msgpack_unpacker_ext_registry_lookup(&uk->ext_registry, ext_type);
173
168
  if(proc != Qnil) {
@@ -271,9 +266,10 @@ static int read_raw_body_cont(msgpack_unpacker_t* uk)
271
266
 
272
267
  int ret;
273
268
  if(uk->reading_raw_type == RAW_TYPE_STRING) {
274
- ret = object_complete_string(uk, uk->reading_raw);
275
- } else if(uk->reading_raw_type == RAW_TYPE_BINARY) {
276
- ret = object_complete_binary(uk, uk->reading_raw);
269
+ ENCODING_SET(uk->reading_raw, msgpack_rb_encindex_utf8);
270
+ ret = object_complete(uk, uk->reading_raw);
271
+ } else if (uk->reading_raw_type == RAW_TYPE_BINARY) {
272
+ ret = object_complete(uk, uk->reading_raw);
277
273
  } else {
278
274
  ret = object_complete_ext(uk, uk->reading_raw_type, uk->reading_raw);
279
275
  }
@@ -288,20 +284,26 @@ static inline int read_raw_body_begin(msgpack_unpacker_t* uk, int raw_type)
288
284
  /* try optimized read */
289
285
  size_t length = uk->reading_raw_remaining;
290
286
  if(length <= msgpack_buffer_top_readable_size(UNPACKER_BUFFER_(uk))) {
291
- /* don't use zerocopy for hash keys but get a frozen string directly
292
- * because rb_hash_aset freezes keys and it causes copying */
293
- bool will_freeze = is_reading_map_key(uk);
294
- VALUE string = msgpack_buffer_read_top_as_string(UNPACKER_BUFFER_(uk), length, will_freeze);
295
287
  int ret;
296
- if(raw_type == RAW_TYPE_STRING) {
297
- ret = object_complete_string(uk, string);
298
- } else if(raw_type == RAW_TYPE_BINARY) {
299
- ret = object_complete_binary(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);
300
291
  } else {
301
- ret = object_complete_ext(uk, raw_type, string);
302
- }
303
- if(will_freeze) {
304
- rb_obj_freeze(string);
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
+ }
301
+
302
+ # if !HASH_ASET_DEDUPE
303
+ if(will_freeze) {
304
+ rb_obj_freeze(string);
305
+ }
306
+ # endif
305
307
  }
306
308
  uk->reading_raw_remaining = 0;
307
309
  return ret;
@@ -332,7 +334,7 @@ static int read_primitive(msgpack_unpacker_t* uk)
332
334
  SWITCH_RANGE(b, 0xa0, 0xbf) // FixRaw / fixstr
333
335
  int count = b & 0x1f;
334
336
  if(count == 0) {
335
- return object_complete_string(uk, rb_str_buf_new(0));
337
+ return object_complete(uk, rb_utf8_str_new_static("", 0));
336
338
  }
337
339
  /* read_raw_body_begin sets uk->reading_raw */
338
340
  uk->reading_raw_remaining = count;
@@ -517,7 +519,7 @@ static int read_primitive(msgpack_unpacker_t* uk)
517
519
  READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 1);
518
520
  uint8_t count = cb->u8;
519
521
  if(count == 0) {
520
- return object_complete_string(uk, rb_str_buf_new(0));
522
+ return object_complete(uk, rb_utf8_str_new_static("", 0));
521
523
  }
522
524
  /* read_raw_body_begin sets uk->reading_raw */
523
525
  uk->reading_raw_remaining = count;
@@ -529,7 +531,7 @@ static int read_primitive(msgpack_unpacker_t* uk)
529
531
  READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 2);
530
532
  uint16_t count = _msgpack_be16(cb->u16);
531
533
  if(count == 0) {
532
- return object_complete_string(uk, rb_str_buf_new(0));
534
+ return object_complete(uk, rb_utf8_str_new_static("", 0));
533
535
  }
534
536
  /* read_raw_body_begin sets uk->reading_raw */
535
537
  uk->reading_raw_remaining = count;
@@ -541,7 +543,7 @@ static int read_primitive(msgpack_unpacker_t* uk)
541
543
  READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 4);
542
544
  uint32_t count = _msgpack_be32(cb->u32);
543
545
  if(count == 0) {
544
- return object_complete_string(uk, rb_str_buf_new(0));
546
+ return object_complete(uk, rb_utf8_str_new_static("", 0));
545
547
  }
546
548
  /* read_raw_body_begin sets uk->reading_raw */
547
549
  uk->reading_raw_remaining = count;
@@ -553,7 +555,7 @@ static int read_primitive(msgpack_unpacker_t* uk)
553
555
  READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 1);
554
556
  uint8_t count = cb->u8;
555
557
  if(count == 0) {
556
- return object_complete_binary(uk, rb_str_buf_new(0));
558
+ return object_complete(uk, rb_str_new_static("", 0));
557
559
  }
558
560
  /* read_raw_body_begin sets uk->reading_raw */
559
561
  uk->reading_raw_remaining = count;
@@ -565,7 +567,7 @@ static int read_primitive(msgpack_unpacker_t* uk)
565
567
  READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 2);
566
568
  uint16_t count = _msgpack_be16(cb->u16);
567
569
  if(count == 0) {
568
- return object_complete_binary(uk, rb_str_buf_new(0));
570
+ return object_complete(uk, rb_str_new_static("", 0));
569
571
  }
570
572
  /* read_raw_body_begin sets uk->reading_raw */
571
573
  uk->reading_raw_remaining = count;
@@ -577,7 +579,7 @@ static int read_primitive(msgpack_unpacker_t* uk)
577
579
  READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 4);
578
580
  uint32_t count = _msgpack_be32(cb->u32);
579
581
  if(count == 0) {
580
- return object_complete_binary(uk, rb_str_buf_new(0));
582
+ return object_complete(uk, rb_str_new_static("", 0));
581
583
  }
582
584
  /* read_raw_body_begin sets uk->reading_raw */
583
585
  uk->reading_raw_remaining = count;
@@ -719,18 +721,8 @@ int msgpack_unpacker_read(msgpack_unpacker_t* uk, size_t target_stack_depth)
719
721
  break;
720
722
  case STACK_TYPE_MAP_VALUE:
721
723
  if(uk->symbolize_keys && rb_type(top->key) == T_STRING) {
722
- /* here uses rb_intern_str instead of rb_intern so that Ruby VM can GC unused symbols */
723
- #ifdef HAVE_RB_STR_INTERN
724
- /* 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 */
725
725
  rb_hash_aset(top->object, rb_str_intern(top->key), uk->last_object);
726
- #else
727
- #ifndef HAVE_RB_INTERN_STR
728
- /* MRI 1.8 doesn't have rb_intern_str or rb_intern2 */
729
- rb_hash_aset(top->object, ID2SYM(rb_intern(RSTRING_PTR(top->key))), uk->last_object);
730
- #else
731
- rb_hash_aset(top->object, ID2SYM(rb_intern_str(top->key)), uk->last_object);
732
- #endif
733
- #endif
734
726
  } else {
735
727
  rb_hash_aset(top->object, top->key, uk->last_object);
736
728
  }
@@ -64,7 +64,10 @@ struct msgpack_unpacker_t {
64
64
 
65
65
  /* options */
66
66
  bool symbolize_keys;
67
+ bool freeze;
67
68
  bool allow_unknown_ext;
69
+ bool optimized_symbol_ext_type;
70
+ int symbol_ext_type;
68
71
  };
69
72
 
70
73
  #define UNPACKER_BUFFER_(uk) (&(uk)->buffer)
@@ -96,6 +99,11 @@ static inline void msgpack_unpacker_set_symbolized_keys(msgpack_unpacker_t* uk,
96
99
  uk->symbolize_keys = enable;
97
100
  }
98
101
 
102
+ static inline void msgpack_unpacker_set_freeze(msgpack_unpacker_t* uk, bool enable)
103
+ {
104
+ uk->freeze = enable;
105
+ }
106
+
99
107
  static inline void msgpack_unpacker_set_allow_unknown_ext(msgpack_unpacker_t* uk, bool enable)
100
108
  {
101
109
  uk->allow_unknown_ext = enable;
@@ -77,9 +77,6 @@ VALUE MessagePack_Unpacker_initialize(int argc, VALUE* argv, VALUE self)
77
77
  VALUE v = argv[0];
78
78
  if(rb_type(v) == T_HASH) {
79
79
  options = v;
80
- if(rb_type(options) != T_HASH) {
81
- rb_raise(rb_eArgError, "expected Hash but found %s.", rb_obj_classname(options));
82
- }
83
80
  } else {
84
81
  io = v;
85
82
  }
@@ -108,6 +105,9 @@ VALUE MessagePack_Unpacker_initialize(int argc, VALUE* argv, VALUE self)
108
105
  v = rb_hash_aref(options, ID2SYM(rb_intern("symbolize_keys")));
109
106
  msgpack_unpacker_set_symbolized_keys(uk, RTEST(v));
110
107
 
108
+ v = rb_hash_aref(options, ID2SYM(rb_intern("freeze")));
109
+ msgpack_unpacker_set_freeze(uk, RTEST(v));
110
+
111
111
  v = rb_hash_aref(options, ID2SYM(rb_intern("allow_unknown_ext")));
112
112
  msgpack_unpacker_set_allow_unknown_ext(uk, RTEST(v));
113
113
  }
@@ -121,6 +121,12 @@ static VALUE Unpacker_symbolized_keys_p(VALUE self)
121
121
  return uk->symbolize_keys ? Qtrue : Qfalse;
122
122
  }
123
123
 
124
+ static VALUE Unpacker_freeze_p(VALUE self)
125
+ {
126
+ UNPACKER(self, uk);
127
+ return uk->freeze ? Qtrue : Qfalse;
128
+ }
129
+
124
130
  static VALUE Unpacker_allow_unknown_ext_p(VALUE self)
125
131
  {
126
132
  UNPACKER(self, uk);
@@ -256,6 +262,17 @@ static VALUE Unpacker_feed(VALUE self, VALUE data)
256
262
  return self;
257
263
  }
258
264
 
265
+ static VALUE Unpacker_feed_reference(VALUE self, VALUE data)
266
+ {
267
+ UNPACKER(self, uk);
268
+
269
+ StringValue(data);
270
+
271
+ msgpack_buffer_append_string_reference(UNPACKER_BUFFER_(uk), data);
272
+
273
+ return self;
274
+ }
275
+
259
276
  static VALUE Unpacker_each_impl(VALUE self)
260
277
  {
261
278
  UNPACKER(self, uk);
@@ -312,8 +329,7 @@ static VALUE Unpacker_feed_each(VALUE self, VALUE data)
312
329
  }
313
330
  #endif
314
331
 
315
- // TODO optimize
316
- Unpacker_feed(self, data);
332
+ Unpacker_feed_reference(self, data);
317
333
  return Unpacker_each(self);
318
334
  }
319
335
 
@@ -353,12 +369,7 @@ static VALUE Unpacker_register_type(int argc, VALUE* argv, VALUE self)
353
369
  case 1:
354
370
  /* register_type(0x7f) {|data| block... } */
355
371
  rb_need_block();
356
- #ifdef HAVE_RB_BLOCK_LAMBDA
357
372
  proc = rb_block_lambda();
358
- #else
359
- /* MRI 1.8 */
360
- proc = rb_block_proc();
361
- #endif
362
373
  arg = proc;
363
374
  ext_module = Qnil;
364
375
  break;
@@ -386,9 +397,6 @@ static VALUE Unpacker_full_unpack(VALUE self)
386
397
  {
387
398
  UNPACKER(self, uk);
388
399
 
389
- /* prefer reference than copying; see MessagePack_Unpacker_module_init */
390
- msgpack_buffer_set_write_reference_threshold(UNPACKER_BUFFER_(uk), 0);
391
-
392
400
  int r = msgpack_unpacker_read(uk, 0);
393
401
  if(r < 0) {
394
402
  raise_unpacker_error(r);
@@ -434,6 +442,7 @@ void MessagePack_Unpacker_module_init(VALUE mMessagePack)
434
442
 
435
443
  rb_define_method(cMessagePack_Unpacker, "initialize", MessagePack_Unpacker_initialize, -1);
436
444
  rb_define_method(cMessagePack_Unpacker, "symbolize_keys?", Unpacker_symbolized_keys_p, 0);
445
+ rb_define_method(cMessagePack_Unpacker, "freeze?", Unpacker_freeze_p, 0);
437
446
  rb_define_method(cMessagePack_Unpacker, "allow_unknown_ext?", Unpacker_allow_unknown_ext_p, 0);
438
447
  rb_define_method(cMessagePack_Unpacker, "buffer", Unpacker_buffer, 0);
439
448
  rb_define_method(cMessagePack_Unpacker, "read", Unpacker_read, 0);
@@ -444,6 +453,7 @@ void MessagePack_Unpacker_module_init(VALUE mMessagePack)
444
453
  rb_define_method(cMessagePack_Unpacker, "read_map_header", Unpacker_read_map_header, 0);
445
454
  //rb_define_method(cMessagePack_Unpacker, "peek_next_type", Unpacker_peek_next_type, 0); // TODO
446
455
  rb_define_method(cMessagePack_Unpacker, "feed", Unpacker_feed, 1);
456
+ rb_define_method(cMessagePack_Unpacker, "feed_reference", Unpacker_feed_reference, 1);
447
457
  rb_define_method(cMessagePack_Unpacker, "each", Unpacker_each, 0);
448
458
  rb_define_method(cMessagePack_Unpacker, "feed_each", Unpacker_feed_each, 1);
449
459
  rb_define_method(cMessagePack_Unpacker, "reset", Unpacker_reset, 0);
@@ -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
@@ -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
@@ -1,9 +1,6 @@
1
1
  module MessagePack
2
- VERSION = "1.2.6"
3
-
4
- # NOTE for msgpack-ruby maintainer:
5
- # Check these things to release new binaryes for new Ruby versions (especially for Windows):
6
- # * versions/supports of rake-compiler & rake-compiler-dock
7
- # * update RUBY_CC_VERSION in Rakefile
8
- # * check Ruby dependency of released mswin gem details
2
+ VERSION = "1.4.4"
3
+ # Note for maintainers:
4
+ # Don't miss building/releasing the JRuby version (rake buld:java)
5
+ # See "How to build -java rubygems" in README for more details.
9
6
  end
data/lib/msgpack.rb CHANGED
@@ -1,15 +1,10 @@
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
- begin
9
- require "msgpack/#{RUBY_VERSION[/\d+.\d+/]}/msgpack"
10
- rescue LoadError
11
- require "msgpack/msgpack"
12
- end
7
+ require "msgpack/msgpack"
13
8
  end
14
9
 
15
10
  require "msgpack/packer"
@@ -17,18 +12,21 @@ require "msgpack/unpacker"
17
12
  require "msgpack/factory"
18
13
  require "msgpack/symbol"
19
14
  require "msgpack/core_ext"
15
+ require "msgpack/timestamp"
16
+ require "msgpack/time"
20
17
 
21
18
  module MessagePack
22
19
  DefaultFactory = MessagePack::Factory.new
20
+ DEFAULT_EMPTY_PARAMS = {}.freeze
23
21
 
24
22
  def load(src, param = nil)
25
23
  unpacker = nil
26
24
 
27
25
  if src.is_a? String
28
- unpacker = DefaultFactory.unpacker param
29
- unpacker.feed src
26
+ unpacker = DefaultFactory.unpacker param || DEFAULT_EMPTY_PARAMS
27
+ unpacker.feed_reference src
30
28
  else
31
- unpacker = DefaultFactory.unpacker src, param
29
+ unpacker = DefaultFactory.unpacker src, param || DEFAULT_EMPTY_PARAMS
32
30
  end
33
31
 
34
32
  unpacker.full_unpack
data/msgpack.gemspec CHANGED
@@ -10,7 +10,6 @@ Gem::Specification.new do |s|
10
10
  s.email = ["frsyuki@gmail.com", "theo@iconara.net", "tagomoris@gmail.com"]
11
11
  s.license = "Apache 2.0"
12
12
  s.homepage = "http://msgpack.org/"
13
- s.rubyforge_project = "msgpack"
14
13
  s.require_paths = ["lib"]
15
14
  if /java/ =~ RUBY_PLATFORM
16
15
  s.files = Dir['lib/**/*.rb', 'lib/**/*.jar']
@@ -19,15 +18,12 @@ Gem::Specification.new do |s|
19
18
  s.files = `git ls-files`.split("\n")
20
19
  s.extensions = ["ext/msgpack/extconf.rb"]
21
20
  end
22
- s.test_files = `git ls-files -- {test,spec}/*`.split("\n")
21
+
22
+ s.required_ruby_version = ">= 2.4"
23
23
 
24
24
  s.add_development_dependency 'bundler'
25
25
  s.add_development_dependency 'rake'
26
- s.add_development_dependency 'rake-compiler', ['~> 1.0']
27
- if /java/ !~ RUBY_PLATFORM
28
- # NOTE: rake-compiler-dock SHOULD be updated for new Ruby versions
29
- s.add_development_dependency 'rake-compiler-dock', ['~> 0.7.0']
30
- end
26
+ s.add_development_dependency 'rake-compiler', ['>= 1.1.9']
31
27
  s.add_development_dependency 'rspec', ['~> 3.3']
32
28
  s.add_development_dependency 'yard'
33
29
  s.add_development_dependency 'json'
@@ -1,6 +1,11 @@
1
1
  require 'spec_helper'
2
2
  require 'random_compat'
3
3
 
4
+ require 'stringio'
5
+ if defined?(Encoding)
6
+ Encoding.default_external = 'ASCII-8BIT'
7
+ end
8
+
4
9
  describe Buffer do
5
10
  STATIC_EXAMPLES = {}
6
11
  STATIC_EXAMPLES[:empty01] = ''
@@ -45,7 +50,7 @@ describe Buffer do
45
50
  b.read(n)
46
51
  s.slice!(0, n)
47
52
  end
48
- key = :"random#{"%02d"%i}"
53
+ key = :"random#{"%02d" % i}"
49
54
  cases[key] = b
50
55
  examples[key] = s
51
56
  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'