| 
 | 1 | +// Copyright 2024-Present Datadog, Inc. https://www.datadoghq.com/  | 
 | 2 | +// SPDX-License-Identifier: Apache-2.0  | 
 | 3 | + | 
 | 4 | +use crate::msgpack_decoder::decode::buffer::Buffer;  | 
 | 5 | +use crate::msgpack_decoder::decode::error::DecodeError;  | 
 | 6 | +use crate::msgpack_decoder::decode::number::read_nullable_number;  | 
 | 7 | +use crate::msgpack_decoder::decode::span_event::read_span_events;  | 
 | 8 | +use crate::msgpack_decoder::decode::span_link::read_span_links;  | 
 | 9 | +use crate::msgpack_decoder::decode::string::{  | 
 | 10 | +    read_nullable_str_map_to_strings, read_nullable_string,  | 
 | 11 | +};  | 
 | 12 | +use crate::msgpack_decoder::decode::{meta_struct::read_meta_struct, metrics::read_metrics};  | 
 | 13 | +use crate::span::{v04::Span, SpanKey, TraceData};  | 
 | 14 | +use std::borrow::Borrow;  | 
 | 15 | + | 
 | 16 | +/// Decodes a slice of bytes into a `Span` object.  | 
 | 17 | +///  | 
 | 18 | +/// # Arguments  | 
 | 19 | +///  | 
 | 20 | +/// * `buf` - A mutable reference to a slice of bytes containing the encoded data.  | 
 | 21 | +///  | 
 | 22 | +/// # Returns  | 
 | 23 | +///  | 
 | 24 | +/// * `Ok(Span)` - A decoded `Span` object if successful.  | 
 | 25 | +/// * `Err(DecodeError)` - An error if the decoding process fails.  | 
 | 26 | +///  | 
 | 27 | +/// # Errors  | 
 | 28 | +///  | 
 | 29 | +/// This function will return an error if:  | 
 | 30 | +/// - The map length cannot be read.  | 
 | 31 | +/// - Any key or value cannot be decoded.  | 
 | 32 | +pub fn decode_span<T: TraceData>(buffer: &mut Buffer<T>) -> Result<Span<T>, DecodeError> {  | 
 | 33 | +    let mut span = Span::<T>::default();  | 
 | 34 | + | 
 | 35 | +    let span_size = rmp::decode::read_map_len(buffer.as_mut_slice()).map_err(|_| {  | 
 | 36 | +        DecodeError::InvalidFormat("Unable to get map len for span size".to_owned())  | 
 | 37 | +    })?;  | 
 | 38 | + | 
 | 39 | +    for _ in 0..span_size {  | 
 | 40 | +        fill_span(&mut span, buffer)?;  | 
 | 41 | +    }  | 
 | 42 | + | 
 | 43 | +    Ok(span)  | 
 | 44 | +}  | 
 | 45 | + | 
 | 46 | +// Safety: read_string_ref checks utf8 validity, so we don't do it again when creating the  | 
 | 47 | +// BytesStrings  | 
 | 48 | +fn fill_span<T: TraceData>(span: &mut Span<T>, buf: &mut Buffer<T>) -> Result<(), DecodeError> {  | 
 | 49 | +    let key = buf  | 
 | 50 | +        .read_string()?  | 
 | 51 | +        .borrow()  | 
 | 52 | +        .parse::<SpanKey>()  | 
 | 53 | +        .map_err(|e| DecodeError::InvalidFormat(e.message))?;  | 
 | 54 | + | 
 | 55 | +    match key {  | 
 | 56 | +        SpanKey::Service => span.service = read_nullable_string(buf)?,  | 
 | 57 | +        SpanKey::Name => span.name = read_nullable_string(buf)?,  | 
 | 58 | +        SpanKey::Resource => span.resource = read_nullable_string(buf)?,  | 
 | 59 | +        SpanKey::TraceId => span.trace_id = read_nullable_number(buf)?,  | 
 | 60 | +        SpanKey::SpanId => span.span_id = read_nullable_number(buf)?,  | 
 | 61 | +        SpanKey::ParentId => span.parent_id = read_nullable_number(buf)?,  | 
 | 62 | +        SpanKey::Start => span.start = read_nullable_number(buf)?,  | 
 | 63 | +        SpanKey::Duration => span.duration = read_nullable_number(buf)?,  | 
 | 64 | +        SpanKey::Error => span.error = read_nullable_number(buf)?,  | 
 | 65 | +        SpanKey::Type => span.r#type = read_nullable_string(buf)?,  | 
 | 66 | +        SpanKey::Meta => span.meta = read_nullable_str_map_to_strings(buf)?,  | 
 | 67 | +        SpanKey::Metrics => span.metrics = read_metrics(buf)?,  | 
 | 68 | +        SpanKey::MetaStruct => span.meta_struct = read_meta_struct(buf)?,  | 
 | 69 | +        SpanKey::SpanLinks => span.span_links = read_span_links(buf)?,  | 
 | 70 | +        SpanKey::SpanEvents => span.span_events = read_span_events(buf)?,  | 
 | 71 | +    }  | 
 | 72 | +    Ok(())  | 
 | 73 | +}  | 
 | 74 | + | 
 | 75 | +#[cfg(test)]  | 
 | 76 | +mod tests {  | 
 | 77 | +    use super::SpanKey;  | 
 | 78 | +    use crate::span::SpanKeyParseError;  | 
 | 79 | +    use std::str::FromStr;  | 
 | 80 | + | 
 | 81 | +    #[test]  | 
 | 82 | +    fn test_span_key_from_str() {  | 
 | 83 | +        assert_eq!(SpanKey::from_str("service").unwrap(), SpanKey::Service);  | 
 | 84 | +        assert_eq!(SpanKey::from_str("name").unwrap(), SpanKey::Name);  | 
 | 85 | +        assert_eq!(SpanKey::from_str("resource").unwrap(), SpanKey::Resource);  | 
 | 86 | +        assert_eq!(SpanKey::from_str("trace_id").unwrap(), SpanKey::TraceId);  | 
 | 87 | +        assert_eq!(SpanKey::from_str("span_id").unwrap(), SpanKey::SpanId);  | 
 | 88 | +        assert_eq!(SpanKey::from_str("parent_id").unwrap(), SpanKey::ParentId);  | 
 | 89 | +        assert_eq!(SpanKey::from_str("start").unwrap(), SpanKey::Start);  | 
 | 90 | +        assert_eq!(SpanKey::from_str("duration").unwrap(), SpanKey::Duration);  | 
 | 91 | +        assert_eq!(SpanKey::from_str("error").unwrap(), SpanKey::Error);  | 
 | 92 | +        assert_eq!(SpanKey::from_str("meta").unwrap(), SpanKey::Meta);  | 
 | 93 | +        assert_eq!(SpanKey::from_str("metrics").unwrap(), SpanKey::Metrics);  | 
 | 94 | +        assert_eq!(SpanKey::from_str("type").unwrap(), SpanKey::Type);  | 
 | 95 | +        assert_eq!(  | 
 | 96 | +            SpanKey::from_str("meta_struct").unwrap(),  | 
 | 97 | +            SpanKey::MetaStruct  | 
 | 98 | +        );  | 
 | 99 | +        assert_eq!(SpanKey::from_str("span_links").unwrap(), SpanKey::SpanLinks);  | 
 | 100 | +        assert_eq!(  | 
 | 101 | +            SpanKey::from_str("span_events").unwrap(),  | 
 | 102 | +            SpanKey::SpanEvents  | 
 | 103 | +        );  | 
 | 104 | + | 
 | 105 | +        let invalid_result = SpanKey::from_str("invalid_key");  | 
 | 106 | +        let msg = format!("SpanKeyParseError: Invalid span key: {}", "invalid_key");  | 
 | 107 | +        assert!(matches!(invalid_result, Err(SpanKeyParseError { .. })));  | 
 | 108 | +        assert_eq!(invalid_result.unwrap_err().to_string(), msg);  | 
 | 109 | +    }  | 
 | 110 | +}  | 
0 commit comments