use crate::MetricEntryParams;
use crate::helpers::*;
pub fn encode_metric_entry(params: &MetricEntryParams<'_>) -> Vec<u8> {
let mut buf = Vec::with_capacity(256);
encode_metric_entry_into(&mut buf, params);
buf
}
pub fn encode_metric_data(encoded_metrics: &[Vec<u8>]) -> Vec<u8> {
let vtable_size: u16 = 4 + 2;
let table_size: u16 = 8;
let metrics_total: usize = encoded_metrics.iter().map(|m| m.len() + 4).sum();
let estimated = 4 + vtable_size as usize + table_size as usize + 4 + metrics_total + 64;
let mut buf = Vec::with_capacity(estimated);
buf.extend_from_slice(&[0u8; 4]);
let vtable_start = buf.len();
write_u16(&mut buf, vtable_size);
write_u16(&mut buf, table_size);
write_u16(&mut buf, 4);
buf.extend_from_slice(&[0u8; 2]);
let table_start = buf.len();
let soffset = (table_start - vtable_start) as i32;
write_i32(&mut buf, soffset);
let metrics_off_pos = buf.len();
write_u32(&mut buf, 0);
align4(&mut buf);
let metrics_vec_start = buf.len();
let count = encoded_metrics.len();
write_u32(&mut buf, count as u32);
let offsets_start = buf.len();
for _ in 0..count {
write_u32(&mut buf, 0);
}
align4(&mut buf);
let mut table_positions = Vec::with_capacity(count);
for metric_bytes in encoded_metrics {
align4(&mut buf);
let metric_start = buf.len();
let root_offset = if metric_bytes.len() >= 4 {
u32::from_le_bytes([
metric_bytes[0],
metric_bytes[1],
metric_bytes[2],
metric_bytes[3],
]) as usize
} else {
0
};
table_positions.push(metric_start + root_offset);
buf.extend_from_slice(metric_bytes);
}
for (i, &table_pos) in table_positions.iter().enumerate() {
let offset_pos = offsets_start + i * 4;
patch_offset(&mut buf, offset_pos, table_pos);
}
patch_offset(&mut buf, metrics_off_pos, metrics_vec_start);
buf[0..4].copy_from_slice(&(table_start as u32).to_le_bytes());
buf
}
pub fn encode_metric_data_into(
buf: &mut Vec<u8>,
metrics: &[MetricEntryParams<'_>],
) -> std::ops::Range<usize> {
let data_start = buf.len();
let count = metrics.len();
let root_pos = buf.len();
buf.extend_from_slice(&[0u8; 4]);
let vtable_start = buf.len();
write_u16(buf, 6); write_u16(buf, 8); write_u16(buf, 4); buf.extend_from_slice(&[0u8; 2]);
let table_start = buf.len();
write_i32(buf, (table_start - vtable_start) as i32);
let metrics_off_pos = buf.len();
write_u32(buf, 0);
align4(buf);
let metrics_vec_start = buf.len();
write_u32(buf, count as u32);
let offsets_start = buf.len();
for _ in 0..count {
write_u32(buf, 0);
}
align4(buf);
let mut table_positions = Vec::with_capacity(count);
for params in metrics {
align4(buf);
let entry_start = buf.len();
encode_metric_entry_into(buf, params);
let root_offset = u32::from_le_bytes([
buf[entry_start],
buf[entry_start + 1],
buf[entry_start + 2],
buf[entry_start + 3],
]) as usize;
table_positions.push(entry_start + root_offset);
}
for (i, &table_pos) in table_positions.iter().enumerate() {
patch_offset(buf, offsets_start + i * 4, table_pos);
}
patch_offset(buf, metrics_off_pos, metrics_vec_start);
buf[root_pos..root_pos + 4].copy_from_slice(&((table_start - data_start) as u32).to_le_bytes());
data_start..buf.len()
}
fn encode_metric_entry_into(buf: &mut Vec<u8>, params: &MetricEntryParams<'_>) {
let has_source = params.source.is_some();
let has_service = params.service.is_some();
let has_labels = !params.labels.is_empty();
let has_histogram = params.histogram.is_some();
let has_session_id = params.session_id.is_some();
let vtable_size: u16 = 4 + 11 * 2;
let table_size: u16 = 52;
let root_pos = buf.len();
buf.extend_from_slice(&[0u8; 4]);
let vtable_start = buf.len();
write_u16(buf, vtable_size);
write_u16(buf, table_size);
write_u16(buf, 48); write_u16(buf, 32); write_u16(buf, 4); write_u16(buf, 40); write_u16(buf, if has_source { 8 } else { 0 }); write_u16(buf, if has_service { 12 } else { 0 }); write_u16(buf, if has_labels { 16 } else { 0 }); write_u16(buf, 49); write_u16(buf, if has_histogram { 24 } else { 0 }); write_u16(buf, if has_session_id { 28 } else { 0 }); write_u16(buf, 0);
buf.extend_from_slice(&[0u8; 2]);
let table_start = buf.len();
let soffset = (table_start - vtable_start) as i32;
write_i32(buf, soffset);
let name_off_pos = buf.len();
write_u32(buf, 0);
let source_off_pos = buf.len();
write_u32(buf, 0);
let service_off_pos = buf.len();
write_u32(buf, 0);
let labels_off_pos = buf.len();
write_u32(buf, 0);
write_u32(buf, 0);
let histogram_off_pos = buf.len();
write_u32(buf, 0);
let session_id_off_pos = buf.len();
write_u32(buf, 0);
write_u64(buf, params.timestamp); write_f64(buf, params.value); buf.push(params.metric_type.as_u8()); buf.push(params.temporality.as_u8()); buf.extend_from_slice(&[0u8; 2]);
align4(buf);
let name_start = write_string(buf, params.name);
align4(buf);
let source_start = params.source.map(|s| write_string(buf, s));
align4(buf);
let service_start = params.service.map(|s| write_string(buf, s));
align4(buf);
let session_id_start = params.session_id.map(|id| write_byte_vector(buf, id));
align4(buf);
let labels_start = if has_labels {
Some(encode_labels(buf, params.labels))
} else {
None
};
let histogram_start = params.histogram.map(|h| encode_histogram(buf, h));
buf[root_pos..root_pos + 4].copy_from_slice(&((table_start - root_pos) as u32).to_le_bytes());
patch_offset(buf, name_off_pos, name_start);
if let Some(start) = source_start {
patch_offset(buf, source_off_pos, start);
}
if let Some(start) = service_start {
patch_offset(buf, service_off_pos, start);
}
if let Some(start) = session_id_start {
patch_offset(buf, session_id_off_pos, start);
}
if let Some(start) = labels_start {
patch_offset(buf, labels_off_pos, start);
}
if let Some(start) = histogram_start {
patch_offset(buf, histogram_off_pos, start);
}
}
fn encode_labels(buf: &mut Vec<u8>, labels: &[crate::LabelParam<'_>]) -> usize {
let count = labels.len();
let vec_start = buf.len();
write_u32(buf, count as u32);
let offsets_start = buf.len();
for _ in 0..count {
write_u32(buf, 0);
}
align4(buf);
let mut table_positions = Vec::with_capacity(count);
for label in labels {
align4(buf);
let vtable_start = buf.len();
write_u16(buf, 8); write_u16(buf, 12); write_u16(buf, 4); write_u16(buf, 8);
let table_start = buf.len();
table_positions.push(table_start);
let soffset = (table_start - vtable_start) as i32;
write_i32(buf, soffset);
let key_off_pos = buf.len();
write_u32(buf, 0);
let value_off_pos = buf.len();
write_u32(buf, 0);
align4(buf);
let key_start = write_string(buf, label.key);
align4(buf);
let value_start = write_string(buf, label.value);
patch_offset(buf, key_off_pos, key_start);
patch_offset(buf, value_off_pos, value_start);
}
for (i, &table_pos) in table_positions.iter().enumerate() {
patch_offset(buf, offsets_start + i * 4, table_pos);
}
vec_start
}
fn encode_histogram(buf: &mut Vec<u8>, h: &crate::HistogramParams) -> usize {
let has_buckets = !h.buckets.is_empty();
let vtable_start = buf.len();
write_u16(buf, 14); write_u16(buf, 40);
write_u16(buf, 4); write_u16(buf, 12); write_u16(buf, if has_buckets { 20 } else { 0 }); write_u16(buf, 24); write_u16(buf, 32);
align4(buf);
let table_start = buf.len();
write_i32(buf, (table_start - vtable_start) as i32);
write_u64(buf, h.count);
write_f64(buf, h.sum);
let buckets_off_pos = buf.len();
write_u32(buf, 0);
write_f64(buf, h.min);
write_f64(buf, h.max);
align4(buf);
if has_buckets {
let start = encode_buckets(buf, &h.buckets);
patch_offset(buf, buckets_off_pos, start);
}
table_start
}
fn encode_buckets(buf: &mut Vec<u8>, buckets: &[(f64, u64)]) -> usize {
let vec_start = buf.len();
write_u32(buf, buckets.len() as u32);
let slots_start = buf.len();
for _ in 0..buckets.len() {
write_u32(buf, 0);
}
align4(buf);
let mut offsets = Vec::with_capacity(buckets.len());
for &(upper_bound, count) in buckets {
let vtable_start = buf.len();
write_u16(buf, 8); write_u16(buf, 20); write_u16(buf, 4); write_u16(buf, 12);
align4(buf);
let table_start = buf.len();
write_i32(buf, (table_start - vtable_start) as i32);
write_f64(buf, upper_bound);
write_u64(buf, count);
align4(buf);
offsets.push(table_start);
}
for (i, &offset) in offsets.iter().enumerate() {
patch_offset(buf, slots_start + i * 4, offset);
}
vec_start
}