Merge: doc: fixed some typos and other misc. corrections
[nit.git] / lib / msgpack / write.nit
1 # This file is part of NIT ( http://www.nitlanguage.org ).
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 # http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14
15 # Low-level write in MessagePack format to `Writer` streams
16 module write
17
18 import binary
19
20 redef class Writer
21
22 # Write `null`, or nil, in MessagePack format
23 fun write_msgpack_null do write_byte 0xC0
24
25 # Write `bool` in MessagePack format
26 fun write_msgpack_bool(bool: Bool)
27 do write_byte(if bool then 0xC3 else 0xC2)
28
29 # ---
30 # Integers
31
32 # Write the integer `value` either as the shortest possible MessagePack _int_
33 fun write_msgpack_int(value: Int)
34 do
35 if value >= -0x20 and value <= 0x7F then
36 write_msgpack_fixint value
37 else if value >= 0 then
38 if value <= 0xFF then
39 write_msgpack_uint8 value
40 else if value <= 0xFFFF then
41 write_msgpack_uint16 value
42 else if value <= 0xFFFF_FFFF then
43 write_msgpack_uint32 value
44 else #if value <= 0xFFFF_FFFF_FFFF_FFFF then
45 write_msgpack_uint64 value
46 end
47 else if value >= -128 then
48 write_msgpack_int8 value
49 else if value >= -32768 then
50 write_msgpack_int16 value
51 else if value >= -2147483648 then
52 write_msgpack_int32 value
53 else
54 write_msgpack_int64 value
55 end
56 end
57
58 # Write `value` as a single byte with metadata
59 #
60 # Require: `value >= -0x20 and value <= 0x7F`
61 fun write_msgpack_fixint(value: Int)
62 do
63 assert value >= -0x20 and value <= 0x7F
64 write_byte value
65 end
66
67 # Write `value` over one unsigned byte, following 1 metadata byte
68 #
69 # Require: `value >= 0x00 and value <= 0xFF`
70 fun write_msgpack_uint8(value: Int)
71 do
72 write_byte 0xCC
73 write_bytes value.to_bytes(n_bytes=1)
74 end
75
76 # Write `value` over two unsigned bytes, following 1 metadata byte
77 #
78 # Require: `value >= 0x00 and value <= 0xFFFF`
79 fun write_msgpack_uint16(value: Int)
80 do
81 write_byte 0xCD
82 write_bytes value.to_bytes(n_bytes=2)
83 end
84
85 # Write `value` over 4 unsigned bytes, following 1 metadata byte
86 #
87 # Require: `value >= 0x00 and value <= 0xFFFF_FFFF`
88 fun write_msgpack_uint32(value: Int)
89 do
90 write_byte 0xCE
91 write_bytes value.to_bytes(n_bytes=4)
92 end
93
94 # Write `value` over 8 unsigned bytes, following 1 metadata byte
95 #
96 # Require: `value >= 0x00 and value <= 0xFFFF_FFFF_FFFF_FFFF`
97 fun write_msgpack_uint64(value: Int)
98 do
99 write_byte 0xCF
100 write_bytes value.to_bytes(n_bytes=8)
101 end
102
103 # Write `value` over one signed byte, following 1 metadata byte
104 #
105 # Require: `value >= -128 and value <= 127`
106 fun write_msgpack_int8(value: Int)
107 do
108 write_byte 0xD0
109 write_bytes value.to_bytes(n_bytes=1)
110 end
111
112 # Write `value` over two signed bytes, following 1 metadata byte
113 fun write_msgpack_int16(value: Int)
114 do
115 write_byte 0xD1
116 write_bytes value.to_bytes(n_bytes=2)
117 end
118
119 # Write `value` over 4 signed bytes, following 1 metadata byte
120 fun write_msgpack_int32(value: Int)
121 do
122 write_byte 0xD2
123 write_bytes value.to_bytes(n_bytes=4)
124 end
125
126 # Write `value` over 8 signed bytes, following 1 metadata byte
127 fun write_msgpack_int64(value: Int)
128 do
129 write_byte 0xD3
130 write_int64 value
131 end
132
133 # ---
134 # Floats
135
136 # Write `value` as a MessagePack float (losing precision)
137 fun write_msgpack_float(value: Float)
138 do
139 write_byte 0xCA
140 write_float value
141 end
142
143 # Write `value` as a MessagePack double
144 fun write_msgpack_double(value: Float)
145 do
146 write_byte 0xCB
147 write_double value
148 end
149
150 # ---
151 # Strings
152
153 # Write `text` in the shortest possible MessagePack format
154 #
155 # Require: `text.byte_length <= 0xFFFF_FFFF`
156 fun write_msgpack_str(text: Text)
157 do
158 var len = text.byte_length
159 if len <= 0x1F then
160 write_msgpack_fixstr text
161 else if len <= 0xFF then
162 write_msgpack_str8 text
163 else if len <= 0xFFFF then
164 write_msgpack_str16 text
165 else if len <= 0xFFFF_FFFF then
166 write_msgpack_str32 text
167 else
168 abort
169 end
170 end
171
172 # Write `text` in _fixstr_ format, max of 0x1F bytes
173 #
174 # Require: `text.byte_length <= 0x1F`
175 fun write_msgpack_fixstr(text: Text)
176 do
177 var len = text.byte_length
178 assert len <= 0x1F
179
180 var b = 0b1010_0000 | len
181 write_byte b
182
183 write text
184 end
185
186 # Write `text` in _str8_ format, max of 0xFF bytes
187 #
188 # Require: `text.byte_length <= 0xFF`
189 fun write_msgpack_str8(text: Text)
190 do
191 var len = text.byte_length
192 assert len <= 0xFF
193
194 write_byte 0xD9
195 write_byte len
196 write text
197 end
198
199 # Write `text` in _str16_ format, max of 0xFFFF bytes
200 #
201 # Require: `text.byte_length <= 0xFFFF`
202 fun write_msgpack_str16(text: Text)
203 do
204 var len = text.byte_length
205 assert len <= 0xFFFF
206
207 write_byte 0xDA
208 var len_bytes = len.to_bytes
209 write_byte len_bytes[0]
210 write_byte if len_bytes.length > 1 then len_bytes[1] else 0
211 write text
212 end
213
214 # Write `text` in _str32_ format, max of 0xFFFF_FFFF bytes
215 #
216 # Require: `text.byte_length <= 0xFFFF_FFFF`
217 fun write_msgpack_str32(text: Text)
218 do
219 var len = text.byte_length
220 assert len <= 0xFFFF_FFFF
221
222 write_byte 0xDB
223 var len_bytes = len.to_bytes
224 write_byte len_bytes[0]
225 for i in [1..4[ do
226 write_byte if len_bytes.length > i then len_bytes[i] else 0
227 end
228 write text
229 end
230
231 # ---
232 # Binary data
233
234 # Write `data` in the shortest possible MessagePack _bin_ format
235 #
236 # Require: `data.length <= 0xFFFF_FFFF`
237 fun write_msgpack_bin(data: Bytes)
238 do
239 var len = data.length
240 if len <= 0xFF then
241 write_msgpack_bin8 data
242 else if len <= 0xFFFF then
243 write_msgpack_bin16 data
244 else if len <= 0xFFFF_FFFF then
245 write_msgpack_bin32 data
246 else abort
247 end
248
249 # Write `data` in _bin8_ format, max of 0xFF bytes
250 #
251 # Require: `data.length <= 0xFF`
252 fun write_msgpack_bin8(data: Bytes)
253 do
254 var len = data.length
255 assert len <= 0xFF
256
257 write_byte 0xC4
258 write_byte len
259 write_bytes data
260 end
261
262 # Write `data` in _bin16_ format, max of 0xFFFF bytes
263 #
264 # Require: `data.length <= 0xFFFF`
265 fun write_msgpack_bin16(data: Bytes)
266 do
267 var len = data.length
268 assert len <= 0xFFFF
269
270 write_byte 0xC5
271 write_bytes len.to_bytes(n_bytes=2)
272 write_bytes data
273 end
274
275 # Write `data` in _bin32_ format, max of 0xFFFF_FFFF bytes
276 #
277 # Require: `data.length <= 0xFFFF_FFFF`
278 fun write_msgpack_bin32(data: Bytes)
279 do
280 var len = data.length
281 assert len <= 0xFFFF_FFFF
282
283 write_byte 0xC6
284 write_bytes len.to_bytes(n_bytes=4)
285 write_bytes data
286 end
287
288 # ---
289 # Arrays
290
291 # Write an array header for `len` items in the shortest possible MessagePack _array_ format
292 #
293 # After writing the header, clients should write the array items.
294 #
295 # Require: `len <= 0xFFFF_FFFF`
296 fun write_msgpack_array(len: Int)
297 do
298 if len <= 0x0F then
299 write_msgpack_fixarray len
300 else if len <= 0xFFFF then
301 write_msgpack_array16 len
302 else if len <= 0xFFFF_FFFF then
303 write_msgpack_array32 len
304 else
305 abort
306 end
307 end
308
309 # Write an array header for `len` items, max of 0x0F items
310 #
311 # After writing the header, clients should write the array items.
312 #
313 # Require: `len <= 0x0F`
314 fun write_msgpack_fixarray(len: Int)
315 do
316 assert len <= 0x0F
317 write_byte 0b1001_0000 | len
318 end
319
320 # Write an array header for `len` items, max of 0xFFFF items
321 #
322 # After writing the header, clients should write the array items.
323 #
324 # Require: `len <= 0xFFFF`
325 fun write_msgpack_array16(len: Int)
326 do
327 assert len <= 0xFFFF
328 write_byte 0xDC
329 write_bytes len.to_bytes(n_bytes=2)
330 end
331
332 # Write an array header for `len` items, max of 0xFFFF_FFFF items
333 #
334 # After writing the header, clients should write the array items.
335 #
336 # Require: `len <= 0xFFFF_FFFF`
337 fun write_msgpack_array32(len: Int)
338 do
339 assert len <= 0xFFFF_FFFF
340 write_byte 0xDD
341 write_bytes len.to_bytes(n_bytes=4)
342 end
343
344 # ---
345 # Map
346
347 # Write a map header for `len` keys/value pairs in the shortest possible MessagePack _map_ format
348 #
349 # After writing the header, clients should write the map data, alternating
350 # between keys and values.
351 #
352 # Require: `len <= 0xFFFF_FFFF`
353 fun write_msgpack_map(len: Int)
354 do
355 if len <= 0x0F then
356 write_msgpack_fixmap len
357 else if len <= 0xFFFF then
358 write_msgpack_map16 len
359 else if len <= 0xFFFF_FFFF then
360 write_msgpack_map32 len
361 else
362 abort
363 end
364 end
365
366 # Write a map header for `len` key/value pairs, max of 0x0F pairs
367 #
368 # After writing the header, clients should write the map data, alternating
369 # between keys and values.
370 #
371 # Require: `len <= 0x0F`
372 fun write_msgpack_fixmap(len: Int)
373 do
374 assert len <= 0x0F
375 write_byte 0b1000_0000 | len
376 end
377
378 # Write a map header for `len` key/value pairs, max of 0xFFFF pairs
379 #
380 # After writing the header, clients should write the map data, alternating
381 # between keys and values.
382 #
383 # Require: `len <= 0xFFFF`
384 fun write_msgpack_map16(len: Int)
385 do
386 assert len <= 0xFFFF
387 write_byte 0xDE
388 write_bytes len.to_bytes(n_bytes=2)
389 end
390
391 # Write a map header for `len` key/value pairs, max of 0xFFFF_FFFF pairs
392 #
393 # After writing the header, clients should write the map data, alternating
394 # between keys and values.
395 #
396 # Require: `len <= 0xFFFF_FFFF`
397 fun write_msgpack_map32(len: Int)
398 do
399 assert len <= 0xFFFF_FFFF
400 write_byte 0xDF
401 write_bytes len.to_bytes(n_bytes=4)
402 end
403
404 # ---
405 # Ext
406
407 # Write an application-specific extension for `typ` and `bytes` in the shortest possible MessagePack _ext_ format
408 #
409 # Require: `bytes.length <= 0xFFFF_FFFF`
410 #
411 # ~~~
412 # var writer = new BytesWriter
413 # writer.write_msgpack_ext(0x0A, b"\x0B\x0C\x0D")
414 # assert writer.bytes == b"\xC7\x03\x0A\x0B\x0C\x0D"
415 # ~~~
416 fun write_msgpack_ext(typ: Int, bytes: Bytes)
417 do
418 var len = bytes.length
419 if len == 1 then
420 write_msgpack_fixext1 typ
421 write_byte bytes.first
422 else if len == 2 then
423 write_msgpack_fixext2 typ
424 write_bytes bytes
425 else if len == 4 then
426 write_msgpack_fixext4 typ
427 write_bytes bytes
428 else if len == 8 then
429 write_msgpack_fixext8 typ
430 write_bytes bytes
431 else if len == 16 then
432 write_msgpack_fixext16 typ
433 write_bytes bytes
434 else if len <= 0xFF then
435 write_msgpack_ext8(typ, len)
436 write_bytes bytes
437 else if len <= 0xFFFF then
438 write_msgpack_ext16(typ, len)
439 write_bytes bytes
440 else if len <= 0xFFFF_FFFF then
441 write_msgpack_ext32(typ, len)
442 write_bytes bytes
443 else
444 abort
445 end
446 end
447
448 # Write the header for an application-specific extension of one data byte
449 #
450 # After writing the header, clients should write the data byte.
451 fun write_msgpack_fixext1(typ: Int)
452 do
453 write_byte 0xD4
454 write_byte typ
455 end
456
457 # Write the header for an application-specific extension of two data bytes
458 #
459 # After writing the header, clients should write the two data bytes.
460 fun write_msgpack_fixext2(typ: Int)
461 do
462 write_byte 0xD5
463 write_byte typ
464 end
465
466 # Write the header for an application-specific extension of 4 data bytes
467 #
468 # After writing the header, clients should write the 4 data bytes.
469 fun write_msgpack_fixext4(typ: Int)
470 do
471 write_byte 0xD6
472 write_byte typ
473 end
474
475 # Write the header for an application-specific extension of 8 data bytes
476 #
477 # After writing the header, clients should write the 8 data bytes.
478 fun write_msgpack_fixext8(typ: Int)
479 do
480 write_byte 0xD7
481 write_byte typ
482 end
483
484 # Write the header for an application-specific extension of 16 data bytes
485 #
486 # After writing the header, clients should write the 16 data bytes.
487 fun write_msgpack_fixext16(typ: Int)
488 do
489 write_byte 0xD8
490 write_byte typ
491 end
492
493 # Write the header for an application-specific extension of `len` data bytes
494 #
495 # After writing the header, clients should write the data bytes.
496 #
497 # Require: `len >= 0 and <= 0xFF`
498 fun write_msgpack_ext8(typ, len: Int)
499 do
500 assert len >= 0 and len <= 0xFF
501 write_byte 0xC7
502 write_byte len
503 write_byte typ
504 end
505
506 # Write the header for an application-specific extension of `len` data bytes
507 #
508 # After writing the header, clients should write the data bytes.
509 #
510 # Require: `len >= 0 and <= 0xFFFF`
511 fun write_msgpack_ext16(typ, len: Int)
512 do
513 assert len >= 0 and len <= 0xFFFF
514 write_byte 0xC8
515 write_bytes len.to_bytes(n_bytes=2)
516 write_byte typ
517 end
518
519 # Write the header for an application-specific extension of `len` data bytes
520 #
521 # After writing the header, clients should write the data bytes.
522 #
523 # Require: `len >= 0 and <= 0xFFFF_FFFF`
524 fun write_msgpack_ext32(typ, len: Int)
525 do
526 assert len >= 0 and len <= 0xFFFF_FFFF
527 write_byte 0xC9
528 write_bytes len.to_bytes(n_bytes=4)
529 write_byte typ
530 end
531
532 # TODO timestamps
533 end