arith/
lib.rs

1//! Containers with arithmetic operations support.
2
3use std::collections::HashMap;
4use std::fmt;
5use std::ops::{Add, AddAssign, Sub, SubAssign, Mul, MulAssign};
6
7
8#[derive(Eq, PartialEq, Default)]
9pub struct ArithMap<'a, V> {
10    pub hashmap: HashMap<&'a str, V>,
11}
12
13impl<V> fmt::Debug for ArithMap<'_, V>
14where
15    V: fmt::Debug,
16{
17    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
18        f.debug_map()
19            .entries(self.hashmap.iter().map(|(k, v)| (k, v)))
20            .finish()
21    }
22}
23
24#[macro_export(local_inner_macros)]
25/// ```
26/// # use arith::*;
27/// let map = arithmap!{"a" => 1, "b" => 2};
28/// assert_eq!(map.hashmap["a"], 1);
29/// assert_eq!(map.hashmap["b"], 2);
30/// assert_eq!(map.hashmap.get("c"), None);
31/// ```
32macro_rules! arithmap {
33    (@single $($x:tt)*) => (());
34    (@count $($rest:expr),*) => (<[()]>::len(&[$(arithmap!(@single $rest)),*]));
35    ($($key:expr => $value:expr,)+) => { arithmap!($($key => $value),+) };
36    ($($key:expr => $value:expr),*) => {
37        {
38            let _cap = arithmap!(@count $($key),*);
39            let mut _map = ::std::collections::HashMap::with_capacity(_cap);
40            $(
41                let _ = _map.insert($key, $value);
42            )*
43            ArithMap{hashmap: _map}
44        }
45    };
46}
47
48impl<V> ArithMap<'_, V>
49where
50    V: Copy + Default + PartialEq,
51{
52    /// ```
53    /// # use arith::*;
54    /// let mut x = arithmap!{"a" => 0, "b" => 1};
55    /// let y = arithmap!{"b" => 1};
56    /// x.prune();
57    ///
58    /// assert_eq!(x, y);
59    /// ```
60    pub fn prune(&mut self) {
61        let zero: V = Default::default();
62        self.hashmap.retain(|_, &mut v| v != zero);
63    }
64}
65
66/// ```
67/// # use arith::*;
68/// let x = arithmap!{"a" => 1, "b" => 2};
69/// let y = arithmap!{"a" => 2, "b" => 3};
70///
71/// assert_eq!(x + 1, y);
72/// ```
73impl<V> Add<V> for ArithMap<'_, V>
74where
75    V: AddAssign + Copy,
76{
77    type Output = Self;
78    fn add(mut self: Self, other: V) -> Self {
79        for v in self.hashmap.values_mut() {
80            *v += other;
81        }
82        self
83    }
84}
85
86/// ```
87/// # use arith::*;
88/// let mut x = arithmap!{"a" => 1, "b" => 2};
89/// x += 1;
90/// let y = arithmap!{"a" => 2, "b" => 3};
91///
92/// assert_eq!(x, y);
93/// ```
94impl<V> AddAssign<V> for ArithMap<'_, V>
95where
96    V: AddAssign + Copy,
97{
98    fn add_assign(&mut self, other: V) {
99        for v in self.hashmap.values_mut() {
100            *v += other;
101        }
102    }
103}
104
105/// ```
106/// # use arith::*;
107/// let x = arithmap!{"a" => 1, "b" => 2};
108/// let y = arithmap!{"a" => 0, "b" => 1};
109///
110/// assert_eq!(x - 1, y);
111/// ```
112impl<V> Sub<V> for ArithMap<'_, V>
113where
114    V: SubAssign + Copy,
115{
116    type Output = Self;
117    fn sub(mut self: Self, other: V) -> Self {
118        for v in self.hashmap.values_mut() {
119            *v -= other;
120        }
121        self
122    }
123}
124
125/// ```
126/// # use arith::*;
127/// let mut x = arithmap!{"a" => 1, "b" => 2};
128/// x -= 1;
129/// let y = arithmap!{"a" => 0, "b" => 1};
130///
131/// assert_eq!(x, y);
132/// ```
133impl<V> SubAssign<V> for ArithMap<'_, V>
134where
135    V: SubAssign + Copy,
136{
137    fn sub_assign(&mut self, other: V) {
138        for v in self.hashmap.values_mut() {
139            *v -= other;
140        }
141    }
142}
143
144/// ```
145/// # use arith::*;
146/// let x = arithmap!{"a" => 1.0, "b" => 2.0};
147/// let y = arithmap!{"a" => 2.0, "b" => 4.0};
148///
149/// assert_eq!(x * 2.0, y);
150/// ```
151impl<V> Mul<V> for ArithMap<'_, V>
152where
153    V: MulAssign + Copy,
154{
155    type Output = Self;
156    fn mul(mut self: Self, other: V) -> Self {
157        for v in self.hashmap.values_mut() {
158            *v *= other;
159        }
160        self
161    }
162}
163
164/// ```
165/// # use arith::*;
166/// let mut x = arithmap!{"a" => 1, "b" => 2};
167/// x *= 2;
168/// let y = arithmap!{"a" => 2, "b" => 4};
169///
170/// assert_eq!(x, y);
171/// ```
172impl<V> MulAssign<V> for ArithMap<'_, V>
173where
174    V: MulAssign + Copy,
175{
176    fn mul_assign(&mut self, other: V) {
177        for v in self.hashmap.values_mut() {
178            *v *= other;
179        }
180    }
181}
182
183/// ```
184/// # use arith::*;
185/// let x = arithmap!{"a" => 1, "b" => 2};
186/// let y = arithmap!{"b" => 2, "c" => 3};
187/// let z = arithmap!{"a" => 1, "b" => 4, "c" => 3};
188///
189/// assert_eq!(x + y, z);
190/// ```
191impl<V> Add for ArithMap<'_, V>
192where
193    V: Add<Output = V> + AddAssign + Copy + Default,
194{
195    type Output = Self;
196    fn add(self: Self, other: Self) -> Self {
197        let mut r: Self = Default::default();
198        for (k, v) in self.hashmap.iter() {
199            r.hashmap.insert(*k, *v);
200        }
201        for (k, v2) in other.hashmap.iter() {
202            if let Some(v1) = r.hashmap.get_mut(k) {
203                *v1 += *v2;
204            } else {
205                r.hashmap.insert(*k, *v2);
206            }
207        }
208        r
209    }
210}
211
212/// ```
213/// # use arith::*;
214/// let mut x = arithmap!{"a" => 1, "b" => 2};
215/// let y = arithmap!{"b" => 2, "c" => 3};
216/// x += y;
217/// let z = arithmap!{"a" => 1, "b" => 4, "c" => 3};
218///
219/// assert_eq!(x, z);
220/// ```
221impl<V> AddAssign for ArithMap<'_, V>
222where
223    V: Add<Output = V> + AddAssign + Copy + Default,
224{
225    fn add_assign(&mut self, other: Self) {
226        for (k, v2) in other.hashmap.iter() {
227            if let Some(v1) = self.hashmap.get_mut(k) {
228                *v1 += *v2;
229            } else {
230                self.hashmap.insert(*k, *v2);
231            }
232        }
233    }
234}
235
236/// ```
237/// # use arith::*;
238/// let x = arithmap!{"a" => 1, "b" => 2};
239/// let y = arithmap!{"b" => 2, "c" => 3};
240/// let z = arithmap!{"a" => 1, "b" => 0, "c" => -3};
241///
242/// assert_eq!(x - y, z);
243/// ```
244impl<V> Sub for ArithMap<'_, V>
245where
246    V: Sub<Output = V> + SubAssign + Copy + Default,
247{
248    type Output = Self;
249    fn sub(self: Self, other: Self) -> Self {
250        let zero: V = Default::default();
251        let mut r: Self = Default::default();
252        for (k, v) in self.hashmap.iter() {
253            r.hashmap.insert(*k, *v);
254        }
255        for (k, v2) in other.hashmap.iter() {
256            if let Some(v1) = r.hashmap.get_mut(k) {
257                *v1 -= *v2;
258            } else {
259                r.hashmap.insert(*k, zero - *v2);
260            }
261        }
262        r
263    }
264}
265
266/// ```
267/// # use arith::*;
268/// let mut x = arithmap!{"a" => 1, "b" => 2};
269/// let y = arithmap!{"b" => 2, "c" => 3};
270/// x -= y;
271/// let z = arithmap!{"a" => 1, "b" => 0, "c" => -3};
272///
273/// assert_eq!(x, z);
274/// ```
275impl<V> SubAssign for ArithMap<'_, V>
276where
277    V: Sub<Output = V> + SubAssign + Copy + Default,
278{
279    fn sub_assign(&mut self, other: Self) {
280        let zero: V = Default::default();
281        for (k, v2) in other.hashmap.iter() {
282            if let Some(v1) = self.hashmap.get_mut(k) {
283                *v1 -= *v2;
284            } else {
285                self.hashmap.insert(*k, zero - *v2);
286            }
287        }
288    }
289}