over/
macros.rs

1//! Module containing crate macros.
2
3/// Given an int, creates and returns a `BigInt`.
4#[macro_export]
5macro_rules! int {
6    ($int:expr) => {{
7        use num_bigint::BigInt;
8
9        let _b: BigInt = $int.into();
10        _b
11    }};
12}
13
14/// Given two ints, creates and returns a `BigRational`.
15#[macro_export]
16macro_rules! frac {
17    ($int1:expr, $int2:expr) => {{
18        ::num_rational::BigRational::new($int1.into(), $int2.into())
19    }};
20}
21
22/// Given a list of elements, converts each element to a `Value` and returns an `Arr` containing a
23/// vector of the values. For a non-panicking version, see `try_arr!`.
24///
25/// # Panics
26/// Panics if the types don't check out.
27#[macro_export]
28macro_rules! arr {
29    [] => {
30        $crate::arr::Arr::from_vec(vec![]).unwrap()
31    };
32    [ $( $elem:expr ),+ , ] => {
33        // Rule with trailing comma.
34        try_arr![ $( $elem ),+ ].unwrap()
35    };
36    [ $( $elem:expr ),+ ] => {
37        try_arr![ $( $elem ),+ ].unwrap()
38    };
39}
40
41/// Given a list of elements, converts each element to a `Value` and returns an `Arr` containing a
42/// vector of the values. Returns an `OverResult` instead of panicking on error. To create an empty
43/// `Arr`, use `arr!` as it will never fail.
44#[macro_export]
45macro_rules! try_arr {
46    [ $( $elem:expr ),+ , ] => {
47        // Rule with trailing comma.
48        try_arr![ $( $elem ),+ ]
49    };
50    [ $( $elem:expr ),+ ] => {
51        {
52            $crate::arr::Arr::from_vec(vec![ $( $elem.into() ),+ ])
53        }
54    };
55}
56
57/// Given a list of elements, converts each element to `Value`s and returns a `Tup` containing a
58/// vector of the values.
59#[macro_export]
60macro_rules! tup {
61    ( $( $elem:expr ),* , ) => {
62        tup!( $( $elem ),* )
63    };
64    ( $( $elem:expr ),* ) => {
65        {
66            $crate::tup::Tup::from_vec(vec![ $( $elem.into() ),+ ])
67        }
68    };
69}
70
71/// Given a list of field/value pairs, returns an `Obj` containing each pair.
72/// For a non-panicking version, see `try_obj!`.
73///
74/// # Panics
75/// Panics if a field name is invalid.
76#[macro_export]
77macro_rules! obj {
78    {} => {
79        $crate::obj::Obj::from_map_unchecked(::std::collections::HashMap::new())
80    };
81    { $( $field:expr => $inner:expr ),+ , } => {
82        // Rule with trailing comma.
83        try_obj!{ $( $field => $inner ),+ }.unwrap()
84    };
85    { $( $field:expr => $inner:expr ),+ } => {
86        try_obj!{ $( $field => $inner ),+ }.unwrap()
87    };
88}
89
90/// Given a list of field to `Value` pairs, returns an `Obj` with the fields and values.
91/// Returns an `OverResult` instead of panicking on error. To create an empty `Obj`, use `obj!` as
92/// it will never fail.
93#[macro_export]
94macro_rules! try_obj {
95    { $( $field:expr => $inner:expr ),+ , } => {
96        // Rule with trailing comma.
97        try_obj!{ $( $field => $inner ),* };
98    };
99    { $( $field:expr => $inner:expr ),+ } => {
100        #[allow(clippy::useless_let_if_seq)]
101        {
102            use $crate::obj::Obj;
103
104            let mut _map = ::std::collections::HashMap::new();
105            let mut _parent: Option<$crate::value::Value> = None;
106
107            $(
108                if $field == "^" {
109                    _parent = Some($inner.into());
110                } else {
111                    _map.insert($field.into(), $inner.into());
112                }
113            )*
114
115            match _parent {
116                Some(parent) => match parent.get_obj() {
117                    Ok(parent) => Obj::from_map_with_parent(_map, parent),
118                    e @ Err(_) => e,
119                }
120                None => Obj::from_map(_map),
121            }
122        }
123    };
124}
125
126#[cfg(test)]
127mod tests {
128    use crate::obj::Obj;
129    use crate::types::Type::*;
130    use crate::value::Value;
131    use crate::OverError;
132
133    #[test]
134    fn arr_basic() {
135        assert_eq!(
136            arr![Value::Int(1.into()), Value::Int(2.into())],
137            try_arr![1, 2].unwrap()
138        );
139
140        assert_ne!(
141            arr![-1, 2],
142            try_arr![Value::Int(1.into()), Value::Int(2.into())].unwrap()
143        );
144    }
145
146    #[test]
147    fn try_arr_mismatch() {
148        assert_eq!(
149            try_arr![arr![1, 1], arr!['c']],
150            Err(OverError::ArrTypeMismatch(
151                Arr(Box::new(Int)),
152                Arr(Box::new(Char)),
153            ))
154        );
155        assert_eq!(try_arr![1, 'c'], Err(OverError::ArrTypeMismatch(Int, Char)));
156    }
157
158    #[test]
159    fn obj_basic() {
160        let obj = Obj::from_map_unchecked(map! {"a".into() => 1.into(),
161        "b".into() => arr![1, 2].into()});
162
163        assert_eq!(
164            obj,
165            obj! {
166                "a" => 1,
167                "b" => arr![1, 2]
168            }
169        );
170    }
171}