lib.rs

  1#[cfg(feature = "test-support")]
  2pub mod test;
  3
  4use futures::Future;
  5use std::{
  6    cmp::Ordering,
  7    pin::Pin,
  8    task::{Context, Poll},
  9};
 10
 11pub fn post_inc(value: &mut usize) -> usize {
 12    let prev = *value;
 13    *value += 1;
 14    prev
 15}
 16
 17/// Extend a sorted vector with a sorted sequence of items, maintaining the vector's sort order and
 18/// enforcing a maximum length. Sort the items according to the given callback. Before calling this,
 19/// both `vec` and `new_items` should already be sorted according to the `cmp` comparator.
 20pub fn extend_sorted<T, I, F>(vec: &mut Vec<T>, new_items: I, limit: usize, mut cmp: F)
 21where
 22    I: IntoIterator<Item = T>,
 23    F: FnMut(&T, &T) -> Ordering,
 24{
 25    let mut start_index = 0;
 26    for new_item in new_items {
 27        if let Err(i) = vec[start_index..].binary_search_by(|m| cmp(m, &new_item)) {
 28            let index = start_index + i;
 29            if vec.len() < limit {
 30                vec.insert(index, new_item);
 31            } else if index < vec.len() {
 32                vec.pop();
 33                vec.insert(index, new_item);
 34            }
 35            start_index = index;
 36        }
 37    }
 38}
 39pub trait ResultExt {
 40    type Ok;
 41
 42    fn log_err(self) -> Option<Self::Ok>;
 43}
 44
 45impl<T> ResultExt for anyhow::Result<T> {
 46    type Ok = T;
 47
 48    fn log_err(self) -> Option<T> {
 49        match self {
 50            Ok(value) => Some(value),
 51            Err(error) => {
 52                log::error!("{:?}", error);
 53                None
 54            }
 55        }
 56    }
 57}
 58
 59pub trait TryFutureExt {
 60    fn log_err(self) -> LogErrorFuture<Self>
 61    where
 62        Self: Sized;
 63}
 64
 65impl<F, T> TryFutureExt for F
 66where
 67    F: Future<Output = anyhow::Result<T>>,
 68{
 69    fn log_err(self) -> LogErrorFuture<Self>
 70    where
 71        Self: Sized,
 72    {
 73        LogErrorFuture(self)
 74    }
 75}
 76
 77pub struct LogErrorFuture<F>(F);
 78
 79impl<F, T> Future for LogErrorFuture<F>
 80where
 81    F: Future<Output = anyhow::Result<T>>,
 82{
 83    type Output = Option<T>;
 84
 85    fn poll(self: std::pin::Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
 86        let inner = unsafe { Pin::new_unchecked(&mut self.get_unchecked_mut().0) };
 87        match inner.poll(cx) {
 88            Poll::Ready(output) => Poll::Ready(output.log_err()),
 89            Poll::Pending => Poll::Pending,
 90        }
 91    }
 92}
 93
 94#[cfg(test)]
 95mod tests {
 96    use super::*;
 97
 98    #[test]
 99    fn test_extend_sorted() {
100        let mut vec = vec![];
101
102        extend_sorted(&mut vec, vec![21, 17, 13, 8, 1, 0], 5, |a, b| b.cmp(a));
103        assert_eq!(vec, &[21, 17, 13, 8, 1]);
104
105        extend_sorted(&mut vec, vec![101, 19, 17, 8, 2], 8, |a, b| b.cmp(a));
106        assert_eq!(vec, &[101, 21, 19, 17, 13, 8, 2, 1]);
107
108        extend_sorted(&mut vec, vec![1000, 19, 17, 9, 5], 8, |a, b| b.cmp(a));
109        assert_eq!(vec, &[1000, 101, 21, 19, 17, 13, 9, 8]);
110    }
111}
112
113// Allow surf Results to accept context like other Results do when
114// using anyhow.
115pub trait SurfResultExt {
116    fn context<C>(self, cx: C) -> Self
117    where
118        C: std::fmt::Display + Send + Sync + 'static;
119
120    fn with_context<C, F>(self, f: F) -> Self
121    where
122        C: std::fmt::Display + Send + Sync + 'static,
123        F: FnOnce() -> C;
124}
125
126impl<T> SurfResultExt for surf::Result<T> {
127    fn context<C>(self, cx: C) -> Self
128    where
129        C: std::fmt::Display + Send + Sync + 'static,
130    {
131        self.map_err(|e| surf::Error::new(e.status(), e.into_inner().context(cx)))
132    }
133
134    fn with_context<C, F>(self, f: F) -> Self
135    where
136        C: std::fmt::Display + Send + Sync + 'static,
137        F: FnOnce() -> C,
138    {
139        self.map_err(|e| surf::Error::new(e.status(), e.into_inner().context(f())))
140    }
141}