Merge: lib/config: fix doc
[nit.git] / lib / msgpack / read.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 read MessagePack format from `Reader` streams
16 module read
17
18 import serialization
19 private import binary
20
21 import ext
22
23 redef class Reader
24
25 # Read the next MessagePack object and return it as a simple Nit object
26 #
27 # The return value is composed of:
28 # * the simple types `null`, `Bool`, `Int`, `Float`, `String` and `Bytes`,
29 # * collections of simple Nit objects `Array[nullable Serializable]`
30 # and `Map[nullable Serializable, nullable Serializable]`,
31 # * and `MsgPackExt` for custom MessagePack *ext* data.
32 #
33 # This method reads plain MessagePack data, as written by `MsgPackSerializer`
34 # when `plain_msgpack == true`. To deserialize full Nit objects from
35 # MessagePack with metadata use `Reader::deserialize_msgpack`.
36 fun read_msgpack: nullable Serializable
37 do
38 if last_error != null then return 0
39
40 var typ = read_byte
41 if typ == null then
42 # Error, return default `null`
43 return null
44
45 else if typ & 0b1000_0000u8 == 0u8 or typ & 0b1110_0000u8 == 0b1110_0000u8 then
46 # fixint
47 var bytes = new Bytes.with_capacity(1)
48 bytes.add typ
49 return bytes.to_i(signed=true)
50
51 else if typ & 0b1111_0000u8 == 0b1000_0000u8 then
52 # fixmap
53 var len = typ & 0b0000_1111u8
54 return read_msgpack_map_data(len.to_i)
55
56 else if typ & 0b1111_0000u8 == 0b1001_0000u8 then
57 # fixarray
58 var len = typ & 0b0000_1111u8
59 return read_msgpack_array_data(len.to_i)
60
61 else if typ & 0b1110_0000u8 == 0b1010_0000u8 then
62 # fixstr
63 var len = typ & 0b0001_1111u8
64 return read_bytes(len.to_i).to_s
65
66 else if typ == 0xC0u8 then
67 return null
68 else if typ == 0xC2u8 then
69 return false
70 else if typ == 0xC3u8 then
71 return true
72
73 else if typ == 0xCCu8 then
74 # uint8
75 return (read_byte or else 0u8).to_i
76 else if typ == 0xCDu8 then
77 # uint16
78 return read_bytes(2).to_i
79 else if typ == 0xCEu8 then
80 # uint32
81 return read_bytes(4).to_i
82 else if typ == 0xCFu8 then
83 # uint64
84 return read_bytes(8).to_i
85 else if typ == 0xD0u8 then
86 # int8
87 return read_bytes(1).to_i(true)
88 else if typ == 0xD1u8 then
89 # int16
90 return read_bytes(2).to_i(true)
91 else if typ == 0xD2u8 then
92 # int32
93 return read_bytes(4).to_i(true)
94 else if typ == 0xD3u8 then
95 # int64
96 return read_int64
97
98 else if typ == 0xCAu8 then
99 return read_float
100 else if typ == 0xCBu8 then
101 return read_double
102
103 else if typ == 0xD9u8 then
104 # str8
105 var len = read_byte
106 if len == null then return null
107 return read_bytes(len.to_i).to_s
108 else if typ == 0xDAu8 then
109 # str16
110 var len = read_bytes(2)
111 return read_bytes(len.to_i).to_s
112 else if typ == 0xDBu8 then
113 # str32
114 var len = read_bytes(4)
115 return read_bytes(len.to_i).to_s
116
117 else if typ == 0xC4u8 then
118 # bin8
119 var len = read_byte
120 if len == null then return null
121 return read_bytes(len.to_i)
122 else if typ == 0xC5u8 then
123 # bin16
124 var len = read_bytes(2)
125 return read_bytes(len.to_i)
126 else if typ == 0xC6u8 then
127 # bin32
128 var len = read_bytes(4)
129 return read_bytes(len.to_i)
130
131 else if typ == 0xDCu8 then
132 # array16
133 var len = read_bytes(2)
134 return read_msgpack_array_data(len.to_i)
135 else if typ == 0xDDu8 then
136 # array32
137 var len = read_bytes(4)
138 return read_msgpack_array_data(len.to_i)
139
140 else if typ == 0xDEu8 then
141 # map16
142 var len = read_bytes(2)
143 return read_msgpack_map_data(len.to_i)
144 else if typ == 0xDFu8 then
145 # map32
146 var len = read_bytes(4)
147 return read_msgpack_map_data(len.to_i)
148
149 else if typ == 0xD4u8 then
150 # fixext1
151 return read_msgpack_fixext_data(1)
152 else if typ == 0xD5u8 then
153 # fixext2
154 return read_msgpack_fixext_data(2)
155 else if typ == 0xD6u8 then
156 # fixext4
157 return read_msgpack_fixext_data(4)
158 else if typ == 0xD7u8 then
159 # fixext8
160 return read_msgpack_fixext_data(8)
161 else if typ == 0xD8u8 then
162 # fixext16
163 return read_msgpack_fixext_data(16)
164
165 else if typ == 0xC7u8 then
166 # ext1
167 return read_msgpack_ext_data(1)
168 else if typ == 0xC8u8 then
169 # ext2
170 return read_msgpack_ext_data(2)
171 else if typ == 0xC9u8 then
172 # ext4
173 return read_msgpack_ext_data(4)
174 end
175
176 print_error "MessagePack Warning: Found no match for typ {typ} / 0b{typ.to_i.to_base(2)}"
177 return null
178 end
179
180 # Read the content of a map, `len` keys and values
181 private fun read_msgpack_map_data(len: Int): Map[nullable Serializable, nullable Serializable]
182 do
183 var map = new Map[nullable Serializable, nullable Serializable]
184 for i in [0..len.to_i[ do map[read_msgpack] = read_msgpack
185 return map
186 end
187
188 # Read the content of an array of `len` items
189 private fun read_msgpack_array_data(len: Int): Array[nullable Serializable]
190 do
191 return [for i in [0..len[ do read_msgpack]
192 end
193
194 # Read the content of a *fixext* of `len` bytes
195 #
196 # ~~~
197 # var reader = new BytesReader(b"\xC7\x03\x0A\x0B\x0C\x0D")
198 # var ext = reader.read_msgpack
199 # assert ext isa MsgPackExt
200 # assert ext.typ == 0x0Au8
201 # assert ext.data == b"\x0B\x0C\x0D"
202 # ~~~
203 private fun read_msgpack_fixext_data(len: Int): MsgPackExt
204 do
205 var exttyp = read_byte or else 0u8
206 var data = read_bytes(len)
207 return new MsgPackExt(exttyp, data)
208 end
209
210 # Read the content of a dynamic *ext* including the length on `len_len` bytes
211 private fun read_msgpack_ext_data(len_len: Int): MsgPackExt
212 do
213 var len = read_bytes(len_len).to_i
214 return read_msgpack_fixext_data(len)
215 end
216 end