packsnap 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. data/.gitignore +17 -0
  2. data/ChangeLog +29 -0
  3. data/README.rdoc +26 -0
  4. data/Rakefile +150 -0
  5. data/doclib/msgpack.rb +54 -0
  6. data/doclib/packsnap/buffer.rb +177 -0
  7. data/doclib/packsnap/error.rb +14 -0
  8. data/doclib/packsnap/packer.rb +131 -0
  9. data/doclib/packsnap/unpacker.rb +130 -0
  10. data/ext/packsnap/buffer.cc +684 -0
  11. data/ext/packsnap/buffer.hh +439 -0
  12. data/ext/packsnap/buffer_class.cc +490 -0
  13. data/ext/packsnap/buffer_class.hh +32 -0
  14. data/ext/packsnap/compat.h +128 -0
  15. data/ext/packsnap/extconf.rb +94 -0
  16. data/ext/packsnap/packer.cc +137 -0
  17. data/ext/packsnap/packer.h +334 -0
  18. data/ext/packsnap/packer_class.cc +288 -0
  19. data/ext/packsnap/packer_class.hh +32 -0
  20. data/ext/packsnap/packsnap.h +4 -0
  21. data/ext/packsnap/rbinit.cc +52 -0
  22. data/ext/packsnap/rmem.cc +110 -0
  23. data/ext/packsnap/rmem.h +100 -0
  24. data/ext/packsnap/sysdep.h +112 -0
  25. data/ext/packsnap/sysdep_endian.h +50 -0
  26. data/ext/packsnap/sysdep_types.h +46 -0
  27. data/ext/packsnap/unpacker.cc +654 -0
  28. data/ext/packsnap/unpacker.hh +108 -0
  29. data/ext/packsnap/unpacker_class.cc +392 -0
  30. data/ext/packsnap/unpacker_class.hh +32 -0
  31. data/lib/packsnap.rb +12 -0
  32. data/lib/packsnap/version.rb +3 -0
  33. data/packsnap.gemspec +23 -0
  34. data/spec/buffer_io_spec.rb +228 -0
  35. data/spec/buffer_spec.rb +572 -0
  36. data/spec/cases.json +1 -0
  37. data/spec/cases.msg +0 -0
  38. data/spec/cases_compact.msg +0 -0
  39. data/spec/cases_spec.rb +39 -0
  40. data/spec/format_spec.rb +225 -0
  41. data/spec/packer_spec.rb +127 -0
  42. data/spec/random_compat.rb +24 -0
  43. data/spec/spec_helper.rb +21 -0
  44. data/spec/unpacker_spec.rb +128 -0
  45. metadata +183 -0
@@ -0,0 +1,288 @@
1
+ /*
2
+ * MessagePack for Ruby
3
+ *
4
+ * Copyright (C) 2008-2012 FURUHASHI Sadayuki
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 "packsnap.h"
20
+ #include "compat.h"
21
+ #include "ruby.h"
22
+ #include "packer.h"
23
+ #include "packer_class.hh"
24
+ #include "buffer_class.hh"
25
+
26
+ VALUE cMessagePack_Packer;
27
+
28
+ static ID s_to_msgpack;
29
+ static ID s_write;
30
+
31
+ //static VALUE s_packer_value;
32
+ //static msgpack_packer_t* s_packer;
33
+
34
+ #define PACKER(from, name) \
35
+ msgpack_packer_t* name; \
36
+ Data_Get_Struct(from, msgpack_packer_t, name); \
37
+ if(name == NULL) { \
38
+ rb_raise(rb_eArgError, "NULL found for " # name " when shouldn't be."); \
39
+ }
40
+
41
+ static void Packer_free(msgpack_packer_t* pk)
42
+ {
43
+ if(pk == NULL) {
44
+ return;
45
+ }
46
+ msgpack_packer_destroy(pk);
47
+ free(pk);
48
+ }
49
+
50
+ static VALUE Packer_alloc(VALUE klass)
51
+ {
52
+ msgpack_packer_t* pk = ALLOC_N(msgpack_packer_t, 1);
53
+ msgpack_packer_init(pk);
54
+
55
+ VALUE self = Data_Wrap_Struct(klass, msgpack_packer_mark, Packer_free, pk);
56
+
57
+ msgpack_packer_set_to_msgpack_method(pk, s_to_msgpack, self);
58
+ pk->buffer_ref = MessagePack_Buffer_wrap(PACKER_BUFFER_(pk), self);
59
+
60
+ return self;
61
+ }
62
+
63
+ static VALUE Packer_initialize(int argc, VALUE* argv, VALUE self)
64
+ {
65
+ VALUE io = Qnil;
66
+ VALUE options = Qnil;
67
+
68
+ if(argc == 0 || (argc == 1 && argv[0] == Qnil)) {
69
+ /* Qnil */
70
+
71
+ } else if(argc == 1) {
72
+ VALUE v = argv[0];
73
+ if(rb_type(v) == T_HASH) {
74
+ options = v;
75
+ } else {
76
+ io = v;
77
+ }
78
+
79
+ } else if(argc == 2) {
80
+ io = argv[0];
81
+ options = argv[1];
82
+ if(rb_type(options) != T_HASH) {
83
+ rb_raise(rb_eArgError, "expected Hash but found %s.", rb_obj_classname(io));
84
+ }
85
+
86
+ } else {
87
+ rb_raise(rb_eArgError, "wrong number of arguments (%d for 0..1)", argc);
88
+ }
89
+
90
+ PACKER(self, pk);
91
+ if(io != Qnil || options != Qnil) {
92
+ MessagePack_Buffer_initialize(PACKER_BUFFER_(pk), io, options);
93
+ }
94
+
95
+ // TODO options
96
+
97
+ return self;
98
+ }
99
+
100
+ static VALUE Packer_buffer(VALUE self)
101
+ {
102
+ PACKER(self, pk);
103
+ return pk->buffer_ref;
104
+ }
105
+
106
+ static VALUE Packer_write(VALUE self, VALUE v)
107
+ {
108
+ PACKER(self, pk);
109
+ msgpack_packer_write_value(pk, v);
110
+ return self;
111
+ }
112
+
113
+ static VALUE Packer_write_nil(VALUE self)
114
+ {
115
+ PACKER(self, pk);
116
+ msgpack_packer_write_nil(pk);
117
+ return self;
118
+ }
119
+
120
+ static VALUE Packer_write_array_header(VALUE self, VALUE n)
121
+ {
122
+ PACKER(self, pk);
123
+ msgpack_packer_write_array_header(pk, NUM2UINT(n));
124
+ return self;
125
+ }
126
+
127
+ static VALUE Packer_write_map_header(VALUE self, VALUE n)
128
+ {
129
+ PACKER(self, pk);
130
+ msgpack_packer_write_map_header(pk, NUM2UINT(n));
131
+ return self;
132
+ }
133
+
134
+ static VALUE Packer_flush(VALUE self)
135
+ {
136
+ PACKER(self, pk);
137
+ msgpack_buffer_flush(PACKER_BUFFER_(pk));
138
+ return self;
139
+ }
140
+
141
+ static VALUE Packer_clear(VALUE self)
142
+ {
143
+ PACKER(self, pk);
144
+ msgpack_buffer_clear(PACKER_BUFFER_(pk));
145
+ return Qnil;
146
+ }
147
+
148
+ static VALUE Packer_size(VALUE self)
149
+ {
150
+ PACKER(self, pk);
151
+ size_t size = msgpack_buffer_all_readable_size(PACKER_BUFFER_(pk));
152
+ return SIZET2NUM(size);
153
+ }
154
+
155
+ static VALUE Packer_empty_p(VALUE self)
156
+ {
157
+ PACKER(self, pk);
158
+ if(msgpack_buffer_top_readable_size(PACKER_BUFFER_(pk)) == 0) {
159
+ return Qtrue;
160
+ } else {
161
+ return Qfalse;
162
+ }
163
+ }
164
+
165
+ static VALUE Packer_to_str(VALUE self)
166
+ {
167
+ PACKER(self, pk);
168
+ return msgpack_buffer_all_as_string(PACKER_BUFFER_(pk));
169
+ }
170
+
171
+ static VALUE Packer_to_a(VALUE self)
172
+ {
173
+ PACKER(self, pk);
174
+ return msgpack_buffer_all_as_string_array(PACKER_BUFFER_(pk));
175
+ }
176
+
177
+ static VALUE Packer_write_to(VALUE self, VALUE io)
178
+ {
179
+ PACKER(self, pk);
180
+ size_t sz = msgpack_buffer_flush_to_io(PACKER_BUFFER_(pk), io, s_write, true);
181
+ return ULONG2NUM(sz);
182
+ }
183
+
184
+ //static VALUE Packer_append(VALUE self, VALUE string_or_buffer)
185
+ //{
186
+ // PACKER(self, pk);
187
+ //
188
+ // // TODO if string_or_buffer is a Buffer
189
+ // VALUE string = string_or_buffer;
190
+ //
191
+ // msgpack_buffer_append_string(PACKER_BUFFER_(pk), string);
192
+ //
193
+ // return self;
194
+ //}
195
+
196
+ extern "C"
197
+ VALUE MessagePack_pack(int argc, VALUE* argv)
198
+ {
199
+ // TODO options
200
+
201
+ VALUE v;
202
+ VALUE io = Qnil;
203
+
204
+ switch(argc) {
205
+ case 2:
206
+ io = argv[1];
207
+ /* pass-through */
208
+ case 1:
209
+ v = argv[0];
210
+ break;
211
+ default:
212
+ rb_raise(rb_eArgError, "wrong number of arguments (%d for 1..2)", argc);
213
+ }
214
+
215
+ VALUE self = Packer_alloc(cMessagePack_Packer);
216
+ PACKER(self, pk);
217
+ //msgpack_packer_reset(s_packer);
218
+ //msgpack_buffer_reset_io(PACKER_BUFFER_(s_packer));
219
+
220
+ if(io != Qnil) {
221
+ MessagePack_Buffer_initialize(PACKER_BUFFER_(pk), io, Qnil);
222
+ }
223
+
224
+ msgpack_packer_write_value(pk, v);
225
+
226
+ VALUE retval;
227
+ if(io != Qnil) {
228
+ msgpack_buffer_flush(PACKER_BUFFER_(pk));
229
+ retval = Qnil;
230
+ } else {
231
+ retval = msgpack_buffer_all_as_string(PACKER_BUFFER_(pk));
232
+ }
233
+
234
+ msgpack_buffer_clear(PACKER_BUFFER_(pk)); /* to free rmem before GC */
235
+ return retval;
236
+ }
237
+
238
+ static VALUE MessagePack_dump_module_method(int argc, VALUE* argv, VALUE mod)
239
+ {
240
+ UNUSED(mod);
241
+ return MessagePack_pack(argc, argv);
242
+ }
243
+
244
+ static VALUE MessagePack_pack_module_method(int argc, VALUE* argv, VALUE mod)
245
+ {
246
+ UNUSED(mod);
247
+ return MessagePack_pack(argc, argv);
248
+ }
249
+
250
+ extern "C"
251
+ void MessagePack_Packer_module_init(VALUE mMessagePack)
252
+ {
253
+ s_to_msgpack = rb_intern("to_msgpack");
254
+ s_write = rb_intern("write");
255
+
256
+ cMessagePack_Packer = rb_define_class_under(mMessagePack, "Packer", rb_cObject);
257
+
258
+ rb_define_alloc_func(cMessagePack_Packer, (VALUE (*)(VALUE))Packer_alloc);
259
+
260
+ rb_define_method(cMessagePack_Packer, "initialize", (VALUE (*)(...))Packer_initialize, -1);
261
+ rb_define_method(cMessagePack_Packer, "buffer", (VALUE (*)(...))Packer_buffer, 0);
262
+ rb_define_method(cMessagePack_Packer, "write", (VALUE (*)(...))Packer_write, 1);
263
+ rb_define_alias(cMessagePack_Packer, "pack", "write");
264
+ rb_define_method(cMessagePack_Packer, "write_nil", (VALUE (*)(...))Packer_write_nil, 0);
265
+ rb_define_method(cMessagePack_Packer, "write_array_header", (VALUE (*)(...))Packer_write_array_header, 1);
266
+ rb_define_method(cMessagePack_Packer, "write_map_header", (VALUE (*)(...))Packer_write_map_header, 1);
267
+ rb_define_method(cMessagePack_Packer, "flush", (VALUE (*)(...))Packer_flush, 0);
268
+
269
+ /* delegation methods */
270
+ rb_define_method(cMessagePack_Packer, "clear", (VALUE (*)(...))Packer_clear, 0);
271
+ rb_define_method(cMessagePack_Packer, "size", (VALUE (*)(...))Packer_size, 0);
272
+ rb_define_method(cMessagePack_Packer, "empty?", (VALUE (*)(...))Packer_empty_p, 0);
273
+ rb_define_method(cMessagePack_Packer, "write_to", (VALUE (*)(...))Packer_write_to, 1);
274
+ rb_define_method(cMessagePack_Packer, "to_str", (VALUE (*)(...))Packer_to_str, 0);
275
+ rb_define_alias(cMessagePack_Packer, "to_s", "to_str");
276
+ rb_define_method(cMessagePack_Packer, "to_a", (VALUE (*)(...))Packer_to_a, 0);
277
+ //rb_define_method(cMessagePack_Packer, "append", Packer_append, 1);
278
+ //rb_define_alias(cMessagePack_Packer, "<<", "append");
279
+
280
+ //s_packer_value = Packer_alloc(cMessagePack_Packer);
281
+ //rb_gc_register_address(&s_packer_value);
282
+ //Data_Get_Struct(s_packer_value, msgpack_packer_t, s_packer);
283
+
284
+ /* MessagePack.pack(x) */
285
+ rb_define_module_function(mMessagePack, "pack", (VALUE (*)(...))MessagePack_pack_module_method, -1);
286
+ rb_define_module_function(mMessagePack, "dump", (VALUE (*)(...))MessagePack_dump_module_method, -1);
287
+ }
288
+
@@ -0,0 +1,32 @@
1
+ /*
2
+ * MessagePack for Ruby
3
+ *
4
+ * Copyright (C) 2008-2012 FURUHASHI Sadayuki
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_PACKER_CLASS_H__
19
+ #define MSGPACK_RUBY_PACKER_CLASS_H__
20
+
21
+ #include "packer.h"
22
+
23
+ extern VALUE cMessagePack_Packer;
24
+
25
+ extern "C"
26
+ void MessagePack_Packer_module_init(VALUE mMessagePack);
27
+
28
+ extern "C"
29
+ VALUE MessagePack_pack(int argc, VALUE* argv);
30
+
31
+ #endif
32
+
@@ -0,0 +1,4 @@
1
+ #include "ruby.h"
2
+ static VALUE rb_mPacksnap;
3
+ static VALUE rb_ePacksnap;
4
+
@@ -0,0 +1,52 @@
1
+ /*
2
+ * MessagePack for Ruby
3
+ *
4
+ * Copyright (C) 2008-2012 FURUHASHI Sadayuki
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 "packsnap.h"
20
+
21
+ #include "buffer_class.hh"
22
+ #include "packer_class.hh"
23
+ #include "unpacker_class.hh"
24
+
25
+ #ifdef COMPAT_HAVE_ENCODING
26
+ /* see compat.h*/
27
+ int s_enc_utf8;
28
+ int s_enc_ascii8bit;
29
+ int s_enc_usascii;
30
+ VALUE s_enc_utf8_value;
31
+ #endif
32
+
33
+ extern "C"
34
+ void Init_packsnap(void)
35
+ {
36
+ #ifdef COMPAT_HAVE_ENCODING
37
+ s_enc_ascii8bit = rb_ascii8bit_encindex();
38
+ s_enc_utf8 = rb_utf8_encindex();
39
+ s_enc_usascii = rb_usascii_encindex();
40
+ s_enc_utf8_value = rb_enc_from_encoding(rb_utf8_encoding());
41
+ #endif
42
+
43
+ VALUE mMessagePack = rb_define_module("Packsnap");
44
+ rb_mPacksnap = mMessagePack;
45
+
46
+ rb_ePacksnap = rb_define_class_under(rb_mPacksnap, "Error", rb_eStandardError);
47
+
48
+ MessagePack_Buffer_module_init(mMessagePack);
49
+ MessagePack_Packer_module_init(mMessagePack);
50
+ MessagePack_Unpacker_module_init(mMessagePack);
51
+ }
52
+
@@ -0,0 +1,110 @@
1
+ /*
2
+ * MessagePack for Ruby
3
+ *
4
+ * Copyright (C) 2008-2012 FURUHASHI Sadayuki
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 "rmem.h"
20
+
21
+ void msgpack_rmem_init(msgpack_rmem_t* pm)
22
+ {
23
+ memset(pm, 0, sizeof(msgpack_rmem_t));
24
+ pm->head.pages = (char*)malloc(MSGPACK_RMEM_PAGE_SIZE * 32);
25
+ pm->head.mask = 0xffffffff; /* all bit is 1 = available */
26
+ }
27
+
28
+ void msgpack_rmem_destroy(msgpack_rmem_t* pm)
29
+ {
30
+ msgpack_rmem_chunk_t* c = pm->array_first;
31
+ msgpack_rmem_chunk_t* cend = pm->array_last;
32
+ for(; c != cend; c++) {
33
+ free(c->pages);
34
+ }
35
+ free(pm->head.pages);
36
+ free(pm->array_first);
37
+ }
38
+
39
+ void* _msgpack_rmem_alloc2(msgpack_rmem_t* pm)
40
+ {
41
+ msgpack_rmem_chunk_t* c = pm->array_first;
42
+ msgpack_rmem_chunk_t* last = pm->array_last;
43
+ for(; c != last; c++) {
44
+ if(_msgpack_rmem_chunk_available(c)) {
45
+ void* mem = _msgpack_rmem_chunk_alloc(c);
46
+
47
+ /* move to head */
48
+ msgpack_rmem_chunk_t tmp = pm->head;
49
+ pm->head = *c;
50
+ *c = tmp;
51
+ return mem;
52
+ }
53
+ }
54
+
55
+ if(c == pm->array_end) {
56
+ size_t capacity = c - pm->array_first;
57
+ size_t length = last - pm->array_first;
58
+ capacity = (capacity == 0) ? 8 : capacity * 2;
59
+ msgpack_rmem_chunk_t* array = (msgpack_rmem_chunk_t*)realloc(pm->array_first, capacity * sizeof(msgpack_rmem_chunk_t));
60
+ pm->array_first = array;
61
+ pm->array_last = array + length;
62
+ pm->array_end = array + capacity;
63
+ }
64
+
65
+ /* allocate new chunk */
66
+ c = pm->array_last++;
67
+
68
+ /* move to head */
69
+ msgpack_rmem_chunk_t tmp = pm->head;
70
+ pm->head = *c;
71
+ *c = tmp;
72
+
73
+ pm->head.mask = 0xffffffff & (~1); /* first chunk is already allocated */
74
+ pm->head.pages = (char*)malloc(MSGPACK_RMEM_PAGE_SIZE * 32);
75
+
76
+ return pm->head.pages;
77
+ }
78
+
79
+ static inline void handle_empty_chunk(msgpack_rmem_t* pm, msgpack_rmem_chunk_t* c)
80
+ {
81
+ if(pm->array_first->mask == 0xffffffff) {
82
+ /* free and move to last */
83
+ pm->array_last--;
84
+ free(c->pages);
85
+ *c = *pm->array_last;
86
+ return;
87
+ }
88
+
89
+ /* move to first */
90
+ msgpack_rmem_chunk_t tmp = *pm->array_first;
91
+ *pm->array_first = *c;
92
+ *c = tmp;
93
+ }
94
+
95
+ bool _msgpack_rmem_free2(msgpack_rmem_t* pm, void* mem)
96
+ {
97
+ /* search from last */
98
+ msgpack_rmem_chunk_t* c = pm->array_last - 1;
99
+ msgpack_rmem_chunk_t* before_first = pm->array_first - 1;
100
+ for(; c != before_first; c--) {
101
+ if(_msgpack_rmem_chunk_try_free(c, mem)) {
102
+ if(c != pm->array_first && c->mask == 0xffffffff) {
103
+ handle_empty_chunk(pm, c);
104
+ }
105
+ return true;
106
+ }
107
+ }
108
+ return false;
109
+ }
110
+