use crate::msgpack_scan::{
KvBodyShape, inject_str_field, kv_body_shape, write_map_header, write_str,
};
pub fn kv_row_msgpack(key: &str, value: &[u8]) -> Vec<u8> {
if kv_body_shape(value) == KvBodyShape::Map {
return inject_str_field(value, "key", key);
}
let mut buf = Vec::with_capacity(value.len() + key.len() + 16);
write_map_header(&mut buf, 2);
write_str(&mut buf, "key");
write_str(&mut buf, key);
write_str(&mut buf, "value");
write_str(&mut buf, &String::from_utf8_lossy(value));
buf
}
#[cfg(test)]
mod tests {
use super::kv_row_msgpack;
use crate::msgpack_scan::extract_field;
fn field_str(mp: &[u8], name: &str) -> Option<String> {
let (start, _end) = extract_field(mp, 0, name)?;
crate::msgpack_scan::read_str(mp, start).map(str::to_string)
}
#[test]
fn a_raw_value_is_wrapped_as_a_string_not_appended_verbatim() {
let mp = kv_row_msgpack("k1", b"v1");
assert_eq!(field_str(&mp, "key").as_deref(), Some("k1"));
assert_eq!(field_str(&mp, "value").as_deref(), Some("v1"));
}
#[test]
fn a_msgpack_map_value_keeps_its_fields_and_gains_the_key() {
let mut body = Vec::new();
crate::msgpack_scan::write_map_header(&mut body, 1);
crate::msgpack_scan::write_str(&mut body, "n");
crate::msgpack_scan::write_str(&mut body, "7");
let mp = kv_row_msgpack("k2", &body);
assert_eq!(field_str(&mp, "key").as_deref(), Some("k2"));
assert_eq!(field_str(&mp, "n").as_deref(), Some("7"));
}
#[test]
fn a_body_that_already_carries_a_key_field_keeps_its_own() {
let mut body = Vec::new();
crate::msgpack_scan::write_map_header(&mut body, 1);
crate::msgpack_scan::write_str(&mut body, "key");
crate::msgpack_scan::write_str(&mut body, "stored");
let mp = kv_row_msgpack("slot", &body);
assert_eq!(field_str(&mp, "key").as_deref(), Some("stored"));
}
#[test]
fn a_non_utf8_raw_value_still_produces_well_formed_msgpack() {
let mp = kv_row_msgpack("k3", &[0xff, 0xfe]);
assert_eq!(field_str(&mp, "key").as_deref(), Some("k3"));
assert!(
field_str(&mp, "value").is_some(),
"a lossy string is still a readable msgpack string"
);
}
}