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 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.to_string())
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        match self {
271            Some(v) => v.to_arma(),
272            None => Value::Null,
273        }
274    }
275}
276
277#[cfg(test)]
278#[test]
279fn test_option() {
280    assert_eq!(String::from("null"), None::<i32>.to_arma().to_string());
281    assert_eq!(String::from("1"), Some(1).to_arma().to_string());
282}
283
284impl<K, V, S> IntoArma for std::collections::HashMap<K, V, S>
285where
286    K: IntoArma,
287    V: IntoArma,
288    S: std::hash::BuildHasher,
289{
290    fn to_arma(&self) -> Value {
291        self.iter()
292            .map(|(k, v)| vec![k.to_arma(), v.to_arma()])
293            .collect::<Vec<Vec<Value>>>()
294            .to_arma()
295    }
296}
297
298impl<K, S> IntoArma for std::collections::HashMap<K, Value, S>
299where
300    K: IntoArma,
301    S: std::hash::BuildHasher,
302{
303    fn to_arma(&self) -> Value {
304        self.iter()
305            .map(|(k, v)| vec![k.to_arma(), v.clone()])
306            .collect::<Vec<Vec<Value>>>()
307            .to_arma()
308    }
309}
310
311#[cfg(test)]
312#[test]
313fn test_hashmap() {
314    use std::collections::HashMap;
315    {
316        let mut map = HashMap::new();
317        map.insert("key".to_string(), "value".to_string());
318        let map = map.to_arma();
319        assert_eq!(map.to_string(), r#"[["key","value"]]"#.to_string());
320    }
321    {
322        let mut map = HashMap::new();
323        map.insert("key1".to_string(), "value1".to_string());
324        map.insert("key2".to_string(), "value2".to_string());
325        let map = map.to_arma().to_string();
326        assert!(
327            map == r#"[["key1","value1"],["key2","value2"]]"#
328                || map == r#"[["key2","value2"],["key1","value1"]]"#
329        )
330    }
331}
332
333impl Value {
334    #[must_use]
335    /// Returns an Option representing if the value is null
336    pub const fn as_null(&self) -> Option<()> {
337        match self {
338            Self::Null => Some(()),
339            _ => None,
340        }
341    }
342
343    #[must_use]
344    /// Checks if the value is a null variant
345    pub const fn is_null(&self) -> bool {
346        self.as_null().is_some()
347    }
348
349    #[must_use]
350    /// Returns an Option representing if the value is a number
351    pub const fn as_f64(&self) -> Option<f64> {
352        match *self {
353            Self::Number(n) => Some(n),
354            _ => None,
355        }
356    }
357
358    #[must_use]
359    /// Checks if the value is a number
360    pub const fn is_number(&self) -> bool {
361        self.as_f64().is_some()
362    }
363
364    #[must_use]
365    /// Returns an Option representing if the value is an array
366    pub const fn as_vec(&self) -> Option<&Vec<Self>> {
367        match *self {
368            Self::Array(ref vec) => Some(vec),
369            _ => None,
370        }
371    }
372
373    #[must_use]
374    /// Checks if the value is an array
375    pub const fn is_array(&self) -> bool {
376        self.as_vec().is_some()
377    }
378
379    #[must_use]
380    /// Returns an Option representing if the value is a boolean
381    pub const fn as_bool(&self) -> Option<bool> {
382        match *self {
383            Self::Boolean(bool) => Some(bool),
384            _ => None,
385        }
386    }
387
388    #[must_use]
389    /// Checks if the value is a boolean
390    pub const fn is_boolean(&self) -> bool {
391        self.as_bool().is_some()
392    }
393
394    #[must_use]
395    /// Returns an Option representing if the value is a string
396    pub fn as_str(&self) -> Option<&str> {
397        match *self {
398            Self::String(ref string) => Some(string),
399            _ => None,
400        }
401    }
402
403    #[must_use]
404    /// Checks if the value is a string
405    pub fn is_string(&self) -> bool {
406        self.as_str().is_some()
407    }
408
409    #[must_use]
410    /// Checks if the value is empty
411    pub fn is_empty(&self) -> bool {
412        match self {
413            Self::Null => true,
414            Self::Number(n) => *n == 0.0,
415            Self::Array(a) => a.is_empty(),
416            Self::Boolean(b) => !*b,
417            Self::String(s) => s.is_empty(),
418            _ => false,
419        }
420    }
421}
422
423#[cfg(test)]
424mod tests {
425    use super::*;
426
427    #[test]
428    fn is_null() {
429        assert!(Value::Null.is_null());
430        assert!(!Value::Boolean(false).is_null());
431    }
432
433    #[test]
434    fn is_number() {
435        assert!(Value::Number(54.0).is_number());
436        assert!(!Value::Boolean(false).is_number());
437    }
438
439    #[test]
440    fn is_array() {
441        assert!(Value::Array(Vec::new()).is_array());
442        assert!(!Value::Boolean(false).is_array());
443    }
444
445    #[test]
446    fn is_boolean() {
447        assert!(Value::Boolean(false).is_boolean());
448        assert!(!Value::Number(54.0).is_boolean());
449    }
450
451    #[test]
452    fn is_string() {
453        assert!(Value::String(String::new()).is_string());
454        assert!(!Value::Boolean(false).is_string());
455    }
456
457    #[test]
458    fn as_nil() {
459        assert!(Value::Null.as_null().is_some())
460    }
461
462    #[test]
463    fn as_f32() {
464        let v = Value::Number(54.0).as_f64().unwrap();
465        assert!((54.0 - v) == 0.0)
466    }
467
468    #[test]
469    fn as_vec() {
470        let array = Value::Array(vec![Value::String("hello".into())]);
471        assert_eq!(array.to_string(), r#"["hello"]"#.to_string());
472    }
473
474    #[test]
475    fn as_bool() {
476        assert!(Value::Boolean(true).as_bool().unwrap());
477    }
478
479    #[test]
480    fn as_str() {
481        let v = Value::String("hello world".into());
482        let s = v.as_str().unwrap();
483        assert_eq!(s, "hello world");
484    }
485
486    #[test]
487    fn is_empty() {
488        assert!(Value::String("".into()).is_empty());
489        assert!(Value::Array(vec![]).is_empty());
490        assert!(Value::Boolean(false).is_empty());
491        assert!(Value::String(String::new()).is_empty());
492        assert!(Value::Number(0.0).is_empty());
493        assert!(Value::Null.is_empty());
494
495        assert!(!Value::String("test".into()).is_empty());
496        assert!(!Value::Array(vec![Value::Boolean(false)]).is_empty());
497        assert!(!Value::Boolean(true).is_empty());
498        assert!(!Value::Number(55.0).is_empty());
499    }
500
501    #[test]
502    fn to_array() {
503        let array = Value::Array(vec![]);
504        assert_eq!(array.to_string(), r#"[]"#.to_string());
505    }
506}