sereal 0.0.9 → 0.0.10
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/bin/rsrl +14 -4
- data/ext/sereal/buffer.h +17 -2
- data/ext/sereal/decode.c +113 -20
- data/ext/sereal/decode.h +6 -4
- data/ext/sereal/encode.c +83 -25
- data/ext/sereal/proto.h +5 -2
- data/ext/sereal/sereal.c +238 -28
- data/ext/sereal/sereal.h +34 -11
- metadata +7 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0e7b9572c05e8fd8dbb6d80be1a9cd5d15ecabec
|
4
|
+
data.tar.gz: a7dc03f83063a2f39378ed99dedf96345440aaa7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ac8b523cf687622f153b5778cb107dae447d5a68f9fb702cc71abb2240e4c62dc173665ac0a6cbd50a4955f03c2658ead475d1e7dd611d208d42c630c8ab4411
|
7
|
+
data.tar.gz: 560fea321249afbce734d49e633886fd33fa371b3e11cb4da9d9ae653f56262acc40c560d4044fb59bb14bc776a40ebcfa2db0b65cca0bd37342f80e67f4da0f
|
data/bin/rsrl
CHANGED
@@ -1,12 +1,23 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
+
require 'pp'
|
3
|
+
|
2
4
|
begin
|
3
5
|
require File.join(".",File.dirname(__FILE__),'..','lib','sereal')
|
4
6
|
rescue LoadError
|
5
7
|
require 'sereal'
|
6
8
|
end
|
7
9
|
|
10
|
+
class SerealPerlObject
|
11
|
+
def inspect
|
12
|
+
"#{@class} - #{@value.inspect}"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
8
16
|
content = ENV['Sereal_STREAM'] ? STDIN : ARGF.read
|
9
17
|
compress = Sereal::RAW
|
18
|
+
debug = ENV['Sereal_DEBUG'] ? Sereal::DEBUG : 0
|
19
|
+
debug |= ENV['Sereal_REF'] ? Sereal::REF : 0
|
20
|
+
debug |= ENV['Sereal_COPY'] ? Sereal::COPY : 0
|
10
21
|
|
11
22
|
{'Sereal_SNAPPY' => Sereal::SNAPPY,'Sereal_SNAPPY_INCR' => Sereal::SNAPPY_INCR }.each do |k,v|
|
12
23
|
if ENV[k]
|
@@ -15,10 +26,9 @@ compress = Sereal::RAW
|
|
15
26
|
end
|
16
27
|
|
17
28
|
if ENV['Sereal_STREAM'] || content[0..3] == '=srl'
|
18
|
-
Sereal.decode(content) do |x|
|
19
|
-
|
20
|
-
puts
|
29
|
+
Sereal.decode(content,debug | Sereal::THAW) do |x|
|
30
|
+
PP.pp(x)
|
21
31
|
end
|
22
32
|
else
|
23
|
-
STDOUT.write(Sereal.encode(eval(content), compress))
|
33
|
+
STDOUT.write(Sereal.encode(eval(content), compress | debug))
|
24
34
|
end
|
data/ext/sereal/buffer.h
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
static void s_dump(sereal_t *s);
|
4
4
|
|
5
5
|
static inline void s_free_data_if_not_mine(sereal_t *s) {
|
6
|
-
if (!(s->flags &
|
6
|
+
if (!(s->flags & __NOT_MINE)) {
|
7
7
|
if (s->data)
|
8
8
|
free(s->data);
|
9
9
|
s->data = NULL;
|
@@ -12,6 +12,7 @@ static inline void s_free_data_if_not_mine(sereal_t *s) {
|
|
12
12
|
|
13
13
|
static inline void s_init_tracker(sereal_t *s) {
|
14
14
|
if (s->tracked == Qnil) {
|
15
|
+
SD(s,"initializing tracker");
|
15
16
|
s->tracked = rb_hash_new();
|
16
17
|
rb_gc_mark(s->tracked);
|
17
18
|
}
|
@@ -23,6 +24,13 @@ static inline void s_reset_tracker(sereal_t *s) {
|
|
23
24
|
}
|
24
25
|
}
|
25
26
|
|
27
|
+
static inline void s_init_copy(sereal_t *s) {
|
28
|
+
if (s->copy == Qnil) {
|
29
|
+
s->copy = rb_hash_new();
|
30
|
+
rb_gc_mark(s->copy);
|
31
|
+
}
|
32
|
+
}
|
33
|
+
|
26
34
|
static inline void s_destroy(sereal_t *s) {
|
27
35
|
if (!s)
|
28
36
|
return;
|
@@ -46,6 +54,8 @@ static inline sereal_t * s_create(void) {
|
|
46
54
|
sereal_t *s = s_alloc_or_raise(NULL,sizeof(*s));
|
47
55
|
ZERO(s,sizeof(*s));
|
48
56
|
s->tracked = Qnil;
|
57
|
+
s->copy = Qnil;
|
58
|
+
|
49
59
|
return s;
|
50
60
|
}
|
51
61
|
|
@@ -98,7 +108,7 @@ static inline int s_read_stream(sereal_t *s, u32 end) {
|
|
98
108
|
static inline void *s_get_p_at_pos(sereal_t *s, u32 pos,u32 req) {
|
99
109
|
// returning s->data[pos], so we just make size count from 0
|
100
110
|
if (pos + req >= s->size) {
|
101
|
-
if (s->flags &
|
111
|
+
if (s->flags & __STREAM) {
|
102
112
|
if (s_read_stream(s,pos + req + 1) < 0) {
|
103
113
|
s_raise(s,rb_eRangeError,"stream request for %d bytes failed (err: %s)",
|
104
114
|
req,strerror(errno));
|
@@ -169,6 +179,11 @@ static inline u32 s_shift_position_bang(sereal_t *s, u32 len) {
|
|
169
179
|
return len;
|
170
180
|
}
|
171
181
|
|
182
|
+
static inline void s_set_flag_at_pos(sereal_t *s, u32 pos, u8 flag) {
|
183
|
+
u8 *p = s_get_p_at_pos(s,pos,0);
|
184
|
+
*p |= flag;
|
185
|
+
}
|
186
|
+
|
172
187
|
static void b_dump(u8 *p, u32 len, u32 pos) {
|
173
188
|
int i;
|
174
189
|
|
data/ext/sereal/decode.c
CHANGED
@@ -180,34 +180,112 @@ static VALUE s_read_extend(sereal_t *s, u8 tag) {
|
|
180
180
|
}
|
181
181
|
|
182
182
|
static VALUE s_read_ref(sereal_t *s, u8 tag) {
|
183
|
-
u64 off = s_get_varint_bang(s);
|
184
183
|
if (s->tracked == Qnil)
|
185
184
|
s_raise(s,rb_eArgError,"there are no references stored");
|
186
|
-
|
185
|
+
u64 off = s_get_varint_bang(s);
|
186
|
+
VALUE object = rb_hash_lookup(s->tracked,INT2FIX(off + s->hdr_end));
|
187
|
+
SD(s,"reading reference from offset: %d, id: %d",off + s->hdr_end,FIX2INT(rb_obj_id(object)));
|
188
|
+
return object;
|
187
189
|
}
|
188
190
|
|
191
|
+
#define TRAVEL(s,__stored) \
|
192
|
+
do { \
|
193
|
+
u32 offset = s_get_varint_bang(s) - 1; \
|
194
|
+
__stored = s->pos; \
|
195
|
+
s->pos = offset + s->hdr_end; \
|
196
|
+
SD(s,"going back offset: %d, stored position: %d (tag: %d)",offset,stored_pos,tag); \
|
197
|
+
} while(0)
|
198
|
+
#define BACK(s,__stored) \
|
199
|
+
do { \
|
200
|
+
if (__stored > 0) { \
|
201
|
+
SD(s,"going forward to pos: %d",__stored); \
|
202
|
+
s->pos = __stored; \
|
203
|
+
} \
|
204
|
+
} while(0);
|
205
|
+
|
206
|
+
|
189
207
|
static VALUE s_read_copy(sereal_t *s, u8 tag) {
|
190
|
-
|
191
|
-
|
208
|
+
u32 stored_pos = 0;
|
209
|
+
TRAVEL(s,stored_pos);
|
210
|
+
VALUE object = sereal_to_rb_object(s);
|
211
|
+
BACK(s,stored_pos);
|
212
|
+
return object;
|
213
|
+
}
|
214
|
+
|
215
|
+
|
216
|
+
#define MUST_BE_SOMETHING(__klass,__type) \
|
217
|
+
if (TYPE(__klass) != __type) \
|
218
|
+
s_raise(s,rb_eTypeError,"unexpected object type: %s (expecting: %s(%d) got: %s(%d))",rb_obj_classname(__klass),(__type == T_STRING ? "String" : (__type == T_ARRAY ? "Array" : "_unknown_")),__type, rb_obj_classname(__klass),TYPE(__klass));
|
219
|
+
|
220
|
+
static VALUE s_read_perl_object(sereal_t *s, u8 tag) {
|
221
|
+
u32 stored_pos = 0;
|
222
|
+
if (tag == SRL_HDR_OBJECTV)
|
223
|
+
TRAVEL(s,stored_pos);
|
224
|
+
|
225
|
+
VALUE s_klass = sereal_to_rb_object(s);
|
226
|
+
BACK(s,stored_pos);
|
227
|
+
MUST_BE_SOMETHING(s_klass,T_STRING);
|
228
|
+
|
229
|
+
SD(s,"fetched perl class named: %s",RSTRING_PTR(s_klass));
|
230
|
+
|
231
|
+
VALUE object = sereal_to_rb_object(s);
|
232
|
+
|
233
|
+
VALUE pobj = rb_class_new_instance(0,NULL,SerealPerlObject);
|
234
|
+
rb_ivar_set(pobj,ID_CLASS,s_klass);
|
235
|
+
rb_ivar_set(pobj,ID_VALUE,object);
|
236
|
+
return pobj;
|
192
237
|
}
|
193
238
|
|
239
|
+
static VALUE s_read_object_freeze(sereal_t *s, u8 tag) {
|
240
|
+
if (!(s->flags & __THAW))
|
241
|
+
s_raise(s,rb_eTypeError,"object_freeze received, but decoder is initialized without Sereal::THAW option");
|
242
|
+
|
243
|
+
u32 stored_pos = 0;
|
244
|
+
if (tag == SRL_HDR_OBJECTV_FREEZE)
|
245
|
+
TRAVEL(s,stored_pos);
|
246
|
+
|
247
|
+
VALUE s_klass = sereal_to_rb_object(s);
|
248
|
+
BACK(s,stored_pos);
|
249
|
+
MUST_BE_SOMETHING(s_klass,T_STRING);
|
250
|
+
|
251
|
+
// hash it?
|
252
|
+
VALUE klass = rb_const_get(rb_cObject, rb_intern(RSTRING_PTR(s_klass)));
|
253
|
+
if (!rb_obj_respond_to(klass,THAW,0))
|
254
|
+
s_raise(s,rb_eTypeError,"class: %s does not respond to THAW",
|
255
|
+
rb_obj_classname(s_klass));
|
256
|
+
|
257
|
+
VALUE object = sereal_to_rb_object(s);
|
258
|
+
MUST_BE_SOMETHING(object,T_ARRAY);
|
259
|
+
rb_ary_unshift(object,ID2SYM(SEREAL));
|
260
|
+
|
261
|
+
return rb_funcall2(klass,THAW,RARRAY_LEN(object),RARRAY_PTR(object));
|
262
|
+
}
|
263
|
+
#undef TRAVEL
|
264
|
+
#undef BACK
|
265
|
+
|
194
266
|
VALUE sereal_to_rb_object(sereal_t *s) {
|
195
267
|
u8 t, tracked;
|
196
268
|
S_RECURSE_INC(s);
|
197
269
|
u32 pos;
|
198
|
-
while (s->pos < s->size || (s->flags &
|
270
|
+
while (s->pos < s->size || (s->flags & __STREAM)) {
|
199
271
|
t = s_get_u8_bang(s);
|
200
272
|
tracked = (t & SRL_HDR_TRACK_FLAG ? 1 : 0);
|
201
273
|
t &= ~SRL_HDR_TRACK_FLAG;
|
202
|
-
pos = s->pos;
|
203
274
|
|
204
|
-
|
275
|
+
pos = s->pos;
|
205
276
|
|
206
277
|
VALUE decoded = (*READERS[t])(s,t);
|
278
|
+
|
207
279
|
if (tracked) {
|
208
280
|
s_init_tracker(s);
|
209
|
-
|
281
|
+
SD(s,"tracking object of class: %s(id: %d) at position: %d",rb_obj_classname(decoded),FIX2INT(rb_obj_id(decoded)),pos);
|
282
|
+
VALUE v_pos = INT2FIX(pos);
|
283
|
+
if (rb_hash_lookup(s->tracked,v_pos) == Qnil)
|
284
|
+
rb_hash_aset(s->tracked,INT2FIX(pos),decoded);
|
210
285
|
}
|
286
|
+
|
287
|
+
SD(s,"object: %s: %s",rb_obj_classname(decoded),RSTRING_PTR(rb_funcall(decoded,rb_intern("to_s"),0)));
|
288
|
+
S_RECURSE_DEC(s);
|
211
289
|
return decoded;
|
212
290
|
}
|
213
291
|
s_raise(s,rb_eArgError,"bad packet, or broken decoder");
|
@@ -218,9 +296,19 @@ VALUE method_sereal_decode(VALUE self, VALUE args) {
|
|
218
296
|
u32 argc = RARRAY_LEN(args);
|
219
297
|
if (argc < 1)
|
220
298
|
rb_raise(rb_eArgError,"need at least 1 argument (object)");
|
221
|
-
VALUE payload =
|
299
|
+
VALUE payload = rb_ary_entry(args,0);
|
300
|
+
|
222
301
|
u8 have_block = rb_block_given_p();
|
223
302
|
sereal_t *s = s_create();
|
303
|
+
if (argc == 2) {
|
304
|
+
VALUE flags = rb_ary_entry(args,1);
|
305
|
+
if (flags != Qnil && flags != Qfalse) {
|
306
|
+
if (TYPE(flags) == T_FIXNUM)
|
307
|
+
s->flags = FIX2LONG(flags) & __ARGUMENT_FLAGS;
|
308
|
+
else
|
309
|
+
s_raise(s,rb_eArgError,"second argument must be an integer (used only for flags) %s given",rb_obj_classname(flags));
|
310
|
+
}
|
311
|
+
}
|
224
312
|
u64 offset = 0;
|
225
313
|
|
226
314
|
if (TYPE(payload) == T_FILE) {
|
@@ -229,8 +317,9 @@ VALUE method_sereal_decode(VALUE self, VALUE args) {
|
|
229
317
|
|
230
318
|
rb_io_t *fptr;
|
231
319
|
GetOpenFile(payload, fptr);
|
232
|
-
s->flags |=
|
320
|
+
s->flags |= __STREAM;
|
233
321
|
s->fd = fptr->fd;
|
322
|
+
SD(s,"reading strea with fd: %d",s->fd);
|
234
323
|
} else if (TYPE(payload) != T_STRING) {
|
235
324
|
rb_raise(rb_eTypeError,"can not decode objects of type %s",rb_obj_classname(payload));
|
236
325
|
}
|
@@ -239,14 +328,13 @@ again:
|
|
239
328
|
s->pos = 0;
|
240
329
|
s_reset_tracker(s);
|
241
330
|
|
242
|
-
if (s->flags &
|
331
|
+
if (s->flags & __STREAM) {
|
243
332
|
s->size = 0;
|
244
333
|
s->rsize = 0;
|
245
334
|
if (s_read_stream(s,__MIN_SIZE) < 0) {
|
246
335
|
s_destroy(s);
|
247
336
|
return Qnil;
|
248
337
|
}
|
249
|
-
|
250
338
|
} else {
|
251
339
|
u32 size = RSTRING_LEN(payload) - offset;
|
252
340
|
if (offset > RSTRING_LEN(payload) || (offset > 0 && size < __MIN_SIZE)) {
|
@@ -256,7 +344,7 @@ again:
|
|
256
344
|
if (size < __MIN_SIZE)
|
257
345
|
s_raise(s,rb_eTypeError,"size(%d) is less then min packet size %d, offset: %d",size,__MIN_SIZE,offset);
|
258
346
|
|
259
|
-
s->flags |=
|
347
|
+
s->flags |= __NOT_MINE;
|
260
348
|
s->data = RSTRING_PTR(payload) + offset;
|
261
349
|
s->size = size;
|
262
350
|
}
|
@@ -269,12 +357,15 @@ again:
|
|
269
357
|
u8 suffix = s_get_varint_bang(s);
|
270
358
|
u8 is_compressed;
|
271
359
|
|
272
|
-
if ((version & SRL_PROTOCOL_ENCODING_MASK) == SRL_PROTOCOL_ENCODING_SNAPPY)
|
360
|
+
if ((version & SRL_PROTOCOL_ENCODING_MASK) == SRL_PROTOCOL_ENCODING_SNAPPY) {
|
273
361
|
is_compressed = __SNAPPY;
|
274
|
-
else if ((version & SRL_PROTOCOL_ENCODING_MASK) == SRL_PROTOCOL_ENCODING_SNAPPY_INCR)
|
362
|
+
} else if ((version & SRL_PROTOCOL_ENCODING_MASK) == SRL_PROTOCOL_ENCODING_SNAPPY_INCR) {
|
275
363
|
is_compressed = __SNAPPY_INCR;
|
276
|
-
else
|
364
|
+
} else {
|
277
365
|
is_compressed = __RAW;
|
366
|
+
}
|
367
|
+
|
368
|
+
SD(s,"initialized (s) with compression type: %d",is_compressed);
|
278
369
|
|
279
370
|
if (is_compressed) {
|
280
371
|
u32 uncompressed_len;
|
@@ -283,13 +374,13 @@ again:
|
|
283
374
|
if (is_compressed == __SNAPPY_INCR) {
|
284
375
|
compressed_len = s_get_varint_bang(s);
|
285
376
|
} else {
|
286
|
-
if (s->flags &
|
377
|
+
if (s->flags & __STREAM)
|
287
378
|
s_raise(s,rb_eTypeError,"parsing non incremental compressed objects, from stream of data, is not supported");
|
288
379
|
|
289
380
|
compressed_len = s->size - s->pos;
|
290
381
|
}
|
291
|
-
|
292
|
-
if (s->flags &
|
382
|
+
SD(s,"compressed len: %d",compressed_len);
|
383
|
+
if (s->flags & __STREAM)
|
293
384
|
s_get_p_req_inclusive(s,compressed_len);
|
294
385
|
|
295
386
|
int snappy_header_len = csnappy_get_uncompressed_length(s_get_p_req_inclusive(s,compressed_len),
|
@@ -312,9 +403,11 @@ again:
|
|
312
403
|
s->size = uncompressed_len;
|
313
404
|
offset += s->pos + compressed_len;
|
314
405
|
s->pos = 0;
|
315
|
-
s->flags &= ~
|
406
|
+
s->flags &= ~__NOT_MINE;
|
316
407
|
}
|
408
|
+
|
317
409
|
s->hdr_end = s->pos;
|
410
|
+
SD(s,"header end at %d",s->hdr_end);
|
318
411
|
VALUE result = sereal_to_rb_object(s);
|
319
412
|
if (!is_compressed)
|
320
413
|
offset += s->pos;
|
data/ext/sereal/decode.h
CHANGED
@@ -23,6 +23,8 @@ static VALUE s_read_pad(sereal_t *s, u8 tag);
|
|
23
23
|
static VALUE s_read_extend(sereal_t *s, u8 tag);
|
24
24
|
static VALUE s_read_ref(sereal_t *s, u8 tag);
|
25
25
|
static VALUE s_read_copy(sereal_t *s, u8 tag);
|
26
|
+
static VALUE s_read_object_freeze(sereal_t *s, u8 tag);
|
27
|
+
static VALUE s_read_perl_object(sereal_t *s, u8 tag);
|
26
28
|
|
27
29
|
static VALUE (*READERS[256])(sereal_t *, u8) = {
|
28
30
|
s_read_small_positive_int, // 0 SRL_HDR_POS_LOW
|
@@ -69,14 +71,14 @@ static VALUE (*READERS[256])(sereal_t *, u8) = {
|
|
69
71
|
s_read_ref, // 41 SRL_HDR_REFP
|
70
72
|
s_read_hash, // 42 SRL_HDR_HASH
|
71
73
|
s_read_array, // 43 SRL_HDR_ARRAY
|
72
|
-
|
73
|
-
|
74
|
+
s_read_perl_object, // 44 SRL_HDR_OBJECT
|
75
|
+
s_read_perl_object, // 45 SRL_HDR_OBJECTV
|
74
76
|
s_read_ref, // 46 SRL_HDR_ALIAS
|
75
77
|
s_read_copy, // 47 SRL_HDR_COPY
|
76
78
|
s_default_reader, /* XXX */ // 48 SRL_HDR_WEAKEN
|
77
79
|
s_read_regexp, // 49 SRL_HDR_REGEXP
|
78
|
-
|
79
|
-
|
80
|
+
s_read_object_freeze, // 50 OBJECT_FREEZE
|
81
|
+
s_read_object_freeze, // 51 OBJECTV_FREEZE
|
80
82
|
s_default_reader, /* XXX */ // 52
|
81
83
|
s_default_reader, /* XXX */ // 53
|
82
84
|
s_default_reader, /* XXX */ // 54
|
data/ext/sereal/encode.c
CHANGED
@@ -28,6 +28,12 @@
|
|
28
28
|
#elif T_NIL > W_SIZE
|
29
29
|
#define W_SIZE T_NIL
|
30
30
|
#endif
|
31
|
+
#define COMPLEX(object) \
|
32
|
+
(TYPE(object) == T_ARRAY || \
|
33
|
+
TYPE(object) == T_HASH || \
|
34
|
+
TYPE(object) == T_SYMBOL || \
|
35
|
+
TYPE(object) == T_OBJECT || \
|
36
|
+
TYPE(object) == T_STRING)
|
31
37
|
|
32
38
|
/* function pointer array */
|
33
39
|
void (*WRITER[W_SIZE])(sereal_t *,VALUE);
|
@@ -146,15 +152,57 @@ static void s_append_hash(sereal_t *s, VALUE object) {
|
|
146
152
|
convert symbols to strings
|
147
153
|
*/
|
148
154
|
static void s_append_symbol(sereal_t *s, VALUE object) {
|
149
|
-
|
150
|
-
|
155
|
+
VALUE string = rb_sym_to_s(object);
|
156
|
+
s_append_rb_string(s,string);
|
151
157
|
}
|
152
158
|
|
159
|
+
static void s_append_copy(sereal_t *s, VALUE object) {
|
160
|
+
u32 pos = FIX2LONG(object);
|
161
|
+
s_append_hdr_with_varint(s,SRL_HDR_COPY,pos - s->hdr_end + 1);
|
162
|
+
}
|
163
|
+
|
164
|
+
static VALUE s_copy_or_keep_in_mind(sereal_t *s, VALUE object) {
|
165
|
+
if (s->copy == Qnil)
|
166
|
+
return Qnil;
|
167
|
+
|
168
|
+
VALUE stored_position = rb_hash_lookup(s->copy,object);
|
169
|
+
if (stored_position == Qnil)
|
170
|
+
rb_hash_aset(s->copy,object,INT2FIX(s->pos));
|
171
|
+
return stored_position;
|
172
|
+
}
|
173
|
+
|
174
|
+
|
153
175
|
/*
|
154
|
-
|
176
|
+
try to FREEZE the object so it can be THAW-ed at decode time
|
177
|
+
if not possible (no Sereal::THAW argument or object does not
|
178
|
+
repsond to FREEZE), just call object.to_srl and serialize the
|
179
|
+
result
|
155
180
|
*/
|
156
181
|
static void s_append_object(sereal_t *s, VALUE object) {
|
157
|
-
|
182
|
+
if (s->flags & __THAW && rb_obj_respond_to(object,FREEZE,0)) {
|
183
|
+
VALUE klass = rb_class_name(CLASS_OF(object));
|
184
|
+
VALUE copy = s_copy_or_keep_in_mind(s,klass);
|
185
|
+
if (copy != Qnil) {
|
186
|
+
s_append_u8(s,SRL_HDR_OBJECTV_FREEZE);
|
187
|
+
s_append_copy(s,copy);
|
188
|
+
} else {
|
189
|
+
s_append_u8(s,SRL_HDR_OBJECT_FREEZE);
|
190
|
+
s_append_rb_string(s,rb_class_name(CLASS_OF(object)));
|
191
|
+
}
|
192
|
+
VALUE frozen = rb_funcall(object,FREEZE,1,ID2SYM(SEREAL));
|
193
|
+
if (TYPE(frozen) != T_ARRAY)
|
194
|
+
s_raise(s,rb_eTypeError,"Sereal spec requires FREEZE to return array instead %s",rb_obj_classname(frozen));
|
195
|
+
|
196
|
+
// REFN + ARRAY
|
197
|
+
s_append_u8(s,SRL_HDR_REFN);
|
198
|
+
s_append_hdr_with_varint(s,SRL_HDR_ARRAY,RARRAY_LEN(frozen));
|
199
|
+
int i;
|
200
|
+
for (i = 0; i < RARRAY_LEN(frozen); i++)
|
201
|
+
rb_object_to_sereal(s,rb_ary_entry(frozen,i));
|
202
|
+
|
203
|
+
} else {
|
204
|
+
rb_object_to_sereal(s,rb_funcall(object,TO_SRL,0));
|
205
|
+
}
|
158
206
|
}
|
159
207
|
|
160
208
|
|
@@ -219,31 +267,31 @@ static void s_append_nil(sereal_t *s, VALUE object) {
|
|
219
267
|
static void s_append_refp(sereal_t *s, VALUE object) {
|
220
268
|
u32 pos = FIX2LONG(object);
|
221
269
|
s_append_hdr_with_varint(s,SRL_HDR_REFP,pos - s->hdr_end + 1);
|
222
|
-
|
223
|
-
*reference |= SRL_HDR_TRACK_FLAG;
|
270
|
+
s_set_flag_at_pos(s,pos,SRL_HDR_TRACK_FLAG);
|
224
271
|
}
|
225
272
|
|
226
273
|
/* writer function pointers */
|
227
274
|
static void rb_object_to_sereal(sereal_t *s, VALUE object) {
|
228
275
|
S_RECURSE_INC(s);
|
229
276
|
u32 pos = s->pos;
|
230
|
-
|
231
|
-
|
232
|
-
TYPE(object) == T_ARRAY ||
|
233
|
-
TYPE(object) == T_HASH ||
|
234
|
-
TYPE(object) == T_SYMBOL ||
|
235
|
-
TYPE(object) == T_STRING) {
|
236
|
-
|
277
|
+
if (COMPLEX(object)) {
|
278
|
+
VALUE stored;
|
237
279
|
if (s->tracked != Qnil) {
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
280
|
+
if (s->tracked != Qnil) {
|
281
|
+
VALUE id = rb_obj_id(object);
|
282
|
+
stored = rb_hash_lookup(s->tracked,id);
|
283
|
+
if (stored != Qnil) {
|
284
|
+
s_append_refp(s,stored);
|
285
|
+
goto out;
|
286
|
+
}
|
244
287
|
rb_hash_aset(s->tracked,id,INT2FIX(pos));
|
245
288
|
}
|
246
289
|
}
|
290
|
+
stored = s_copy_or_keep_in_mind(s,object);
|
291
|
+
if (stored != Qnil) {
|
292
|
+
s_append_copy(s,stored);
|
293
|
+
goto out;
|
294
|
+
}
|
247
295
|
}
|
248
296
|
|
249
297
|
(*WRITER[TYPE(object)])(s,object);
|
@@ -267,16 +315,21 @@ void fixup_varint_from_to(u8 *varint_start, u8 *varint_end, u32 number) {
|
|
267
315
|
}
|
268
316
|
}
|
269
317
|
|
270
|
-
|
318
|
+
|
319
|
+
/*
|
320
|
+
* Encodes object into Sereal
|
321
|
+
*/
|
322
|
+
VALUE
|
323
|
+
method_sereal_encode(VALUE self, VALUE args) {
|
271
324
|
u32 argc = RARRAY_LEN(args);
|
272
325
|
if (argc < 1)
|
273
326
|
rb_raise(rb_eArgError,"need at least 1 argument (object)");
|
274
327
|
|
275
328
|
sereal_t *s = s_create();
|
276
|
-
VALUE payload =
|
329
|
+
VALUE payload = rb_ary_entry(args,0);
|
277
330
|
VALUE compress = Qfalse;
|
278
331
|
if (argc == 2)
|
279
|
-
compress =
|
332
|
+
compress = rb_ary_entry(args,1);
|
280
333
|
|
281
334
|
u8 do_compress;
|
282
335
|
u8 version = SRL_PROTOCOL_VERSION;
|
@@ -286,10 +339,15 @@ VALUE method_sereal_encode(VALUE self, VALUE args) {
|
|
286
339
|
} else {
|
287
340
|
do_compress = (compress == Qtrue ? 1 : 0);
|
288
341
|
}
|
289
|
-
|
290
|
-
|
342
|
+
|
343
|
+
s->flags = do_compress & __ARGUMENT_FLAGS;
|
344
|
+
do_compress &=~ __ARGUMENT_FLAGS;
|
345
|
+
if (s->flags & __REF)
|
291
346
|
s_init_tracker(s);
|
292
|
-
|
347
|
+
|
348
|
+
if (s->flags & __COPY)
|
349
|
+
s_init_copy(s);
|
350
|
+
|
293
351
|
switch(do_compress) {
|
294
352
|
case __SNAPPY:
|
295
353
|
version |= SRL_PROTOCOL_ENCODING_SNAPPY;
|
data/ext/sereal/proto.h
CHANGED
@@ -33,16 +33,19 @@
|
|
33
33
|
#define SRL_HDR_ARRAY ((char)43) /* <COUNT-VARINT> [<ITEM-TAG> ...] - count followed by items */
|
34
34
|
#define SRL_HDR_OBJECT ((char)44) /* <STR-TAG> <ITEM-TAG> - class, object-item */
|
35
35
|
#define SRL_HDR_OBJECTV ((char)45) /* <OFFSET-VARINT> <ITEM-TAG> - offset of previously used classname tag - object-item */
|
36
|
+
|
36
37
|
#define SRL_HDR_ALIAS ((char)46) /* <OFFSET-VARINT> - alias to item defined at offset */
|
37
38
|
#define SRL_HDR_COPY ((char)47) /* <OFFSET-VARINT> - copy of item defined at offset */
|
38
39
|
|
39
40
|
#define SRL_HDR_WEAKEN ((char)48) /* <REF-TAG> - Weaken the following reference */
|
40
41
|
#define SRL_HDR_REGEXP ((char)49) /* <PATTERN-STR-TAG> <MODIFIERS-STR-TAG>*/
|
42
|
+
#define SRL_HDR_OBJECT_FREEZE ((char)50) /* <STR-TAG> <ITEM-TAG> - class, object-item. Need to call "THAW" method on class after decoding */
|
43
|
+
#define SRL_HDR_OBJECTV_FREEZE ((char)51) /* <OFFSET-VARINT> <ITEM-TAG> - (OBJECTV_FREEZE is to OBJECT_FREEZE as OBJECTV is to OBJECT) */
|
41
44
|
|
42
45
|
/* Note: Can do reserved check with a range now, but as we start using
|
43
46
|
* them, might have to explicit == check later. */
|
44
|
-
#define SRL_HDR_RESERVED ((char)
|
45
|
-
#define SRL_HDR_RESERVED_LOW ((char)
|
47
|
+
#define SRL_HDR_RESERVED ((char)52) /* reserved */
|
48
|
+
#define SRL_HDR_RESERVED_LOW ((char)52)
|
46
49
|
#define SRL_HDR_RESERVED_HIGH ((char)57)
|
47
50
|
|
48
51
|
#define SRL_HDR_FALSE ((char)58) /* false (PL_sv_no) */
|
data/ext/sereal/sereal.c
CHANGED
@@ -2,36 +2,44 @@
|
|
2
2
|
#include "encode.h"
|
3
3
|
|
4
4
|
VALUE Sereal = Qnil;
|
5
|
+
VALUE SerealPerlObject = Qnil;
|
6
|
+
ID FREEZE;
|
7
|
+
ID THAW;
|
8
|
+
ID TO_SRL;
|
9
|
+
ID SEREAL;
|
10
|
+
ID ID_CLASS;
|
11
|
+
ID ID_VALUE;
|
5
12
|
void Init_sereal();
|
6
13
|
|
7
14
|
/*
|
8
15
|
* Encode/Decode object using Sereal binary protocol:
|
9
16
|
* https://github.com/Sereal/Sereal/blob/master/sereal_spec.pod
|
10
17
|
*
|
11
|
-
*
|
12
|
-
* Sereal.encode(object,Sereal::SNAPPY_INCR) -> snappy compressed blob
|
13
|
-
* Sereal.encode(object,Sereal::SNAPPY) -> snappy compressed blob
|
18
|
+
* ==install:
|
14
19
|
*
|
15
|
-
*
|
16
|
-
* decoder will know what to do.
|
20
|
+
* $ gem install sereal
|
17
21
|
*
|
18
|
-
*
|
19
|
-
*
|
22
|
+
* or you can build it from github which requires:
|
23
|
+
* 1. rake compiler - <code>gem install rake-compiler</code> (https://github.com/luislavena/rake-compiler)
|
24
|
+
* 2. ruby 1.9+ or rubinius supporting 1.9+
|
20
25
|
*
|
21
|
-
*
|
22
|
-
*
|
23
|
-
*
|
24
|
-
*
|
25
|
-
* two = [ one, one ]
|
26
|
-
* Sereal.encode(two,Sereal::REF)
|
27
|
-
* will send 'one' only once, and one REFP that points to the first one
|
28
|
-
* it uses one.object_id as a hash key in a local tracker hash
|
29
|
-
* and if it sees this object_id again it just sends the offset.
|
26
|
+
* $ git clone https://github.com/Sereal/Sereal
|
27
|
+
* $ cd Sereal/ruby
|
28
|
+
* $ gem build sereal.gemspec
|
29
|
+
* $ gem install sereal-0.0.?.gem
|
30
30
|
*
|
31
|
+
* ==serialize:
|
32
|
+
* require 'sereal'
|
33
|
+
* Sereal.encode(object)
|
31
34
|
*
|
32
|
-
*
|
33
|
-
*
|
34
|
-
*
|
35
|
+
* ===serializing objects
|
36
|
+
* if Sereal::THAW option is given the encoder will try to call FREEZE() instance method on
|
37
|
+
* the object beeing serialized, and it will serialize the class name + the output of FREEZE (look the THAW constant for more information)
|
38
|
+
* if the object does not respond to FREEZE it will call <code>to_srl</code> and serialize the result of that
|
39
|
+
* ==deserialize:
|
40
|
+
* require 'sereal'
|
41
|
+
* Sereal.decode(blob)
|
42
|
+
* If the blob contains multiple compressed objects
|
35
43
|
* sub-blobs you should call it with:
|
36
44
|
*
|
37
45
|
* Sereal.decode(blob) do |decoded|
|
@@ -39,6 +47,7 @@ void Init_sereal();
|
|
39
47
|
* end
|
40
48
|
*
|
41
49
|
* otherwise only the first decoded object will be returned
|
50
|
+
* ===stream decoding
|
42
51
|
* there is also streaming support which takes any kind of IO object
|
43
52
|
* like socket, or just regular File, and it is really easy to use:
|
44
53
|
*
|
@@ -46,7 +55,7 @@ void Init_sereal();
|
|
46
55
|
* # do something with the decoded object
|
47
56
|
* end
|
48
57
|
*
|
49
|
-
* it works both with
|
58
|
+
* it works both with SNAPPY_INCR and with just combined sereal packets.
|
50
59
|
* another example but with TCPSocket:
|
51
60
|
*
|
52
61
|
* s = TCPSocket.new 'localhost', 2000
|
@@ -54,15 +63,216 @@ void Init_sereal();
|
|
54
63
|
* # do something with the decoded object
|
55
64
|
* end
|
56
65
|
*
|
66
|
+
* ===multiple packets in one buffer
|
67
|
+
* it also supports decoding of multiple packets in one buffer:
|
68
|
+
*
|
69
|
+
* buf = ""
|
70
|
+
* buf << Sereal.encode([1,2,3],Sereal::SNAPPY_INCR)
|
71
|
+
* buf << Sereal.encode([3,4,5])
|
72
|
+
* buf << Sereal.encode([7,8,9],Sereal::SNAPPY_INCR)
|
73
|
+
* Sereal.decode(buf) do |decoded|
|
74
|
+
* p decoded
|
75
|
+
* end
|
76
|
+
* ==Sereal.encode() and Sereal.decode() accept:
|
77
|
+
* 1. compression types: RAW, SNAPPY_INCR, and SNAPPY
|
78
|
+
* 2. flags: REF, COPY, THAW and DEBUG
|
79
|
+
*
|
80
|
+
* flags and compression types can be used in combinations like:
|
81
|
+
*
|
82
|
+
* Sereal.encode([1,2,3],Sereal::REF|Sereal::COPY|Sereal::THAW|Sereal::SNAPPY_INCR)
|
83
|
+
*
|
84
|
+
* but you can not use 2 types of compression in the same time
|
85
|
+
*
|
86
|
+
* ==LZ4
|
87
|
+
* For brief period (version 0.0.5 to 0.0.6) there was a support for LZ4 and LZ4HC, which was pushed to the master branch by mistake. if you are depending on it please convert yout data using <code>bin/rsrl</code> or just use <code>0.0.5</code> version of the sereal gem.
|
88
|
+
*
|
89
|
+
* gem 'sereal', '= 0.0.5'
|
90
|
+
* #or
|
91
|
+
* $ gem install sereal -v 0.0.5
|
92
|
+
*
|
57
93
|
*/
|
58
94
|
void Init_sereal() {
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
95
|
+
TO_SRL = rb_intern("to_srl");
|
96
|
+
THAW = rb_intern("THAW");
|
97
|
+
FREEZE = rb_intern("FREEZE");
|
98
|
+
SEREAL = rb_intern("Sereal");
|
99
|
+
ID_CLASS = rb_intern("@class");
|
100
|
+
ID_VALUE = rb_intern("@value");
|
101
|
+
|
102
|
+
SerealPerlObject = rb_define_class("SerealPerlObject", rb_cObject);
|
103
|
+
|
104
|
+
Sereal = rb_define_class("Sereal", rb_cObject);
|
105
|
+
rb_define_singleton_method(Sereal, "encode", method_sereal_encode, -2);
|
106
|
+
|
107
|
+
rb_define_singleton_method(Sereal, "decode", method_sereal_decode, -2);
|
108
|
+
|
109
|
+
/*
|
110
|
+
* instructs the encoder to use Snappy compression
|
111
|
+
* nb: this is Sereal protocol version 1 only
|
112
|
+
* do not use it if possible.
|
113
|
+
*
|
114
|
+
* Sereal.encode(object,Sereal::SNAPPY)
|
115
|
+
*/
|
116
|
+
rb_define_const(Sereal, "SNAPPY",INT2NUM(__SNAPPY));
|
117
|
+
|
118
|
+
|
119
|
+
/*
|
120
|
+
* instructs the encoder to use Snappy compression
|
121
|
+
* but with support for incremental packet (meaning
|
122
|
+
* you can combine packets into one big blob of data
|
123
|
+
* and the encoder will be confident that there is no
|
124
|
+
* corruption, because the SNAPPY_INCR packet contains the
|
125
|
+
* uncompressed length)
|
126
|
+
*
|
127
|
+
* Sereal.encode(object,Sereal::SNAPPY_INCR)
|
128
|
+
*/
|
129
|
+
rb_define_const(Sereal, "SNAPPY_INCR",INT2NUM(__SNAPPY_INCR));
|
130
|
+
|
131
|
+
/*
|
132
|
+
* intructs the encoder to use no compression (default)
|
133
|
+
*
|
134
|
+
* Sereal.encode(object,Sereal::RAW)
|
135
|
+
*/
|
136
|
+
rb_define_const(Sereal, "RAW",INT2NUM(__RAW));
|
137
|
+
|
138
|
+
/*
|
139
|
+
* (can also be used with any compression type/RAW)
|
140
|
+
* instructs the encoder to keep track of object_ids
|
141
|
+
* and when it sees that object with the same id has
|
142
|
+
* already been encoded, it just creates REFP reference
|
143
|
+
* with offset to the first item
|
144
|
+
* so:
|
145
|
+
* name = "john doe"
|
146
|
+
* object = [ name, name ]
|
147
|
+
* Sereal.encode(name,Sereal::REF|Sereal::SNAPPY_INCR)
|
148
|
+
*
|
149
|
+
* will actually create something that looks like:
|
150
|
+
*
|
151
|
+
* 000006/000001: 42 066 ARRAYREF(2)
|
152
|
+
* 000007/000002: 68* 232 SHORT_BINARY(8): 'john doe'
|
153
|
+
* 000016/000011: 29 041 REFP(2)
|
154
|
+
*
|
155
|
+
* instead of:
|
156
|
+
*
|
157
|
+
* 000006/000001: 42 066 ARRAYREF(2)
|
158
|
+
* 000007/000002: 68 104 SHORT_BINARY(8): 'john doe'
|
159
|
+
* 000016/000011: 68 104 SHORT_BINARY(8): 'john doe'
|
160
|
+
*
|
161
|
+
* as you can see Sereal saved us 7 bytes
|
162
|
+
*
|
163
|
+
* this can hurts performance because the encoder must get the
|
164
|
+
* object_id of every encoded object, and put it in a hash
|
165
|
+
* with the current position, so it can be looked up later
|
166
|
+
*/
|
167
|
+
rb_define_const(Sereal, "REF",INT2NUM(__REF));
|
168
|
+
|
169
|
+
|
170
|
+
/*
|
171
|
+
* very similar to Sereal::REF, but it instructs the decoder
|
172
|
+
* to create new item, by going back in time as if the OFFSET
|
173
|
+
* of the COPY tag was beeing read right now
|
174
|
+
* it puts every object as a key in a hash (instead of its
|
175
|
+
* object_id)
|
176
|
+
*
|
177
|
+
* object = [ { name => "john"} , { name => "john"} ]
|
178
|
+
* Sereal.encode(name,Sereal::COPY|Sereal::SNAPPY_INCR)
|
179
|
+
*
|
180
|
+
* will produce:
|
181
|
+
*
|
182
|
+
* 000006/000001: 42 066 ARRAYREF(2)
|
183
|
+
* 000007/000002: 51 081 HASHREF(2)
|
184
|
+
* KEY:
|
185
|
+
* 000008/000003: 64 100 SHORT_BINARY(4): 'name'
|
186
|
+
* VALUE:
|
187
|
+
* 000013/000008: 64 100 SHORT_BINARY(4): 'john'
|
188
|
+
* 000018/000013: 2f 047 COPY(2)
|
189
|
+
*
|
190
|
+
* as you can see the hash is sent only once
|
191
|
+
*
|
192
|
+
* COPY can be used with REF like:
|
193
|
+
*
|
194
|
+
* object = "bazinga"
|
195
|
+
*
|
196
|
+
* Sereal.encode([object,"bazinga",object],Sereal::REF|Sereal::COPY)
|
197
|
+
*
|
198
|
+
* will produce:
|
199
|
+
* 000006/000001: 43 067 ARRAYREF(3)
|
200
|
+
* 000007/000002: 67* 231 SHORT_BINARY(7): 'bazinga'
|
201
|
+
* 000015/000010: 2f 047 COPY(2)
|
202
|
+
* 000017/000012: 29 041 REFP(2)
|
203
|
+
*
|
204
|
+
* using Sereal::COPY also hurts performance because every encoding step
|
205
|
+
* the encoder must look into a hash if the object exists in it
|
206
|
+
* so it can create a COPY tag instead of encoding the object again
|
207
|
+
*/
|
208
|
+
rb_define_const(Sereal, "COPY",INT2NUM(__COPY));
|
209
|
+
|
210
|
+
/*
|
211
|
+
* add support for FREEZE/THAW
|
212
|
+
* it calls <code>object.FREEZE(:Sereal)</code> and it serializes the result of that
|
213
|
+
* with the object's class name, when deserializing it calls
|
214
|
+
* <code>class.THAW(:Sereal,the output of FREEZE)</code>
|
215
|
+
*
|
216
|
+
* class StorableFile
|
217
|
+
* attr_accessor :path
|
218
|
+
* def initialize(path,pos)
|
219
|
+
* @path = path
|
220
|
+
* @pos = pos
|
221
|
+
* end
|
222
|
+
* def read
|
223
|
+
* @pos += 1
|
224
|
+
* end
|
225
|
+
* def FREEZE(serializer)
|
226
|
+
* [@path,@pos]
|
227
|
+
* end
|
228
|
+
* def self.THAW(serializer,path,pos)
|
229
|
+
* self.new(path,pos)
|
230
|
+
* end
|
231
|
+
* end
|
232
|
+
*
|
233
|
+
* obj = StorableFile.new("/tmp/sereal.txt",0)
|
234
|
+
* obj.read # read some data
|
235
|
+
* encoded = Sereal.encode(obj,Sereal::THAW)
|
236
|
+
* # this actually encodes something like:
|
237
|
+
* # 'StorableFile' -> [ "/tmp/sereal.txt", 1 ]
|
238
|
+
* restored = Sereal.decode(encoded,Sereal::THAW)
|
239
|
+
* # this will call Sereal.THAW(:Sereal,"/tmp/sereal.txt",1)
|
240
|
+
*
|
241
|
+
* as you can see the array returned from FREEZE is exploded into
|
242
|
+
* arguments for THAW, FREEZE *MUST* return array, otherwise the
|
243
|
+
* encoder throws TypeException.
|
244
|
+
* *BOTH* encoder *AND* decoder must be started with Sereal::THAW option
|
245
|
+
* in order for it to work properly
|
246
|
+
*/
|
247
|
+
rb_define_const(Sereal, "THAW",INT2NUM(__THAW));
|
248
|
+
|
249
|
+
/*
|
250
|
+
* the argument given to FREEZE() and THAW() as serializer
|
251
|
+
* which at the moment is:
|
252
|
+
*
|
253
|
+
* :Sereal
|
254
|
+
*/
|
255
|
+
rb_define_const(Sereal, "FREEZER",ID2SYM(SEREAL));
|
256
|
+
|
257
|
+
/*
|
258
|
+
* enable debug output
|
259
|
+
*
|
260
|
+
* name = "john"
|
261
|
+
* Sereal.decode([name,name],Sereal::REF|Sereal::DEBUG)
|
262
|
+
*
|
263
|
+
* procudes:
|
264
|
+
*
|
265
|
+
* initialized (s) with compression type: 0 { p: 6, s: 14, l: 0, h: 0 } method_sereal_decode()
|
266
|
+
* header end at 6 { p: 6, s: 14, l: 0, h: 6 } method_sereal_decode()
|
267
|
+
* tracking object of class: String(id: 7678920) at position: 8 { p: 12, s: 14, l: 2, h: 6 } sereal_to_rb_object()
|
268
|
+
* object: String: john { p: 12, s: 14, l: 2, h: 6 } sereal_to_rb_object()
|
269
|
+
* reading reference from offset: 8, id: 7678920 { p: 14, s: 14, l: 2, h: 6 } s_read_ref()
|
270
|
+
* object: String: john { p: 14, s: 14, l: 2, h: 6 } sereal_to_rb_object()
|
271
|
+
* object: Array: ["john", "john"] { p: 14, s: 14, l: 1, h: 6 } sereal_to_rb_object()
|
272
|
+
*
|
273
|
+
*/
|
274
|
+
rb_define_const(Sereal, "DEBUG",INT2NUM(__DEBUG));
|
275
|
+
|
276
|
+
s_init_writers();
|
67
277
|
}
|
68
278
|
|
data/ext/sereal/sereal.h
CHANGED
@@ -12,7 +12,6 @@ typedef unsigned int u32;
|
|
12
12
|
typedef unsigned short u16;
|
13
13
|
typedef unsigned char u8;
|
14
14
|
typedef struct _sereal sereal_t;
|
15
|
-
typedef struct _track_entry track_t;
|
16
15
|
|
17
16
|
#define TRUE 1
|
18
17
|
#define FALSE 0
|
@@ -41,19 +40,27 @@ typedef struct _track_entry track_t;
|
|
41
40
|
#define EXTENDED RE_OPTION_EXTENDED
|
42
41
|
#endif
|
43
42
|
|
44
|
-
#define FORMAT(fmt,arg...) fmt "
|
43
|
+
#define FORMAT(fmt,arg...) fmt " %s()\n",##arg,__func__
|
45
44
|
#define E(fmt,arg...) fprintf(stderr,FORMAT(fmt,##arg))
|
46
45
|
#define D(fmt,arg...) printf(FORMAT(fmt,##arg))
|
46
|
+
#define SD(s,fmt,arg...) \
|
47
|
+
do { \
|
48
|
+
if (s->flags & __DEBUG) { \
|
49
|
+
int i; \
|
50
|
+
for (i = 0; i < s->level; i++) { \
|
51
|
+
printf(" "); \
|
52
|
+
} \
|
53
|
+
D(fmt " { p: %d, s: %d, l: %u, h: %u } ",##arg,s->pos,s->size,s->level,s->hdr_end); \
|
54
|
+
} \
|
55
|
+
} while(0);
|
47
56
|
|
48
57
|
#define s_raise(what,ex,arg...) \
|
49
58
|
do { \
|
59
|
+
SD(s,"s_raise"); \
|
50
60
|
s_destroy(what); \
|
51
61
|
rb_raise(ex,##arg); \
|
52
62
|
} while(0);
|
53
63
|
|
54
|
-
#define FLAG_NOT_MINE 1
|
55
|
-
#define FLAG_STREAM 2
|
56
|
-
#define FLAG_REF 4
|
57
64
|
struct _sereal {
|
58
65
|
u8 *data;
|
59
66
|
u32 size;
|
@@ -61,7 +68,9 @@ struct _sereal {
|
|
61
68
|
u32 rsize;
|
62
69
|
u32 level;
|
63
70
|
u8 flags;
|
71
|
+
u8 expect;
|
64
72
|
VALUE tracked;
|
73
|
+
VALUE copy;
|
65
74
|
u32 hdr_end;
|
66
75
|
int fd;
|
67
76
|
struct buffer {
|
@@ -73,13 +82,20 @@ struct _sereal {
|
|
73
82
|
|
74
83
|
VALUE method_sereal_encode(VALUE self, VALUE args);
|
75
84
|
VALUE method_sereal_decode(VALUE self, VALUE payload);
|
85
|
+
extern ID FREEZE;
|
86
|
+
extern ID THAW;
|
87
|
+
extern ID TO_SRL;
|
88
|
+
extern ID SEREAL;
|
89
|
+
extern ID ID_CLASS;
|
90
|
+
extern ID ID_VALUE;
|
91
|
+
extern VALUE SerealPerlObject;
|
76
92
|
|
77
|
-
#define S_RECURSE_INC(s)
|
78
|
-
do {
|
79
|
-
if((s)->level++ > MAX_RECURSION_DEPTH)
|
80
|
-
|
81
|
-
|
82
|
-
|
93
|
+
#define S_RECURSE_INC(s) \
|
94
|
+
do { \
|
95
|
+
if((s)->level++ > MAX_RECURSION_DEPTH) \
|
96
|
+
s_raise((s),rb_eArgError, \
|
97
|
+
"max recursion depth reached: %d (level: %d)", \
|
98
|
+
MAX_RECURSION_DEPTH, s->level); \
|
83
99
|
} while(0);
|
84
100
|
|
85
101
|
#define S_RECURSE_DEC(s) ((s)->level--)
|
@@ -94,5 +110,12 @@ VALUE method_sereal_decode(VALUE self, VALUE payload);
|
|
94
110
|
#define __SNAPPY 1
|
95
111
|
#define __SNAPPY_INCR 2
|
96
112
|
#define __REF 4
|
113
|
+
#define __DEBUG 8
|
114
|
+
#define __NOT_MINE 16
|
115
|
+
#define __STREAM 32
|
116
|
+
#define __THAW 64
|
117
|
+
#define __COPY 64
|
118
|
+
#define __ARGUMENT_FLAGS (__DEBUG|__THAW|__REF|__COPY)
|
119
|
+
|
97
120
|
#define __MIN_SIZE 6
|
98
121
|
#endif
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sereal
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.10
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Borislav Nikolov
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-01-
|
11
|
+
date: 2014-01-07 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake-compiler
|
@@ -30,7 +30,8 @@ executables:
|
|
30
30
|
- rsrl
|
31
31
|
extensions:
|
32
32
|
- ext/sereal/extconf.rb
|
33
|
-
extra_rdoc_files:
|
33
|
+
extra_rdoc_files:
|
34
|
+
- ext/sereal/sereal.c
|
34
35
|
files:
|
35
36
|
- ext/sereal/decode.c
|
36
37
|
- ext/sereal/encode.c
|
@@ -52,7 +53,9 @@ homepage: https://github.com/Sereal/Sereal
|
|
52
53
|
licenses: []
|
53
54
|
metadata: {}
|
54
55
|
post_install_message:
|
55
|
-
rdoc_options:
|
56
|
+
rdoc_options:
|
57
|
+
- --exclude
|
58
|
+
- .*\.so
|
56
59
|
require_paths:
|
57
60
|
- lib
|
58
61
|
required_ruby_version: !ruby/object:Gem::Requirement
|