aboutsummaryrefslogtreecommitdiff
path: root/mingling_core/src/program/string_vec.rs
blob: d38be851b7497ddea70cbd38fd4788b20f242ba2 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
/// A type wrapper around `Vec<String>`.
///
/// `StringVec` simplifies the process of creating a `Vec<String>` from various
/// string collection types (such as arrays, slices, `Vec<&str>`, `Vec<String>`, etc.)
/// by providing multiple convenient `From` conversion implementations.
/// It also implements [`Deref`] and `Into<Vec<String>>`, allowing you to manipulate it
/// just like a regular `Vec<String>`.
///
/// # Examples
///
/// ```
/// # use mingling_core::StringVec;
/// // Create from a string array
/// let sv = StringVec::from(["hello", "world"]);
///
/// // Has the Deref behavior of a regular Vec, can be used like a Vec<String>
/// assert_eq!(sv.len(), 2);
/// assert_eq!(sv[0], "hello");
///
/// // Iterate
/// for s in sv.iter() {
///     println!("{}", s);
/// }
///
/// // Convert back to Vec<String>
/// let v: Vec<String> = sv.into();
/// assert_eq!(v, vec!["hello".to_string(), "world".to_string()]);
/// ```
///
/// # Supported conversion sources
///
/// - `[&str; N]`: fixed-length string literal arrays
/// - `&[&str]`: string literal slice references
/// - `Vec<&str>`: string literal dynamic arrays
/// - `Vec<String>`: `String` dynamic arrays (moved directly, no copy)
/// - `&[String]`: `String` slice references (shallow copies elements)
///
/// # Notes
///
/// This type is marked as `#[doc(hidden)]`, typically used internally
/// and not usually shown directly in public documentation.
#[derive(Debug, Clone)]
#[doc(hidden)]
pub struct StringVec {
    /// The internally stored actual string vector.
    vec: Vec<String>,
}

impl std::ops::Deref for StringVec {
    type Target = Vec<String>;

    fn deref(&self) -> &Self::Target {
        &self.vec
    }
}

impl From<StringVec> for Vec<String> {
    fn from(val: StringVec) -> Self {
        val.vec
    }
}

impl<const N: usize> From<[&str; N]> for StringVec {
    fn from(slice: [&str; N]) -> Self {
        Self {
            vec: slice.iter().map(|&s| s.to_string()).collect(),
        }
    }
}

impl From<&[&str]> for StringVec {
    fn from(slice: &[&str]) -> Self {
        Self {
            vec: slice.iter().map(|&s| s.to_string()).collect(),
        }
    }
}
impl From<Vec<String>> for StringVec {
    fn from(vec: Vec<String>) -> Self {
        Self { vec }
    }
}

impl From<&[String]> for StringVec {
    fn from(slice: &[String]) -> Self {
        Self {
            vec: slice.to_vec(),
        }
    }
}

impl From<Vec<&str>> for StringVec {
    fn from(vec: Vec<&str>) -> Self {
        Self {
            vec: vec.iter().map(|&s| s.to_string()).collect(),
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_string_vec_from_array() {
        let sv = StringVec::from(["a", "b", "c"]);
        assert_eq!(sv.vec, vec!["a", "b", "c"]);
    }

    #[test]
    fn test_string_vec_from_slice_ref() {
        let arr = ["x", "y"];
        let sv = StringVec::from(&arr[..]);
        assert_eq!(sv.vec, vec!["x", "y"]);
    }

    #[test]
    fn test_string_vec_from_vec_string() {
        let original = vec!["one".to_string(), "two".to_string()];
        let sv = StringVec::from(original.clone());
        assert_eq!(sv.vec, original);
    }

    #[test]
    fn test_string_vec_from_slice_string() {
        let original = vec!["a".to_string(), "b".to_string()];
        let sv = StringVec::from(&original[..]);
        assert_eq!(sv.vec, original);
    }

    #[test]
    fn test_string_vec_from_vec_str() {
        let sv = StringVec::from(vec!["hello", "world"]);
        assert_eq!(sv.vec, vec!["hello", "world"]);
    }

    #[test]
    fn test_string_vec_deref() {
        let sv = StringVec::from(["alpha", "beta"]);
        let inner: &Vec<String> = &sv;
        assert_eq!(inner.len(), 2);
        assert_eq!(inner[0], "alpha");
    }

    #[test]
    fn test_string_vec_into_vec() {
        let sv = StringVec::from(["foo", "bar"]);
        let v: Vec<String> = sv.into();
        assert_eq!(v, vec!["foo", "bar"]);
    }

    #[test]
    fn test_string_vec_empty_from_empty_array() {
        let sv = StringVec::from([] as [&str; 0]);
        assert!(sv.vec.is_empty());
    }
}