freeswitch_log_parser/message/varname.rs
1//! [`VarName`], the channel-variable name a classified message carries.
2
3use std::fmt;
4
5use freeswitch_types::VARIABLE_PREFIX;
6
7/// The name of a FreeSWITCH channel variable, stored bare.
8///
9/// A dump spells its keys `variable_sip_call_id` while every other narration
10/// (`set`, `export`, `CoreSession::setVariable`) spells the same variable
11/// `sip_call_id`. This type holds the bare spelling once, and [`Display`] and
12/// [`to_prefixed`](Self::to_prefixed) render the dump's form for a reader.
13///
14/// It deliberately does not compare against `&str`. A consumer written against
15/// the prefixed spelling — `name == "variable_sip_call_id"`, or a
16/// `starts_with("variable_")` filter — is the mistake this type exists to turn
17/// into a compile error rather than a match that silently stops firing. Compare
18/// against [`bare`](Self::bare), or against a `freeswitch-types` variable enum's
19/// `as_str`.
20///
21/// [`Display`]: std::fmt::Display
22// No Deref, AsRef<str>, Borrow<str> or PartialEq<str>: any of them restores the
23// silent `name == "variable_x"` comparison this type was introduced to break.
24#[derive(Debug, Clone, PartialEq, Eq, Hash)]
25pub struct VarName(String);
26
27impl VarName {
28 /// Wrap a name already stripped of the `variable_` prefix.
29 pub fn new(bare: impl Into<String>) -> Self {
30 VarName(bare.into())
31 }
32
33 /// Wrap a name that may carry the `variable_` prefix, stripping it if so.
34 pub fn from_prefixed(name: &str) -> Self {
35 VarName(
36 name.strip_prefix(VARIABLE_PREFIX)
37 .unwrap_or(name)
38 .to_string(),
39 )
40 }
41
42 /// The bare name, as `set` and the variable enums spell it.
43 pub fn bare(&self) -> &str {
44 &self.0
45 }
46
47 /// The prefixed name, as a CHANNEL_DATA dump spells it.
48 pub fn to_prefixed(&self) -> String {
49 freeswitch_types::variable_key(&self.0)
50 }
51}
52
53impl fmt::Display for VarName {
54 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
55 write!(f, "{VARIABLE_PREFIX}{}", self.0)
56 }
57}
58
59#[cfg(test)]
60mod tests {
61 use super::*;
62
63 #[test]
64 fn from_prefixed_strips_once() {
65 assert_eq!(
66 VarName::from_prefixed("variable_sip_call_id").bare(),
67 "sip_call_id"
68 );
69 assert_eq!(VarName::from_prefixed("sip_call_id").bare(), "sip_call_id");
70 assert_eq!(
71 VarName::from_prefixed("variable_variable_odd").bare(),
72 "variable_odd"
73 );
74 }
75
76 #[test]
77 fn renders_the_prefixed_spelling() {
78 let name = VarName::new("sip_call_id");
79 assert_eq!(name.to_string(), "variable_sip_call_id");
80 assert_eq!(name.to_prefixed(), "variable_sip_call_id");
81 }
82}