use fastrace::{Span, prelude::LocalSpan};
use std::time::Instant;
const ENCODE_BER_SPAN: &str = "asn1.encode.BER";
const ENCODE_DER_SPAN: &str = "asn1.encode.DER";
const ENCODE_OER_SPAN: &str = "asn1.encode.OER";
const ENCODE_PER_SPAN: &str = "asn1.encode.PER";
const ENCODE_XER_SPAN: &str = "asn1.encode.XER";
const ENCODE_JER_SPAN: &str = "asn1.encode.JER";
const DECODE_BER_SPAN: &str = "asn1.decode.BER";
const DECODE_DER_SPAN: &str = "asn1.decode.DER";
const DECODE_OER_SPAN: &str = "asn1.decode.OER";
const DECODE_PER_SPAN: &str = "asn1.decode.PER";
const DECODE_XER_SPAN: &str = "asn1.decode.XER";
const DECODE_JER_SPAN: &str = "asn1.decode.JER";
const SCHEMA_VALIDATE_SPAN: &str = "asn1.schema.validate";
const SCHEMA_LOOKUP_SPAN: &str = "asn1.schema.lookup";
const SCHEMA_COMPILE_SPAN: &str = "asn1.schema.compile";
const SCHEMA_TRANSFORM_SPAN: &str = "asn1.schema.transform";
const SCHEMA_PARSE_SPAN: &str = "asn1.schema.parse";
const SCHEMA_SERIALIZE_SPAN: &str = "asn1.schema.serialize";
#[inline]
pub fn encoding_span(encoding_rule: &str, _message_type: &str) -> Span {
match encoding_rule {
"BER" => Span::enter_with_local_parent(ENCODE_BER_SPAN),
"DER" => Span::enter_with_local_parent(ENCODE_DER_SPAN),
"OER" => Span::enter_with_local_parent(ENCODE_OER_SPAN),
"PER" => Span::enter_with_local_parent(ENCODE_PER_SPAN),
"XER" => Span::enter_with_local_parent(ENCODE_XER_SPAN),
"JER" => Span::enter_with_local_parent(ENCODE_JER_SPAN),
_ => Span::enter_with_local_parent("asn1.encode.unknown"),
}
}
#[inline]
pub fn decoding_span(encoding_rule: &str, _data_size: usize) -> Span {
match encoding_rule {
"BER" => Span::enter_with_local_parent(DECODE_BER_SPAN),
"DER" => Span::enter_with_local_parent(DECODE_DER_SPAN),
"OER" => Span::enter_with_local_parent(DECODE_OER_SPAN),
"PER" => Span::enter_with_local_parent(DECODE_PER_SPAN),
"XER" => Span::enter_with_local_parent(DECODE_XER_SPAN),
"JER" => Span::enter_with_local_parent(DECODE_JER_SPAN),
_ => Span::enter_with_local_parent("asn1.decode.unknown"),
}
}
#[inline]
pub fn schema_span(operation: &str) -> Span {
match operation {
"validate" => Span::enter_with_local_parent(SCHEMA_VALIDATE_SPAN),
"lookup" => Span::enter_with_local_parent(SCHEMA_LOOKUP_SPAN),
"compile" => Span::enter_with_local_parent(SCHEMA_COMPILE_SPAN),
"transform" => Span::enter_with_local_parent(SCHEMA_TRANSFORM_SPAN),
"parse" => Span::enter_with_local_parent(SCHEMA_PARSE_SPAN),
"serialize" => Span::enter_with_local_parent(SCHEMA_SERIALIZE_SPAN),
_ => Span::enter_with_local_parent("asn1.schema.unknown"),
}
}
pub struct EncodingMetrics {
start: Instant,
encoding_rule: &'static str,
message_type: String,
field_count: usize,
}
impl EncodingMetrics {
pub fn new(encoding_rule: &'static str, message_type: String) -> Self {
Self {
start: Instant::now(),
encoding_rule,
message_type,
field_count: 0,
}
}
pub fn record_field(&mut self) {
self.field_count += 1;
}
pub fn complete(self, encoded_size: usize) {
let duration = self.start.elapsed();
log::debug!(
"ASN.1 encoding completed: rule={}, type={}, fields={}, size={}, duration={:?}",
self.encoding_rule,
self.message_type,
self.field_count,
encoded_size,
duration
);
}
pub fn encoding_rule(&self) -> &'static str {
self.encoding_rule
}
pub fn message_type(&self) -> &str {
&self.message_type
}
pub fn field_count(&self) -> usize {
self.field_count
}
}
pub struct DecodingMetrics {
start: Instant,
encoding_rule: &'static str,
input_size: usize,
}
impl DecodingMetrics {
pub fn new(encoding_rule: &'static str, input_size: usize) -> Self {
Self {
start: Instant::now(),
encoding_rule,
input_size,
}
}
pub fn complete(self, message_type: &str, field_count: usize) {
let duration = self.start.elapsed();
log::debug!(
"ASN.1 decoding completed: rule={}, type={}, fields={}, input_size={}, duration={:?}",
self.encoding_rule,
message_type,
field_count,
self.input_size,
duration
);
}
pub fn encoding_rule(&self) -> &'static str {
self.encoding_rule
}
pub fn input_size(&self) -> usize {
self.input_size
}
}
pub fn record_buffer_allocation(_size: usize, _purpose: &str) {
let _span = LocalSpan::enter_with_local_parent("buffer_allocation");
}
pub fn record_schema_lookup(_message_type: &str, _found: bool, _duration_ns: u64) {
let _span = LocalSpan::enter_with_local_parent("schema_lookup");
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_encoding_metrics() {
let mut metrics = EncodingMetrics::new("DER", "NewOrderSingle".to_string());
metrics.record_field();
metrics.record_field();
metrics.complete(256);
}
#[test]
fn test_decoding_metrics() {
let metrics = DecodingMetrics::new("BER", 512);
metrics.complete("ExecutionReport", 15);
}
#[test]
fn test_encoding_span_known_rules() {
let _span_ber = encoding_span("BER", "TestMessage");
let _span_der = encoding_span("DER", "TestMessage");
let _span_oer = encoding_span("OER", "TestMessage");
let _span_per = encoding_span("PER", "TestMessage");
let _span_xer = encoding_span("XER", "TestMessage");
let _span_jer = encoding_span("JER", "TestMessage");
}
#[test]
fn test_encoding_span_unknown_rule() {
let _span = encoding_span("UNKNOWN_RULE", "TestMessage");
}
#[test]
fn test_decoding_span_known_rules() {
let _span_ber = decoding_span("BER", 1024);
let _span_der = decoding_span("DER", 1024);
let _span_oer = decoding_span("OER", 1024);
let _span_per = decoding_span("PER", 1024);
let _span_xer = decoding_span("XER", 1024);
let _span_jer = decoding_span("JER", 1024);
}
#[test]
fn test_decoding_span_unknown_rule() {
let _span = decoding_span("UNKNOWN_RULE", 1024);
}
#[test]
fn test_schema_span_known_operations() {
let _span_validate = schema_span("validate");
let _span_lookup = schema_span("lookup");
let _span_compile = schema_span("compile");
let _span_transform = schema_span("transform");
let _span_parse = schema_span("parse");
let _span_serialize = schema_span("serialize");
}
#[test]
fn test_schema_span_unknown_operation() {
let _span = schema_span("unknown_operation");
}
#[test]
fn test_span_constants() {
assert_eq!(ENCODE_BER_SPAN, "asn1.encode.BER");
assert_eq!(ENCODE_DER_SPAN, "asn1.encode.DER");
assert_eq!(ENCODE_OER_SPAN, "asn1.encode.OER");
assert_eq!(ENCODE_PER_SPAN, "asn1.encode.PER");
assert_eq!(ENCODE_XER_SPAN, "asn1.encode.XER");
assert_eq!(ENCODE_JER_SPAN, "asn1.encode.JER");
assert_eq!(DECODE_BER_SPAN, "asn1.decode.BER");
assert_eq!(DECODE_DER_SPAN, "asn1.decode.DER");
assert_eq!(DECODE_OER_SPAN, "asn1.decode.OER");
assert_eq!(DECODE_PER_SPAN, "asn1.decode.PER");
assert_eq!(DECODE_XER_SPAN, "asn1.decode.XER");
assert_eq!(DECODE_JER_SPAN, "asn1.decode.JER");
assert_eq!(SCHEMA_VALIDATE_SPAN, "asn1.schema.validate");
assert_eq!(SCHEMA_LOOKUP_SPAN, "asn1.schema.lookup");
assert_eq!(SCHEMA_COMPILE_SPAN, "asn1.schema.compile");
assert_eq!(SCHEMA_TRANSFORM_SPAN, "asn1.schema.transform");
assert_eq!(SCHEMA_PARSE_SPAN, "asn1.schema.parse");
assert_eq!(SCHEMA_SERIALIZE_SPAN, "asn1.schema.serialize");
}
#[test]
fn test_utility_functions() {
record_buffer_allocation(1024, "test_buffer");
record_schema_lookup("NewOrderSingle", true, 1000);
record_schema_lookup("NonExistentMessage", false, 500);
}
}