ic/
util.rs

1//! General utilities, not related, but used by this app.
2
3pub use cmp::by_dist_sq::ComparedByDistSq;
4pub mod cmp;
5
6pub use ascii_char::AsciiChar7Bit;
7pub mod ascii_char {
8    use derive_more::Into;
9    use std::{fmt::Display, str::FromStr};
10
11    /// Special char with values restricted to 7-bit ascii table.
12    ///
13    /// Can be parses from string as its only character.
14    /// Is NOT parsed from numeric representation like [`u8`] would be.
15    #[derive(Clone, Copy, Debug, Eq, PartialEq, PartialOrd, Ord, Hash, Into)]
16    pub struct AsciiChar7Bit(
17        // Invariant: Encodes a valid 1-byte UTF-8 string on its own.
18        u8,
19    );
20
21    impl AsciiChar7Bit {
22        pub const COMMA: Self = Self(b',');
23    }
24
25    /// Displays self's symbol, not ascii code.
26    impl Display for AsciiChar7Bit {
27        fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
28            f.write_str(
29                std::str::from_utf8(&[self.0])
30                    .expect("self.0 should encode a valid 1-byte UTF-8 string on its own."),
31            )
32        }
33    }
34    /// Parses `Self` from symbol, not intiger (ascii code).
35    impl FromStr for AsciiChar7Bit {
36        type Err = anyhow::Error;
37
38        fn from_str(s: &str) -> Result<Self, Self::Err> {
39            match s.as_bytes() {
40                &[byte] => Ok(Self(byte)),
41                _ => Err(anyhow::anyhow!(
42                    "Wrong number of bytes. Expected 1. Got {}",
43                    s.len()
44                )),
45            }
46        }
47    }
48}
49
50use crate::IrisSpecies;
51use std::collections::HashMap;
52
53/// Returns the most common element in the iterator.
54pub fn mode(classifications: impl Iterator<Item = IrisSpecies>) -> anyhow::Result<IrisSpecies> {
55    let mut counts = HashMap::new();
56    for classification in classifications {
57        *counts.entry(classification).or_insert(0) += 1;
58    }
59    let mode = counts
60        .into_iter()
61        .max_by_key(|&(_, count)| count)
62        .map(|(val, _)| val)
63        .unwrap();
64    Ok(mode)
65}