rapidjson 0.2.1 → 0.2.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 17354e68c40c730955b333eacdc5232255f5c0e12605a2e35ea0a90dd84def19
4
- data.tar.gz: c3d95c72fb9e4416f33007bf7076ed616e82bd138b2637e0a2e0a57a5b55faed
3
+ metadata.gz: 5e6a9c6ee55bf39622dca0dec0df0edb42de2f121dfd81b6711e3e730c7beb90
4
+ data.tar.gz: 2d3f80f79aa7e61cc0340f253891bfb4c6f67d3c80c1bf8a6e23b132d7dd8334
5
5
  SHA512:
6
- metadata.gz: 5d3dc6b671e1cc4110c457a8551fdf05b62ef03ff355a93531406b32853fd0b9174bc6a9ae3b743f891fd1ff4fe8eb95506b36bff9753ca1ed8f60970e694ed7
7
- data.tar.gz: 26195d47a4c2a68b190f0d46da8e09d2df7125b89ad53478758c9db74bf59e65c5a0a6b9fb10f47372da45fe25e269a0c6e48c44b36af10f3f22222739e70497
6
+ metadata.gz: f0e242022084c035eec3fc8deede180bf390f9275aae83bf923ee7ab2076bb5abc1860eded72bc6c43aa8eb9803d492b7477f1923fa343cc2348d72dff809872
7
+ data.tar.gz: 34092b2851dade4bf8adcec4dcf8e8fe66a561a41910c9ff99ac721d6aad48d6340bde69f586973d1f004583aa5eb5c5d278117375418edfe0365a91f339a963
data/README.md CHANGED
@@ -2,6 +2,8 @@
2
2
 
3
3
  (Maybe) Ruby's fastest JSON library! Built using the [RapidJSON C++ library](https://rapidjson.org/)
4
4
 
5
+ No monkey patches, ActiveSupport integration, `json` gem emulation.
6
+
5
7
  ## Installation
6
8
 
7
9
  Add this line to your application's Gemfile:
@@ -42,6 +44,58 @@ RapidJSON.pretty_encode(json_string)
42
44
  # }
43
45
  ```
44
46
 
47
+ By default the encoder is "strict" and will raise an exception
48
+
49
+ ## ActiveSupport
50
+
51
+ RapidJSON provides a drop-in replacement ActiveSupport encoder, with very good compatibility.
52
+ Add the following to an initializer to opt-in.
53
+
54
+ ```
55
+ # config/initializers/rapidjson.rb
56
+
57
+ ActiveSupport::JSON::Encoding.json_encoder = RapidJSON::ActiveSupportEncoder
58
+ ```
59
+
60
+ This makes `model.to_json` ~15x faster, and `nested_hash.to_json` ~27x faster (compred using Rails 7.0)
61
+
62
+ ## JSON gem compatibility
63
+
64
+ Contrary to some other JSON libraries, `RapidJSON` doesn't provice a monkey patch to entirely replace the stdlib JSON gem.
65
+
66
+ However it does provide a module that behave like the stdlib JSON gem and that can be used to monkey patch existing code.
67
+
68
+ ```ruby
69
+ module SomeLibrary
70
+ def do_stuff(payload)
71
+ JSON.parse(payload)
72
+ end
73
+ end
74
+ ```
75
+
76
+ ```ruby
77
+ SomeLibrary::JSON = RapidJSON::JSONGem
78
+ ```
79
+
80
+ Note that this module only use `RapidJSON` when it's certain it is safe to do so. If the JSON gem is called with
81
+ some options that `RapidJSON` doesn't support, it automatically fallbacks to calling the JSON gem.
82
+
83
+ ## Advanced usage
84
+
85
+ By default RapidJSON will only encode "JSON-ready" types: `Hash`, `Array`, `Integer`, `Float`, `String`, `Symbol`, `true`, `false`, and `nil`.
86
+
87
+ RapidJSON::Coder can be initialized with a block which allows the behaviour to be customized. This is how the ActiveSupport encoder and JSON compatibility above are implemented! Just using Ruby :heart:.
88
+
89
+ ```
90
+ RapidJSON::Coder.new do |object, is_key|
91
+ object.to_s # Convert any unknown object to string
92
+ end
93
+ ```
94
+
95
+ The block is called only for unrecognized types. The return value is expected to be a "JSON ready" type which will then be encoded.
96
+
97
+ One additional special type is `RapidJSON::Fragment`, which is interpreted as an existing JSON-encoded string. This can be used to efficiently embed an existing JSON document, or to provide compatibility.
98
+
45
99
  ## Performance
46
100
 
47
101
  Your current JSON parser/encoder is probably fine.
@@ -88,27 +142,6 @@ I spent a week working on YAJL/yajl-ruby, and though I really liked the library,
88
142
 
89
143
  However, if you're happy with your current Ruby JSON library (including `json`) you should keep using it. They're all very good.
90
144
 
91
- ## JSON gem compatibility
92
-
93
- Contrary to some other JSON libraries, `RapidJSON` doesn't provice a monkey patch to entirely replace the stdlib JSON gem.
94
-
95
- However it does provide a module that behave like the stdlib JSON gem and that can be used to monkey patch existing code.
96
-
97
- ```ruby
98
- module SomeLibrary
99
- def do_stuff(payload)
100
- JSON.parse(payload)
101
- end
102
- end
103
- ```
104
-
105
- ```ruby
106
- SomeLibrary::JSON = RapidJSON::JSONGem
107
- ```
108
-
109
- Note that this module only use `RapidJSON` when it's certain it is safe to do so. If the JSON gem is called with
110
- some options that `RapidJSON` doesn't support, it automatically fallbacks to calling the JSON gem.
111
-
112
145
  ## Development
113
146
 
114
147
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
@@ -12,9 +12,16 @@ class RubyStringBuffer {
12
12
  mem = RSTRING_PTR(ruby_string);
13
13
  }
14
14
 
15
- void Reserve(size_t size) {
16
- if (capacity - used < size) {
17
- resize(capacity * 2);
15
+ void Reserve(size_t want) {
16
+ if (capacity - used < want) {
17
+ size_t new_capacity = capacity;
18
+ while (new_capacity - used < want) {
19
+ if (new_capacity >= SIZE_MAX / 2) {
20
+ ruby_malloc_size_overflow(capacity, 2);
21
+ }
22
+ new_capacity <<= 1;
23
+ }
24
+ resize(new_capacity);
18
25
  }
19
26
  }
20
27
 
@@ -19,26 +19,44 @@ typedef RubyStringBuffer DefaultBuffer;
19
19
  static VALUE
20
20
  dump(VALUE _self, VALUE obj, VALUE pretty, VALUE as_json, VALUE allow_nan) {
21
21
  // NB: as_json here is not marked by the extension, but is always on the stack
22
+ VALUE result;
23
+ int state;
24
+
22
25
  if (RTEST(pretty)) {
23
26
  RubyObjectEncoder<DefaultBuffer, PrettyWriter<DefaultBuffer> > encoder(as_json, RTEST(allow_nan));
24
- return encoder.encode(obj);
27
+ encoder.writer.SetIndent(' ', 2);
28
+ result = encoder.encode_protected(obj, &state);
25
29
  } else {
26
30
  RubyObjectEncoder<DefaultBuffer, Writer<DefaultBuffer> > encoder(as_json, RTEST(allow_nan));
27
- return encoder.encode(obj);
31
+ result = encoder.encode_protected(obj, &state);
32
+ }
33
+
34
+ if (state) {
35
+ rb_jump_tag(state);
28
36
  }
37
+ return result;
29
38
  }
30
39
 
31
40
  static VALUE
32
- load(VALUE _self, VALUE string) {
33
- RubyObjectHandler handler;
34
- Reader reader;
35
- char *cstring = StringValueCStr(string); // fixme?
36
- StringStream ss(cstring);
37
- ParseResult ok = reader.Parse(ss, handler);
41
+ load(VALUE _self, VALUE string, VALUE allow_nan) {
42
+ RubyObjectHandler handler(RTEST(allow_nan));
43
+ ParseResult ok;
44
+
45
+ {
46
+ char *cstring = StringValueCStr(string); // fixme?
47
+ StringStream ss(cstring);
48
+ Reader reader;
49
+ ok = reader.Parse<kParseNanAndInfFlag>(ss, handler);
50
+ }
38
51
 
39
52
  if (!ok) {
40
- rb_raise(rb_eParseError, "JSON parse error: %s (%lu)",
41
- GetParseError_En(ok.Code()), ok.Offset());
53
+ VALUE err = handler.GetErr();
54
+ if (RTEST(err)) {
55
+ rb_exc_raise(err);
56
+ } else {
57
+ rb_raise(rb_eParseError, "JSON parse error: %s (%lu)",
58
+ GetParseError_En(ok.Code()), ok.Offset());
59
+ }
42
60
  }
43
61
 
44
62
  return handler.GetRoot();
@@ -68,7 +86,7 @@ Init_rapidjson(void)
68
86
  rb_global_variable(&rb_cRapidJSONFragment);
69
87
 
70
88
  rb_define_private_method(rb_cCoder, "_dump", dump, 4);
71
- rb_define_method(rb_cCoder, "load", load, 1);
89
+ rb_define_method(rb_cCoder, "_load", load, 2);
72
90
  rb_define_method(rb_cCoder, "valid_json?", valid_json_p, 1);
73
91
 
74
92
  VALUE rb_eRapidJSONError = rb_const_get(rb_mRapidJSON, rb_intern("Error"));
@@ -8,7 +8,6 @@ using namespace rapidjson;
8
8
  template <typename B = RubyStringBuffer, typename W=Writer<B> >
9
9
  class RubyObjectEncoder {
10
10
  B buf;
11
- W writer;
12
11
  VALUE as_json;
13
12
  bool allow_nan;
14
13
 
@@ -200,10 +199,26 @@ class RubyObjectEncoder {
200
199
  allow_nan = allow_nan_;
201
200
  };
202
201
 
202
+ W writer;
203
203
  int depth;
204
204
 
205
205
  VALUE encode(VALUE obj) {
206
206
  encode_any(obj, true);
207
207
  return buf.GetRubyString();
208
208
  }
209
+
210
+ struct protected_args {
211
+ RubyObjectEncoder *encoder;
212
+ VALUE obj;
213
+ };
214
+
215
+ static VALUE encode_protected_cb(VALUE data) {
216
+ struct protected_args *args = (struct protected_args *)data;
217
+ return args->encoder->encode(args->obj);
218
+ }
219
+
220
+ VALUE encode_protected(VALUE obj, int *state) {
221
+ struct protected_args args = { this, obj };
222
+ return rb_protect(encode_protected_cb, (VALUE)&args, state);
223
+ }
209
224
  };
@@ -50,6 +50,10 @@ struct RubyObjectHandler : public BaseReaderHandler<UTF8<>, RubyObjectHandler> {
50
50
  }
51
51
 
52
52
  bool Double(double d) {
53
+ if (!isfinite(d) && !allow_nan) {
54
+ err = rb_exc_new_cstr(rb_eParseError, "JSON parse error: Invalid float value");
55
+ return false;
56
+ }
53
57
  return PutValue(rb_float_new(d));
54
58
  }
55
59
 
@@ -92,7 +96,7 @@ struct RubyObjectHandler : public BaseReaderHandler<UTF8<>, RubyObjectHandler> {
92
96
  depth++;
93
97
  return true;
94
98
  } else {
95
- rb_raise(rb_eParseError, "JSON parse error: input too deep");
99
+ err = rb_exc_new_cstr(rb_eParseError, "JSON parse error: input too deep");
96
100
  return false;
97
101
  }
98
102
  }
@@ -140,12 +144,18 @@ struct RubyObjectHandler : public BaseReaderHandler<UTF8<>, RubyObjectHandler> {
140
144
  return stack[0];
141
145
  }
142
146
 
143
- RubyObjectHandler(): depth(0) {
147
+ VALUE GetErr() {
148
+ return err;
149
+ }
150
+
151
+ RubyObjectHandler(bool allow_nan): err(Qfalse), depth(0), allow_nan(allow_nan) {
144
152
  stack[0] = Qundef;
145
153
  }
146
154
 
147
155
  static const int MAX_DEPTH = 256;
148
- int depth;
149
156
  VALUE stack[MAX_DEPTH];
150
157
  VALUE last_key[MAX_DEPTH];
158
+ VALUE err;
159
+ int depth;
160
+ bool allow_nan;
151
161
  };
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module RapidJSON
4
- VERSION = "0.2.1"
4
+ VERSION = "0.2.3"
5
5
  end
data/lib/rapidjson.rb CHANGED
@@ -17,6 +17,10 @@ module RapidJSON
17
17
  def dump(object)
18
18
  _dump(object, @pretty, @to_json_proc, @allow_nan)
19
19
  end
20
+
21
+ def load(string)
22
+ _load(string, @allow_nan)
23
+ end
20
24
  end
21
25
  end
22
26
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rapidjson
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.2.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - John Hawthorn
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-06-27 00:00:00.000000000 Z
11
+ date: 2023-12-27 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Fast JSON encoder/decoder based using RapidJSON
14
14
  email:
@@ -93,7 +93,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
93
93
  - !ruby/object:Gem::Version
94
94
  version: '0'
95
95
  requirements: []
96
- rubygems_version: 3.3.26
96
+ rubygems_version: 3.4.10
97
97
  signing_key:
98
98
  specification_version: 4
99
99
  summary: Fast JSON encoder/decoder based using RapidJSON