rapidjson 0.2.0 → 0.2.2
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.
- checksums.yaml +4 -4
- data/README.md +54 -21
- data/ext/rapidjson/buffer.hh +10 -3
- data/ext/rapidjson/json_escape.h +90 -0
- data/lib/rapidjson/version.rb +1 -1
- metadata +2 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 722ff2bcb2ebfc8ab861d5066e53e938933bd03d2e7f4bca7662233fa0a8a314
|
4
|
+
data.tar.gz: 59d25e68af12d81bc3b5517a88de320a76a72c6b5d7cc9d26758084bd604b9fe
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4eea208e695986e0e312c3794ba44852057f86a8159c4d862518482d263f2d13ef94fff481c38e2d7a79f881a13cef08e65eff4d49ded5c85378891bc79dab85
|
7
|
+
data.tar.gz: cafbbb2e33c4adecdfac50d1fc0bb34e3c1b019828af29714b0005a8a24955c3914c79e7a9690161589597b3df12928d6adddad8887014fd48fb36b58525f25d
|
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.
|
data/ext/rapidjson/buffer.hh
CHANGED
@@ -12,9 +12,16 @@ class RubyStringBuffer {
|
|
12
12
|
mem = RSTRING_PTR(ruby_string);
|
13
13
|
}
|
14
14
|
|
15
|
-
void Reserve(size_t
|
16
|
-
if (capacity - used <
|
17
|
-
|
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
|
|
@@ -0,0 +1,90 @@
|
|
1
|
+
#include "ruby.h"
|
2
|
+
#include "ruby/encoding.h"
|
3
|
+
|
4
|
+
/* strlen("\\u2029") == 6 */
|
5
|
+
#define ESCAPE_JSON_MAX_LEN 6
|
6
|
+
|
7
|
+
static inline long
|
8
|
+
json_escaped_length(VALUE str)
|
9
|
+
{
|
10
|
+
const long len = RSTRING_LEN(str);
|
11
|
+
if (len >= LONG_MAX / ESCAPE_JSON_MAX_LEN) {
|
12
|
+
ruby_malloc_size_overflow(len, ESCAPE_JSON_MAX_LEN);
|
13
|
+
}
|
14
|
+
return len * ESCAPE_JSON_MAX_LEN;
|
15
|
+
}
|
16
|
+
|
17
|
+
static VALUE
|
18
|
+
escape_json(VALUE self, VALUE str)
|
19
|
+
{
|
20
|
+
if (!RB_TYPE_P(str, T_STRING)) {
|
21
|
+
str = rb_convert_type(str, T_STRING, "String", "to_s");
|
22
|
+
}
|
23
|
+
|
24
|
+
rb_encoding *enc = rb_enc_get(str);
|
25
|
+
if (enc != rb_utf8_encoding() && enc != rb_usascii_encoding()) {
|
26
|
+
rb_raise(rb_eEncCompatError, "input string must be UTF-8 or ASCII");
|
27
|
+
}
|
28
|
+
|
29
|
+
const char *cstr = RSTRING_PTR(str);
|
30
|
+
const unsigned long str_len = RSTRING_LEN(str);
|
31
|
+
const char *end = cstr + RSTRING_LEN(str);
|
32
|
+
|
33
|
+
size_t initial_match = strcspn(cstr, "&<>\xe2");
|
34
|
+
if (initial_match == str_len) {
|
35
|
+
return str;
|
36
|
+
}
|
37
|
+
|
38
|
+
VALUE escaped = rb_str_buf_new(json_escaped_length(str));
|
39
|
+
rb_str_resize(escaped, json_escaped_length(str));
|
40
|
+
char *buf = RSTRING_PTR(escaped);
|
41
|
+
char *dest = buf;
|
42
|
+
|
43
|
+
memcpy(dest, cstr, initial_match);
|
44
|
+
cstr += initial_match;
|
45
|
+
dest += initial_match;
|
46
|
+
|
47
|
+
while (cstr < end) {
|
48
|
+
const char c = *cstr++;
|
49
|
+
|
50
|
+
#define JSON_ESCAPE_CONCAT(s) do { \
|
51
|
+
memcpy(dest, ("\\u" s), strlen(s) + 2); \
|
52
|
+
dest += strlen(s) + 2; \
|
53
|
+
} while (0)
|
54
|
+
|
55
|
+
if (0) {
|
56
|
+
}
|
57
|
+
else if (c == '&') {
|
58
|
+
JSON_ESCAPE_CONCAT("0026");
|
59
|
+
}
|
60
|
+
else if (c == '>') {
|
61
|
+
JSON_ESCAPE_CONCAT("003e");
|
62
|
+
}
|
63
|
+
else if (c == '<') {
|
64
|
+
JSON_ESCAPE_CONCAT("003c");
|
65
|
+
}
|
66
|
+
else if (c == '\xe2' && cstr[0] == '\x80' && cstr[1] == '\xa8') {
|
67
|
+
JSON_ESCAPE_CONCAT("2028");
|
68
|
+
cstr += 2;
|
69
|
+
}
|
70
|
+
else if (c == '\xe2' && cstr[0] == '\x80' && cstr[1] == '\xa9') {
|
71
|
+
JSON_ESCAPE_CONCAT("2029");
|
72
|
+
cstr += 2;
|
73
|
+
}
|
74
|
+
else {
|
75
|
+
*dest++ = c;
|
76
|
+
}
|
77
|
+
|
78
|
+
initial_match = strcspn(cstr, "&<>\xe2");
|
79
|
+
memcpy(dest, cstr, initial_match);
|
80
|
+
cstr += initial_match;
|
81
|
+
dest += initial_match;
|
82
|
+
|
83
|
+
#undef JSON_ESCAPE_CONCAT
|
84
|
+
}
|
85
|
+
|
86
|
+
rb_str_resize(escaped, dest - buf);
|
87
|
+
rb_enc_associate(escaped, rb_enc_get(str));
|
88
|
+
|
89
|
+
return escaped;
|
90
|
+
}
|
data/lib/rapidjson/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rapidjson
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- John Hawthorn
|
@@ -27,6 +27,7 @@ files:
|
|
27
27
|
- ext/rapidjson/cext.hh
|
28
28
|
- ext/rapidjson/encoder.hh
|
29
29
|
- ext/rapidjson/extconf.rb
|
30
|
+
- ext/rapidjson/json_escape.h
|
30
31
|
- ext/rapidjson/parser.hh
|
31
32
|
- ext/rapidjson/rapidjson/include/rapidjson/allocators.h
|
32
33
|
- ext/rapidjson/rapidjson/include/rapidjson/cursorstreamwrapper.h
|