Skip to main content

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}