Message pack decoder
/*
Copyright 2017 The Pony MessagePack Developers
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
use "buffered"
type MessagePackType is U8
primitive MessagePackDecoder
"""
Implements low-level decoding from the [MessagePack serialization format](https://github.com/msgpack/msgpack/blob/master/spec.md).
You should be familiar with how MessagePack encodes messages if you use this
API directly. There are very few guardrails preventing you from incorrectly
decoding documents. This is particularly true when using the `array` and
`map` format family encoding methods.
"""
//
// nil format family
//
fun nil(b: Reader ref): None ? =>
"""
Returns nothing. Throws an error if the next byte isn't a MessagePack nil.
"""
if _read_type(b)? != _FormatName.nil() then
error
end
//
// bool format family
//
fun bool(b: Reader ref): Bool ? =>
match _read_type(b)?
| _FormatName.truthy() => true
| _FormatName.falsey() => false
else
error
end
//
// fixed number family
//
fun positive_fixint(b: Reader ref): U8 ? =>
b.u8()?
fun negative_fixint(b: Reader ref): I8 ? =>
b.i8()?
//
// unsigned int family
//
fun u8(b: Reader ref): U8 ? =>
if _read_type(b)? != _FormatName.uint_8() then
error
end
b.u8()?
fun u16(b: Reader ref): U16 ? =>
if _read_type(b)? != _FormatName.uint_16() then
error
end
b.u16_be()?
fun u32(b: Reader ref): U32 ? =>
if _read_type(b)? != _FormatName.uint_32() then
error
end
b.u32_be()?
fun u64(b: Reader ref): U64 ? =>
if _read_type(b)? != _FormatName.uint_64() then
error
end
b.u64_be()?
//
// signed integer family
//
fun i8(b: Reader ref): I8 ? =>
if _read_type(b)? != _FormatName.int_8() then
error
end
b.i8()?
fun i16(b: Reader ref): I16 ? =>
if _read_type(b)? != _FormatName.int_16() then
error
end
b.i16_be()?
fun i32(b: Reader ref): I32 ? =>
if _read_type(b)? != _FormatName.int_32() then
error
end
b.i32_be()?
fun i64(b: Reader ref): I64 ? =>
if _read_type(b)? != _FormatName.int_64() then
error
end
b.i64_be()?
//
// float format family
//
fun f32(b: Reader ref): F32 ? =>
if _read_type(b)? != _FormatName.float_32() then
error
end
b.f32_be()?
fun f64(b: Reader ref): F64 ? =>
if _read_type(b)? != _FormatName.float_64() then
error
end
b.f64_be()?
//
// str family
//
fun fixstr(b: Reader): String iso^ ? =>
let len = (b.u8()?.usize() and _Limit.fixstr())
String.from_iso_array(b.block(len)?)
fun str(b: Reader): String iso^ ? =>
let t = _read_type(b)?
let len = if t == _FormatName.str_8() then
b.u8()?
elseif t == _FormatName.str_16() then
b.u16_be()?.usize()
elseif t == _FormatName.str_32() then
b.u32_be()?.usize()
else
error
end
String.from_iso_array(b.block(len.usize())?)
//
// byte array family
//
fun byte_array(b: Reader): Array[U8] iso^ ? =>
let t = _read_type(b)?
let len = if t == _FormatName.bin_8() then
b.u8()?
elseif t == _FormatName.bin_16() then
b.u16_be()?.usize()
elseif t == _FormatName.bin_32() then
b.u32_be()?.usize()
else
error
end
b.block(len.usize())?
//
// array format family
//
fun fixarray(b: Reader): U8 ? =>
"""
Reads a header for a MessgePack "fixarray". This only reads the
header. The number of array items returned by this method needs
to be read via other methods after this is called.
"""
(b.u8()? and _Limit.fixarray())
fun array_16(b: Reader): U16 ? =>
"""
Reads a header for a MessgePack "array_16". This only reads the
header. The number of array items returned by this method needs
to be read via other methods after this is called.
"""
if _read_type(b)? != _FormatName.array_16() then
error
end
b.u16_be()?
fun array_32(b: Reader): U32 ? =>
"""
Reads a header for a MessgePack "array_32". This only reads the
header. The number of array items returned by this method needs
to be read via other methods after this is called.
"""
if _read_type(b)? != _FormatName.array_32() then
error
end
b.u32_be()?
//
// map format family
//
fun fixmap(b: Reader): U8 ? =>
"""
Reads a header for a MessgePack "fixmap". This only reads the
header. The number of map items returned by this method needs
to be read via other methods after this is called.
"""
(b.u8()? and _Limit.fixmap())
fun map_16(b: Reader): U16 ? =>
"""
Reads a header for a MessgePack "map_16". This only reads the
header. The number of map items returned by this method needs
to be read via other methods after this is called.
"""
if _read_type(b)? != _FormatName.map_16() then
error
end
b.u16_be()?
fun map_32(b: Reader): U32 ? =>
"""
Reads a header for a MessgePack "map_32". This only reads the
header. The number of map items returned by this method needs
to be read via other methods after this is called.
"""
if _read_type(b)? != _FormatName.map_32() then
error
end
b.u32_be()?
//
// ext format family
//
fun ext(b: Reader): (U8, Array[U8] val) ? =>
"""
Allows for the reading of user supplied extensions to the MessagePack
format.
fixext * types return a tuple representing:
(user supplied type indentifier, data byte array)
"""
let t = _read_type(b)?
let size: USize = if t == _FormatName.fixext_1() then
1
elseif t == _FormatName.fixext_2() then
2
elseif t == _FormatName.fixext_4() then
4
elseif t == _FormatName.fixext_8() then
8
elseif t == _FormatName.fixext_16() then
16
elseif t == _FormatName.ext_8() then
b.u8()?.usize()
elseif t == _FormatName.ext_16() then
b.u16_be()?.usize()
elseif t == _FormatName.ext_32() then
b.u32_be()?.usize()
else
error
end
(b.u8()?, b.block(size)?)
//
// timestamp format family
//
fun timestamp(b: Reader): (I64, I64) ? =>
let t = _read_type(b)?
b.i8()?
var nsec: I64 = 0
var sec: I64 = 0
if t == _FormatName.fixext_4() then
sec = b.u32_be()?.i64()
elseif t == _FormatName.fixext_8() then
let u: U64 = b.u64_be()?
nsec = (u >> 34).i64()
sec = (u - (nsec.u64() << 34)).i64()
elseif t == _FormatName.ext_8() then
b.u8()?
nsec = b.u32_be()?.i64()
sec = b.i64_be()?
else
error
end
(sec, nsec)
//
// support functions
//
fun _read_type(b: Reader ref): MessagePackType ? =>
b.u8()?