msgpack 0.6.2 → 0.7.0dev1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (60) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +33 -0
  3. data/README.rdoc +2 -6
  4. data/Rakefile +9 -0
  5. data/appveyor.yml +18 -0
  6. data/doclib/msgpack/error.rb +6 -1
  7. data/doclib/msgpack/extension_value.rb +9 -0
  8. data/doclib/msgpack/factory.rb +68 -0
  9. data/doclib/msgpack/packer.rb +38 -0
  10. data/doclib/msgpack/unpacker.rb +39 -2
  11. data/ext/java/org/msgpack/jruby/Buffer.java +4 -0
  12. data/ext/java/org/msgpack/jruby/Decoder.java +44 -0
  13. data/ext/java/org/msgpack/jruby/Encoder.java +46 -4
  14. data/ext/java/org/msgpack/jruby/ExtensionValue.java +55 -60
  15. data/ext/java/org/msgpack/jruby/MessagePackLibrary.java +18 -5
  16. data/ext/java/org/msgpack/jruby/Packer.java +17 -4
  17. data/ext/java/org/msgpack/jruby/Unpacker.java +59 -2
  18. data/ext/msgpack/buffer_class.c +2 -2
  19. data/ext/msgpack/buffer_class.h +1 -1
  20. data/ext/msgpack/compat.h +12 -0
  21. data/ext/msgpack/core_ext.c +15 -0
  22. data/ext/msgpack/extconf.rb +4 -1
  23. data/ext/msgpack/extension_value_class.c +34 -0
  24. data/ext/msgpack/extension_value_class.h +31 -0
  25. data/ext/msgpack/factory_class.c +213 -0
  26. data/ext/msgpack/factory_class.h +35 -0
  27. data/ext/msgpack/packer.c +14 -7
  28. data/ext/msgpack/packer.h +46 -8
  29. data/ext/msgpack/packer_class.c +92 -45
  30. data/ext/msgpack/packer_class.h +4 -2
  31. data/ext/msgpack/packer_ext_registry.c +87 -0
  32. data/ext/msgpack/packer_ext_registry.h +101 -0
  33. data/ext/msgpack/rbinit.c +4 -0
  34. data/ext/msgpack/unpacker.c +128 -23
  35. data/ext/msgpack/unpacker.h +11 -0
  36. data/ext/msgpack/unpacker_class.c +117 -38
  37. data/ext/msgpack/unpacker_class.h +4 -2
  38. data/ext/msgpack/unpacker_ext_registry.c +68 -0
  39. data/ext/msgpack/unpacker_ext_registry.h +62 -0
  40. data/lib/msgpack.rb +4 -0
  41. data/lib/msgpack/factory.rb +60 -0
  42. data/lib/msgpack/packer.rb +28 -0
  43. data/lib/msgpack/unpacker.rb +28 -0
  44. data/lib/msgpack/version.rb +1 -1
  45. data/msgpack.gemspec +4 -3
  46. data/spec/cruby/buffer_io_spec.rb +2 -3
  47. data/spec/cruby/buffer_spec.rb +1 -3
  48. data/spec/cruby/unpacker_spec.rb +14 -2
  49. data/spec/ext_value_spec.rb +99 -0
  50. data/spec/exttypes.rb +51 -0
  51. data/spec/factory_spec.rb +236 -0
  52. data/spec/jruby/msgpack/unpacker_spec.rb +25 -0
  53. data/spec/{jruby/msgpack_spec.rb → msgpack_spec.rb} +1 -1
  54. data/spec/pack_spec.rb +0 -6
  55. data/spec/packer_spec.rb +95 -0
  56. data/spec/spec_helper.rb +12 -1
  57. data/spec/unpack_spec.rb +1 -4
  58. data/spec/unpacker_spec.rb +133 -0
  59. metadata +53 -15
  60. data/Dockerfile +0 -55
@@ -0,0 +1,31 @@
1
+ /*
2
+ * MessagePack for Ruby
3
+ *
4
+ * Copyright (C) 2008-2015 Sadayuki Furuhashi
5
+ *
6
+ * Licensed under the Apache License, Version 2.0 (the "License");
7
+ * you may not use this file except in compliance with the License.
8
+ * You may obtain a copy of the License at
9
+ *
10
+ * http://www.apache.org/licenses/LICENSE-2.0
11
+ *
12
+ * Unless required by applicable law or agreed to in writing, software
13
+ * distributed under the License is distributed on an "AS IS" BASIS,
14
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ * See the License for the specific language governing permissions and
16
+ * limitations under the License.
17
+ */
18
+ #ifndef MSGPACK_RUBY_EXTENSION_VALUE_CLASS_H__
19
+ #define MSGPACK_RUBY_EXTENSION_VALUE_CLASS_H__
20
+
21
+ #include "compat.h"
22
+ #include "sysdep.h"
23
+
24
+ extern VALUE cMessagePack_ExtensionValue;
25
+
26
+ VALUE MessagePack_ExtensionValue_new(int ext_type, VALUE payload);
27
+
28
+ void MessagePack_ExtensionValue_module_init(VALUE mMessagePack);
29
+
30
+ #endif
31
+
@@ -0,0 +1,213 @@
1
+ /*
2
+ * MessagePack for Ruby
3
+ *
4
+ * Copyright (C) 2008-2013 Sadayuki Furuhashi
5
+ *
6
+ * Licensed under the Apache License, Version 2.0 (the "License");
7
+ * you may not use this file except in compliance with the License.
8
+ * You may obtain a copy of the License at
9
+ *
10
+ * http://www.apache.org/licenses/LICENSE-2.0
11
+ *
12
+ * Unless required by applicable law or agreed to in writing, software
13
+ * distributed under the License is distributed on an "AS IS" BASIS,
14
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ * See the License for the specific language governing permissions and
16
+ * limitations under the License.
17
+ */
18
+
19
+ #include "factory_class.h"
20
+ #include "packer_ext_registry.h"
21
+ #include "unpacker_ext_registry.h"
22
+ #include "buffer_class.h"
23
+ #include "packer_class.h"
24
+ #include "unpacker_class.h"
25
+
26
+ VALUE cMessagePack_Factory;
27
+ VALUE cMessagePack_DefaultFactory;
28
+
29
+ struct msgpack_factory_t;
30
+ typedef struct msgpack_factory_t msgpack_factory_t;
31
+
32
+ struct msgpack_factory_t {
33
+ msgpack_packer_ext_registry_t pkrg;
34
+ msgpack_unpacker_ext_registry_t ukrg;
35
+ };
36
+
37
+ #define FACTORY(from, name) \
38
+ msgpack_factory_t *name = NULL; \
39
+ Data_Get_Struct(from, msgpack_factory_t, name); \
40
+ if(name == NULL) { \
41
+ rb_raise(rb_eArgError, "NULL found for " # name " when shouldn't be."); \
42
+ }
43
+
44
+ static void Factory_free(msgpack_factory_t* fc)
45
+ {
46
+ if(fc == NULL) {
47
+ return;
48
+ }
49
+ msgpack_packer_ext_registry_destroy(&fc->pkrg);
50
+ msgpack_unpacker_ext_registry_destroy(&fc->ukrg);
51
+ free(fc);
52
+ }
53
+
54
+ void Factory_mark(msgpack_factory_t* fc)
55
+ {
56
+ msgpack_packer_ext_registry_mark(&fc->pkrg);
57
+ msgpack_unpacker_ext_registry_mark(&fc->ukrg);
58
+ }
59
+
60
+ static VALUE Factory_alloc(VALUE klass)
61
+ {
62
+ msgpack_factory_t* fc = ALLOC_N(msgpack_factory_t, 1);
63
+
64
+ msgpack_packer_ext_registry_init(&fc->pkrg);
65
+ msgpack_unpacker_ext_registry_init(&fc->ukrg);
66
+
67
+ VALUE self = Data_Wrap_Struct(klass, Factory_mark, Factory_free, fc);
68
+ return self;
69
+ }
70
+
71
+ static VALUE Factory_initialize(int argc, VALUE* argv, VALUE self)
72
+ {
73
+ FACTORY(self, fc);
74
+
75
+ switch (argc) {
76
+ case 0:
77
+ break;
78
+ default:
79
+ // TODO options is not supported yet
80
+ rb_raise(rb_eArgError, "wrong number of arguments (%d for 0)", argc);
81
+ }
82
+
83
+ return Qnil;
84
+ }
85
+
86
+ VALUE MessagePack_Factory_packer(int argc, VALUE* argv, VALUE self)
87
+ {
88
+ FACTORY(self, fc);
89
+
90
+ VALUE packer = MessagePack_Packer_alloc(cMessagePack_Packer);
91
+ MessagePack_Packer_initialize(argc, argv, packer);
92
+
93
+ msgpack_packer_t* pk;
94
+ Data_Get_Struct(packer, msgpack_packer_t, pk);
95
+
96
+ msgpack_packer_ext_registry_destroy(&pk->ext_registry);
97
+ msgpack_packer_ext_registry_dup(&fc->pkrg, &pk->ext_registry);
98
+
99
+ return packer;
100
+ }
101
+
102
+ VALUE MessagePack_Factory_unpacker(int argc, VALUE* argv, VALUE self)
103
+ {
104
+ FACTORY(self, fc);
105
+
106
+ VALUE unpacker = MessagePack_Unpacker_alloc(cMessagePack_Unpacker);
107
+ MessagePack_Unpacker_initialize(argc, argv, unpacker);
108
+
109
+ msgpack_unpacker_t* uk;
110
+ Data_Get_Struct(unpacker, msgpack_unpacker_t, uk);
111
+
112
+ msgpack_unpacker_ext_registry_destroy(&uk->ext_registry);
113
+ msgpack_unpacker_ext_registry_dup(&fc->ukrg, &uk->ext_registry);
114
+
115
+ return unpacker;
116
+ }
117
+
118
+ static VALUE Factory_registered_types_internal(VALUE self)
119
+ {
120
+ FACTORY(self, fc);
121
+
122
+ VALUE uk_mapping = rb_hash_new();
123
+ for(int i=0; i < 256; i++) {
124
+ if(fc->ukrg.array[i] != Qnil) {
125
+ rb_hash_aset(uk_mapping, INT2FIX(i - 128), fc->ukrg.array[i]);
126
+ }
127
+ }
128
+ #ifdef HAVE_RB_HASH_DUP
129
+ return rb_ary_new3(2, rb_hash_dup(fc->pkrg.hash), uk_mapping);
130
+ #else
131
+ return rb_ary_new3(2, rb_funcall(fc->pkrg.hash, rb_intern("dup"), 0), uk_mapping);
132
+ #endif
133
+ }
134
+
135
+ static VALUE Factory_register_type(int argc, VALUE* argv, VALUE self)
136
+ {
137
+ FACTORY(self, fc);
138
+
139
+ int ext_type;
140
+ VALUE ext_class;
141
+ VALUE options;
142
+ VALUE packer_arg, unpacker_arg;
143
+ VALUE packer_proc, unpacker_proc;
144
+
145
+ switch (argc) {
146
+ case 2:
147
+ /* register_type(0x7f, Time) */
148
+ packer_arg = ID2SYM(rb_intern("to_msgpack_ext"));
149
+ unpacker_arg = ID2SYM(rb_intern("from_msgpack_ext"));
150
+ break;
151
+ case 3:
152
+ /* register_type(0x7f, Time, packer: proc-like, unapcker: proc-like) */
153
+ options = argv[2];
154
+ if(rb_type(options) != T_HASH) {
155
+ rb_raise(rb_eArgError, "expected Hash but found %s.", rb_obj_classname(options));
156
+ }
157
+ packer_arg = rb_hash_aref(options, ID2SYM(rb_intern("packer")));
158
+ unpacker_arg = rb_hash_aref(options, ID2SYM(rb_intern("unpacker")));
159
+ break;
160
+ default:
161
+ rb_raise(rb_eArgError, "wrong number of arguments (%d for 2..3)", argc);
162
+ }
163
+
164
+ ext_type = rb_num2int(argv[0]);
165
+ if(ext_type < -128 || ext_type > 127) {
166
+ rb_raise(rb_eRangeError, "integer %d too big to convert to `signed char'", ext_type);
167
+ }
168
+
169
+ ext_class = argv[1];
170
+ if(rb_type(ext_class) != T_CLASS) {
171
+ rb_raise(rb_eArgError, "expected Class but found %s.", rb_obj_classname(ext_class));
172
+ }
173
+
174
+ packer_proc = Qnil;
175
+ unpacker_proc = Qnil;
176
+
177
+ if(packer_arg != Qnil) {
178
+ packer_proc = rb_funcall(packer_arg, rb_intern("to_proc"), 0);
179
+ }
180
+
181
+ if(unpacker_arg != Qnil) {
182
+ if(rb_type(unpacker_arg) == T_SYMBOL || rb_type(unpacker_arg) == T_STRING) {
183
+ unpacker_proc = rb_obj_method(ext_class, unpacker_arg);
184
+ } else {
185
+ unpacker_proc = rb_funcall(unpacker_arg, rb_intern("method"), 1, ID2SYM(rb_intern("call")));
186
+ }
187
+ }
188
+
189
+ msgpack_packer_ext_registry_put(&fc->pkrg, ext_class, ext_type, packer_proc, packer_arg);
190
+
191
+ msgpack_unpacker_ext_registry_put(&fc->ukrg, ext_class, ext_type, unpacker_proc, unpacker_arg);
192
+
193
+ return Qnil;
194
+ }
195
+
196
+ void MessagePack_Factory_module_init(VALUE mMessagePack)
197
+ {
198
+ cMessagePack_Factory = rb_define_class_under(mMessagePack, "Factory", rb_cObject);
199
+
200
+ rb_define_alloc_func(cMessagePack_Factory, Factory_alloc);
201
+
202
+ rb_define_method(cMessagePack_Factory, "initialize", Factory_initialize, -1);
203
+
204
+ rb_define_method(cMessagePack_Factory, "packer", MessagePack_Factory_packer, -1);
205
+ rb_define_method(cMessagePack_Factory, "unpacker", MessagePack_Factory_unpacker, -1);
206
+
207
+ rb_define_private_method(cMessagePack_Factory, "registered_types_internal", Factory_registered_types_internal, 0);
208
+ rb_define_method(cMessagePack_Factory, "register_type", Factory_register_type, -1);
209
+
210
+ cMessagePack_DefaultFactory = Factory_alloc(cMessagePack_Factory);
211
+ Factory_initialize(0, NULL, cMessagePack_DefaultFactory);
212
+ rb_define_const(mMessagePack, "DefaultFactory", cMessagePack_DefaultFactory);
213
+ }
@@ -0,0 +1,35 @@
1
+ /*
2
+ * MessagePack for Ruby
3
+ *
4
+ * Copyright (C) 2008-2015 Sadayuki Furuhashi
5
+ *
6
+ * Licensed under the Apache License, Version 2.0 (the "License");
7
+ * you may not use this file except in compliance with the License.
8
+ * You may obtain a copy of the License at
9
+ *
10
+ * http://www.apache.org/licenses/LICENSE-2.0
11
+ *
12
+ * Unless required by applicable law or agreed to in writing, software
13
+ * distributed under the License is distributed on an "AS IS" BASIS,
14
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ * See the License for the specific language governing permissions and
16
+ * limitations under the License.
17
+ */
18
+ #ifndef MSGPACK_RUBY_FACTORY_CLASS_H__
19
+ #define MSGPACK_RUBY_FACTORY_CLASS_H__
20
+
21
+ #include "compat.h"
22
+ #include "sysdep.h"
23
+
24
+ extern VALUE cMessagePack_Factory;
25
+
26
+ extern VALUE cMessagePack_DefaultFactory;
27
+
28
+ extern VALUE MessagePack_Factory_packer(int argc, VALUE* argv, VALUE self);
29
+
30
+ extern VALUE MessagePack_Factory_unpacker(int argc, VALUE* argv, VALUE self);
31
+
32
+ void MessagePack_Factory_module_init(VALUE mMessagePack);
33
+
34
+ #endif
35
+
@@ -25,6 +25,8 @@ static ID s_key;
25
25
  static ID s_value;
26
26
  #endif
27
27
 
28
+ static ID s_call;
29
+
28
30
  void msgpack_packer_static_init()
29
31
  {
30
32
  #ifdef RUBINIUS
@@ -33,6 +35,8 @@ void msgpack_packer_static_init()
33
35
  s_key = rb_intern("key");
34
36
  s_value = rb_intern("value");
35
37
  #endif
38
+
39
+ s_call = rb_intern("call");
36
40
  }
37
41
 
38
42
  void msgpack_packer_static_destroy()
@@ -43,8 +47,6 @@ void msgpack_packer_init(msgpack_packer_t* pk)
43
47
  memset(pk, 0, sizeof(msgpack_packer_t));
44
48
 
45
49
  msgpack_buffer_init(PACKER_BUFFER_(pk));
46
-
47
- pk->io = Qnil;
48
50
  }
49
51
 
50
52
  void msgpack_packer_destroy(msgpack_packer_t* pk)
@@ -54,8 +56,6 @@ void msgpack_packer_destroy(msgpack_packer_t* pk)
54
56
 
55
57
  void msgpack_packer_mark(msgpack_packer_t* pk)
56
58
  {
57
- rb_gc_mark(pk->io);
58
-
59
59
  /* See MessagePack_Buffer_wrap */
60
60
  /* msgpack_buffer_mark(PACKER_BUFFER_(pk)); */
61
61
  rb_gc_mark(pk->buffer_ref);
@@ -65,8 +65,6 @@ void msgpack_packer_reset(msgpack_packer_t* pk)
65
65
  {
66
66
  msgpack_buffer_clear(PACKER_BUFFER_(pk));
67
67
 
68
- pk->io = Qnil;
69
- pk->io_write_all_method = 0;
70
68
  pk->buffer_ref = Qnil;
71
69
  }
72
70
 
@@ -125,7 +123,16 @@ void msgpack_packer_write_hash_value(msgpack_packer_t* pk, VALUE v)
125
123
 
126
124
  static void _msgpack_packer_write_other_value(msgpack_packer_t* pk, VALUE v)
127
125
  {
128
- rb_funcall(v, pk->to_msgpack_method, 1, pk->to_msgpack_arg);
126
+ int ext_type;
127
+ VALUE proc = msgpack_packer_ext_registry_lookup(&pk->ext_registry,
128
+ rb_obj_class(v), &ext_type);
129
+ if(proc != Qnil) {
130
+ VALUE payload = rb_funcall(proc, s_call, 1, v);
131
+ StringValue(payload);
132
+ msgpack_packer_write_ext(pk, ext_type, payload);
133
+ } else {
134
+ rb_funcall(v, pk->to_msgpack_method, 1, pk->to_msgpack_arg);
135
+ }
129
136
  }
130
137
 
131
138
  void msgpack_packer_write_value(msgpack_packer_t* pk, VALUE v)
@@ -19,6 +19,7 @@
19
19
  #define MSGPACK_RUBY_PACKER_H__
20
20
 
21
21
  #include "buffer.h"
22
+ #include "packer_ext_registry.h"
22
23
 
23
24
  #ifndef MSGPACK_PACKER_IO_FLUSH_THRESHOLD_TO_WRITE_STRING_BODY
24
25
  #define MSGPACK_PACKER_IO_FLUSH_THRESHOLD_TO_WRITE_STRING_BODY (1024)
@@ -30,8 +31,6 @@ typedef struct msgpack_packer_t msgpack_packer_t;
30
31
  struct msgpack_packer_t {
31
32
  msgpack_buffer_t buffer;
32
33
 
33
- VALUE io;
34
- ID io_write_all_method;
35
34
  bool compatibility_mode;
36
35
 
37
36
  ID to_msgpack_method;
@@ -41,6 +40,7 @@ struct msgpack_packer_t {
41
40
 
42
41
  /* options */
43
42
  bool comaptibility_mode;
43
+ msgpack_packer_ext_registry_t ext_registry;
44
44
  };
45
45
 
46
46
  #define PACKER_BUFFER_(pk) (&(pk)->buffer)
@@ -62,12 +62,6 @@ static inline void msgpack_packer_set_to_msgpack_method(msgpack_packer_t* pk,
62
62
  pk->to_msgpack_arg = to_msgpack_arg;
63
63
  }
64
64
 
65
- static inline void msgpack_packer_set_io(msgpack_packer_t* pk, VALUE io, ID io_write_all_method)
66
- {
67
- pk->io = io;
68
- pk->io_write_all_method = io_write_all_method;
69
- }
70
-
71
65
  void msgpack_packer_reset(msgpack_packer_t* pk);
72
66
 
73
67
  static inline void msgpack_packer_set_compat(msgpack_packer_t* pk, bool enable)
@@ -345,6 +339,50 @@ static inline void msgpack_packer_write_map_header(msgpack_packer_t* pk, unsigne
345
339
  }
346
340
  }
347
341
 
342
+ static inline void msgpack_packer_write_ext(msgpack_packer_t* pk, int ext_type, VALUE payload)
343
+ {
344
+ unsigned long len = RSTRING_LEN(payload);
345
+ switch (len) {
346
+ case 1:
347
+ msgpack_buffer_ensure_writable(PACKER_BUFFER_(pk), 2);
348
+ msgpack_buffer_write_2(PACKER_BUFFER_(pk), 0xd4, ext_type);
349
+ break;
350
+ case 2:
351
+ msgpack_buffer_ensure_writable(PACKER_BUFFER_(pk), 2);
352
+ msgpack_buffer_write_2(PACKER_BUFFER_(pk), 0xd5, ext_type);
353
+ break;
354
+ case 4:
355
+ msgpack_buffer_ensure_writable(PACKER_BUFFER_(pk), 2);
356
+ msgpack_buffer_write_2(PACKER_BUFFER_(pk), 0xd6, ext_type);
357
+ break;
358
+ case 8:
359
+ msgpack_buffer_ensure_writable(PACKER_BUFFER_(pk), 2);
360
+ msgpack_buffer_write_2(PACKER_BUFFER_(pk), 0xd7, ext_type);
361
+ break;
362
+ case 16:
363
+ msgpack_buffer_ensure_writable(PACKER_BUFFER_(pk), 2);
364
+ msgpack_buffer_write_2(PACKER_BUFFER_(pk), 0xd8, ext_type);
365
+ break;
366
+ default:
367
+ if(len < 255) {
368
+ msgpack_buffer_ensure_writable(PACKER_BUFFER_(pk), 3);
369
+ msgpack_buffer_write_2(PACKER_BUFFER_(pk), 0xc7, len);
370
+ msgpack_buffer_write_1(PACKER_BUFFER_(pk), ext_type);
371
+ } else if(len < 65536) {
372
+ msgpack_buffer_ensure_writable(PACKER_BUFFER_(pk), 4);
373
+ uint16_t be = _msgpack_be16(len);
374
+ msgpack_buffer_write_byte_and_data(PACKER_BUFFER_(pk), 0xc8, (const void*)&be, 2);
375
+ msgpack_buffer_write_1(PACKER_BUFFER_(pk), ext_type);
376
+ } else {
377
+ msgpack_buffer_ensure_writable(PACKER_BUFFER_(pk), 6);
378
+ uint32_t be = _msgpack_be32(len);
379
+ msgpack_buffer_write_byte_and_data(PACKER_BUFFER_(pk), 0xc9, (const void*)&be, 4);
380
+ msgpack_buffer_write_1(PACKER_BUFFER_(pk), ext_type);
381
+ }
382
+ }
383
+ msgpack_buffer_append_string(PACKER_BUFFER_(pk), payload);
384
+ }
385
+
348
386
  #ifdef COMPAT_HAVE_ENCODING
349
387
  static inline bool msgpack_packer_is_binary(VALUE v, int encindex)
350
388
  {
@@ -21,6 +21,7 @@
21
21
  #include "packer.h"
22
22
  #include "packer_class.h"
23
23
  #include "buffer_class.h"
24
+ #include "factory_class.h"
24
25
 
25
26
  VALUE cMessagePack_Packer;
26
27
 
@@ -42,24 +43,32 @@ static void Packer_free(msgpack_packer_t* pk)
42
43
  if(pk == NULL) {
43
44
  return;
44
45
  }
46
+ msgpack_packer_ext_registry_destroy(&pk->ext_registry);
45
47
  msgpack_packer_destroy(pk);
46
48
  free(pk);
47
49
  }
48
50
 
49
- static VALUE Packer_alloc(VALUE klass)
51
+ static void Packer_mark(msgpack_packer_t* pk)
52
+ {
53
+ msgpack_packer_mark(pk);
54
+ msgpack_packer_ext_registry_mark(&pk->ext_registry);
55
+ }
56
+
57
+ VALUE MessagePack_Packer_alloc(VALUE klass)
50
58
  {
51
59
  msgpack_packer_t* pk = ALLOC_N(msgpack_packer_t, 1);
52
60
  msgpack_packer_init(pk);
53
61
 
54
- VALUE self = Data_Wrap_Struct(klass, msgpack_packer_mark, Packer_free, pk);
62
+ VALUE self = Data_Wrap_Struct(klass, Packer_mark, Packer_free, pk);
55
63
 
56
64
  msgpack_packer_set_to_msgpack_method(pk, s_to_msgpack, self);
65
+ msgpack_packer_ext_registry_init(&pk->ext_registry);
57
66
  pk->buffer_ref = MessagePack_Buffer_wrap(PACKER_BUFFER_(pk), self);
58
67
 
59
68
  return self;
60
69
  }
61
70
 
62
- static VALUE Packer_initialize(int argc, VALUE* argv, VALUE self)
71
+ VALUE MessagePack_Packer_initialize(int argc, VALUE* argv, VALUE self)
63
72
  {
64
73
  VALUE io = Qnil;
65
74
  VALUE options = Qnil;
@@ -88,14 +97,7 @@ static VALUE Packer_initialize(int argc, VALUE* argv, VALUE self)
88
97
 
89
98
  PACKER(self, pk);
90
99
 
91
- MessagePack_Packer_initialize(pk, io, options);
92
-
93
- return self;
94
- }
95
-
96
- void MessagePack_Packer_initialize(msgpack_packer_t* pk, VALUE io, VALUE options)
97
- {
98
- MessagePack_Buffer_initialize(PACKER_BUFFER_(pk), io, options);
100
+ MessagePack_Buffer_set_options(PACKER_BUFFER_(pk), io, options);
99
101
 
100
102
  if(options != Qnil) {
101
103
  VALUE v;
@@ -103,6 +105,8 @@ void MessagePack_Packer_initialize(msgpack_packer_t* pk, VALUE io, VALUE options
103
105
  v = rb_hash_aref(options, ID2SYM(rb_intern("compatibility_mode")));
104
106
  msgpack_packer_set_compat(pk, RTEST(v));
105
107
  }
108
+
109
+ return self;
106
110
  }
107
111
 
108
112
  static VALUE Packer_buffer(VALUE self)
@@ -139,6 +143,18 @@ static VALUE Packer_write_map_header(VALUE self, VALUE n)
139
143
  return self;
140
144
  }
141
145
 
146
+ static VALUE Packer_write_ext(VALUE self, VALUE type, VALUE data)
147
+ {
148
+ PACKER(self, pk);
149
+ int ext_type = rb_num2int(type);
150
+ if(ext_type < -128 || ext_type > 127) {
151
+ rb_raise(rb_eRangeError, "integer %d too big to convert to `signed char'", ext_type);
152
+ }
153
+ StringValue(data);
154
+ msgpack_packer_write_ext(pk, ext_type, data);
155
+ return self;
156
+ }
157
+
142
158
  static VALUE Packer_flush(VALUE self)
143
159
  {
144
160
  PACKER(self, pk);
@@ -201,51 +217,77 @@ static VALUE Packer_write_to(VALUE self, VALUE io)
201
217
  // return self;
202
218
  //}
203
219
 
204
- VALUE MessagePack_pack(int argc, VALUE* argv)
220
+ static VALUE Packer_registered_types_internal(VALUE self)
205
221
  {
206
- VALUE v;
207
- VALUE io = Qnil;
208
- VALUE options = Qnil;
222
+ PACKER(self, pk);
223
+ #ifdef HAVE_RB_HASH_DUP
224
+ return rb_hash_dup(pk->ext_registry.hash);
225
+ #else
226
+ return rb_funcall(pk->ext_registry.hash, rb_intern("dup"), 0);
227
+ #endif
228
+ }
209
229
 
210
- if(argc == 1) {
211
- v = argv[0];
230
+ static VALUE Packer_register_type(int argc, VALUE* argv, VALUE self)
231
+ {
232
+ PACKER(self, pk);
212
233
 
213
- } else if(argc == 2) {
214
- v = argv[0];
215
- if(rb_type(argv[1]) == T_HASH) {
216
- options = argv[1];
217
- } else {
218
- io = argv[1];
219
- }
234
+ int ext_type;
235
+ VALUE ext_class;
236
+ VALUE proc;
237
+ VALUE arg;
238
+
239
+ switch (argc) {
240
+ case 2:
241
+ /* register_type(0x7f, Time) {|obj| block... } */
242
+ rb_need_block();
243
+ #ifdef HAVE_RB_BLOCK_LAMBDA
244
+ proc = rb_block_lambda();
245
+ #else
246
+ /* MRI 1.8 */
247
+ proc = rb_block_proc();
248
+ #endif
249
+ arg = proc;
250
+ break;
251
+ case 3:
252
+ /* register_type(0x7f, Time, :to_msgpack_ext) */
253
+ arg = argv[2];
254
+ proc = rb_funcall(arg, rb_intern("to_proc"), 0);
255
+ break;
256
+ default:
257
+ rb_raise(rb_eArgError, "wrong number of arguments (%d for 2..3)", argc);
258
+ }
220
259
 
221
- } else if(argc == 3) {
222
- v = argv[0];
223
- io = argv[1];
224
- options = argv[2];
225
- if(rb_type(options) != T_HASH) {
226
- rb_raise(rb_eArgError, "expected Hash but found %s.", rb_obj_classname(options));
227
- }
260
+ ext_type = rb_num2int(argv[0]);
261
+ if(ext_type < -128 || ext_type > 127) {
262
+ rb_raise(rb_eRangeError, "integer %d too big to convert to `signed char'", ext_type);
263
+ }
228
264
 
229
- } else {
230
- rb_raise(rb_eArgError, "wrong number of arguments (%d for 1..3)", argc);
265
+ ext_class = argv[1];
266
+ if(rb_type(ext_class) != T_CLASS) {
267
+ rb_raise(rb_eArgError, "expected Class but found %s.", rb_obj_classname(ext_class));
231
268
  }
232
269
 
233
- VALUE self = Packer_alloc(cMessagePack_Packer);
234
- PACKER(self, pk);
270
+ msgpack_packer_ext_registry_put(&pk->ext_registry, ext_class, ext_type, proc, arg);
235
271
 
236
- if (options != Qnil) {
237
- pk->compatibility_mode = RTEST(rb_hash_aref(options, ID2SYM(rb_intern("compatibility_mode"))));
238
- }
272
+ return Qnil;
273
+ }
274
+
275
+ VALUE MessagePack_pack(int argc, VALUE* argv)
276
+ {
277
+ VALUE v;
239
278
 
240
- //msgpack_packer_reset(s_packer);
241
- //msgpack_buffer_reset_io(PACKER_BUFFER_(s_packer));
279
+ if (argc < 0 || argc > 3) {
280
+ rb_raise(rb_eArgError, "wrong number of arguments (%d for 1..3)", argc);
281
+ }
282
+ v = argv[0];
242
283
 
243
- MessagePack_Packer_initialize(pk, io, options);
284
+ VALUE self = MessagePack_Factory_packer(argc - 1, argv + 1, cMessagePack_DefaultFactory);
285
+ PACKER(self, pk);
244
286
 
245
287
  msgpack_packer_write_value(pk, v);
246
288
 
247
289
  VALUE retval;
248
- if(io != Qnil) {
290
+ if(msgpack_buffer_has_io(PACKER_BUFFER_(pk))) {
249
291
  msgpack_buffer_flush(PACKER_BUFFER_(pk));
250
292
  retval = Qnil;
251
293
  } else {
@@ -281,18 +323,20 @@ void MessagePack_Packer_module_init(VALUE mMessagePack)
281
323
  s_write = rb_intern("write");
282
324
 
283
325
  msgpack_packer_static_init();
326
+ msgpack_packer_ext_registry_static_init();
284
327
 
285
328
  cMessagePack_Packer = rb_define_class_under(mMessagePack, "Packer", rb_cObject);
286
329
 
287
- rb_define_alloc_func(cMessagePack_Packer, Packer_alloc);
330
+ rb_define_alloc_func(cMessagePack_Packer, MessagePack_Packer_alloc);
288
331
 
289
- rb_define_method(cMessagePack_Packer, "initialize", Packer_initialize, -1);
332
+ rb_define_method(cMessagePack_Packer, "initialize", MessagePack_Packer_initialize, -1);
290
333
  rb_define_method(cMessagePack_Packer, "buffer", Packer_buffer, 0);
291
334
  rb_define_method(cMessagePack_Packer, "write", Packer_write, 1);
292
335
  rb_define_alias(cMessagePack_Packer, "pack", "write");
293
336
  rb_define_method(cMessagePack_Packer, "write_nil", Packer_write_nil, 0);
294
337
  rb_define_method(cMessagePack_Packer, "write_array_header", Packer_write_array_header, 1);
295
338
  rb_define_method(cMessagePack_Packer, "write_map_header", Packer_write_map_header, 1);
339
+ rb_define_method(cMessagePack_Packer, "write_ext", Packer_write_ext, 2);
296
340
  rb_define_method(cMessagePack_Packer, "flush", Packer_flush, 0);
297
341
 
298
342
  /* delegation methods */
@@ -306,7 +350,10 @@ void MessagePack_Packer_module_init(VALUE mMessagePack)
306
350
  //rb_define_method(cMessagePack_Packer, "append", Packer_append, 1);
307
351
  //rb_define_alias(cMessagePack_Packer, "<<", "append");
308
352
 
309
- //s_packer_value = Packer_alloc(cMessagePack_Packer);
353
+ rb_define_private_method(cMessagePack_Packer, "registered_types_internal", Packer_registered_types_internal, 0);
354
+ rb_define_method(cMessagePack_Packer, "register_type", Packer_register_type, -1);
355
+
356
+ //s_packer_value = MessagePack_Packer_alloc(cMessagePack_Packer);
310
357
  //rb_gc_register_address(&s_packer_value);
311
358
  //Data_Get_Struct(s_packer_value, msgpack_packer_t, s_packer);
312
359