1#![allow(clippy::default_trait_access)]
2#![allow(clippy::cast_precision_loss)]
3#![allow(clippy::cast_possible_truncation)]
4#![allow(clippy::module_name_repetitions)]
5#![allow(clippy::missing_panics_doc)]
6#![allow(clippy::use_self)]
7
8use num_traits::ToPrimitive;
9use std::cmp::Ordering;
10use std::hash;
11
12use serde::{Deserialize, Serialize};
13
14pub use frequency::{Frequencies, UniqueValues};
15pub use minmax::MinMax;
16pub use online::{OnlineStats, mean, stddev, variance};
17pub use unsorted::{
18 Unsorted, antimodes, atkinson, gini, kurtosis, mad, median, mode, modes, percentile_rank,
19 quartiles,
20};
21
22#[allow(clippy::non_send_fields_in_send_ty)]
27#[allow(clippy::derive_ord_xor_partial_ord)]
28#[derive(Clone, PartialEq, PartialOrd, Serialize, Deserialize)]
29struct Partial<T>(pub T);
30
31impl<T: PartialEq> Eq for Partial<T> {}
32unsafe impl<T> Send for Partial<T> {}
33unsafe impl<T> Sync for Partial<T> {}
34
35#[allow(clippy::derive_ord_xor_partial_ord)]
36impl<T: PartialOrd> Ord for Partial<T> {
37 #[inline]
38 fn cmp(&self, other: &Partial<T>) -> Ordering {
39 self.partial_cmp(other).unwrap_or(Ordering::Less)
40 }
41}
42
43impl<T: ToPrimitive> ToPrimitive for Partial<T> {
44 #[inline]
45 fn to_isize(&self) -> Option<isize> {
46 self.0.to_isize()
47 }
48 #[inline]
49 fn to_i8(&self) -> Option<i8> {
50 self.0.to_i8()
51 }
52 #[inline]
53 fn to_i16(&self) -> Option<i16> {
54 self.0.to_i16()
55 }
56 #[inline]
57 fn to_i32(&self) -> Option<i32> {
58 self.0.to_i32()
59 }
60 #[inline]
61 fn to_i64(&self) -> Option<i64> {
62 self.0.to_i64()
63 }
64
65 #[inline]
66 fn to_usize(&self) -> Option<usize> {
67 self.0.to_usize()
68 }
69 #[inline]
70 fn to_u8(&self) -> Option<u8> {
71 self.0.to_u8()
72 }
73 #[inline]
74 fn to_u16(&self) -> Option<u16> {
75 self.0.to_u16()
76 }
77 #[inline]
78 fn to_u32(&self) -> Option<u32> {
79 self.0.to_u32()
80 }
81 #[inline]
82 fn to_u64(&self) -> Option<u64> {
83 self.0.to_u64()
84 }
85
86 #[inline]
87 fn to_f32(&self) -> Option<f32> {
88 self.0.to_f32()
89 }
90 #[inline]
91 fn to_f64(&self) -> Option<f64> {
92 self.0.to_f64()
93 }
94}
95
96#[allow(clippy::derived_hash_with_manual_eq)]
97impl<T: hash::Hash> hash::Hash for Partial<T> {
98 #[inline]
99 fn hash<H: hash::Hasher>(&self, state: &mut H) {
100 self.0.hash(state);
101 }
102}
103
104pub trait Commute: Sized {
109 fn merge(&mut self, other: Self);
111
112 #[inline]
114 fn consume<I: Iterator<Item = Self>>(&mut self, other: I) {
115 for v in other {
116 self.merge(v);
117 }
118 }
119}
120
121#[inline]
125pub fn merge_all<T: Commute, I: Iterator<Item = T>>(mut it: I) -> Option<T> {
126 it.next().map_or_else(
127 || None,
128 |mut init| {
129 init.consume(it);
130 Some(init)
131 },
132 )
133}
134
135impl<T: Commute> Commute for Option<T> {
136 #[inline]
137 fn merge(&mut self, other: Option<T>) {
138 match *self {
139 None => {
140 *self = other;
141 }
142 Some(ref mut v1) => {
143 if let Some(v2) = other {
144 v1.merge(v2);
145 }
146 }
147 }
148 }
149}
150
151impl<T: Commute, E> Commute for Result<T, E> {
152 #[inline]
153 fn merge(&mut self, other: Result<T, E>) {
154 if !self.is_err() && other.is_err() {
155 *self = other;
156 return;
157 }
158 #[allow(clippy::let_unit_value)]
159 #[allow(clippy::ignored_unit_patterns)]
160 let _ = self.as_mut().map_or((), |v1| {
161 other.map_or_else(
162 |_| {
163 unreachable!();
164 },
165 |v2| {
166 v1.merge(v2);
167 },
168 );
169 });
170 }
171}
172
173impl<T: Commute> Commute for Vec<T> {
174 #[inline]
175 fn merge(&mut self, other: Vec<T>) {
176 assert_eq!(self.len(), other.len());
177 for (v1, v2) in self.iter_mut().zip(other) {
178 v1.merge(v2);
179 }
180 }
181}
182
183mod frequency;
184mod minmax;
185mod online;
186mod unsorted;
187
188#[cfg(test)]
189mod test {
190 use crate::Commute;
191 use crate::unsorted::Unsorted;
192
193 #[test]
194 fn options() {
195 let v1: Unsorted<usize> = vec![2, 1, 3, 2].into_iter().collect();
196 let v2: Unsorted<usize> = vec![5, 6, 5, 5].into_iter().collect();
197 let mut merged = Some(v1);
198 merged.merge(Some(v2));
199 assert_eq!(merged.unwrap().mode(), Some(5));
200 }
201}