use crate::api;
use std::convert::TryInto;
pub trait BinaryFormat {
fn to_bytes(&self, context: &api::SpanContext) -> [u8; 29];
fn from_bytes(&self, bytes: Vec<u8>) -> api::SpanContext;
}
#[derive(Debug, Default)]
pub struct BinaryPropagator {}
impl BinaryPropagator {
pub fn new() -> Self {
BinaryPropagator {}
}
}
impl BinaryFormat for BinaryPropagator {
fn to_bytes(&self, context: &api::SpanContext) -> [u8; 29] {
let mut res = [0u8; 29];
if !context.is_valid() {
return res;
}
res[2..18].copy_from_slice(&context.trace_id().to_u128().to_be_bytes());
res[18] = 1;
res[19..27].copy_from_slice(&context.span_id().to_u64().to_be_bytes());
res[27] = 2;
res[28] = context.trace_flags();
res
}
fn from_bytes(&self, bytes: Vec<u8>) -> api::SpanContext {
if bytes.is_empty() {
return api::SpanContext::empty_context();
}
let trace_id: u128;
let mut span_id = 0;
let mut trace_flags = 0;
let mut b = &bytes[1..];
if b.len() >= 17 && b[0] == 0 {
trace_id = u128::from_be_bytes(b[1..17].try_into().unwrap());
b = &b[17..];
} else {
return api::SpanContext::empty_context();
}
if b.len() >= 9 && b[0] == 1 {
span_id = u64::from_be_bytes(b[1..9].try_into().unwrap());
b = &b[9..];
}
if b.len() >= 2 && b[0] == 2 {
trace_flags = b[1]
}
let span_context = api::SpanContext::new(
api::TraceId::from_u128(trace_id),
api::SpanId::from_u64(span_id),
trace_flags,
true,
);
if span_context.is_valid() {
span_context
} else {
api::SpanContext::empty_context()
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[rustfmt::skip]
fn to_bytes_data() -> Vec<(api::SpanContext, [u8; 29])> {
vec![
(api::SpanContext::new(
api::TraceId::from_u128(0x4bf9_2f35_77b3_4da6_a3ce_929d_0e0e_4736),
api::SpanId::from_u64(0x00f0_67aa_0ba9_02b7), 1, true), [
0x00, 0x00, 0x4b, 0xf9, 0x2f, 0x35, 0x77, 0xb3, 0x4d, 0xa6, 0xa3, 0xce, 0x92, 0x9d, 0x0e, 0x0e, 0x47, 0x36,
0x01, 0x00, 0xf0, 0x67, 0xaa, 0x0b, 0xa9, 0x02, 0xb7,
0x02, 0x01,
]),
(api::SpanContext::new(
api::TraceId::from_u128(0x4bf9_2f35_77b3_4da6_a3ce_929d_0e0e_4736),
api::SpanId::from_u64(0x00f0_67aa_0ba9_02b7), 0, true), [
0x00, 0x00, 0x4b, 0xf9, 0x2f, 0x35, 0x77, 0xb3, 0x4d, 0xa6, 0xa3, 0xce, 0x92, 0x9d, 0x0e, 0x0e, 0x47, 0x36,
0x01, 0x00, 0xf0, 0x67, 0xaa, 0x0b, 0xa9, 0x02, 0xb7,
0x02, 0x00,
]),
(api::SpanContext::empty_context(), [0u8; 29]),
]
}
#[rustfmt::skip]
fn from_bytes_data() -> Vec<(api::SpanContext, Vec<u8>)> {
vec![
(api::SpanContext::new(api::TraceId::from_u128(0x4bf9_2f35_77b3_4da6_a3ce_929d_0e0e_4736), api::SpanId::from_u64(0x00f0_67aa_0ba9_02b7), 1, true), vec![
0x02, 0x00, 0x4b, 0xf9, 0x2f, 0x35, 0x77, 0xb3, 0x4d, 0xa6, 0xa3, 0xce, 0x92, 0x9d, 0x0e, 0x0e, 0x47, 0x36,
0x01, 0x00, 0xf0, 0x67, 0xaa, 0x0b, 0xa9, 0x02, 0xb7,
0x02, 0x01,
]),
(api::SpanContext::new(api::TraceId::from_u128(0x4bf9_2f35_77b3_4da6_a3ce_929d_0e0e_4736), api::SpanId::from_u64(0x00f0_67aa_0ba9_02b7), 1, true), vec![
0x02, 0x00, 0x4b, 0xf9, 0x2f, 0x35, 0x77, 0xb3, 0x4d, 0xa6, 0xa3, 0xce, 0x92, 0x9d, 0x0e, 0x0e, 0x47, 0x36,
0x01, 0x00, 0xf0, 0x67, 0xaa, 0x0b, 0xa9, 0x02, 0xb7,
0x02, 0x01,
]),
(api::SpanContext::new(api::TraceId::from_u128(0x4bf9_2f35_77b3_4da6_a3ce_929d_0e0e_4736), api::SpanId::from_u64(0x00f0_67aa_0ba9_02b7), 0, true), vec![
0x00, 0x00, 0x4b, 0xf9, 0x2f, 0x35, 0x77, 0xb3, 0x4d, 0xa6, 0xa3, 0xce, 0x92, 0x9d, 0x0e, 0x0e, 0x47, 0x36,
0x01, 0x00, 0xf0, 0x67, 0xaa, 0x0b, 0xa9, 0x02, 0xb7,
]),
(api::SpanContext::empty_context(), vec![
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x02, 0x01,
]),
(api::SpanContext::empty_context(), vec![
0x00, 0x00, 0x4b, 0xf9, 0x2f, 0x35, 0x77, 0xb3, 0x4d, 0xa6, 0xa3, 0xce, 0x92, 0x9d, 0x0e, 0x0e, 0x47, 0x36,
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x02, 0x01,
]),
(api::SpanContext::empty_context(), vec![
0x00, 0x01, 0x4b, 0xf9, 0x2f, 0x35, 0x77, 0xb3, 0x4d, 0xa6, 0xa3, 0xce, 0x92, 0x9d, 0x0e, 0x0e, 0x47, 0x36,
0x01, 0x00, 0xf0, 0x67, 0xaa, 0x0b, 0xa9, 0x02, 0xb7,
]),
(api::SpanContext::empty_context(), vec![
0x00, 0x00, 0x4b, 0xf9, 0x2f, 0x35, 0x77, 0xb3, 0x4d,
]),
]
}
#[test]
fn to_bytes_conversion() {
let propagator = BinaryPropagator::new();
for (context, data) in to_bytes_data() {
assert_eq!(propagator.to_bytes(&context), data)
}
}
#[test]
fn from_bytes_conversion() {
let propagator = BinaryPropagator::new();
for (context, data) in from_bytes_data() {
assert_eq!(propagator.from_bytes(data), context)
}
}
}