messagepack 1.0.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 +7 -0
- data/README.adoc +773 -0
- data/Rakefile +8 -0
- data/docs/Gemfile +7 -0
- data/docs/README.md +85 -0
- data/docs/_config.yml +137 -0
- data/docs/_guides/index.adoc +14 -0
- data/docs/_guides/io-streaming.adoc +226 -0
- data/docs/_guides/migration.adoc +218 -0
- data/docs/_guides/performance.adoc +189 -0
- data/docs/_pages/buffer.adoc +85 -0
- data/docs/_pages/extension-types.adoc +117 -0
- data/docs/_pages/factory-pattern.adoc +115 -0
- data/docs/_pages/index.adoc +20 -0
- data/docs/_pages/serialization.adoc +159 -0
- data/docs/_pages/streaming.adoc +97 -0
- data/docs/_pages/symbol-extension.adoc +69 -0
- data/docs/_pages/timestamp-extension.adoc +88 -0
- data/docs/_references/api.adoc +360 -0
- data/docs/_references/extensions.adoc +198 -0
- data/docs/_references/format.adoc +301 -0
- data/docs/_references/index.adoc +14 -0
- data/docs/_tutorials/extension-types.adoc +170 -0
- data/docs/_tutorials/getting-started.adoc +165 -0
- data/docs/_tutorials/index.adoc +14 -0
- data/docs/_tutorials/thread-safety.adoc +157 -0
- data/docs/index.adoc +77 -0
- data/docs/lychee.toml +42 -0
- data/lib/messagepack/bigint.rb +131 -0
- data/lib/messagepack/buffer.rb +534 -0
- data/lib/messagepack/core_ext.rb +34 -0
- data/lib/messagepack/error.rb +24 -0
- data/lib/messagepack/extensions/base.rb +55 -0
- data/lib/messagepack/extensions/registry.rb +154 -0
- data/lib/messagepack/extensions/symbol.rb +38 -0
- data/lib/messagepack/extensions/timestamp.rb +110 -0
- data/lib/messagepack/extensions/value.rb +38 -0
- data/lib/messagepack/factory.rb +349 -0
- data/lib/messagepack/format.rb +99 -0
- data/lib/messagepack/packer.rb +702 -0
- data/lib/messagepack/symbol.rb +4 -0
- data/lib/messagepack/time.rb +29 -0
- data/lib/messagepack/timestamp.rb +4 -0
- data/lib/messagepack/unpacker.rb +1418 -0
- data/lib/messagepack/version.rb +5 -0
- data/lib/messagepack.rb +81 -0
- metadata +94 -0
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Extension types reference
|
|
3
|
+
nav_order: 3
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
== Purpose
|
|
7
|
+
|
|
8
|
+
Reference for built-in and custom extension types in MessagePack Ruby.
|
|
9
|
+
|
|
10
|
+
== Concepts
|
|
11
|
+
|
|
12
|
+
Extension types allow serialization of objects that don't have native MessagePack
|
|
13
|
+
representations. Each extension type has:
|
|
14
|
+
|
|
15
|
+
* **Type ID** - An integer from -128 to 127
|
|
16
|
+
* **Packer** - Method to convert object to binary
|
|
17
|
+
* **Unpacker** - Method to reconstruct object from binary
|
|
18
|
+
|
|
19
|
+
== Built-in extension types
|
|
20
|
+
|
|
21
|
+
=== Timestamp (-1)
|
|
22
|
+
|
|
23
|
+
Type ID: -1 (reserved by MessagePack specification)
|
|
24
|
+
|
|
25
|
+
Serializes Time objects with nanosecond precision.
|
|
26
|
+
|
|
27
|
+
==== Format selection
|
|
28
|
+
|
|
29
|
+
The implementation automatically selects the most compact format:
|
|
30
|
+
|
|
31
|
+
* **Timestamp32** (4 bytes) - Seconds only, fits in 32 bits
|
|
32
|
+
* **Timestamp64** (8 bytes) - Seconds + nanoseconds, fits in 64 bits
|
|
33
|
+
* **Timestamp96** (12 bytes) - Full precision
|
|
34
|
+
|
|
35
|
+
[source,ruby]
|
|
36
|
+
----
|
|
37
|
+
factory.register_type(-1, Time,
|
|
38
|
+
packer: Messagepack::Time::Packer,
|
|
39
|
+
unpacker: Messagepack::Time::Unpacker
|
|
40
|
+
)
|
|
41
|
+
----
|
|
42
|
+
|
|
43
|
+
==== Registration
|
|
44
|
+
|
|
45
|
+
The default factory includes timestamp registration:
|
|
46
|
+
|
|
47
|
+
[source,ruby]
|
|
48
|
+
----
|
|
49
|
+
# Already registered in DefaultFactory
|
|
50
|
+
Messagepack::DefaultFactory.register_type(-1, Time,
|
|
51
|
+
packer: Messagepack::Time::Packer,
|
|
52
|
+
unpacker: Messagepack::Time::Unpacker
|
|
53
|
+
)
|
|
54
|
+
----
|
|
55
|
+
|
|
56
|
+
==== Example
|
|
57
|
+
|
|
58
|
+
[source,ruby]
|
|
59
|
+
----
|
|
60
|
+
# Current time with nanoseconds
|
|
61
|
+
now = Time.now
|
|
62
|
+
binary = factory.pack(now)
|
|
63
|
+
restored = factory.unpack(binary)
|
|
64
|
+
|
|
65
|
+
# Nanoseconds are preserved
|
|
66
|
+
puts restored.tv_nsec
|
|
67
|
+
----
|
|
68
|
+
|
|
69
|
+
=== Symbol (0)
|
|
70
|
+
|
|
71
|
+
Type ID: 0 (common convention, not reserved)
|
|
72
|
+
|
|
73
|
+
Efficiently serializes Ruby symbols.
|
|
74
|
+
|
|
75
|
+
[source,ruby]
|
|
76
|
+
----
|
|
77
|
+
factory.register_type(0, Symbol,
|
|
78
|
+
packer: ->(sym) { sym.to_s },
|
|
79
|
+
unpacker: ->(str) { str.to_sym }
|
|
80
|
+
)
|
|
81
|
+
----
|
|
82
|
+
|
|
83
|
+
NOTE: The symbol extension is not registered by default.
|
|
84
|
+
|
|
85
|
+
==== Example
|
|
86
|
+
|
|
87
|
+
[source,ruby]
|
|
88
|
+
----
|
|
89
|
+
factory = Messagepack::Factory.new
|
|
90
|
+
factory.register_type(0, Symbol)
|
|
91
|
+
|
|
92
|
+
data = { status: :active, tags: [:urgent, :important] }
|
|
93
|
+
binary = factory.pack(data)
|
|
94
|
+
result = factory.unpack(binary)
|
|
95
|
+
# => {:status=>:active, :tags=>[:urgent, :important]}
|
|
96
|
+
----
|
|
97
|
+
|
|
98
|
+
== Custom extension types
|
|
99
|
+
|
|
100
|
+
=== Type ID ranges
|
|
101
|
+
|
|
102
|
+
* `-128 to -1` - Reserved for future MessagePack specifications
|
|
103
|
+
* `0` - Convention for symbol extension
|
|
104
|
+
* `1 to 127` - Available for application-specific types
|
|
105
|
+
|
|
106
|
+
=== Registration patterns
|
|
107
|
+
|
|
108
|
+
==== Method name (simple)
|
|
109
|
+
|
|
110
|
+
[source,ruby]
|
|
111
|
+
----
|
|
112
|
+
class MyClass
|
|
113
|
+
def to_msgpack_ext
|
|
114
|
+
# Return binary string
|
|
115
|
+
[value].pack("I")
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
def self.from_msgpack_ext(data)
|
|
119
|
+
# Parse and return instance
|
|
120
|
+
new(data.unpack("I").first)
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
factory.register_type(0x10, MyClass,
|
|
125
|
+
packer: :to_msgpack_ext,
|
|
126
|
+
unpacker: :from_msgpack_ext
|
|
127
|
+
)
|
|
128
|
+
----
|
|
129
|
+
|
|
130
|
+
==== Proc (flexible)
|
|
131
|
+
|
|
132
|
+
[source,ruby]
|
|
133
|
+
----
|
|
134
|
+
factory.register_type(0x11, URI,
|
|
135
|
+
packer: ->(uri) { uri.to_s },
|
|
136
|
+
unpacker: ->(str) { URI.parse(str) }
|
|
137
|
+
)
|
|
138
|
+
----
|
|
139
|
+
|
|
140
|
+
==== Recursive (nested structures)
|
|
141
|
+
|
|
142
|
+
[source,ruby]
|
|
143
|
+
----
|
|
144
|
+
factory.register_type(0x12, TreeNode,
|
|
145
|
+
packer: ->(obj, packer) {
|
|
146
|
+
packer.write({ value: obj.value, left: obj.left, right: obj.right })
|
|
147
|
+
},
|
|
148
|
+
unpacker: ->(unpacker) {
|
|
149
|
+
data = unpacker.read
|
|
150
|
+
TreeNode.new(data[:value], data[:left], data[:right])
|
|
151
|
+
},
|
|
152
|
+
recursive: true
|
|
153
|
+
)
|
|
154
|
+
----
|
|
155
|
+
|
|
156
|
+
== Extension value class
|
|
157
|
+
|
|
158
|
+
The `Messagepack::ExtensionValue` class represents raw extension types.
|
|
159
|
+
|
|
160
|
+
=== Accessing extension data
|
|
161
|
+
|
|
162
|
+
[source,ruby]
|
|
163
|
+
----
|
|
164
|
+
# Register extension that produces ExtensionValue
|
|
165
|
+
factory.register_type(0x20, MyClass, ...)
|
|
166
|
+
|
|
167
|
+
# When unpacking, access raw extension data
|
|
168
|
+
obj = factory.unpack(binary)
|
|
169
|
+
if obj.is_a?(Messagepack::ExtensionValue)
|
|
170
|
+
puts "Type: #{obj.type}"
|
|
171
|
+
puts "Data: #{obj.data.inspect}"
|
|
172
|
+
end
|
|
173
|
+
----
|
|
174
|
+
|
|
175
|
+
=== Creating extension values
|
|
176
|
+
|
|
177
|
+
[source,ruby]
|
|
178
|
+
----
|
|
179
|
+
ext = Messagepack::ExtensionValue.new(0x20, "payload")
|
|
180
|
+
binary = factory.pack(ext)
|
|
181
|
+
----
|
|
182
|
+
|
|
183
|
+
== Type ID registry
|
|
184
|
+
|
|
185
|
+
This table tracks commonly used type IDs:
|
|
186
|
+
|
|
187
|
+
[width="40%",options="header"]
|
|
188
|
+
|===
|
|
189
|
+
|Type ID |Type |Status
|
|
190
|
+
|-128 to -1|Reserved|MessagePack specification
|
|
191
|
+
|0|Symbol|Convention
|
|
192
|
+
|1-127|Application|Available
|
|
193
|
+
|===
|
|
194
|
+
|
|
195
|
+
When creating custom extension types:
|
|
196
|
+
* Check existing registrations for conflicts
|
|
197
|
+
* Document your type IDs
|
|
198
|
+
* Consider using a registry for distributed applications
|
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Format specification
|
|
3
|
+
nav_order: 2
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
== Purpose
|
|
7
|
+
|
|
8
|
+
Detailed specification of the MessagePack binary format.
|
|
9
|
+
|
|
10
|
+
== References
|
|
11
|
+
|
|
12
|
+
* https://github.com/msgpack/msgpack/blob/master/spec.md[Official MessagePack specification]
|
|
13
|
+
|
|
14
|
+
== Format overview
|
|
15
|
+
|
|
16
|
+
MessagePack uses a compact binary format where the first byte contains both
|
|
17
|
+
format information and often the value itself.
|
|
18
|
+
|
|
19
|
+
== Integer types
|
|
20
|
+
|
|
21
|
+
=== Positive fixint (0x00 - 0x7F)
|
|
22
|
+
|
|
23
|
+
Stores integers 0-127 in a single byte.
|
|
24
|
+
|
|
25
|
+
[source]
|
|
26
|
+
----
|
|
27
|
+
+--------+
|
|
28
|
+
|0XXXXXXX|
|
|
29
|
+
+--------+
|
|
30
|
+
|
|
31
|
+
stores 0-127 in one byte
|
|
32
|
+
----
|
|
33
|
+
|
|
34
|
+
=== Negative fixint (0xE0 - 0xFF)
|
|
35
|
+
|
|
36
|
+
Stores integers -1 to -32 in a single byte.
|
|
37
|
+
|
|
38
|
+
[source]
|
|
39
|
+
----
|
|
40
|
+
+--------+
|
|
41
|
+
|111XXXXX|
|
|
42
|
+
+--------+
|
|
43
|
+
|
|
44
|
+
stores -32 to -1 in one byte
|
|
45
|
+
----
|
|
46
|
+
|
|
47
|
+
=== uint8 (0xCC)
|
|
48
|
+
|
|
49
|
+
Stores unsigned 8-bit integer.
|
|
50
|
+
|
|
51
|
+
[source]
|
|
52
|
+
----
|
|
53
|
+
+--------+--------+
|
|
54
|
+
| 0xCC |XXXXXXX|
|
|
55
|
+
+--------+--------+
|
|
56
|
+
|
|
57
|
+
stores 0-255 in two bytes
|
|
58
|
+
----
|
|
59
|
+
|
|
60
|
+
=== uint16 (0xCD)
|
|
61
|
+
|
|
62
|
+
Stores unsigned 16-bit integer (big-endian).
|
|
63
|
+
|
|
64
|
+
[source]
|
|
65
|
+
----
|
|
66
|
+
+--------+--------+--------+
|
|
67
|
+
| 0xCD |ZZZZZZZZ|ZZZZZZZZ|
|
|
68
|
+
+--------+--------+--------+
|
|
69
|
+
|
|
70
|
+
stores 0-65535 in three bytes
|
|
71
|
+
----
|
|
72
|
+
|
|
73
|
+
=== uint32 (0xCE)
|
|
74
|
+
|
|
75
|
+
Stores unsigned 32-bit integer (big-endian).
|
|
76
|
+
|
|
77
|
+
[source]
|
|
78
|
+
----
|
|
79
|
+
+--------+--------+--------+--------+--------+
|
|
80
|
+
| 0xCE |AAAAAAAA|AAAAAAAA|AAAAAAAA|AAAAAAAA|
|
|
81
|
+
+--------+--------+--------+--------+--------+
|
|
82
|
+
|
|
83
|
+
stores 0-4294967295 in five bytes
|
|
84
|
+
----
|
|
85
|
+
|
|
86
|
+
=== uint64 (0xCF)
|
|
87
|
+
|
|
88
|
+
Stores unsigned 64-bit integer (big-endian).
|
|
89
|
+
|
|
90
|
+
[source]
|
|
91
|
+
----
|
|
92
|
+
+--------+--------+--------+--------+--------+--------+--------+--------+--------+
|
|
93
|
+
| 0xCF |AAAAAAAA|AAAAAAAA|AAAAAAAA|AAAAAAAA|AAAAAAAA|AAAAAAAA|AAAAAAAA|AAAAAAAA|
|
|
94
|
+
+--------+--------+--------+--------+--------+--------+--------+--------+--------+
|
|
95
|
+
|
|
96
|
+
stores 0-18446744073709551615 in nine bytes
|
|
97
|
+
----
|
|
98
|
+
|
|
99
|
+
=== int8 (0xD0)
|
|
100
|
+
|
|
101
|
+
Stores signed 8-bit integer.
|
|
102
|
+
|
|
103
|
+
[source]
|
|
104
|
+
----
|
|
105
|
+
+--------+--------+
|
|
106
|
+
| 0xD0 |ZZZZZZZZ|
|
|
107
|
+
+--------+--------+
|
|
108
|
+
|
|
109
|
+
stores -128 to 127 in two bytes
|
|
110
|
+
----
|
|
111
|
+
|
|
112
|
+
=== int16 (0xD1)
|
|
113
|
+
|
|
114
|
+
Stores signed 16-bit integer (big-endian).
|
|
115
|
+
|
|
116
|
+
=== int32 (0xD2)
|
|
117
|
+
|
|
118
|
+
Stores signed 32-bit integer (big-endian).
|
|
119
|
+
|
|
120
|
+
=== int64 (0xD3)
|
|
121
|
+
|
|
122
|
+
Stores signed 64-bit integer (big-endian).
|
|
123
|
+
|
|
124
|
+
== Floating point types
|
|
125
|
+
|
|
126
|
+
=== float32 (0xCA)
|
|
127
|
+
|
|
128
|
+
Stores IEEE 754 single precision floating point (big-endian).
|
|
129
|
+
|
|
130
|
+
[source]
|
|
131
|
+
----
|
|
132
|
+
+--------+--------+--------+--------+--------+
|
|
133
|
+
| 0xCA |FFFFFFFF|FFFFFFFF|FFFFFFFF|FFFFFFFF|
|
|
134
|
+
+--------+--------+--------+--------+--------+
|
|
135
|
+
|
|
136
|
+
stores float32 in five bytes
|
|
137
|
+
----
|
|
138
|
+
|
|
139
|
+
=== float64 (0xCB)
|
|
140
|
+
|
|
141
|
+
Stores IEEE 754 double precision floating point (big-endian).
|
|
142
|
+
|
|
143
|
+
[source]
|
|
144
|
+
----
|
|
145
|
+
+--------+--------+--------+--------+--------+--------+--------+--------+--------+
|
|
146
|
+
| 0xCB |FFFFFFFF|FFFFFFFF|FFFFFFFF|FFFFFFFF|FFFFFFFF|FFFFFFFF|FFFFFFFF|FFFFFFFF|
|
|
147
|
+
+--------+--------+--------+--------+--------+--------+--------+--------+--------+
|
|
148
|
+
|
|
149
|
+
stores float64 in nine bytes
|
|
150
|
+
----
|
|
151
|
+
|
|
152
|
+
== String types
|
|
153
|
+
|
|
154
|
+
=== fixstr (0xA0 - 0xBF)
|
|
155
|
+
|
|
156
|
+
Stores strings with length 0-31.
|
|
157
|
+
|
|
158
|
+
[source]
|
|
159
|
+
----
|
|
160
|
+
+--------+========+
|
|
161
|
+
|101XXXXX| data |
|
|
162
|
+
+--------+========+
|
|
163
|
+
|
|
164
|
+
stores 0-31 byte strings in 2-32 bytes
|
|
165
|
+
----
|
|
166
|
+
|
|
167
|
+
=== str8 (0xD9)
|
|
168
|
+
|
|
169
|
+
Stores strings with length 0-255.
|
|
170
|
+
|
|
171
|
+
[source]
|
|
172
|
+
----
|
|
173
|
+
+--------+--------+========+
|
|
174
|
+
| 0xD9 |YYYYYYYY| data |
|
|
175
|
+
+--------+--------+========+
|
|
176
|
+
|
|
177
|
+
stores 0-255 byte strings in 2-257 bytes
|
|
178
|
+
----
|
|
179
|
+
|
|
180
|
+
=== str16 (0xDA)
|
|
181
|
+
|
|
182
|
+
Stores strings with length 0-65535.
|
|
183
|
+
|
|
184
|
+
[source]
|
|
185
|
+
----
|
|
186
|
+
+--------+--------+--------+========+
|
|
187
|
+
| 0xDA |ZZZZZZZZ|ZZZZZZZZ| data |
|
|
188
|
+
+--------+--------+--------+========+
|
|
189
|
+
|
|
190
|
+
stores 0-65535 byte strings in 4-65539 bytes
|
|
191
|
+
----
|
|
192
|
+
|
|
193
|
+
=== str32 (0xDB)
|
|
194
|
+
|
|
195
|
+
Stores strings with length 0-4294967295.
|
|
196
|
+
|
|
197
|
+
== Binary types
|
|
198
|
+
|
|
199
|
+
=== bin8 (0xC4)
|
|
200
|
+
|
|
201
|
+
Stores binary data with length 0-255.
|
|
202
|
+
|
|
203
|
+
=== bin16 (0xC5)
|
|
204
|
+
|
|
205
|
+
Stores binary data with length 0-65535.
|
|
206
|
+
|
|
207
|
+
=== bin32 (0xC6)
|
|
208
|
+
|
|
209
|
+
Stores binary data with length 0-4294967295.
|
|
210
|
+
|
|
211
|
+
== Array types
|
|
212
|
+
|
|
213
|
+
=== fixarray (0x90 - 0x9F)
|
|
214
|
+
|
|
215
|
+
Stores arrays with 0-15 elements.
|
|
216
|
+
|
|
217
|
+
[source]
|
|
218
|
+
----
|
|
219
|
+
+--------+~~~~~~~~~~~~~~~~~+
|
|
220
|
+
|1001XXXX| N objects |
|
|
221
|
+
+--------+~~~~~~~~~~~~~~~~~+
|
|
222
|
+
|
|
223
|
+
stores 0-15 element arrays
|
|
224
|
+
----
|
|
225
|
+
|
|
226
|
+
=== array16 (0xDC)
|
|
227
|
+
|
|
228
|
+
Stores arrays with 0-65535 elements.
|
|
229
|
+
|
|
230
|
+
=== array32 (0xDD)
|
|
231
|
+
|
|
232
|
+
Stores arrays with 0-4294967295 elements.
|
|
233
|
+
|
|
234
|
+
== Map types
|
|
235
|
+
|
|
236
|
+
=== fixmap (0x80 - 0x8F)
|
|
237
|
+
|
|
238
|
+
Stores maps with 0-15 key-value pairs.
|
|
239
|
+
|
|
240
|
+
=== map16 (0xDE)
|
|
241
|
+
|
|
242
|
+
Stores maps with 0-65535 key-value pairs.
|
|
243
|
+
|
|
244
|
+
=== map32 (0xDF)
|
|
245
|
+
|
|
246
|
+
Stores maps with 0-4294967295 key-value pairs.
|
|
247
|
+
|
|
248
|
+
== Extension types
|
|
249
|
+
|
|
250
|
+
=== fixext1 (0xD4)
|
|
251
|
+
|
|
252
|
+
Stores extension with 1 byte data.
|
|
253
|
+
|
|
254
|
+
=== fixext2 (0xD5)
|
|
255
|
+
|
|
256
|
+
Stores extension with 2 bytes data.
|
|
257
|
+
|
|
258
|
+
=== fixext4 (0xD6)
|
|
259
|
+
|
|
260
|
+
Stores extension with 4 bytes data.
|
|
261
|
+
|
|
262
|
+
=== fixext8 (0xD7)
|
|
263
|
+
|
|
264
|
+
Stores extension with 8 bytes data.
|
|
265
|
+
|
|
266
|
+
=== fixext16 (0xD8)
|
|
267
|
+
|
|
268
|
+
Stores extension with 16 bytes data.
|
|
269
|
+
|
|
270
|
+
=== ext8 (0xC7)
|
|
271
|
+
|
|
272
|
+
Stores extension with length 0-255.
|
|
273
|
+
|
|
274
|
+
=== ext16 (0xC8)
|
|
275
|
+
|
|
276
|
+
Stores extension with length 0-65535.
|
|
277
|
+
|
|
278
|
+
=== ext32 (0xC9)
|
|
279
|
+
|
|
280
|
+
Stores extension with length 0-4294967295.
|
|
281
|
+
|
|
282
|
+
== Reserved types
|
|
283
|
+
|
|
284
|
+
=== nil (0xC0)
|
|
285
|
+
|
|
286
|
+
Represents nil/null.
|
|
287
|
+
|
|
288
|
+
[source]
|
|
289
|
+
----
|
|
290
|
+
+--------+
|
|
291
|
+
| 0xC0 |
|
|
292
|
+
+--------+
|
|
293
|
+
----
|
|
294
|
+
|
|
295
|
+
=== false (0xC2)
|
|
296
|
+
|
|
297
|
+
Represents boolean false.
|
|
298
|
+
|
|
299
|
+
=== true (0xC3)
|
|
300
|
+
|
|
301
|
+
Represents boolean true.
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: References
|
|
3
|
+
nav_order: 1
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
== Purpose
|
|
7
|
+
|
|
8
|
+
References provide detailed technical specifications and API documentation.
|
|
9
|
+
|
|
10
|
+
== References
|
|
11
|
+
|
|
12
|
+
* link:../references/api[API reference] - Complete API documentation
|
|
13
|
+
* link:../references/format[Format specification] - MessagePack binary format details
|
|
14
|
+
* link:../references/extensions[Extension types reference] - Built-in and custom extension types
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Custom extension types
|
|
3
|
+
nav_order: 2
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
== Purpose
|
|
7
|
+
|
|
8
|
+
This tutorial shows how to create custom extension types for serializing objects
|
|
9
|
+
that don't have native MessagePack support.
|
|
10
|
+
|
|
11
|
+
== References
|
|
12
|
+
|
|
13
|
+
* link:../pages/extension-types[Extension types] - Extension type concepts
|
|
14
|
+
* link:../references/extensions[Extension types reference] - Detailed documentation
|
|
15
|
+
|
|
16
|
+
== Prerequisites
|
|
17
|
+
|
|
18
|
+
* Completed link:../tutorials/getting-started[Getting started] tutorial
|
|
19
|
+
|
|
20
|
+
== Understanding extension types
|
|
21
|
+
|
|
22
|
+
MessagePack defines a set of built-in types (nil, boolean, integer, float, string,
|
|
23
|
+
array, map). For custom Ruby classes, you need to register an extension type.
|
|
24
|
+
|
|
25
|
+
An extension type requires:
|
|
26
|
+
|
|
27
|
+
* A type ID (-128 to 127)
|
|
28
|
+
* A packing method that converts your object to binary
|
|
29
|
+
* An unpacking method that reconstructs your object from binary
|
|
30
|
+
|
|
31
|
+
== Simple example: Point class
|
|
32
|
+
|
|
33
|
+
=== Define the class
|
|
34
|
+
|
|
35
|
+
[source,ruby]
|
|
36
|
+
----
|
|
37
|
+
class Point
|
|
38
|
+
attr_reader :x, :y
|
|
39
|
+
|
|
40
|
+
def initialize(x, y)
|
|
41
|
+
@x = x
|
|
42
|
+
@y = y
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def to_msgpack_ext
|
|
46
|
+
# Pack as two 32-bit integers
|
|
47
|
+
[@x, @y].pack("ll")
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def self.from_msgpack_ext(data)
|
|
51
|
+
x, y = data.unpack("ll")
|
|
52
|
+
new(x, y)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def to_s
|
|
56
|
+
"(#{@x}, #{@y})"
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
----
|
|
60
|
+
|
|
61
|
+
=== Register with factory
|
|
62
|
+
|
|
63
|
+
[source,ruby]
|
|
64
|
+
----
|
|
65
|
+
factory = Messagepack::Factory.new
|
|
66
|
+
factory.register_type(0x01, Point,
|
|
67
|
+
packer: :to_msgpack_ext,
|
|
68
|
+
unpacker: :from_msgpack_ext
|
|
69
|
+
)
|
|
70
|
+
----
|
|
71
|
+
|
|
72
|
+
=== Use it
|
|
73
|
+
|
|
74
|
+
[source,ruby]
|
|
75
|
+
----
|
|
76
|
+
point = Point.new(10, 20)
|
|
77
|
+
binary = factory.pack(point)
|
|
78
|
+
result = factory.unpack(binary)
|
|
79
|
+
puts result # => "(10, 20)"
|
|
80
|
+
----
|
|
81
|
+
|
|
82
|
+
== Complex example: Nested objects
|
|
83
|
+
|
|
84
|
+
=== Define a container class
|
|
85
|
+
|
|
86
|
+
[source,ruby]
|
|
87
|
+
----
|
|
88
|
+
class TreeNode
|
|
89
|
+
attr_reader :value, :left, :right
|
|
90
|
+
|
|
91
|
+
def initialize(value, left = nil, right = nil)
|
|
92
|
+
@value = value
|
|
93
|
+
@left = left
|
|
94
|
+
@right = right
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def to_msgpack_ext(packer)
|
|
98
|
+
# Serialize as hash with recursive packing
|
|
99
|
+
packer.write({
|
|
100
|
+
value: @value,
|
|
101
|
+
left: @left,
|
|
102
|
+
right: @right
|
|
103
|
+
})
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def self.from_msgpack_ext(unpacker)
|
|
107
|
+
# Recursively deserialize
|
|
108
|
+
data = unpacker.read
|
|
109
|
+
new(
|
|
110
|
+
data[:value],
|
|
111
|
+
data[:left],
|
|
112
|
+
data[:right]
|
|
113
|
+
)
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
----
|
|
117
|
+
|
|
118
|
+
=== Register as recursive
|
|
119
|
+
|
|
120
|
+
[source,ruby]
|
|
121
|
+
----
|
|
122
|
+
factory = Messagepack::Factory.new
|
|
123
|
+
factory.register_type(0x02, TreeNode,
|
|
124
|
+
packer: ->(obj, packer) { obj.to_msgpack_ext(packer) },
|
|
125
|
+
unpacker: ->(unpacker) { TreeNode.from_msgpack_ext(unpacker) },
|
|
126
|
+
recursive: true
|
|
127
|
+
)
|
|
128
|
+
----
|
|
129
|
+
|
|
130
|
+
=== Use it
|
|
131
|
+
|
|
132
|
+
[source,ruby]
|
|
133
|
+
----
|
|
134
|
+
tree = TreeNode.new(
|
|
135
|
+
1,
|
|
136
|
+
TreeNode.new(2),
|
|
137
|
+
TreeNode.new(3, TreeNode.new(4))
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
binary = factory.pack(tree)
|
|
141
|
+
result = factory.unpack(binary)
|
|
142
|
+
puts result.value # => 1
|
|
143
|
+
puts result.left.value # => 2
|
|
144
|
+
puts result.right.left.value # => 4
|
|
145
|
+
----
|
|
146
|
+
|
|
147
|
+
== Using procs for simple types
|
|
148
|
+
|
|
149
|
+
For simple classes, you can use procs directly:
|
|
150
|
+
|
|
151
|
+
[source,ruby]
|
|
152
|
+
----
|
|
153
|
+
require 'uri'
|
|
154
|
+
|
|
155
|
+
factory = Messagepack::Factory.new
|
|
156
|
+
factory.register_type(0x10, URI,
|
|
157
|
+
packer: ->(uri) { uri.to_s },
|
|
158
|
+
unpacker: ->(str) { URI.parse(str) }
|
|
159
|
+
)
|
|
160
|
+
|
|
161
|
+
uri = URI.parse("https://example.com")
|
|
162
|
+
binary = factory.pack(uri)
|
|
163
|
+
result = factory.unpack(binary)
|
|
164
|
+
# => #<URI::HTTPS https://example.com>
|
|
165
|
+
----
|
|
166
|
+
|
|
167
|
+
== Next steps
|
|
168
|
+
|
|
169
|
+
* link:../tutorials/thread-safety[Thread-safe usage] - Use factories in multi-threaded applications
|
|
170
|
+
* link:../guides/io-streaming[IO streaming] - Work with streams and networks
|