util.rs

  1use rand::prelude::*;
  2use std::cmp::Ordering;
  3
  4#[derive(Copy, Clone, Eq, PartialEq, Debug, Hash)]
  5pub enum Bias {
  6    Left,
  7    Right,
  8}
  9
 10impl PartialOrd for Bias {
 11    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
 12        Some(self.cmp(other))
 13    }
 14}
 15
 16impl Ord for Bias {
 17    fn cmp(&self, other: &Self) -> Ordering {
 18        match (self, other) {
 19            (Self::Left, Self::Left) => Ordering::Equal,
 20            (Self::Left, Self::Right) => Ordering::Less,
 21            (Self::Right, Self::Right) => Ordering::Equal,
 22            (Self::Right, Self::Left) => Ordering::Greater,
 23        }
 24    }
 25}
 26
 27pub fn post_inc(value: &mut usize) -> usize {
 28    let prev = *value;
 29    *value += 1;
 30    prev
 31}
 32
 33/// Extend a sorted vector with a sorted sequence of items, maintaining the vector's sort order and
 34/// enforcing a maximum length. Sort the items according to the given callback. Before calling this,
 35/// both `vec` and `new_items` should already be sorted according to the `cmp` comparator.
 36pub fn extend_sorted<T, I, F>(vec: &mut Vec<T>, new_items: I, limit: usize, mut cmp: F)
 37where
 38    I: IntoIterator<Item = T>,
 39    F: FnMut(&T, &T) -> Ordering,
 40{
 41    let mut start_index = 0;
 42    for new_item in new_items {
 43        if let Err(i) = vec[start_index..].binary_search_by(|m| cmp(m, &new_item)) {
 44            let index = start_index + i;
 45            if vec.len() < limit {
 46                vec.insert(index, new_item);
 47            } else if index < vec.len() {
 48                vec.pop();
 49                vec.insert(index, new_item);
 50            }
 51            start_index = index;
 52        }
 53    }
 54}
 55
 56pub struct RandomCharIter<T: Rng>(T);
 57
 58impl<T: Rng> RandomCharIter<T> {
 59    #[cfg(test)]
 60    pub fn new(rng: T) -> Self {
 61        Self(rng)
 62    }
 63}
 64
 65impl<T: Rng> Iterator for RandomCharIter<T> {
 66    type Item = char;
 67
 68    fn next(&mut self) -> Option<Self::Item> {
 69        if self.0.gen_bool(1.0 / 5.0) {
 70            Some('\n')
 71        }
 72        // two-byte greek letters
 73        else if self.0.gen_bool(1.0 / 8.0) {
 74            Some(std::char::from_u32(self.0.gen_range(('α' as u32)..('ω' as u32 + 1))).unwrap())
 75        }
 76        // three-byte characters
 77        else if self.0.gen_bool(1.0 / 10.0) {
 78            ['✋', '✅', '❌', '❎', '⭐'].choose(&mut self.0).cloned()
 79        }
 80        // four-byte characters
 81        else if self.0.gen_bool(1.0 / 12.0) {
 82            ['🍐', '🏀', '🍗', '🎉'].choose(&mut self.0).cloned()
 83        }
 84        // ascii letters
 85        else {
 86            Some(self.0.gen_range(b'a'..b'z' + 1).into())
 87        }
 88    }
 89}
 90
 91#[cfg(test)]
 92mod tests {
 93    use super::*;
 94
 95    #[test]
 96    fn test_extend_sorted() {
 97        let mut vec = vec![];
 98
 99        extend_sorted(&mut vec, vec![21, 17, 13, 8, 1, 0], 5, |a, b| b.cmp(a));
100        assert_eq!(vec, &[21, 17, 13, 8, 1]);
101
102        extend_sorted(&mut vec, vec![101, 19, 17, 8, 2], 8, |a, b| b.cmp(a));
103        assert_eq!(vec, &[101, 21, 19, 17, 13, 8, 2, 1]);
104
105        extend_sorted(&mut vec, vec![1000, 19, 17, 9, 5], 8, |a, b| b.cmp(a));
106        assert_eq!(vec, &[1000, 101, 21, 19, 17, 13, 9, 8]);
107    }
108}
109
110// Allow surf Results to accept context like other Results do when
111// using anyhow.
112pub trait SurfResultExt {
113    fn context<C>(self, cx: C) -> Self
114    where
115        C: std::fmt::Display + Send + Sync + 'static;
116
117    fn with_context<C, F>(self, f: F) -> Self
118    where
119        C: std::fmt::Display + Send + Sync + 'static,
120        F: FnOnce() -> C;
121}
122
123impl<T> SurfResultExt for surf::Result<T> {
124    fn context<C>(self, cx: C) -> Self
125    where
126        C: std::fmt::Display + Send + Sync + 'static,
127    {
128        self.map_err(|e| surf::Error::new(e.status(), e.into_inner().context(cx)))
129    }
130
131    fn with_context<C, F>(self, f: F) -> Self
132    where
133        C: std::fmt::Display + Send + Sync + 'static,
134        F: FnOnce() -> C,
135    {
136        self.map_err(|e| surf::Error::new(e.status(), e.into_inner().context(f())))
137    }
138}