#[inline]
pub fn write_map_header(buf: &mut Vec<u8>, len: usize) {
if len < 16 {
buf.push(0x80 | len as u8);
} else if len <= u16::MAX as usize {
buf.push(0xDE);
buf.extend_from_slice(&(len as u16).to_be_bytes());
} else {
buf.push(0xDF);
buf.extend_from_slice(&(len as u32).to_be_bytes());
}
}
#[inline]
pub fn write_array_header(buf: &mut Vec<u8>, len: usize) {
if len < 16 {
buf.push(0x90 | len as u8);
} else if len <= u16::MAX as usize {
buf.push(0xDC);
buf.extend_from_slice(&(len as u16).to_be_bytes());
} else {
buf.push(0xDD);
buf.extend_from_slice(&(len as u32).to_be_bytes());
}
}
#[inline]
pub fn write_str(buf: &mut Vec<u8>, s: &str) {
let bytes = s.as_bytes();
let len = bytes.len();
if len < 32 {
buf.push(0xA0 | len as u8);
} else if len <= u8::MAX as usize {
buf.push(0xD9);
buf.push(len as u8);
} else if len <= u16::MAX as usize {
buf.push(0xDA);
buf.extend_from_slice(&(len as u16).to_be_bytes());
} else {
buf.push(0xDB);
buf.extend_from_slice(&(len as u32).to_be_bytes());
}
buf.extend_from_slice(bytes);
}
#[inline]
pub fn write_i64(buf: &mut Vec<u8>, i: i64) {
if (0..=127).contains(&i) {
buf.push(i as u8);
} else if (-32..0).contains(&i) {
buf.push(i as u8); } else if i >= i8::MIN as i64 && i <= i8::MAX as i64 {
buf.push(0xD0);
buf.push(i as i8 as u8);
} else if i >= i16::MIN as i64 && i <= i16::MAX as i64 {
buf.push(0xD1);
buf.extend_from_slice(&(i as i16).to_be_bytes());
} else if i >= i32::MIN as i64 && i <= i32::MAX as i64 {
buf.push(0xD2);
buf.extend_from_slice(&(i as i32).to_be_bytes());
} else {
buf.push(0xD3);
buf.extend_from_slice(&i.to_be_bytes());
}
}
#[inline]
pub fn write_f64(buf: &mut Vec<u8>, f: f64) {
buf.push(0xCB);
buf.extend_from_slice(&f.to_be_bytes());
}
#[inline]
pub fn write_bool(buf: &mut Vec<u8>, b: bool) {
buf.push(if b { 0xC3 } else { 0xC2 });
}
#[inline]
pub fn write_null(buf: &mut Vec<u8>) {
buf.push(0xC0);
}
#[inline]
pub fn write_bin(buf: &mut Vec<u8>, data: &[u8]) {
let len = data.len();
if len <= u8::MAX as usize {
buf.push(0xC4);
buf.push(len as u8);
} else if len <= u16::MAX as usize {
buf.push(0xC5);
buf.extend_from_slice(&(len as u16).to_be_bytes());
} else {
buf.push(0xC6);
buf.extend_from_slice(&(len as u32).to_be_bytes());
}
buf.extend_from_slice(data);
}
#[inline]
pub fn write_kv_str(buf: &mut Vec<u8>, key: &str, value: &str) {
write_str(buf, key);
write_str(buf, value);
}
#[inline]
pub fn write_kv_i64(buf: &mut Vec<u8>, key: &str, value: i64) {
write_str(buf, key);
write_i64(buf, value);
}
#[inline]
pub fn write_kv_f64(buf: &mut Vec<u8>, key: &str, value: f64) {
write_str(buf, key);
write_f64(buf, value);
}
#[inline]
pub fn write_kv_bool(buf: &mut Vec<u8>, key: &str, value: bool) {
write_str(buf, key);
write_bool(buf, value);
}
#[inline]
pub fn write_kv_raw(buf: &mut Vec<u8>, key: &str, raw_value: &[u8]) {
write_str(buf, key);
buf.extend_from_slice(raw_value);
}
#[inline]
pub fn write_kv_null(buf: &mut Vec<u8>, key: &str) {
write_str(buf, key);
write_null(buf);
}
pub fn inject_str_field(value: &[u8], field_name: &str, field_value: &str) -> Vec<u8> {
if let Some((count, body_start)) = crate::msgpack_scan::reader::map_header(value, 0) {
if crate::msgpack_scan::extract_field(value, 0, field_name).is_some() {
return value.to_vec();
}
let mut buf = Vec::with_capacity(value.len() + field_name.len() + field_value.len() + 16);
write_map_header(&mut buf, count + 1);
write_kv_str(&mut buf, field_name, field_value);
buf.extend_from_slice(&value[body_start..]);
buf
} else {
let mut buf = Vec::with_capacity(value.len() + field_name.len() + field_value.len() + 16);
write_map_header(&mut buf, 2);
write_kv_str(&mut buf, field_name, field_value);
write_str(&mut buf, "value");
buf.extend_from_slice(value);
buf
}
}
pub fn merge_fields(base: &[u8], updates: &[(&str, &[u8])]) -> Vec<u8> {
use std::collections::HashSet;
let update_names: HashSet<&str> = updates.iter().map(|(k, _)| *k).collect();
let (count, body_start) = match crate::msgpack_scan::reader::map_header(base, 0) {
Some(v) => v,
None => {
let mut buf = Vec::with_capacity(updates.len() * 32);
write_map_header(&mut buf, updates.len());
for (k, v) in updates {
write_str(&mut buf, k);
buf.extend_from_slice(v);
}
return buf;
}
};
let mut kept = 0usize;
let mut pos = body_start;
for _ in 0..count {
let key = crate::msgpack_scan::reader::read_str(base, pos);
pos = match crate::msgpack_scan::reader::skip_value(base, pos) {
Some(p) => p,
None => break,
};
pos = match crate::msgpack_scan::reader::skip_value(base, pos) {
Some(p) => p,
None => break,
};
if let Some(k) = &key {
if !update_names.contains(&k[..]) {
kept += 1;
}
} else {
kept += 1;
}
}
let new_count = kept + updates.len();
let mut buf = Vec::with_capacity(
base.len()
+ updates
.iter()
.map(|(k, v)| k.len() + v.len() + 4)
.sum::<usize>(),
);
write_map_header(&mut buf, new_count);
pos = body_start;
for _ in 0..count {
let key_start = pos;
let key = crate::msgpack_scan::reader::read_str(base, pos);
pos = match crate::msgpack_scan::reader::skip_value(base, pos) {
Some(p) => p,
None => break,
};
pos = match crate::msgpack_scan::reader::skip_value(base, pos) {
Some(p) => p,
None => break,
};
if let Some(k) = &key
&& update_names.contains(&k[..])
{
continue; }
buf.extend_from_slice(&base[key_start..pos]);
}
for (k, v) in updates {
write_str(&mut buf, k);
buf.extend_from_slice(v);
}
buf
}
pub fn build_str_map(pairs: &[(&str, &str)]) -> Vec<u8> {
let mut buf = Vec::with_capacity(pairs.len() * 32);
write_map_header(&mut buf, pairs.len());
for (k, v) in pairs {
write_kv_str(&mut buf, k, v);
}
buf
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn roundtrip_map() {
let mut buf = Vec::new();
write_map_header(&mut buf, 2);
write_kv_str(&mut buf, "name", "alice");
write_kv_i64(&mut buf, "age", 30);
let (count, mut pos) = crate::msgpack_scan::reader::map_header(&buf, 0).unwrap();
assert_eq!(count, 2);
let k1 = crate::msgpack_scan::reader::read_str(&buf, pos).unwrap();
assert_eq!(k1, "name");
pos = crate::msgpack_scan::reader::skip_value(&buf, pos).unwrap();
let v1 = crate::msgpack_scan::reader::read_str(&buf, pos).unwrap();
assert_eq!(v1, "alice");
pos = crate::msgpack_scan::reader::skip_value(&buf, pos).unwrap();
let k2 = crate::msgpack_scan::reader::read_str(&buf, pos).unwrap();
assert_eq!(k2, "age");
pos = crate::msgpack_scan::reader::skip_value(&buf, pos).unwrap();
let v2 = crate::msgpack_scan::reader::read_i64(&buf, pos).unwrap();
assert_eq!(v2, 30);
}
#[test]
fn write_kv_raw_splices_correctly() {
let mut val_buf = Vec::new();
write_str(&mut val_buf, "hello");
let mut buf = Vec::new();
write_map_header(&mut buf, 1);
write_kv_raw(&mut buf, "greeting", &val_buf);
let field = crate::msgpack_scan::field::extract_field(&buf, 0, "greeting").unwrap();
let s = crate::msgpack_scan::reader::read_str(&buf, field.0).unwrap();
assert_eq!(s, "hello");
}
#[test]
fn compact_integer_encoding() {
let mut buf = Vec::new();
write_i64(&mut buf, 42);
assert_eq!(buf, vec![42]);
buf.clear();
write_i64(&mut buf, -1);
assert_eq!(buf, vec![0xFF]);
buf.clear();
write_i64(&mut buf, -100);
assert_eq!(buf, vec![0xD0, (-100i8) as u8]);
}
}