#![allow(
dead_code,
non_snake_case,
non_upper_case_globals,
non_camel_case_types,
clippy::comparison_chain,
clippy::needless_range_loop
)]
pub type mpack_uint32_t = u32;
pub type mpack_sint32_t = i32;
pub type mpack_uintmax_t = u64;
pub type mpack_sintmax_t = i64;
pub const MPACK_OK: i32 = 0;
pub const MPACK_EOF: i32 = 1;
pub const MPACK_ERROR: i32 = 2;
pub const MPACK_EXCEPTION: i32 = -1;
pub const MPACK_NOMEM: i32 = MPACK_ERROR + 1;
pub const MPACK_MAX_TOKEN_LEN: usize = 9;
pub const MPACK_MAX_OBJECT_DEPTH: u32 = 32;
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub enum mpack_token_type_t {
MPACK_TOKEN_NIL = 1,
MPACK_TOKEN_BOOLEAN = 2,
MPACK_TOKEN_UINT = 3,
MPACK_TOKEN_SINT = 4,
MPACK_TOKEN_FLOAT = 5,
MPACK_TOKEN_CHUNK = 6,
MPACK_TOKEN_ARRAY = 7,
MPACK_TOKEN_MAP = 8,
MPACK_TOKEN_BIN = 9,
MPACK_TOKEN_STR = 10,
MPACK_TOKEN_EXT = 11,
}
pub use mpack_token_type_t::*;
#[derive(Debug, Clone, Copy, Default)]
pub struct mpack_value_t {
pub lo: mpack_uint32_t,
pub hi: mpack_uint32_t,
}
#[derive(Debug, Clone)]
pub enum mpack_token_data {
value(mpack_value_t),
chunk_ptr(Vec<u8>),
ext_type(i32),
}
impl Default for mpack_token_data {
fn default() -> Self {
mpack_token_data::value(mpack_value_t::default())
}
}
#[derive(Debug, Clone)]
pub struct mpack_token_t {
pub r#type: mpack_token_type_t,
pub length: mpack_uint32_t,
pub data: mpack_token_data,
}
impl Default for mpack_token_t {
fn default() -> Self {
mpack_token_t {
r#type: MPACK_TOKEN_NIL,
length: 0,
data: mpack_token_data::default(),
}
}
}
#[derive(Debug, Clone)]
pub struct mpack_tokbuf_t {
pub pending: [u8; MPACK_MAX_TOKEN_LEN],
pub pending_tok: mpack_token_t,
pub ppos: usize,
pub plen: usize,
pub passthrough: mpack_uint32_t,
}
impl Default for mpack_tokbuf_t {
fn default() -> Self {
mpack_tokbuf_t {
pending: [0; MPACK_MAX_TOKEN_LEN],
pending_tok: mpack_token_t::default(),
ppos: 0,
plen: 0,
passthrough: 0,
}
}
}
#[derive(Debug, Clone)]
pub enum mpack_data_t<P> {
Null,
p(P),
u(mpack_uintmax_t),
i(mpack_sintmax_t),
d(f64),
}
impl<P> Default for mpack_data_t<P> {
fn default() -> Self {
mpack_data_t::Null
}
}
#[derive(Debug, Clone)]
pub struct mpack_node_t<P> {
pub tok: mpack_token_t,
pub pos: usize,
pub key_visited: i32,
pub data: [mpack_data_t<P>; 2],
}
impl<P> Default for mpack_node_t<P> {
fn default() -> Self {
mpack_node_t {
tok: mpack_token_t::default(),
pos: 0,
key_visited: 0,
data: [mpack_data_t::Null, mpack_data_t::Null],
}
}
}
#[derive(Debug, Clone)]
pub struct mpack_parser_t<P> {
pub data: mpack_data_t<P>,
pub size: mpack_uint32_t,
pub capacity: mpack_uint32_t,
pub status: i32,
pub exiting: i32,
pub tokbuf: mpack_tokbuf_t,
pub items: Vec<mpack_node_t<P>>,
}
pub type mpack_walk_cb<P> = fn(&mut mpack_parser_t<P>, usize);
macro_rules! ADVANCE {
($buf:expr, $buflen:expr) => {{
let __s: &[u8] = *$buf;
let __b = __s[0];
*$buf = &__s[1..];
*$buflen -= 1;
__b
}};
}
macro_rules! TLEN {
($val:expr, $range_start:expr) => {
(1u32 << ($val - $range_start)) as mpack_uint32_t
};
}
macro_rules! MIN {
($x:expr, $y:expr) => {
if $x < $y {
$x
} else {
$y
}
};
}
pub fn mpack_tokbuf_init(tokbuf: &mut mpack_tokbuf_t) {
tokbuf.ppos = 0;
tokbuf.plen = 0;
tokbuf.passthrough = 0;
}
pub fn mpack_read(
tokbuf: &mut mpack_tokbuf_t,
buf: &mut &[u8],
buflen: &mut usize,
tok: &mut mpack_token_t,
) -> i32 {
let status;
let initial_ppos;
let mut ptrlen: usize;
if *buflen == 0 {
return MPACK_EOF;
}
if tokbuf.passthrough != 0 {
tok.r#type = MPACK_TOKEN_CHUNK;
let length = MIN!(*buflen as mpack_uint32_t, tokbuf.passthrough);
tok.length = length;
tok.data = mpack_token_data::chunk_ptr(buf[..length as usize].to_vec());
tokbuf.passthrough -= length;
let s: &[u8] = *buf;
*buf = &s[length as usize..];
*buflen -= length as usize;
return MPACK_OK;
}
initial_ppos = tokbuf.ppos;
let mut cur: &[u8];
if tokbuf.plen != 0 {
if mpack_rpending(buf, buflen, tokbuf) == 0 {
return MPACK_EOF;
}
ptrlen = tokbuf.ppos;
cur = &tokbuf.pending[..ptrlen];
} else {
cur = &buf[..*buflen];
ptrlen = *buflen;
}
let ptr_save_len = ptrlen;
status = mpack_rtoken(&mut cur, &mut ptrlen, tok);
if status != 0 {
if status != MPACK_EOF {
return MPACK_ERROR;
}
debug_assert!(tokbuf.plen == 0);
tokbuf.plen = tok.length as usize + 1;
debug_assert!(tokbuf.plen <= tokbuf.pending.len());
tokbuf.ppos = 0;
let status2 = mpack_rpending(buf, buflen, tokbuf);
debug_assert!(status2 == 0);
let _ = status2;
return MPACK_EOF;
}
let advanced = (ptr_save_len - ptrlen) - initial_ppos;
tokbuf.plen = 0;
tokbuf.ppos = 0;
*buflen -= advanced;
let s: &[u8] = *buf;
*buf = &s[advanced..];
if tok.r#type > MPACK_TOKEN_MAP {
tokbuf.passthrough = tok.length;
}
MPACK_OK
}
pub fn mpack_rtoken(buf: &mut &[u8], buflen: &mut usize, tok: &mut mpack_token_t) -> i32 {
if *buflen == 0 {
return MPACK_EOF;
}
let t: u8 = ADVANCE!(buf, buflen);
if t < 0x80 {
mpack_value(MPACK_TOKEN_UINT, 1, mpack_byte(t), tok)
} else if t < 0x90 {
mpack_blob(MPACK_TOKEN_MAP, (t & 0xf) as mpack_uint32_t, 0, tok)
} else if t < 0xa0 {
mpack_blob(MPACK_TOKEN_ARRAY, (t & 0xf) as mpack_uint32_t, 0, tok)
} else if t < 0xc0 {
mpack_blob(MPACK_TOKEN_STR, (t & 0x1f) as mpack_uint32_t, 0, tok)
} else if t < 0xe0 {
match t {
0xc0 => mpack_value(MPACK_TOKEN_NIL, 0, mpack_byte(0), tok), 0xc2 => mpack_value(MPACK_TOKEN_BOOLEAN, 1, mpack_byte(0), tok), 0xc3 => mpack_value(MPACK_TOKEN_BOOLEAN, 1, mpack_byte(1), tok), 0xc4 | 0xc5 | 0xc6 => mpack_rblob(MPACK_TOKEN_BIN, TLEN!(t, 0xc4), buf, buflen, tok),
0xc7 | 0xc8 | 0xc9 => mpack_rblob(MPACK_TOKEN_EXT, TLEN!(t, 0xc7), buf, buflen, tok),
0xca | 0xcb => mpack_rvalue(MPACK_TOKEN_FLOAT, TLEN!(t, 0xc8), buf, buflen, tok),
0xcc | 0xcd | 0xce | 0xcf => {
mpack_rvalue(MPACK_TOKEN_UINT, TLEN!(t, 0xcc), buf, buflen, tok)
}
0xd0 | 0xd1 | 0xd2 | 0xd3 => {
mpack_rvalue(MPACK_TOKEN_SINT, TLEN!(t, 0xd0), buf, buflen, tok)
}
0xd4 | 0xd5 | 0xd6 | 0xd7 | 0xd8 => {
if *buflen == 0 {
tok.length = 1;
return MPACK_EOF;
}
tok.length = TLEN!(t, 0xd4);
tok.r#type = MPACK_TOKEN_EXT;
tok.data = mpack_token_data::ext_type(ADVANCE!(buf, buflen) as i32);
MPACK_OK
}
0xd9 | 0xda | 0xdb => mpack_rblob(MPACK_TOKEN_STR, TLEN!(t, 0xd9), buf, buflen, tok),
0xdc | 0xdd => mpack_rblob(MPACK_TOKEN_ARRAY, TLEN!(t, 0xdb), buf, buflen, tok),
0xde | 0xdf => mpack_rblob(MPACK_TOKEN_MAP, TLEN!(t, 0xdd), buf, buflen, tok),
_ => MPACK_ERROR,
}
} else {
mpack_value(MPACK_TOKEN_SINT, 1, mpack_byte(t), tok)
}
}
fn mpack_rpending(buf: &mut &[u8], buflen: &mut usize, state: &mut mpack_tokbuf_t) -> i32 {
let count;
debug_assert!(state.ppos < state.plen);
count = MIN!(state.plen - state.ppos, *buflen);
state.pending[state.ppos..state.ppos + count].copy_from_slice(&buf[..count]);
state.ppos += count;
if state.ppos < state.plen {
let s: &[u8] = *buf;
*buf = &s[*buflen..];
*buflen = 0;
return 0;
}
1
}
fn mpack_rvalue(
r#type: mpack_token_type_t,
remaining: mpack_uint32_t,
buf: &mut &[u8],
buflen: &mut usize,
tok: &mut mpack_token_t,
) -> i32 {
let mut remaining = remaining;
if (*buflen as mpack_uint32_t) < remaining {
tok.length = remaining;
return MPACK_EOF;
}
mpack_value(r#type, remaining, mpack_byte(0), tok);
while remaining != 0 {
let byte = ADVANCE!(buf, buflen) as mpack_uint32_t;
remaining -= 1;
let byte_idx = remaining;
let byte_shift = (byte_idx % 4) * 8;
if let mpack_token_data::value(v) = &mut tok.data {
v.lo |= byte << byte_shift;
if remaining == 4 {
v.hi = v.lo;
v.lo = 0;
}
}
}
if r#type == MPACK_TOKEN_SINT {
if let mpack_token_data::value(v) = &tok.data {
let hi = v.hi;
let lo = v.lo;
let msb = (tok.length == 8 && (hi >> 31) != 0)
|| (tok.length == 4 && (lo >> 31) != 0)
|| (tok.length == 2 && (lo >> 15) != 0)
|| (tok.length == 1 && (lo >> 7) != 0);
if !msb {
tok.r#type = MPACK_TOKEN_UINT;
}
}
}
MPACK_OK
}
fn mpack_rblob(
r#type: mpack_token_type_t,
tlen: mpack_uint32_t,
buf: &mut &[u8],
buflen: &mut usize,
tok: &mut mpack_token_t,
) -> i32 {
let mut l = mpack_token_t::default();
let required = tlen + if r#type == MPACK_TOKEN_EXT { 1 } else { 0 };
if (*buflen as mpack_uint32_t) < required {
tok.length = required;
return MPACK_EOF;
}
l.data = mpack_token_data::value(mpack_value_t { lo: 0, hi: 0 });
mpack_rvalue(MPACK_TOKEN_UINT, tlen, buf, buflen, &mut l);
tok.r#type = r#type;
tok.length = match &l.data {
mpack_token_data::value(v) => v.lo,
_ => 0,
};
if r#type == MPACK_TOKEN_EXT {
tok.data = mpack_token_data::ext_type(ADVANCE!(buf, buflen) as i32);
}
MPACK_OK
}
fn mpack_value(
r#type: mpack_token_type_t,
length: mpack_uint32_t,
value: mpack_value_t,
tok: &mut mpack_token_t,
) -> i32 {
tok.r#type = r#type;
tok.length = length;
tok.data = mpack_token_data::value(value);
MPACK_OK
}
fn mpack_blob(
r#type: mpack_token_type_t,
length: mpack_uint32_t,
ext_type: i32,
tok: &mut mpack_token_t,
) -> i32 {
tok.r#type = r#type;
tok.length = length;
tok.data = mpack_token_data::ext_type(ext_type);
MPACK_OK
}
fn mpack_byte(byte: u8) -> mpack_value_t {
mpack_value_t {
lo: byte as mpack_uint32_t,
hi: 0,
}
}
pub fn mpack_parser_init<P>(parser: &mut mpack_parser_t<P>, capacity: mpack_uint32_t) {
mpack_tokbuf_init(&mut parser.tokbuf);
parser.data = mpack_data_t::Null;
parser.capacity = if capacity != 0 {
capacity
} else {
MPACK_MAX_OBJECT_DEPTH
};
parser.size = 0;
parser.exiting = 0;
parser.items = (0..=parser.capacity)
.map(|_| mpack_node_t::default())
.collect();
parser.items[0].pos = usize::MAX; parser.status = 0;
}
pub fn mpack_parse_tok<P>(
parser: &mut mpack_parser_t<P>,
tok: mpack_token_t,
enter_cb: mpack_walk_cb<P>,
exit_cb: mpack_walk_cb<P>,
) -> i32 {
if parser.status == MPACK_EXCEPTION {
return MPACK_EXCEPTION;
}
if parser.exiting == 0 {
if mpack_parser_full(parser) != 0 {
return MPACK_NOMEM;
}
let n = mpack_parser_push(parser);
parser.items[n].tok = tok;
enter_cb(parser, n);
if parser.status == MPACK_EXCEPTION {
return MPACK_EXCEPTION;
}
parser.exiting = 1;
return MPACK_EOF;
}
parser.exiting = 0;
while let Some(n) = mpack_parser_pop(parser) {
exit_cb(parser, n);
if parser.status == MPACK_EXCEPTION {
return MPACK_EXCEPTION;
}
if parser.size == 0 {
return MPACK_OK;
}
}
MPACK_EOF
}
pub fn mpack_parse<P>(
parser: &mut mpack_parser_t<P>,
buf: &mut &[u8],
buflen: &mut usize,
enter_cb: mpack_walk_cb<P>,
exit_cb: mpack_walk_cb<P>,
) -> i32 {
let mut status = MPACK_EOF;
if parser.status == MPACK_EXCEPTION {
return MPACK_EXCEPTION;
}
while *buflen != 0 && status != 0 {
let mut tok = mpack_token_t::default();
let buf_save = *buf;
let buflen_save = *buflen;
status = mpack_read(&mut parser.tokbuf, buf, buflen, &mut tok);
if status == MPACK_EOF {
continue;
} else if status == MPACK_ERROR {
*buf = buf_save;
*buflen = buflen_save;
break;
}
loop {
status = mpack_parse_tok(parser, tok.clone(), enter_cb, exit_cb);
if parser.status == MPACK_EXCEPTION {
return MPACK_EXCEPTION;
}
if parser.exiting == 0 {
break;
}
}
if status != MPACK_NOMEM {
continue;
}
*buf = buf_save;
*buflen = buflen_save;
break;
}
status
}
fn mpack_parser_full<P>(parser: &mpack_parser_t<P>) -> i32 {
(parser.size == parser.capacity) as i32
}
fn mpack_parser_push<P>(parser: &mut mpack_parser_t<P>) -> usize {
debug_assert!(parser.size < parser.capacity);
let top = (parser.size + 1) as usize; parser.items[top].data[0] = mpack_data_t::Null;
parser.items[top].data[1] = mpack_data_t::Null;
parser.items[top].pos = 0;
parser.items[top].key_visited = 0;
parser.size += 1;
top
}
fn mpack_parser_pop<P>(parser: &mut mpack_parser_t<P>) -> Option<usize> {
debug_assert!(parser.size != 0);
let top = parser.size as usize;
if parser.items[top].tok.r#type > MPACK_TOKEN_CHUNK
&& parser.items[top].pos < parser.items[top].tok.length as usize
{
return None;
}
let parent = top - 1;
if parser.items[parent].pos != usize::MAX {
if parser.items[top].tok.r#type == MPACK_TOKEN_CHUNK {
parser.items[parent].pos += parser.items[top].tok.length as usize;
} else if parser.items[parent].tok.r#type == MPACK_TOKEN_MAP {
if parser.items[parent].key_visited != 0 {
parser.items[parent].pos += 1;
}
parser.items[parent].key_visited = (parser.items[parent].key_visited == 0) as i32;
} else {
parser.items[parent].pos += 1;
}
}
parser.size -= 1;
Some(top)
}
fn POW2(n: u32) -> f64 {
(1u64 << (n / 2)) as f64 * (1u64 << (n / 2)) as f64 * (1u64 << (n % 2)) as f64
}
pub fn mpack_unpack_boolean(t: &mpack_token_t) -> bool {
match &t.data {
mpack_token_data::value(v) => v.lo != 0 || v.hi != 0,
_ => false,
}
}
pub fn mpack_unpack_uint(t: &mpack_token_t) -> mpack_uintmax_t {
match &t.data {
mpack_token_data::value(v) => {
(((v.hi as mpack_uintmax_t) << 31) << 1) | v.lo as mpack_uintmax_t
}
_ => 0,
}
}
pub fn mpack_unpack_sint(t: &mpack_token_t) -> mpack_sintmax_t {
let (hi, lo) = match &t.data {
mpack_token_data::value(v) => (v.hi, v.lo),
_ => (0, 0),
};
let mut rv: mpack_uintmax_t = lo as mpack_uintmax_t;
debug_assert!(t.length as usize <= std::mem::size_of::<mpack_sintmax_t>());
if t.length == 8 {
rv |= ((hi as mpack_uintmax_t) << 31) << 1;
}
rv = (!rv & (((1 as mpack_uintmax_t) << ((t.length * 8) - 1)) - 1)) + 1;
-((rv - 1) as mpack_sintmax_t) - 1
}
pub fn mpack_unpack_float_compat(t: &mpack_token_t) -> f64 {
let (vlo, vhi) = match &t.data {
mpack_token_data::value(v) => (v.lo, v.hi),
_ => (0, 0),
};
let sign: mpack_uint32_t;
let mut exponent: mpack_sint32_t;
let mantbits: u32;
let expbits: u32;
let bias: mpack_sint32_t;
let mut mant: f64;
if vlo == 0 && vhi == 0 {
return 0.0;
}
if t.length == 4 {
mantbits = 23;
expbits = 8;
} else {
mantbits = 52;
expbits = 11;
}
bias = (1i32 << (expbits - 1)) - 1;
if mantbits == 52 {
sign = vhi >> 31;
exponent = ((vhi >> 20) & ((1 << 11) - 1)) as mpack_sint32_t;
mant = (vhi & ((1 << 20) - 1)) as f64 * POW2(32);
mant += vlo as f64;
} else {
sign = vlo >> 31;
exponent = ((vlo >> 23) & ((1 << 8) - 1)) as mpack_sint32_t;
mant = (vlo & ((1 << 23) - 1)) as f64;
}
mant /= POW2(mantbits);
if exponent != 0 {
mant += 1.0; } else {
exponent = 1; }
exponent -= bias;
while exponent > 0 {
mant *= 2.0;
exponent -= 1;
}
while exponent < 0 {
mant /= 2.0;
exponent += 1;
}
mant * if sign != 0 { -1.0 } else { 1.0 }
}
pub fn mpack_unpack_float_fast(t: &mpack_token_t) -> f64 {
let (lo, hi) = match &t.data {
mpack_token_data::value(v) => (v.lo, v.hi),
_ => (0, 0),
};
if t.length == 4 {
f32::from_bits(lo) as f64
} else {
let mut m = mpack_value_t { lo, hi };
if mpack_is_be() != 0 {
std::mem::swap(&mut m.lo, &mut m.hi);
}
f64::from_bits(((m.hi as u64) << 32) | m.lo as u64)
}
}
pub fn mpack_unpack_float(t: &mpack_token_t) -> f64 {
mpack_unpack_float_fast(t)
}
pub fn mpack_unpack_number(t: &mpack_token_t) -> f64 {
let rv;
let (mut hi, mut lo) = match &t.data {
mpack_token_data::value(v) => (v.hi, v.lo),
_ => (0, 0),
};
if t.r#type == MPACK_TOKEN_FLOAT {
return mpack_unpack_float(t);
}
debug_assert!(t.r#type == MPACK_TOKEN_UINT || t.r#type == MPACK_TOKEN_SINT);
if t.r#type == MPACK_TOKEN_SINT {
if hi == 0 {
debug_assert!(t.length <= 4);
lo = !lo & (((1 as mpack_uint32_t) << ((t.length * 8) - 1)) - 1);
} else {
hi = !hi;
lo = !lo;
}
lo = lo.wrapping_add(1);
if lo == 0 {
hi = hi.wrapping_add(1);
}
}
rv = lo as f64 + POW2(32) * hi as f64;
if t.r#type == MPACK_TOKEN_SINT {
-rv
} else {
rv
}
}
fn mpack_is_be() -> i32 {
(cfg!(target_endian = "big")) as i32
}
#[cfg(test)]
mod tests {
use super::*;
fn tok_value(
r#type: mpack_token_type_t,
length: mpack_uint32_t,
lo: u32,
hi: u32,
) -> mpack_token_t {
mpack_token_t {
r#type,
length,
data: mpack_token_data::value(mpack_value_t { lo, hi }),
}
}
fn read_one(bytes: &[u8]) -> mpack_token_t {
let mut tb = mpack_tokbuf_t::default();
let mut buf: &[u8] = bytes;
let mut buflen = bytes.len();
let mut tok = mpack_token_t::default();
let st = mpack_read(&mut tb, &mut buf, &mut buflen, &mut tok);
assert_eq!(st, MPACK_OK);
tok
}
#[test]
fn rtoken_positive_and_negative_fixint() {
let t = read_one(&[0x7f]);
assert_eq!(t.r#type, MPACK_TOKEN_UINT);
assert_eq!(mpack_unpack_uint(&t), 127);
let t = read_one(&[0xff]);
assert_eq!(t.r#type, MPACK_TOKEN_SINT);
assert_eq!(mpack_unpack_sint(&t), -1);
}
#[test]
fn rtoken_uint_widths() {
let t = read_one(&[0xcc, 0xff]);
assert_eq!(t.r#type, MPACK_TOKEN_UINT);
assert_eq!(mpack_unpack_uint(&t), 255);
let t = read_one(&[0xcd, 0x01, 0x00]);
assert_eq!(mpack_unpack_uint(&t), 256);
let t = read_one(&[0xce, 0x00, 0x01, 0x00, 0x00]);
assert_eq!(mpack_unpack_uint(&t), 65536);
let t = read_one(&[0xcf, 0, 0, 0, 1, 0, 0, 0, 0]);
assert_eq!(mpack_unpack_uint(&t), 0x1_0000_0000);
}
#[test]
fn rtoken_sint_widths() {
let t = read_one(&[0xd0, 0x80]);
assert_eq!(t.r#type, MPACK_TOKEN_SINT);
assert_eq!(mpack_unpack_sint(&t), -128);
let t = read_one(&[0xd1, 0x80, 0x00]);
assert_eq!(mpack_unpack_sint(&t), -32768);
let t = read_one(&[0xd2, 0x80, 0x00, 0x00, 0x00]);
assert_eq!(mpack_unpack_sint(&t), -(1i64 << 31));
let t = read_one(&[0xd3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff]);
assert_eq!(mpack_unpack_sint(&t), -1);
}
#[test]
fn rtoken_nil_bool() {
assert_eq!(read_one(&[0xc0]).r#type, MPACK_TOKEN_NIL);
assert!(!mpack_unpack_boolean(&read_one(&[0xc2])));
assert!(mpack_unpack_boolean(&read_one(&[0xc3])));
}
#[test]
fn float_unpack_roundtrip() {
let bits = 1.5f64.to_bits().to_be_bytes();
let mut input = vec![0xcb];
input.extend_from_slice(&bits);
let t = read_one(&input);
assert_eq!(t.r#type, MPACK_TOKEN_FLOAT);
assert_eq!(mpack_unpack_float(&t), 1.5);
let bits = (-0.25f32).to_bits().to_be_bytes();
let mut input = vec![0xca];
input.extend_from_slice(&bits);
let t = read_one(&input);
assert_eq!(mpack_unpack_float(&t), -0.25);
}
#[test]
fn unpack_number_matches_int_and_float() {
let t = tok_value(MPACK_TOKEN_UINT, 8, 0x0000_0002, 0x0000_0000);
assert_eq!(mpack_unpack_number(&t), 2.0);
let t = read_one(&[0xfd]); assert_eq!(mpack_unpack_number(&t), -3.0);
}
#[test]
fn rblob_str_length() {
let mut tb = mpack_tokbuf_t::default();
let bytes = [0xa3u8, b'a', b'b', b'c'];
let mut buf: &[u8] = &bytes;
let mut buflen = bytes.len();
let mut tok = mpack_token_t::default();
assert_eq!(
mpack_read(&mut tb, &mut buf, &mut buflen, &mut tok),
MPACK_OK
);
assert_eq!(tok.r#type, MPACK_TOKEN_STR);
assert_eq!(tok.length, 3);
let mut chunk = mpack_token_t::default();
assert_eq!(
mpack_read(&mut tb, &mut buf, &mut buflen, &mut chunk),
MPACK_OK
);
assert_eq!(chunk.r#type, MPACK_TOKEN_CHUNK);
match &chunk.data {
mpack_token_data::chunk_ptr(b) => assert_eq!(b, b"abc"),
_ => panic!("expected chunk_ptr"),
}
}
}