use super::super::msgpack_utils::write_str;
pub(crate) fn encode_raw_document_rows(rows: &[(String, Vec<u8>)]) -> crate::Result<Vec<u8>> {
let data_size: usize = rows.iter().map(|(id, d)| id.len() + d.len() + 16).sum();
let mut buf = Vec::with_capacity(data_size + 8);
msgpack_write_array_header(&mut buf, rows.len());
for (id, data_bytes) in rows {
buf.push(0x82);
write_str(&mut buf, "id");
write_str(&mut buf, id);
write_str(&mut buf, "data");
buf.extend_from_slice(data_bytes);
}
Ok(buf)
}
pub(crate) fn decode_raw_scan_to_docs(bytes: &[u8]) -> Vec<(String, Vec<u8>)> {
use nodedb_query::msgpack_scan;
let mut results = Vec::new();
let mut pos = 0;
while pos < bytes.len() {
let first = bytes[pos];
let (count, hdr_len) = if (0x90..=0x9f).contains(&first) {
((first & 0x0f) as usize, 1)
} else if first == 0xdc && pos + 3 <= bytes.len() {
(
u16::from_be_bytes([bytes[pos + 1], bytes[pos + 2]]) as usize,
3,
)
} else if first == 0xdd && pos + 5 <= bytes.len() {
(
u32::from_be_bytes([
bytes[pos + 1],
bytes[pos + 2],
bytes[pos + 3],
bytes[pos + 4],
]) as usize,
5,
)
} else {
break;
};
let mut inner = pos + hdr_len;
for _ in 0..count {
if inner >= bytes.len() {
break;
}
let elem_start = inner;
let elem_end = msgpack_scan::skip_value(bytes, inner).unwrap_or(bytes.len());
let id = msgpack_scan::extract_field(bytes, elem_start, "id")
.and_then(|(s, _e)| msgpack_scan::read_value(bytes, s))
.and_then(|v| match v {
nodedb_types::Value::String(s) => Some(s),
_ => None,
})
.unwrap_or_default();
let data = msgpack_scan::extract_field(bytes, elem_start, "data")
.map(|(s, e)| bytes[s..e].to_vec())
.unwrap_or_else(|| bytes[elem_start..elem_end].to_vec());
results.push((id, data));
inner = elem_end;
}
pos = inner;
}
results
}
pub fn encode_binary_rows(rows: &[Vec<u8>]) -> Vec<u8> {
let data_size: usize = rows.iter().map(|r| r.len()).sum();
let mut buf = Vec::with_capacity(data_size + 8);
msgpack_write_array_header(&mut buf, rows.len());
for row in rows {
buf.extend_from_slice(row);
}
buf
}
pub(super) fn msgpack_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());
}
}