rocketmq_protocol/trace/
trace_codec.rs1use cheetah_string::CheetahString;
16
17use super::trace_constants::TraceConstants;
18use super::TraceRecord;
19use super::TraceType;
20
21pub fn encode_records(records: &[TraceRecord]) -> CheetahString {
22 let mut output = String::new();
23 for record in records {
24 output.push_str(&record.trace_type.to_string());
25 for field in &record.fields {
26 output.push(TraceConstants::CONTENT_SPLITOR);
27 output.push_str(field);
28 }
29 output.push(TraceConstants::FIELD_SPLITOR);
30 }
31 CheetahString::from_string(output)
32}
33
34pub fn decode_records(input: &str) -> Vec<TraceRecord> {
35 input
36 .split(TraceConstants::FIELD_SPLITOR)
37 .filter(|record| !record.is_empty())
38 .filter_map(|record| {
39 let mut fields = record.split(TraceConstants::CONTENT_SPLITOR);
40 let trace_type = TraceType::parse(fields.next()?)?;
41 Some(TraceRecord::new(
42 trace_type,
43 fields.map(CheetahString::from_slice).collect(),
44 ))
45 })
46 .collect()
47}
48
49#[cfg(test)]
50mod tests {
51 use super::*;
52
53 #[test]
54 fn frozen_pub_trace_round_trip_preserves_delimiters_and_order() {
55 let frozen = "Pub\u{1}1710000000000\u{1}region\u{1}group\u{1}topic\u{1}msg-id\u{2}";
56 let records = decode_records(frozen);
57 assert_eq!(records.len(), 1);
58 assert_eq!(records[0].trace_type, TraceType::Pub);
59 assert_eq!(encode_records(&records), frozen);
60 }
61
62 #[test]
63 fn malformed_and_unknown_records_are_skipped() {
64 let records = decode_records("Unknown\u{1}x\u{2}\u{2}SubAfter\u{1}request\u{2}");
65 assert_eq!(records.len(), 1);
66 assert_eq!(records[0].trace_type, TraceType::SubAfter);
67 }
68}