msgpack 1.2.6 → 1.4.4

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