paquito 0.7.0 → 0.8.0
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/.github/workflows/ci.yml +1 -1
- data/.rubocop.yml +3 -0
- data/CHANGELOG.md +2 -0
- data/Gemfile.lock +23 -23
- data/README.md +11 -1
- data/benchmark/string-bypass.rb +35 -0
- data/lib/paquito/single_byte_prefix_version.rb +12 -2
- data/lib/paquito/single_byte_prefix_version_with_string_bypass.rb +57 -0
- data/lib/paquito/types.rb +5 -5
- data/lib/paquito/version.rb +1 -1
- data/lib/paquito.rb +1 -0
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2cfefa4171fc3e9f968368e99c134e864d493c6651ed21aff0e1bc299a95fb7f
|
4
|
+
data.tar.gz: e92cacde6d2aa0867b740f99a001d3ff109f4c88eddb7d89594305a579122af3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3e032eb7438d07371862c7f9015b8c0a2f72dc8a93004387f1b151f75d06614dba89bc97da21d3eb83399f1c86909f1dc0bbd5702ec8cc4fef1f5001f512a3da
|
7
|
+
data.tar.gz: e1bd239ec600c28dc5e322b8a8a95daeb539aaada4c9167cf046f5ee5716eb3a6231487b663b534d0db8cb6e1ce2ce53d1dd1b6706184b57f36890edbcbfa663
|
data/.github/workflows/ci.yml
CHANGED
data/.rubocop.yml
CHANGED
data/CHANGELOG.md
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,18 +1,18 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
paquito (0.
|
4
|
+
paquito (0.8.0)
|
5
5
|
msgpack (>= 1.5.2)
|
6
6
|
|
7
7
|
GEM
|
8
8
|
remote: https://rubygems.org/
|
9
9
|
specs:
|
10
|
-
activemodel (6.1.
|
11
|
-
activesupport (= 6.1.
|
12
|
-
activerecord (6.1.
|
13
|
-
activemodel (= 6.1.
|
14
|
-
activesupport (= 6.1.
|
15
|
-
activesupport (6.1.
|
10
|
+
activemodel (6.1.6.1)
|
11
|
+
activesupport (= 6.1.6.1)
|
12
|
+
activerecord (6.1.6.1)
|
13
|
+
activemodel (= 6.1.6.1)
|
14
|
+
activesupport (= 6.1.6.1)
|
15
|
+
activesupport (6.1.6.1)
|
16
16
|
concurrent-ruby (~> 1.0, >= 1.0.2)
|
17
17
|
i18n (>= 1.6, < 2)
|
18
18
|
minitest (>= 5.1)
|
@@ -21,38 +21,38 @@ GEM
|
|
21
21
|
ast (2.4.2)
|
22
22
|
benchmark-ips (2.10.0)
|
23
23
|
byebug (11.1.3)
|
24
|
-
concurrent-ruby (1.1.
|
25
|
-
i18n (1.
|
24
|
+
concurrent-ruby (1.1.10)
|
25
|
+
i18n (1.12.0)
|
26
26
|
concurrent-ruby (~> 1.0)
|
27
|
-
minitest (5.
|
28
|
-
msgpack (1.
|
29
|
-
parallel (1.
|
30
|
-
parser (3.1.1
|
27
|
+
minitest (5.16.3)
|
28
|
+
msgpack (1.6.0)
|
29
|
+
parallel (1.22.1)
|
30
|
+
parser (3.1.2.1)
|
31
31
|
ast (~> 2.4.1)
|
32
32
|
rainbow (3.1.1)
|
33
33
|
rake (13.0.6)
|
34
|
-
regexp_parser (2.
|
34
|
+
regexp_parser (2.5.0)
|
35
35
|
rexml (3.2.5)
|
36
|
-
rubocop (1.
|
36
|
+
rubocop (1.30.1)
|
37
37
|
parallel (~> 1.10)
|
38
38
|
parser (>= 3.1.0.0)
|
39
39
|
rainbow (>= 2.2.2, < 4.0)
|
40
40
|
regexp_parser (>= 1.8, < 3.0)
|
41
|
-
rexml
|
42
|
-
rubocop-ast (>= 1.
|
41
|
+
rexml (>= 3.2.5, < 4.0)
|
42
|
+
rubocop-ast (>= 1.18.0, < 2.0)
|
43
43
|
ruby-progressbar (~> 1.7)
|
44
44
|
unicode-display_width (>= 1.4.0, < 3.0)
|
45
|
-
rubocop-ast (1.
|
45
|
+
rubocop-ast (1.21.0)
|
46
46
|
parser (>= 3.1.1.0)
|
47
47
|
rubocop-shopify (2.5.0)
|
48
48
|
rubocop (~> 1.25)
|
49
49
|
ruby-progressbar (1.11.0)
|
50
|
-
sorbet-runtime (0.5.
|
51
|
-
sqlite3 (1.4.
|
52
|
-
tzinfo (2.0.
|
50
|
+
sorbet-runtime (0.5.10365)
|
51
|
+
sqlite3 (1.4.4)
|
52
|
+
tzinfo (2.0.5)
|
53
53
|
concurrent-ruby (~> 1.0)
|
54
|
-
unicode-display_width (2.
|
55
|
-
zeitwerk (2.
|
54
|
+
unicode-display_width (2.2.0)
|
55
|
+
zeitwerk (2.6.0)
|
56
56
|
|
57
57
|
PLATFORMS
|
58
58
|
ruby
|
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# Paquito
|
2
2
|
|
3
|
-
`Paquito`
|
3
|
+
`Paquito` provides utility classes to define optimized and evolutive serializers.
|
4
4
|
|
5
5
|
## Installation
|
6
6
|
|
@@ -62,6 +62,16 @@ coder.dump([1]) # => "\x01[1]"
|
|
62
62
|
coder.load("\x00---\n:foo: 42") # => { foo: 42 }
|
63
63
|
```
|
64
64
|
|
65
|
+
### `SingleBytePrefixVersionWithStringBypass`
|
66
|
+
|
67
|
+
Works like `Paquito::SingleBytePrefixVersion` except that versions `253`, `254` and `255` are reserved for serializing strings
|
68
|
+
in an optimized way.
|
69
|
+
|
70
|
+
When the object to serialize is an `UTF-8`, `ASCII` or `BINARY` string, rather than invoking the underlying serializer, it simply
|
71
|
+
prepends a single byte to the string which indicates the encoding.
|
72
|
+
|
73
|
+
The larger the string the larger the speed gain is, e.g. for a 1MB string, it's over 500x faster than going through `MessagePack` or `Marshal`.
|
74
|
+
|
65
75
|
### `CommentPrefixVersion`
|
66
76
|
|
67
77
|
Similar to the single byte prefix, but meant to be human readable and to allow for migrating unversioned payloads.
|
@@ -0,0 +1,35 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require "bundler/setup"
|
5
|
+
require "paquito"
|
6
|
+
require "benchmark/ips"
|
7
|
+
|
8
|
+
CODEC = Paquito::CodecFactory.build([])
|
9
|
+
VERSIONED = Paquito::SingleBytePrefixVersion.new(0, 0 => CODEC)
|
10
|
+
BYPASS = Paquito::SingleBytePrefixVersionWithStringBypass.new(0, 0 => CODEC)
|
11
|
+
|
12
|
+
[100, 10_000, 1_000_000].each do |size|
|
13
|
+
string = Random.bytes(size).freeze
|
14
|
+
msgpack_payload = VERSIONED.dump(string).freeze
|
15
|
+
bypass_payload = BYPASS.dump(string).freeze
|
16
|
+
marshal_payload = Marshal.dump(string).freeze
|
17
|
+
|
18
|
+
puts " === Read #{size}B ==="
|
19
|
+
Benchmark.ips do |x|
|
20
|
+
x.report("marshal") { Marshal.load(marshal_payload) }
|
21
|
+
x.report("msgpack") { VERSIONED.load(msgpack_payload) }
|
22
|
+
x.report("bypass") { BYPASS.load(bypass_payload) }
|
23
|
+
x.compare!(order: :baseline)
|
24
|
+
end
|
25
|
+
|
26
|
+
puts " === Write #{size}B ==="
|
27
|
+
Benchmark.ips do |x|
|
28
|
+
x.report("marshal") { Marshal.dump(string) }
|
29
|
+
x.report("msgpack") { VERSIONED.dump(string) }
|
30
|
+
x.report("bypass") { BYPASS.dump(string) }
|
31
|
+
x.compare!(order: :baseline)
|
32
|
+
end
|
33
|
+
|
34
|
+
puts
|
35
|
+
end
|
@@ -3,8 +3,8 @@
|
|
3
3
|
module Paquito
|
4
4
|
class SingleBytePrefixVersion
|
5
5
|
def initialize(current_version, coders)
|
6
|
-
@current_version = current_version
|
7
|
-
@coders = coders.transform_values { |c| Paquito.cast(c) }
|
6
|
+
@current_version = validate_version(current_version)
|
7
|
+
@coders = coders.transform_keys { |v| validate_version(v) }.transform_values { |c| Paquito.cast(c) }
|
8
8
|
@current_coder = coders.fetch(current_version)
|
9
9
|
end
|
10
10
|
|
@@ -23,5 +23,15 @@ module Paquito
|
|
23
23
|
end
|
24
24
|
coder.load(payload.byteslice(1..-1))
|
25
25
|
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def validate_version(version)
|
30
|
+
unless (0..255).cover?(version)
|
31
|
+
raise ArgumentError, "Invalid version #{version.inspect}, versions must be an integer between 0 and 255"
|
32
|
+
end
|
33
|
+
|
34
|
+
version
|
35
|
+
end
|
26
36
|
end
|
27
37
|
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Paquito
|
4
|
+
class SingleBytePrefixVersionWithStringBypass < SingleBytePrefixVersion
|
5
|
+
UTF8_VERSION = 255
|
6
|
+
BINARY_VERSION = 254
|
7
|
+
ASCII_VERSION = 253
|
8
|
+
|
9
|
+
def dump(object)
|
10
|
+
if object.class == String # We don't want to match subclasses
|
11
|
+
case object.encoding
|
12
|
+
when Encoding::UTF_8
|
13
|
+
UTF8_VERSION.chr(Encoding::BINARY) << object
|
14
|
+
when Encoding::BINARY
|
15
|
+
BINARY_VERSION.chr(Encoding::BINARY) << object
|
16
|
+
when Encoding::US_ASCII
|
17
|
+
ASCII_VERSION.chr(Encoding::BINARY) << object
|
18
|
+
else
|
19
|
+
super
|
20
|
+
end
|
21
|
+
else
|
22
|
+
super
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def load(payload)
|
27
|
+
payload_version = payload.getbyte(0)
|
28
|
+
unless payload_version
|
29
|
+
raise UnsupportedCodec, "Missing version byte."
|
30
|
+
end
|
31
|
+
|
32
|
+
case payload_version
|
33
|
+
when UTF8_VERSION
|
34
|
+
payload.byteslice(1..-1).force_encoding(Encoding::UTF_8)
|
35
|
+
when BINARY_VERSION
|
36
|
+
payload.byteslice(1..-1).force_encoding(Encoding::BINARY)
|
37
|
+
when ASCII_VERSION
|
38
|
+
payload.byteslice(1..-1).force_encoding(Encoding::US_ASCII)
|
39
|
+
else
|
40
|
+
coder = @coders.fetch(payload_version) do
|
41
|
+
raise UnsupportedCodec, "Unsupported packer version #{payload_version}"
|
42
|
+
end
|
43
|
+
coder.load(payload.byteslice(1..-1))
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
def validate_version(version)
|
50
|
+
unless (0..252).cover?(version)
|
51
|
+
raise ArgumentError, "Invalid version #{version.inspect}, versions must be an integer between 0 and 252"
|
52
|
+
end
|
53
|
+
|
54
|
+
version
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
data/lib/paquito/types.rb
CHANGED
@@ -160,7 +160,7 @@ module Paquito
|
|
160
160
|
|
161
161
|
packer.write(value.to_h)
|
162
162
|
end,
|
163
|
-
unpacker: ->(unpacker) { HashWithIndifferentAccess.new(unpacker.read) },
|
163
|
+
unpacker: ->(unpacker) { ActiveSupport::HashWithIndifferentAccess.new(unpacker.read) },
|
164
164
|
recursive: true,
|
165
165
|
},
|
166
166
|
"ActiveSupport::TimeWithZone" => {
|
@@ -206,11 +206,11 @@ module Paquito
|
|
206
206
|
class << self
|
207
207
|
def register(factory, types)
|
208
208
|
types.each do |type|
|
209
|
-
name = type.name
|
210
|
-
|
211
209
|
# Up to Rails 7 ActiveSupport::TimeWithZone#name returns "Time"
|
212
|
-
|
213
|
-
|
210
|
+
name = if defined?(ActiveSupport::TimeWithZone) && type == ActiveSupport::TimeWithZone
|
211
|
+
"ActiveSupport::TimeWithZone"
|
212
|
+
else
|
213
|
+
type.name
|
214
214
|
end
|
215
215
|
|
216
216
|
type_attributes = TYPES.fetch(name)
|
data/lib/paquito/version.rb
CHANGED
data/lib/paquito.rb
CHANGED
@@ -16,6 +16,7 @@ require "paquito/safe_yaml"
|
|
16
16
|
require "paquito/conditional_compressor"
|
17
17
|
require "paquito/cache_entry_coder"
|
18
18
|
require "paquito/single_byte_prefix_version"
|
19
|
+
require "paquito/single_byte_prefix_version_with_string_bypass"
|
19
20
|
require "paquito/comment_prefix_version"
|
20
21
|
require "paquito/types"
|
21
22
|
require "paquito/codec_factory"
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: paquito
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.8.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jean Boussier
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
11
|
+
date: 2022-11-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: msgpack
|
@@ -41,6 +41,7 @@ files:
|
|
41
41
|
- README.md
|
42
42
|
- Rakefile
|
43
43
|
- benchmark/msgpack-pooling.rb
|
44
|
+
- benchmark/string-bypass.rb
|
44
45
|
- bin/console
|
45
46
|
- bin/setup
|
46
47
|
- dev.yml
|
@@ -57,6 +58,7 @@ files:
|
|
57
58
|
- lib/paquito/safe_yaml.rb
|
58
59
|
- lib/paquito/serialized_column.rb
|
59
60
|
- lib/paquito/single_byte_prefix_version.rb
|
61
|
+
- lib/paquito/single_byte_prefix_version_with_string_bypass.rb
|
60
62
|
- lib/paquito/struct.rb
|
61
63
|
- lib/paquito/translate_errors.rb
|
62
64
|
- lib/paquito/typed_struct.rb
|