arma_rs/value/
into_arma.rs

1use super::Value;
2
3/// Convert a type to a value that can be sent into Arma
4pub trait IntoArma {
5    /// Convert a type to a value that can be sent into Arma
6    fn to_arma(&self) -> Value;
7}
8
9pub struct DirectReturn(Value);
10impl Value {
11    /// A workaround to return a value directly to Arma
12    pub const fn direct(value: Value) -> DirectReturn {
13        DirectReturn(value)
14    }
15}
16
17impl IntoArma for DirectReturn {
18    fn to_arma(&self) -> Value {
19        self.0.clone()
20    }
21}
22
23impl IntoArma for () {
24    fn to_arma(&self) -> Value {
25        Value::Null
26    }
27}
28
29macro_rules! impl_into_arma_tuple {
30    { $c: expr, $($t:ident)* } => {
31        seq_macro::seq!(N in 0..$c {
32            impl<$($t),*> IntoArma for ($($t),*)
33            where
34                $($t: IntoArma),*
35            {
36                fn to_arma(&self) -> Value {
37                    Value::Array(vec![
38                        #(
39                            self.N.to_arma(),
40                        )*
41                    ])
42                }
43            }
44        });
45    };
46}
47
48impl_into_arma_tuple! { 2, A B }
49impl_into_arma_tuple! { 3, A B C }
50impl_into_arma_tuple! { 4, A B C D }
51impl_into_arma_tuple! { 5, A B C D E }
52impl_into_arma_tuple! { 6, A B C D E F }
53impl_into_arma_tuple! { 7, A B C D E F G }
54impl_into_arma_tuple! { 8, A B C D E F G H }
55impl_into_arma_tuple! { 9, A B C D E F G H I }
56impl_into_arma_tuple! { 10, A B C D E F G H I J }
57impl_into_arma_tuple! { 11, A B C D E F G H I J K }
58impl_into_arma_tuple! { 12, A B C D E F G H I J K L }
59impl_into_arma_tuple! { 13, A B C D E F G H I J K L M }
60impl_into_arma_tuple! { 14, A B C D E F G H I J K L M N }
61impl_into_arma_tuple! { 15, A B C D E F G H I J K L M N O }
62impl_into_arma_tuple! { 16, A B C D E F G H I J K L M N O P }
63impl_into_arma_tuple! { 17, A B C D E F G H I J K L M N O P Q }
64impl_into_arma_tuple! { 18, A B C D E F G H I J K L M N O P Q R }
65impl_into_arma_tuple! { 19, A B C D E F G H I J K L M N O P Q R S }
66impl_into_arma_tuple! { 20, A B C D E F G H I J K L M N O P Q R S T }
67impl_into_arma_tuple! { 21, A B C D E F G H I J K L M N O P Q R S T U }
68impl_into_arma_tuple! { 22, A B C D E F G H I J K L M N O P Q R S T U V }
69impl_into_arma_tuple! { 23, A B C D E F G H I J K L M N O P Q R S T U V W }
70impl_into_arma_tuple! { 24, A B C D E F G H I J K L M N O P Q R S T U V W X }
71impl_into_arma_tuple! { 25, A B C D E F G H I J K L M N O P Q R S T U V W X Y }
72impl_into_arma_tuple! { 26, A B C D E F G H I J K L M N O P Q R S T U V W X Y Z }
73
74#[cfg(test)]
75#[test]
76fn test_tuples() {
77    let a = (1, "two");
78    assert_eq!(
79        Value::Array(vec![Value::Number(1.0), Value::String("two".to_string())]),
80        a.to_arma()
81    );
82}
83
84impl IntoArma for Vec<Value> {
85    fn to_arma(&self) -> Value {
86        Value::Array(self.clone())
87    }
88}
89
90impl<T> IntoArma for Vec<T>
91where
92    T: IntoArma,
93{
94    fn to_arma(&self) -> Value {
95        Value::Array(self.iter().map(IntoArma::to_arma).collect())
96    }
97}
98
99#[cfg(test)]
100#[test]
101fn test_vec() {
102    assert_eq!(String::from("[1,2,3]"), vec![1, 2, 3].to_arma().to_string());
103    assert_eq!(
104        String::from(r#"["hello","world"]"#),
105        vec!["hello", "world"].to_arma().to_string()
106    );
107}
108
109impl<T> IntoArma for &[T]
110where
111    T: IntoArma,
112{
113    fn to_arma(&self) -> Value {
114        Value::Array(self.iter().map(IntoArma::to_arma).collect())
115    }
116}
117
118#[cfg(test)]
119#[test]
120fn test_slice() {
121    assert_eq!(
122        String::from("[1,2,3]"),
123        vec![1, 2, 3].as_slice().to_arma().to_string()
124    );
125}
126
127impl IntoArma for String {
128    fn to_arma(&self) -> Value {
129        Value::String(self.clone())
130    }
131}
132
133#[cfg(test)]
134#[test]
135fn test_string() {
136    assert_eq!(
137        String::from("\"hello\""),
138        String::from("hello").to_arma().to_string()
139    );
140    assert_eq!(
141        String::from(r#""hello ""john"".""#),
142        String::from(r#"hello "john"."#).to_arma().to_string()
143    );
144}
145
146impl IntoArma for &'static str {
147    fn to_arma(&self) -> Value {
148        Value::String((*self).to_string())
149    }
150}
151
152#[cfg(test)]
153#[test]
154fn test_static_str() {
155    assert_eq!(String::from("\"hello\""), "hello".to_arma().to_string());
156}
157
158impl IntoArma for bool {
159    fn to_arma(&self) -> Value {
160        Value::Boolean(*self)
161    }
162}
163
164#[cfg(test)]
165#[test]
166fn test_bool() {
167    assert_eq!(String::from("true"), true.to_arma().to_string());
168}
169
170impl IntoArma for i8 {
171    fn to_arma(&self) -> Value {
172        Value::Number(f64::from(self.to_owned()))
173    }
174}
175
176#[cfg(test)]
177#[test]
178fn test_i8() {
179    assert_eq!(String::from("1"), 1i8.to_arma().to_string());
180}
181
182impl IntoArma for i16 {
183    fn to_arma(&self) -> Value {
184        Value::Number(f64::from(self.to_owned()))
185    }
186}
187
188#[cfg(test)]
189#[test]
190fn test_i16() {
191    assert_eq!(String::from("1"), 1i16.to_arma().to_string());
192}
193
194impl IntoArma for i32 {
195    fn to_arma(&self) -> Value {
196        Value::Number(f64::from(*self))
197    }
198}
199
200#[cfg(test)]
201#[test]
202fn test_i32() {
203    assert_eq!(String::from("1"), 1i32.to_arma().to_string());
204}
205
206impl IntoArma for f32 {
207    fn to_arma(&self) -> Value {
208        Value::Number(f64::from(*self))
209    }
210}
211
212#[cfg(test)]
213#[test]
214fn test_f32() {
215    assert_eq!(String::from("1"), 1f32.to_arma().to_string());
216    assert_eq!(String::from("1.5"), 1.5f32.to_arma().to_string());
217}
218
219impl IntoArma for f64 {
220    fn to_arma(&self) -> Value {
221        Value::Number(*self)
222    }
223}
224
225#[cfg(test)]
226#[test]
227fn test_f64() {
228    assert_eq!(String::from("1"), 1f64.to_arma().to_string());
229    assert_eq!(String::from("1.5"), 1.5f64.to_arma().to_string());
230}
231
232impl IntoArma for u8 {
233    fn to_arma(&self) -> Value {
234        Value::Number(f64::from(self.to_owned()))
235    }
236}
237
238#[cfg(test)]
239#[test]
240fn test_u8() {
241    assert_eq!(String::from("1"), 1u8.to_arma().to_string());
242}
243
244impl IntoArma for u16 {
245    fn to_arma(&self) -> Value {
246        Value::Number(f64::from(self.to_owned()))
247    }
248}
249
250#[cfg(test)]
251#[test]
252fn test_u16() {
253    assert_eq!(String::from("1"), 1u16.to_arma().to_string());
254}
255
256impl IntoArma for u32 {
257    fn to_arma(&self) -> Value {
258        Value::Number(f64::from(*self))
259    }
260}
261
262#[cfg(test)]
263#[test]
264fn test_u32() {
265    assert_eq!(String::from("1"), 1u32.to_arma().to_string());
266}
267
268impl<T: IntoArma> IntoArma for Option<T> {
269    fn to_arma(&self) -> Value {
270        self.as_ref().map_or(Value::Null, IntoArma::to_arma)
271    }
272}
273
274#[cfg(test)]
275#[test]
276fn test_option() {
277    assert_eq!(String::from("null"), None::<i32>.to_arma().to_string());
278    assert_eq!(String::from("1"), Some(1).to_arma().to_string());
279}
280
281impl<K, V, S> IntoArma for std::collections::HashMap<K, V, S>
282where
283    K: IntoArma,
284    V: IntoArma,
285    S: std::hash::BuildHasher,
286{
287    fn to_arma(&self) -> Value {
288        self.iter()
289            .map(|(k, v)| vec![k.to_arma(), v.to_arma()])
290            .collect::<Vec<Vec<Value>>>()
291            .to_arma()
292    }
293}
294
295impl<K, S> IntoArma for std::collections::HashMap<K, Value, S>
296where
297    K: IntoArma,
298    S: std::hash::BuildHasher,
299{
300    fn to_arma(&self) -> Value {
301        self.iter()
302            .map(|(k, v)| vec![k.to_arma(), v.clone()])
303            .collect::<Vec<Vec<Value>>>()
304            .to_arma()
305    }
306}
307
308#[cfg(test)]
309#[test]
310fn test_hashmap() {
311    use std::collections::HashMap;
312    {
313        let mut map = HashMap::new();
314        map.insert("key".to_string(), "value".to_string());
315        let map = map.to_arma();
316        assert_eq!(map.to_string(), r#"[["key","value"]]"#.to_string());
317    }
318    {
319        let mut map = HashMap::new();
320        map.insert("key1".to_string(), "value1".to_string());
321        map.insert("key2".to_string(), "value2".to_string());
322        let map = map.to_arma().to_string();
323        assert!(
324            map == r#"[["key1","value1"],["key2","value2"]]"#
325                || map == r#"[["key2","value2"],["key1","value1"]]"#
326        );
327    }
328}
329
330impl Value {
331    #[must_use]
332    /// Returns an Option representing if the value is null
333    pub const fn as_null(&self) -> Option<()> {
334        match self {
335            Self::Null => Some(()),
336            _ => None,
337        }
338    }
339
340    #[must_use]
341    /// Checks if the value is a null variant
342    pub const fn is_null(&self) -> bool {
343        self.as_null().is_some()
344    }
345
346    #[must_use]
347    /// Returns an Option representing if the value is a number
348    pub const fn as_f64(&self) -> Option<f64> {
349        match *self {
350            Self::Number(n) => Some(n),
351            _ => None,
352        }
353    }
354
355    #[must_use]
356    /// Checks if the value is a number
357    pub const fn is_number(&self) -> bool {
358        self.as_f64().is_some()
359    }
360
361    #[must_use]
362    /// Returns an Option representing if the value is an array
363    pub const fn as_vec(&self) -> Option<&Vec<Self>> {
364        match *self {
365            Self::Array(ref vec) => Some(vec),
366            _ => None,
367        }
368    }
369
370    #[must_use]
371    /// Checks if the value is an array
372    pub const fn is_array(&self) -> bool {
373        self.as_vec().is_some()
374    }
375
376    #[must_use]
377    /// Returns an Option representing if the value is a boolean
378    pub const fn as_bool(&self) -> Option<bool> {
379        match *self {
380            Self::Boolean(bool) => Some(bool),
381            _ => None,
382        }
383    }
384
385    #[must_use]
386    /// Checks if the value is a boolean
387    pub const fn is_boolean(&self) -> bool {
388        self.as_bool().is_some()
389    }
390
391    #[must_use]
392    /// Returns an Option representing if the value is a string
393    pub fn as_str(&self) -> Option<&str> {
394        match *self {
395            Self::String(ref string) => Some(string),
396            _ => None,
397        }
398    }
399
400    #[must_use]
401    /// Checks if the value is a string
402    pub fn is_string(&self) -> bool {
403        self.as_str().is_some()
404    }
405
406    #[must_use]
407    /// Checks if the value is empty
408    pub fn is_empty(&self) -> bool {
409        match self {
410            Self::Null => true,
411            Self::Number(n) => *n == 0.0,
412            Self::Array(a) => a.is_empty(),
413            Self::Boolean(b) => !*b,
414            Self::String(s) => s.is_empty(),
415            Self::Unknown(_) => false,
416        }
417    }
418}
419
420#[cfg(test)]
421mod tests {
422    use super::*;
423
424    #[test]
425    fn is_null() {
426        assert!(Value::Null.is_null());
427        assert!(!Value::Boolean(false).is_null());
428    }
429
430    #[test]
431    fn is_number() {
432        assert!(Value::Number(54.0).is_number());
433        assert!(!Value::Boolean(false).is_number());
434    }
435
436    #[test]
437    fn is_array() {
438        assert!(Value::Array(Vec::new()).is_array());
439        assert!(!Value::Boolean(false).is_array());
440    }
441
442    #[test]
443    fn is_boolean() {
444        assert!(Value::Boolean(false).is_boolean());
445        assert!(!Value::Number(54.0).is_boolean());
446    }
447
448    #[test]
449    fn is_string() {
450        assert!(Value::String(String::new()).is_string());
451        assert!(!Value::Boolean(false).is_string());
452    }
453
454    #[test]
455    fn as_nil() {
456        assert!(Value::Null.as_null().is_some());
457    }
458
459    #[test]
460    fn as_f32() {
461        let v = Value::Number(54.0).as_f64().unwrap();
462        assert!((54.0 - v) == 0.0);
463    }
464
465    #[test]
466    fn as_vec() {
467        let array = Value::Array(vec![Value::String("hello".into())]);
468        assert_eq!(array.to_string(), r#"["hello"]"#.to_string());
469    }
470
471    #[test]
472    fn as_bool() {
473        assert!(Value::Boolean(true).as_bool().unwrap());
474    }
475
476    #[test]
477    fn as_str() {
478        let v = Value::String("hello world".into());
479        let s = v.as_str().unwrap();
480        assert_eq!(s, "hello world");
481    }
482
483    #[test]
484    fn is_empty() {
485        assert!(Value::String(String::new()).is_empty());
486        assert!(Value::Array(vec![]).is_empty());
487        assert!(Value::Boolean(false).is_empty());
488        assert!(Value::String(String::new()).is_empty());
489        assert!(Value::Number(0.0).is_empty());
490        assert!(Value::Null.is_empty());
491
492        assert!(!Value::String("test".into()).is_empty());
493        assert!(!Value::Array(vec![Value::Boolean(false)]).is_empty());
494        assert!(!Value::Boolean(true).is_empty());
495        assert!(!Value::Number(55.0).is_empty());
496    }
497
498    #[test]
499    fn to_array() {
500        let array = Value::Array(vec![]);
501        assert_eq!(array.to_string(), r"[]".to_string());
502    }
503}