oj 3.11.0 → 3.16.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (173) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1421 -0
  3. data/README.md +20 -5
  4. data/RELEASE_NOTES.md +61 -0
  5. data/ext/oj/buf.h +48 -38
  6. data/ext/oj/cache.c +329 -0
  7. data/ext/oj/cache.h +22 -0
  8. data/ext/oj/cache8.c +60 -62
  9. data/ext/oj/cache8.h +8 -7
  10. data/ext/oj/circarray.c +35 -35
  11. data/ext/oj/circarray.h +11 -9
  12. data/ext/oj/code.c +156 -174
  13. data/ext/oj/code.h +19 -18
  14. data/ext/oj/compat.c +140 -197
  15. data/ext/oj/custom.c +737 -879
  16. data/ext/oj/debug.c +126 -0
  17. data/ext/oj/dump.c +830 -835
  18. data/ext/oj/dump.h +65 -53
  19. data/ext/oj/dump_compat.c +566 -642
  20. data/ext/oj/dump_leaf.c +95 -182
  21. data/ext/oj/dump_object.c +518 -659
  22. data/ext/oj/dump_strict.c +301 -334
  23. data/ext/oj/encode.h +3 -4
  24. data/ext/oj/encoder.c +43 -0
  25. data/ext/oj/err.c +27 -24
  26. data/ext/oj/err.h +38 -13
  27. data/ext/oj/extconf.rb +23 -7
  28. data/ext/oj/fast.c +1043 -1073
  29. data/ext/oj/intern.c +313 -0
  30. data/ext/oj/intern.h +22 -0
  31. data/ext/oj/mem.c +318 -0
  32. data/ext/oj/mem.h +53 -0
  33. data/ext/oj/mimic_json.c +449 -423
  34. data/ext/oj/object.c +530 -576
  35. data/ext/oj/odd.c +155 -138
  36. data/ext/oj/odd.h +24 -22
  37. data/ext/oj/oj.c +1331 -993
  38. data/ext/oj/oj.h +306 -292
  39. data/ext/oj/parse.c +934 -938
  40. data/ext/oj/parse.h +73 -70
  41. data/ext/oj/parser.c +1600 -0
  42. data/ext/oj/parser.h +101 -0
  43. data/ext/oj/rails.c +795 -845
  44. data/ext/oj/rails.h +7 -7
  45. data/ext/oj/reader.c +132 -140
  46. data/ext/oj/reader.h +67 -78
  47. data/ext/oj/resolve.c +40 -59
  48. data/ext/oj/resolve.h +3 -2
  49. data/ext/oj/rxclass.c +67 -67
  50. data/ext/oj/rxclass.h +11 -9
  51. data/ext/oj/saj.c +441 -480
  52. data/ext/oj/saj2.c +584 -0
  53. data/ext/oj/saj2.h +23 -0
  54. data/ext/oj/scp.c +78 -111
  55. data/ext/oj/sparse.c +726 -730
  56. data/ext/oj/stream_writer.c +146 -165
  57. data/ext/oj/strict.c +103 -123
  58. data/ext/oj/string_writer.c +241 -253
  59. data/ext/oj/trace.c +29 -33
  60. data/ext/oj/trace.h +41 -11
  61. data/ext/oj/usual.c +1218 -0
  62. data/ext/oj/usual.h +69 -0
  63. data/ext/oj/util.c +103 -103
  64. data/ext/oj/util.h +3 -2
  65. data/ext/oj/val_stack.c +60 -49
  66. data/ext/oj/val_stack.h +79 -85
  67. data/ext/oj/validate.c +46 -0
  68. data/ext/oj/wab.c +307 -350
  69. data/lib/oj/active_support_helper.rb +1 -3
  70. data/lib/oj/bag.rb +8 -1
  71. data/lib/oj/easy_hash.rb +9 -9
  72. data/lib/oj/error.rb +1 -2
  73. data/lib/oj/json.rb +162 -150
  74. data/lib/oj/mimic.rb +9 -19
  75. data/lib/oj/saj.rb +20 -6
  76. data/lib/oj/schandler.rb +5 -4
  77. data/lib/oj/state.rb +12 -8
  78. data/lib/oj/version.rb +1 -2
  79. data/lib/oj.rb +2 -0
  80. data/pages/Compatibility.md +1 -1
  81. data/pages/InstallOptions.md +20 -0
  82. data/pages/JsonGem.md +15 -0
  83. data/pages/Modes.md +8 -3
  84. data/pages/Options.md +43 -5
  85. data/pages/Parser.md +309 -0
  86. data/pages/Rails.md +14 -2
  87. data/test/_test_active.rb +8 -9
  88. data/test/_test_active_mimic.rb +7 -8
  89. data/test/_test_mimic_rails.rb +17 -20
  90. data/test/activerecord/result_test.rb +12 -8
  91. data/test/activesupport6/encoding_test.rb +63 -28
  92. data/test/{activesupport5 → activesupport7}/abstract_unit.rb +16 -12
  93. data/test/{activesupport5 → activesupport7}/decoding_test.rb +2 -10
  94. data/test/{activesupport5 → activesupport7}/encoding_test.rb +86 -50
  95. data/test/{activesupport5 → activesupport7}/encoding_test_cases.rb +6 -0
  96. data/test/{activesupport5 → activesupport7}/time_zone_test_helpers.rb +8 -0
  97. data/test/files.rb +15 -15
  98. data/test/foo.rb +17 -43
  99. data/test/helper.rb +16 -3
  100. data/test/isolated/shared.rb +3 -2
  101. data/test/json_gem/json_addition_test.rb +2 -2
  102. data/test/json_gem/json_common_interface_test.rb +8 -6
  103. data/test/json_gem/json_encoding_test.rb +0 -0
  104. data/test/json_gem/json_ext_parser_test.rb +1 -0
  105. data/test/json_gem/json_fixtures_test.rb +3 -2
  106. data/test/json_gem/json_generator_test.rb +71 -41
  107. data/test/json_gem/json_generic_object_test.rb +11 -11
  108. data/test/json_gem/json_parser_test.rb +54 -47
  109. data/test/json_gem/json_string_matching_test.rb +9 -9
  110. data/test/json_gem/test_helper.rb +12 -0
  111. data/test/mem.rb +34 -0
  112. data/test/perf.rb +22 -27
  113. data/test/perf_compat.rb +31 -33
  114. data/test/perf_dump.rb +50 -0
  115. data/test/perf_fast.rb +80 -82
  116. data/test/perf_file.rb +27 -29
  117. data/test/perf_object.rb +65 -69
  118. data/test/perf_once.rb +59 -0
  119. data/test/perf_parser.rb +183 -0
  120. data/test/perf_saj.rb +46 -54
  121. data/test/perf_scp.rb +58 -69
  122. data/test/perf_simple.rb +41 -39
  123. data/test/perf_strict.rb +74 -82
  124. data/test/perf_wab.rb +67 -69
  125. data/test/prec.rb +5 -5
  126. data/test/sample/change.rb +0 -1
  127. data/test/sample/dir.rb +0 -1
  128. data/test/sample/doc.rb +0 -1
  129. data/test/sample/file.rb +0 -1
  130. data/test/sample/group.rb +0 -1
  131. data/test/sample/hasprops.rb +0 -1
  132. data/test/sample/layer.rb +0 -1
  133. data/test/sample/rect.rb +0 -1
  134. data/test/sample/shape.rb +0 -1
  135. data/test/sample/text.rb +0 -1
  136. data/test/sample.rb +16 -16
  137. data/test/sample_json.rb +8 -8
  138. data/test/test_compat.rb +97 -45
  139. data/test/test_custom.rb +73 -51
  140. data/test/test_debian.rb +7 -10
  141. data/test/test_fast.rb +135 -79
  142. data/test/test_file.rb +41 -30
  143. data/test/test_gc.rb +16 -5
  144. data/test/test_generate.rb +21 -0
  145. data/test/test_hash.rb +15 -5
  146. data/test/test_integer_range.rb +9 -9
  147. data/test/test_null.rb +20 -20
  148. data/test/test_object.rb +99 -96
  149. data/test/test_parser.rb +11 -0
  150. data/test/test_parser_debug.rb +27 -0
  151. data/test/test_parser_saj.rb +337 -0
  152. data/test/test_parser_usual.rb +251 -0
  153. data/test/test_rails.rb +2 -2
  154. data/test/test_saj.rb +10 -8
  155. data/test/test_scp.rb +38 -40
  156. data/test/test_strict.rb +40 -32
  157. data/test/test_various.rb +165 -84
  158. data/test/test_wab.rb +48 -44
  159. data/test/test_writer.rb +47 -47
  160. data/test/tests.rb +13 -5
  161. data/test/tests_mimic.rb +12 -3
  162. data/test/tests_mimic_addition.rb +12 -3
  163. metadata +75 -127
  164. data/ext/oj/hash.c +0 -135
  165. data/ext/oj/hash.h +0 -18
  166. data/ext/oj/hash_test.c +0 -484
  167. data/test/activesupport4/decoding_test.rb +0 -108
  168. data/test/activesupport4/encoding_test.rb +0 -531
  169. data/test/activesupport4/test_helper.rb +0 -41
  170. data/test/activesupport5/test_helper.rb +0 -72
  171. data/test/bar.rb +0 -35
  172. data/test/baz.rb +0 -16
  173. data/test/zoo.rb +0 -13
@@ -1,256 +1,259 @@
1
1
  // Copyright (c) 2012, 2017 Peter Ohler. All rights reserved.
2
+ // Licensed under the MIT License. See LICENSE file in the project root for license details.
2
3
 
3
4
  #include "dump.h"
4
5
  #include "encode.h"
6
+ #include "mem.h"
5
7
 
6
- extern VALUE Oj;
8
+ extern VALUE Oj;
7
9
 
8
- bool string_writer_optimized = false;
10
+ bool string_writer_optimized = false;
9
11
 
10
- static void
11
- key_check(StrWriter sw, const char *key) {
12
- DumpType type = sw->types[sw->depth];
12
+ static void key_check(StrWriter sw, const char *key) {
13
+ DumpType type = sw->types[sw->depth];
13
14
 
14
15
  if (0 == key && (ObjectNew == type || ObjectType == type)) {
15
- rb_raise(rb_eStandardError, "Can not push onto an Object without a key.");
16
+ rb_raise(rb_eStandardError, "Can not push onto an Object without a key.");
16
17
  }
17
18
  }
18
19
 
19
- static void
20
- push_type(StrWriter sw, DumpType type) {
20
+ static void push_type(StrWriter sw, DumpType type) {
21
21
  if (sw->types_end <= sw->types + sw->depth + 1) {
22
- size_t size = (sw->types_end - sw->types) * 2;
22
+ size_t size = (sw->types_end - sw->types) * 2;
23
23
 
24
- REALLOC_N(sw->types, char, size);
25
- sw->types_end = sw->types + size;
24
+ OJ_R_REALLOC_N(sw->types, char, size);
25
+ sw->types_end = sw->types + size;
26
26
  }
27
27
  sw->depth++;
28
28
  sw->types[sw->depth] = type;
29
29
  }
30
30
 
31
- static void
32
- maybe_comma(StrWriter sw) {
31
+ static void maybe_comma(StrWriter sw) {
33
32
  switch (sw->types[sw->depth]) {
34
- case ObjectNew:
35
- sw->types[sw->depth] = ObjectType;
36
- break;
37
- case ArrayNew:
38
- sw->types[sw->depth] = ArrayType;
39
- break;
33
+ case ObjectNew: sw->types[sw->depth] = ObjectType; break;
34
+ case ArrayNew: sw->types[sw->depth] = ArrayType; break;
40
35
  case ObjectType:
41
36
  case ArrayType:
42
- // Always have a few characters available in the out.buf.
43
- *sw->out.cur++ = ',';
44
- break;
37
+ // Always have a few characters available in the out.buf.
38
+ *sw->out.cur++ = ',';
39
+ break;
45
40
  }
46
41
  }
47
42
 
48
43
  // Used by stream writer also.
49
- void
50
- oj_str_writer_init(StrWriter sw, int buf_size) {
51
- sw->opts = oj_default_options;
52
- sw->depth = 0;
53
- sw->types = ALLOC_N(char, 256);
54
- sw->types_end = sw->types + 256;
55
- *sw->types = '\0';
44
+ void oj_str_writer_init(StrWriter sw, int buf_size) {
45
+ sw->opts = oj_default_options;
46
+ sw->depth = 0;
47
+ sw->types = OJ_R_ALLOC_N(char, 256);
48
+ sw->types_end = sw->types + 256;
49
+ *sw->types = '\0';
56
50
  sw->keyWritten = 0;
57
51
 
58
52
  if (0 == buf_size) {
59
- buf_size = 4096;
53
+ buf_size = 4096;
60
54
  } else if (buf_size < 1024) {
61
- buf_size = 1024;
55
+ buf_size = 1024;
62
56
  }
63
- sw->out.buf = ALLOC_N(char, buf_size);
64
- sw->out.end = sw->out.buf + buf_size - 10;
57
+ // Must be allocated. Using the out.stack_buffer results in double frees
58
+ // and I haven't figured out why yet.
59
+ sw->out.buf = OJ_R_ALLOC_N(char, buf_size);
60
+ sw->out.cur = sw->out.buf;
61
+ sw->out.end = sw->out.buf + buf_size - BUFFER_EXTRA;
65
62
  sw->out.allocated = true;
66
- sw->out.cur = sw->out.buf;
67
- *sw->out.cur = '\0';
63
+
64
+ *sw->out.cur = '\0';
68
65
  sw->out.circ_cache = NULL;
69
- sw->out.circ_cnt = 0;
70
- sw->out.hash_cnt = 0;
71
- sw->out.opts = &sw->opts;
72
- sw->out.indent = sw->opts.indent;
73
- sw->out.depth = 0;
74
- sw->out.argc = 0;
75
- sw->out.argv = NULL;
76
- sw->out.caller = 0;
77
- sw->out.ropts = NULL;
78
- sw->out.omit_nil = oj_default_options.dump_opts.omit_nil;
66
+ sw->out.circ_cnt = 0;
67
+ sw->out.hash_cnt = 0;
68
+ sw->out.opts = &sw->opts;
69
+ sw->out.indent = sw->opts.indent;
70
+ sw->out.depth = 0;
71
+ sw->out.argc = 0;
72
+ sw->out.argv = NULL;
73
+ sw->out.ropts = NULL;
74
+ sw->out.omit_nil = oj_default_options.dump_opts.omit_nil;
79
75
  }
80
76
 
81
- void
82
- oj_str_writer_push_key(StrWriter sw, const char *key) {
83
- DumpType type = sw->types[sw->depth];
84
- long size;
77
+ void oj_str_writer_push_key(StrWriter sw, const char *key) {
78
+ DumpType type = sw->types[sw->depth];
79
+ long size;
85
80
 
86
81
  if (sw->keyWritten) {
87
- rb_raise(rb_eStandardError, "Can not push more than one key before pushing a non-key.");
82
+ rb_raise(rb_eStandardError, "Can not push more than one key before pushing a non-key.");
88
83
  }
89
84
  if (ObjectNew != type && ObjectType != type) {
90
- rb_raise(rb_eStandardError, "Can only push a key onto an Object.");
85
+ rb_raise(rb_eStandardError, "Can only push a key onto an Object.");
91
86
  }
92
87
  size = sw->depth * sw->out.indent + 3;
93
88
  assure_size(&sw->out, size);
94
89
  maybe_comma(sw);
95
90
  if (0 < sw->depth) {
96
- fill_indent(&sw->out, sw->depth);
91
+ fill_indent(&sw->out, sw->depth);
97
92
  }
98
93
  oj_dump_cstr(key, strlen(key), 0, 0, &sw->out);
99
94
  *sw->out.cur++ = ':';
100
95
  sw->keyWritten = 1;
101
96
  }
102
97
 
103
- void
104
- oj_str_writer_push_object(StrWriter sw, const char *key) {
98
+ void oj_str_writer_push_object(StrWriter sw, const char *key) {
105
99
  if (sw->keyWritten) {
106
- sw->keyWritten = 0;
107
- assure_size(&sw->out, 1);
100
+ sw->keyWritten = 0;
101
+ assure_size(&sw->out, 1);
108
102
  } else {
109
- long size;
110
-
111
- key_check(sw, key);
112
- size = sw->depth * sw->out.indent + 3;
113
- assure_size(&sw->out, size);
114
- maybe_comma(sw);
115
- if (0 < sw->depth) {
116
- fill_indent(&sw->out, sw->depth);
117
- }
118
- if (0 != key) {
119
- oj_dump_cstr(key, strlen(key), 0, 0, &sw->out);
120
- *sw->out.cur++ = ':';
121
- }
103
+ long size;
104
+
105
+ key_check(sw, key);
106
+ size = sw->depth * sw->out.indent + 3;
107
+ assure_size(&sw->out, size);
108
+ maybe_comma(sw);
109
+ if (0 < sw->depth) {
110
+ fill_indent(&sw->out, sw->depth);
111
+ }
112
+ if (0 != key) {
113
+ oj_dump_cstr(key, strlen(key), 0, 0, &sw->out);
114
+ *sw->out.cur++ = ':';
115
+ }
122
116
  }
123
117
  *sw->out.cur++ = '{';
124
118
  push_type(sw, ObjectNew);
125
119
  }
126
120
 
127
- void
128
- oj_str_writer_push_array(StrWriter sw, const char *key) {
121
+ void oj_str_writer_push_array(StrWriter sw, const char *key) {
129
122
  if (sw->keyWritten) {
130
- sw->keyWritten = 0;
131
- assure_size(&sw->out, 1);
123
+ sw->keyWritten = 0;
124
+ assure_size(&sw->out, 1);
132
125
  } else {
133
- long size;
134
-
135
- key_check(sw, key);
136
- size = sw->depth * sw->out.indent + 3;
137
- assure_size(&sw->out, size);
138
- maybe_comma(sw);
139
- if (0 < sw->depth) {
140
- fill_indent(&sw->out, sw->depth);
141
- }
142
- if (0 != key) {
143
- oj_dump_cstr(key, strlen(key), 0, 0, &sw->out);
144
- *sw->out.cur++ = ':';
145
- }
126
+ long size;
127
+
128
+ key_check(sw, key);
129
+ size = sw->depth * sw->out.indent + 3;
130
+ assure_size(&sw->out, size);
131
+ maybe_comma(sw);
132
+ if (0 < sw->depth) {
133
+ fill_indent(&sw->out, sw->depth);
134
+ }
135
+ if (0 != key) {
136
+ oj_dump_cstr(key, strlen(key), 0, 0, &sw->out);
137
+ *sw->out.cur++ = ':';
138
+ }
146
139
  }
147
140
  *sw->out.cur++ = '[';
148
141
  push_type(sw, ArrayNew);
149
142
  }
150
143
 
151
- void
152
- oj_str_writer_push_value(StrWriter sw, VALUE val, const char *key) {
153
- Out out = &sw->out;
144
+ void oj_str_writer_push_value(StrWriter sw, VALUE val, const char *key) {
145
+ Out out = &sw->out;
154
146
 
155
147
  if (sw->keyWritten) {
156
- sw->keyWritten = 0;
148
+ sw->keyWritten = 0;
157
149
  } else {
158
- long size;
159
-
160
- key_check(sw, key);
161
- size = sw->depth * out->indent + 3;
162
- assure_size(out, size);
163
- maybe_comma(sw);
164
- if (0 < sw->depth) {
165
- fill_indent(&sw->out, sw->depth);
166
- }
167
- if (0 != key) {
168
- oj_dump_cstr(key, strlen(key), 0, 0, out);
169
- *out->cur++ = ':';
170
- }
150
+ long size;
151
+
152
+ key_check(sw, key);
153
+ size = sw->depth * out->indent + 3;
154
+ assure_size(out, size);
155
+ maybe_comma(sw);
156
+ if (0 < sw->depth) {
157
+ fill_indent(&sw->out, sw->depth);
158
+ }
159
+ if (0 != key) {
160
+ oj_dump_cstr(key, strlen(key), 0, 0, out);
161
+ *out->cur++ = ':';
162
+ }
171
163
  }
172
164
  switch (out->opts->mode) {
173
- case StrictMode: oj_dump_strict_val(val, sw->depth, out); break;
174
- case NullMode: oj_dump_null_val(val, sw->depth, out); break;
175
- case ObjectMode: oj_dump_obj_val(val, sw->depth, out); break;
176
- case CompatMode: oj_dump_compat_val(val, sw->depth, out, Yes == out->opts->to_json); break;
177
- case RailsMode: oj_dump_rails_val(val, sw->depth, out); break;
178
- case CustomMode: oj_dump_custom_val(val, sw->depth, out, true); break;
179
- default: oj_dump_custom_val(val, sw->depth, out, true); break;
165
+ case StrictMode: oj_dump_strict_val(val, sw->depth, out); break;
166
+ case NullMode: oj_dump_null_val(val, sw->depth, out); break;
167
+ case ObjectMode: oj_dump_obj_val(val, sw->depth, out); break;
168
+ case CompatMode: oj_dump_compat_val(val, sw->depth, out, Yes == out->opts->to_json); break;
169
+ case RailsMode: oj_dump_rails_val(val, sw->depth, out); break;
170
+ case CustomMode: oj_dump_custom_val(val, sw->depth, out, true); break;
171
+ default: oj_dump_custom_val(val, sw->depth, out, true); break;
180
172
  }
181
173
  }
182
174
 
183
- void
184
- oj_str_writer_push_json(StrWriter sw, const char *json, const char *key) {
175
+ void oj_str_writer_push_json(StrWriter sw, const char *json, const char *key) {
185
176
  if (sw->keyWritten) {
186
- sw->keyWritten = 0;
177
+ sw->keyWritten = 0;
187
178
  } else {
188
- long size;
189
-
190
- key_check(sw, key);
191
- size = sw->depth * sw->out.indent + 3;
192
- assure_size(&sw->out, size);
193
- maybe_comma(sw);
194
- if (0 < sw->depth) {
195
- fill_indent(&sw->out, sw->depth);
196
- }
197
- if (0 != key) {
198
- oj_dump_cstr(key, strlen(key), 0, 0, &sw->out);
199
- *sw->out.cur++ = ':';
200
- }
179
+ long size;
180
+
181
+ key_check(sw, key);
182
+ size = sw->depth * sw->out.indent + 3;
183
+ assure_size(&sw->out, size);
184
+ maybe_comma(sw);
185
+ if (0 < sw->depth) {
186
+ fill_indent(&sw->out, sw->depth);
187
+ }
188
+ if (0 != key) {
189
+ oj_dump_cstr(key, strlen(key), 0, 0, &sw->out);
190
+ *sw->out.cur++ = ':';
191
+ }
201
192
  }
202
193
  oj_dump_raw(json, strlen(json), &sw->out);
203
194
  }
204
195
 
205
- void
206
- oj_str_writer_pop(StrWriter sw) {
207
- long size;
208
- DumpType type = sw->types[sw->depth];
196
+ void oj_str_writer_pop(StrWriter sw) {
197
+ long size;
198
+ DumpType type = sw->types[sw->depth];
209
199
 
210
200
  if (sw->keyWritten) {
211
- sw->keyWritten = 0;
212
- rb_raise(rb_eStandardError, "Can not pop after writing a key but no value.");
201
+ sw->keyWritten = 0;
202
+ rb_raise(rb_eStandardError, "Can not pop after writing a key but no value.");
213
203
  }
214
204
  sw->depth--;
215
205
  if (0 > sw->depth) {
216
- rb_raise(rb_eStandardError, "Can not pop with no open array or object.");
206
+ rb_raise(rb_eStandardError, "Can not pop with no open array or object.");
217
207
  }
218
208
  size = sw->depth * sw->out.indent + 2;
219
209
  assure_size(&sw->out, size);
220
210
  fill_indent(&sw->out, sw->depth);
221
211
  switch (type) {
222
212
  case ObjectNew:
223
- case ObjectType:
224
- *sw->out.cur++ = '}';
225
- break;
213
+ case ObjectType: *sw->out.cur++ = '}'; break;
226
214
  case ArrayNew:
227
- case ArrayType:
228
- *sw->out.cur++ = ']';
229
- break;
215
+ case ArrayType: *sw->out.cur++ = ']'; break;
230
216
  }
231
217
  if (0 == sw->depth && 0 <= sw->out.indent) {
232
- *sw->out.cur++ = '\n';
218
+ *sw->out.cur++ = '\n';
233
219
  }
234
220
  }
235
221
 
236
- void
237
- oj_str_writer_pop_all(StrWriter sw) {
222
+ void oj_str_writer_pop_all(StrWriter sw) {
238
223
  while (0 < sw->depth) {
239
- oj_str_writer_pop(sw);
224
+ oj_str_writer_pop(sw);
240
225
  }
241
226
  }
242
227
 
243
- static void
244
- str_writer_free(void *ptr) {
245
- StrWriter sw;
228
+ static void string_writer_free(void *ptr) {
229
+ StrWriter sw;
246
230
 
247
231
  if (0 == ptr) {
248
- return;
232
+ return;
249
233
  }
250
234
  sw = (StrWriter)ptr;
251
- xfree(sw->out.buf);
252
- xfree(sw->types);
253
- xfree(ptr);
235
+
236
+ oj_out_free(&sw->out);
237
+
238
+ OJ_R_FREE(sw->types);
239
+ OJ_R_FREE(ptr);
240
+ }
241
+
242
+ static const rb_data_type_t oj_string_writer_type = {
243
+ "Oj/string_writer",
244
+ {
245
+ NULL,
246
+ string_writer_free,
247
+ NULL,
248
+ },
249
+ 0,
250
+ 0,
251
+ };
252
+
253
+ StrWriter oj_str_writer_unwrap(VALUE writer) {
254
+ StrWriter sw;
255
+ TypedData_Get_Struct(writer, struct _strWriter, &oj_string_writer_type, sw);
256
+ return sw;
254
257
  }
255
258
 
256
259
  /* Document-method: new
@@ -267,21 +270,20 @@ str_writer_free(void *ptr) {
267
270
  * should be.
268
271
  *
269
272
  * - *io* [_IO_] stream to write to
270
- * - *options* [_Hash_] formating options
273
+ * - *options* [_Hash_] formatting options
271
274
  */
272
- static VALUE
273
- str_writer_new(int argc, VALUE *argv, VALUE self) {
274
- StrWriter sw = ALLOC(struct _strWriter);
275
+ static VALUE str_writer_new(int argc, VALUE *argv, VALUE self) {
276
+ StrWriter sw = OJ_R_ALLOC(struct _strWriter);
275
277
 
276
278
  oj_str_writer_init(sw, 0);
277
279
  if (1 == argc) {
278
- oj_parse_options(argv[0], &sw->opts);
280
+ oj_parse_options(argv[0], &sw->opts);
279
281
  }
280
- sw->out.argc = argc - 1;
281
- sw->out.argv = argv + 1;
282
+ sw->out.argc = argc - 1;
283
+ sw->out.argv = argv + 1;
282
284
  sw->out.indent = sw->opts.indent;
283
285
 
284
- return Data_Wrap_Struct(oj_string_writer_class, 0, str_writer_free, sw);
286
+ return TypedData_Wrap_Struct(oj_string_writer_class, &oj_string_writer_type, sw);
285
287
  }
286
288
 
287
289
  /* Document-method: push_key
@@ -292,11 +294,10 @@ str_writer_new(int argc, VALUE *argv, VALUE self) {
292
294
  * the next push then that new key will be ignored.
293
295
  * - *key* [_String_] the key pending for the next push
294
296
  */
295
- static VALUE
296
- str_writer_push_key(VALUE self, VALUE key) {
297
- StrWriter sw = (StrWriter)DATA_PTR(self);
297
+ static VALUE str_writer_push_key(VALUE self, VALUE key) {
298
+ StrWriter sw;
299
+ TypedData_Get_Struct(self, struct _strWriter, &oj_string_writer_type, sw);
298
300
 
299
- rb_check_type(key, T_STRING);
300
301
  oj_str_writer_push_key(sw, StringValuePtr(key));
301
302
 
302
303
  return Qnil;
@@ -309,29 +310,24 @@ str_writer_push_key(VALUE self, VALUE key) {
309
310
  * until a pop() is called.
310
311
  * - *key* [_String_] the key if adding to an object in the JSON document
311
312
  */
312
- static VALUE
313
- str_writer_push_object(int argc, VALUE *argv, VALUE self) {
314
- StrWriter sw = (StrWriter)DATA_PTR(self);
313
+ static VALUE str_writer_push_object(int argc, VALUE *argv, VALUE self) {
314
+ StrWriter sw;
315
+ TypedData_Get_Struct(self, struct _strWriter, &oj_string_writer_type, sw);
315
316
 
316
317
  switch (argc) {
317
- case 0:
318
- oj_str_writer_push_object(sw, 0);
319
- break;
318
+ case 0: oj_str_writer_push_object(sw, 0); break;
320
319
  case 1:
321
- if (Qnil == argv[0]) {
322
- oj_str_writer_push_object(sw, 0);
323
- } else {
324
- rb_check_type(argv[0], T_STRING);
325
- oj_str_writer_push_object(sw, StringValuePtr(argv[0]));
326
- }
327
- break;
328
- default:
329
- rb_raise(rb_eArgError, "Wrong number of argument to 'push_object'.");
330
- break;
320
+ if (Qnil == argv[0]) {
321
+ oj_str_writer_push_object(sw, 0);
322
+ } else {
323
+ oj_str_writer_push_object(sw, StringValuePtr(argv[0]));
324
+ }
325
+ break;
326
+ default: rb_raise(rb_eArgError, "Wrong number of argument to 'push_object'."); break;
331
327
  }
332
328
  if (rb_block_given_p()) {
333
- rb_yield(Qnil);
334
- oj_str_writer_pop(sw);
329
+ rb_yield(Qnil);
330
+ oj_str_writer_pop(sw);
335
331
  }
336
332
  return Qnil;
337
333
  }
@@ -343,29 +339,24 @@ str_writer_push_object(int argc, VALUE *argv, VALUE self) {
343
339
  * until a pop() is called.
344
340
  * - *key* [_String_] the key if adding to an object in the JSON document
345
341
  */
346
- static VALUE
347
- str_writer_push_array(int argc, VALUE *argv, VALUE self) {
348
- StrWriter sw = (StrWriter)DATA_PTR(self);
342
+ static VALUE str_writer_push_array(int argc, VALUE *argv, VALUE self) {
343
+ StrWriter sw;
344
+ TypedData_Get_Struct(self, struct _strWriter, &oj_string_writer_type, sw);
349
345
 
350
346
  switch (argc) {
351
- case 0:
352
- oj_str_writer_push_array(sw, 0);
353
- break;
347
+ case 0: oj_str_writer_push_array(sw, 0); break;
354
348
  case 1:
355
- if (Qnil == argv[0]) {
356
- oj_str_writer_push_array(sw, 0);
357
- } else {
358
- rb_check_type(argv[0], T_STRING);
359
- oj_str_writer_push_array(sw, StringValuePtr(argv[0]));
360
- }
361
- break;
362
- default:
363
- rb_raise(rb_eArgError, "Wrong number of argument to 'push_object'.");
364
- break;
349
+ if (Qnil == argv[0]) {
350
+ oj_str_writer_push_array(sw, 0);
351
+ } else {
352
+ oj_str_writer_push_array(sw, StringValuePtr(argv[0]));
353
+ }
354
+ break;
355
+ default: rb_raise(rb_eArgError, "Wrong number of argument to 'push_object'."); break;
365
356
  }
366
357
  if (rb_block_given_p()) {
367
- rb_yield(Qnil);
368
- oj_str_writer_pop(sw);
358
+ rb_yield(Qnil);
359
+ oj_str_writer_pop(sw);
369
360
  }
370
361
  return Qnil;
371
362
  }
@@ -377,23 +368,20 @@ str_writer_push_array(int argc, VALUE *argv, VALUE self) {
377
368
  * - *value* [_Object_] value to add to the JSON document
378
369
  * - *key* [_String_] the key if adding to an object in the JSON document
379
370
  */
380
- static VALUE
381
- str_writer_push_value(int argc, VALUE *argv, VALUE self) {
371
+ static VALUE str_writer_push_value(int argc, VALUE *argv, VALUE self) {
372
+ StrWriter sw;
373
+ TypedData_Get_Struct(self, struct _strWriter, &oj_string_writer_type, sw);
374
+
382
375
  switch (argc) {
383
- case 1:
384
- oj_str_writer_push_value((StrWriter)DATA_PTR(self), *argv, 0);
385
- break;
376
+ case 1: oj_str_writer_push_value(sw, *argv, 0); break;
386
377
  case 2:
387
- if (Qnil == argv[1]) {
388
- oj_str_writer_push_value((StrWriter)DATA_PTR(self), *argv, 0);
389
- } else {
390
- rb_check_type(argv[1], T_STRING);
391
- oj_str_writer_push_value((StrWriter)DATA_PTR(self), *argv, StringValuePtr(argv[1]));
392
- }
393
- break;
394
- default:
395
- rb_raise(rb_eArgError, "Wrong number of argument to 'push_value'.");
396
- break;
378
+ if (Qnil == argv[1]) {
379
+ oj_str_writer_push_value(sw, *argv, 0);
380
+ } else {
381
+ oj_str_writer_push_value(sw, *argv, StringValuePtr(argv[1]));
382
+ }
383
+ break;
384
+ default: rb_raise(rb_eArgError, "Wrong number of argument to 'push_value'."); break;
397
385
  }
398
386
  return Qnil;
399
387
  }
@@ -407,24 +395,20 @@ str_writer_push_value(int argc, VALUE *argv, VALUE self) {
407
395
  * - *value* [_Object_] value to add to the JSON document
408
396
  * - *key* [_String_] the key if adding to an object in the JSON document
409
397
  */
410
- static VALUE
411
- str_writer_push_json(int argc, VALUE *argv, VALUE self) {
412
- rb_check_type(argv[0], T_STRING);
398
+ static VALUE str_writer_push_json(int argc, VALUE *argv, VALUE self) {
399
+ StrWriter sw;
400
+ TypedData_Get_Struct(self, struct _strWriter, &oj_string_writer_type, sw);
401
+
413
402
  switch (argc) {
414
- case 1:
415
- oj_str_writer_push_json((StrWriter)DATA_PTR(self), StringValuePtr(*argv), 0);
416
- break;
403
+ case 1: oj_str_writer_push_json(sw, StringValuePtr(*argv), 0); break;
417
404
  case 2:
418
- if (Qnil == argv[1]) {
419
- oj_str_writer_push_json((StrWriter)DATA_PTR(self), StringValuePtr(*argv), 0);
420
- } else {
421
- rb_check_type(argv[1], T_STRING);
422
- oj_str_writer_push_json((StrWriter)DATA_PTR(self), StringValuePtr(*argv), StringValuePtr(argv[1]));
423
- }
424
- break;
425
- default:
426
- rb_raise(rb_eArgError, "Wrong number of argument to 'push_json'.");
427
- break;
405
+ if (Qnil == argv[1]) {
406
+ oj_str_writer_push_json(sw, StringValuePtr(*argv), 0);
407
+ } else {
408
+ oj_str_writer_push_json(sw, StringValuePtr(*argv), StringValuePtr(argv[1]));
409
+ }
410
+ break;
411
+ default: rb_raise(rb_eArgError, "Wrong number of argument to 'push_json'."); break;
428
412
  }
429
413
  return Qnil;
430
414
  }
@@ -434,9 +418,11 @@ str_writer_push_json(int argc, VALUE *argv, VALUE self) {
434
418
  * Pops up a level in the JSON document closing the array or object that is
435
419
  * currently open.
436
420
  */
437
- static VALUE
438
- str_writer_pop(VALUE self) {
439
- oj_str_writer_pop((StrWriter)DATA_PTR(self));
421
+ static VALUE str_writer_pop(VALUE self) {
422
+ StrWriter sw;
423
+ TypedData_Get_Struct(self, struct _strWriter, &oj_string_writer_type, sw);
424
+
425
+ oj_str_writer_pop(sw);
440
426
  return Qnil;
441
427
  }
442
428
 
@@ -446,9 +432,11 @@ str_writer_pop(VALUE self) {
446
432
  * Pops all level in the JSON document closing all the array or object that is
447
433
  * currently open.
448
434
  */
449
- static VALUE
450
- str_writer_pop_all(VALUE self) {
451
- oj_str_writer_pop_all((StrWriter)DATA_PTR(self));
435
+ static VALUE str_writer_pop_all(VALUE self) {
436
+ StrWriter sw;
437
+ TypedData_Get_Struct(self, struct _strWriter, &oj_string_writer_type, sw);
438
+
439
+ oj_str_writer_pop_all(sw);
452
440
 
453
441
  return Qnil;
454
442
  }
@@ -458,15 +446,15 @@ str_writer_pop_all(VALUE self) {
458
446
  *
459
447
  * Reset the writer back to the empty state.
460
448
  */
461
- static VALUE
462
- str_writer_reset(VALUE self) {
463
- StrWriter sw = (StrWriter)DATA_PTR(self);
449
+ static VALUE str_writer_reset(VALUE self) {
450
+ StrWriter sw;
451
+ TypedData_Get_Struct(self, struct _strWriter, &oj_string_writer_type, sw);
464
452
 
465
- sw->depth = 0;
466
- *sw->types = '\0';
453
+ sw->depth = 0;
454
+ *sw->types = '\0';
467
455
  sw->keyWritten = 0;
468
- sw->out.cur = sw->out.buf;
469
- *sw->out.cur = '\0';
456
+ sw->out.cur = sw->out.buf;
457
+ *sw->out.cur = '\0';
470
458
 
471
459
  return Qnil;
472
460
  }
@@ -478,10 +466,10 @@ str_writer_reset(VALUE self) {
478
466
  *
479
467
  * *return* [_String_]
480
468
  */
481
- static VALUE
482
- str_writer_to_s(VALUE self) {
483
- StrWriter sw = (StrWriter)DATA_PTR(self);
484
- VALUE rstr = rb_str_new(sw->out.buf, sw->out.cur - sw->out.buf);
469
+ static VALUE str_writer_to_s(VALUE self) {
470
+ StrWriter sw;
471
+ TypedData_Get_Struct(self, struct _strWriter, &oj_string_writer_type, sw);
472
+ VALUE rstr = rb_str_new(sw->out.buf, sw->out.cur - sw->out.buf);
485
473
 
486
474
  return oj_encode(rstr);
487
475
  }
@@ -492,14 +480,13 @@ str_writer_to_s(VALUE self) {
492
480
  * Returns the contents of the writer as a JSON element. If called from inside
493
481
  * an array or hash by Oj the raw buffer will be used othersize a more
494
482
  * inefficient parse of the contents and a return of the result is
495
- * completed. The parse uses the trict mode.
483
+ * completed. The parse uses the strict mode.
496
484
  *
497
485
  * *return* [_Hash_|_Array_|_String_|_Integer_|_Float_|_True_|_False_|_nil|)
498
486
  */
499
- static VALUE
500
- str_writer_as_json(VALUE self) {
487
+ static VALUE str_writer_as_json(VALUE self) {
501
488
  if (string_writer_optimized) {
502
- return self;
489
+ return self;
503
490
  }
504
491
  return rb_hash_new();
505
492
  }
@@ -510,12 +497,13 @@ str_writer_as_json(VALUE self) {
510
497
  * by pushing values into the document. Pushing an array or an object will
511
498
  * create that element in the JSON document and subsequent pushes will add the
512
499
  * elements to that array or object until a pop() is called. When complete
513
- * calling to_s() will return the JSON document. Note tha calling to_s() before
500
+ * calling to_s() will return the JSON document. Note that calling to_s() before
514
501
  * construction is complete will return the document in it's current state.
515
502
  */
516
- void
517
- oj_string_writer_init() {
503
+ void oj_string_writer_init(void) {
518
504
  oj_string_writer_class = rb_define_class_under(Oj, "StringWriter", rb_cObject);
505
+ rb_gc_register_address(&oj_string_writer_class);
506
+ rb_undef_alloc_func(oj_string_writer_class);
519
507
  rb_define_module_function(oj_string_writer_class, "new", str_writer_new, -1);
520
508
  rb_define_method(oj_string_writer_class, "push_key", str_writer_push_key, 1);
521
509
  rb_define_method(oj_string_writer_class, "push_object", str_writer_push_object, -1);