Skip to main content

freeswitch_types/variables/
esl_array.rs

1use std::fmt;
2
3const ARRAY_HEADER: &str = "ARRAY::";
4const ARRAY_SEPARATOR: &str = "|:";
5
6/// Parses FreeSWITCH `ARRAY::item1|:item2|:item3` format
7#[derive(Debug, Clone, PartialEq, Eq)]
8#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
9pub struct EslArray(Vec<String>);
10
11impl EslArray {
12    /// Parse an `ARRAY::` formatted string. Returns `None` if the prefix is missing.
13    pub fn parse(s: &str) -> Option<Self> {
14        let body = s.strip_prefix(ARRAY_HEADER)?;
15        let items = body
16            .split(ARRAY_SEPARATOR)
17            .map(String::from)
18            .collect();
19        Some(Self(items))
20    }
21
22    /// Create a new array from a vec of items.
23    pub fn new(items: Vec<String>) -> Self {
24        Self(items)
25    }
26
27    /// Append an item to the end.
28    pub fn push(&mut self, value: String) {
29        self.0
30            .push(value);
31    }
32
33    /// Prepend an item to the front.
34    pub fn unshift(&mut self, value: String) {
35        self.0
36            .insert(0, value);
37    }
38
39    /// The parsed array items.
40    pub fn items(&self) -> &[String] {
41        &self.0
42    }
43
44    /// Number of items in the array.
45    pub fn len(&self) -> usize {
46        self.0
47            .len()
48    }
49
50    /// Returns `true` if the array has no items.
51    pub fn is_empty(&self) -> bool {
52        self.0
53            .is_empty()
54    }
55}
56
57impl<'a> IntoIterator for &'a EslArray {
58    type Item = &'a String;
59    type IntoIter = std::slice::Iter<'a, String>;
60
61    fn into_iter(self) -> Self::IntoIter {
62        self.0
63            .iter()
64    }
65}
66
67impl IntoIterator for EslArray {
68    type Item = String;
69    type IntoIter = std::vec::IntoIter<String>;
70
71    fn into_iter(self) -> Self::IntoIter {
72        self.0
73            .into_iter()
74    }
75}
76
77impl fmt::Display for EslArray {
78    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
79        f.write_str(ARRAY_HEADER)?;
80        for (i, item) in self
81            .0
82            .iter()
83            .enumerate()
84        {
85            if i > 0 {
86                f.write_str(ARRAY_SEPARATOR)?;
87            }
88            f.write_str(item)?;
89        }
90        Ok(())
91    }
92}
93
94#[cfg(test)]
95mod tests {
96    use super::*;
97
98    #[test]
99    fn parse_single_item() {
100        let arr = EslArray::parse("ARRAY::hello").unwrap();
101        assert_eq!(arr.items(), &["hello"]);
102        assert_eq!(arr.len(), 1);
103    }
104
105    #[test]
106    fn parse_multiple_items() {
107        let arr = EslArray::parse("ARRAY::one|:two|:three").unwrap();
108        assert_eq!(arr.items(), &["one", "two", "three"]);
109        assert_eq!(arr.len(), 3);
110    }
111
112    #[test]
113    fn parse_non_array_returns_none() {
114        assert!(EslArray::parse("not an array").is_none());
115        assert!(EslArray::parse("").is_none());
116        assert!(EslArray::parse("ARRAY:").is_none());
117    }
118
119    #[test]
120    fn display_round_trip() {
121        let input = "ARRAY::one|:two|:three";
122        let arr = EslArray::parse(input).unwrap();
123        assert_eq!(arr.to_string(), input);
124    }
125
126    #[test]
127    fn display_single_item() {
128        let arr = EslArray::parse("ARRAY::only").unwrap();
129        assert_eq!(arr.to_string(), "ARRAY::only");
130    }
131
132    #[test]
133    fn empty_items_in_array() {
134        let arr = EslArray::parse("ARRAY::|:|:stuff").unwrap();
135        assert_eq!(arr.items(), &["", "", "stuff"]);
136    }
137
138    #[test]
139    fn test_new() {
140        let arr = EslArray::new(vec!["a".into(), "b".into(), "c".into()]);
141        assert_eq!(arr.items(), &["a", "b", "c"]);
142        assert_eq!(arr.len(), 3);
143    }
144
145    #[test]
146    fn test_push() {
147        let mut arr = EslArray::new(vec!["first".into()]);
148        arr.push("second".into());
149        arr.push("third".into());
150        assert_eq!(arr.items(), &["first", "second", "third"]);
151        assert_eq!(arr.to_string(), "ARRAY::first|:second|:third");
152    }
153
154    #[test]
155    fn test_unshift() {
156        let mut arr = EslArray::new(vec!["last".into()]);
157        arr.unshift("middle".into());
158        arr.unshift("first".into());
159        assert_eq!(arr.items(), &["first", "middle", "last"]);
160        assert_eq!(arr.to_string(), "ARRAY::first|:middle|:last");
161    }
162
163    #[test]
164    fn parse_sip_uris_with_colons() {
165        let input = "ARRAY::sip:alice@atlanta.example.com|:sip:bob@biloxi.example.com";
166        let arr = EslArray::parse(input).unwrap();
167        assert_eq!(
168            arr.items(),
169            &[
170                "sip:alice@atlanta.example.com",
171                "sip:bob@biloxi.example.com"
172            ]
173        );
174        assert_eq!(arr.to_string(), input);
175    }
176
177    #[test]
178    fn parse_sip_uris_with_angle_brackets_and_params() {
179        let input = "ARRAY::<sip:+15551234567@gw.example.com;user=phone>|:<tel:+15559876543>";
180        let arr = EslArray::parse(input).unwrap();
181        assert_eq!(arr.len(), 2);
182        assert_eq!(
183            arr.items()[0],
184            "<sip:+15551234567@gw.example.com;user=phone>"
185        );
186        assert_eq!(arr.items()[1], "<tel:+15559876543>");
187        assert_eq!(arr.to_string(), input);
188    }
189}