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    fn warn_on_err(self) -> Option<Self::Ok>;
 44}
 45
 46impl<T> ResultExt for anyhow::Result<T> {
 47    type Ok = T;
 48
 49    fn log_err(self) -> Option<T> {
 50        match self {
 51            Ok(value) => Some(value),
 52            Err(error) => {
 53                log::error!("{:?}", error);
 54                None
 55            }
 56        }
 57    }
 58
 59    fn warn_on_err(self) -> Option<T> {
 60        match self {
 61            Ok(value) => Some(value),
 62            Err(error) => {
 63                log::warn!("{:?}", error);
 64                None
 65            }
 66        }
 67    }
 68}
 69
 70pub trait TryFutureExt {
 71    fn log_err(self) -> LogErrorFuture<Self>
 72    where
 73        Self: Sized;
 74    fn warn_on_err(self) -> LogErrorFuture<Self>
 75    where
 76        Self: Sized;
 77}
 78
 79impl<F, T> TryFutureExt for F
 80where
 81    F: Future<Output = anyhow::Result<T>>,
 82{
 83    fn log_err(self) -> LogErrorFuture<Self>
 84    where
 85        Self: Sized,
 86    {
 87        LogErrorFuture(self, log::Level::Error)
 88    }
 89
 90    fn warn_on_err(self) -> LogErrorFuture<Self>
 91    where
 92        Self: Sized,
 93    {
 94        LogErrorFuture(self, log::Level::Warn)
 95    }
 96}
 97
 98pub struct LogErrorFuture<F>(F, log::Level);
 99
100impl<F, T> Future for LogErrorFuture<F>
101where
102    F: Future<Output = anyhow::Result<T>>,
103{
104    type Output = Option<T>;
105
106    fn poll(self: std::pin::Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
107        let level = self.1;
108        let inner = unsafe { Pin::new_unchecked(&mut self.get_unchecked_mut().0) };
109        match inner.poll(cx) {
110            Poll::Ready(output) => Poll::Ready(match output {
111                Ok(output) => Some(output),
112                Err(error) => {
113                    log::log!(level, "{:?}", error);
114                    None
115                }
116            }),
117            Poll::Pending => Poll::Pending,
118        }
119    }
120}
121
122#[cfg(test)]
123mod tests {
124    use super::*;
125
126    #[test]
127    fn test_extend_sorted() {
128        let mut vec = vec![];
129
130        extend_sorted(&mut vec, vec![21, 17, 13, 8, 1, 0], 5, |a, b| b.cmp(a));
131        assert_eq!(vec, &[21, 17, 13, 8, 1]);
132
133        extend_sorted(&mut vec, vec![101, 19, 17, 8, 2], 8, |a, b| b.cmp(a));
134        assert_eq!(vec, &[101, 21, 19, 17, 13, 8, 2, 1]);
135
136        extend_sorted(&mut vec, vec![1000, 19, 17, 9, 5], 8, |a, b| b.cmp(a));
137        assert_eq!(vec, &[1000, 101, 21, 19, 17, 13, 9, 8]);
138    }
139}
140
141// Allow surf Results to accept context like other Results do when
142// using anyhow.
143pub trait SurfResultExt {
144    fn context<C>(self, cx: C) -> Self
145    where
146        C: std::fmt::Display + Send + Sync + 'static;
147
148    fn with_context<C, F>(self, f: F) -> Self
149    where
150        C: std::fmt::Display + Send + Sync + 'static,
151        F: FnOnce() -> C;
152}
153
154impl<T> SurfResultExt for surf::Result<T> {
155    fn context<C>(self, cx: C) -> Self
156    where
157        C: std::fmt::Display + Send + Sync + 'static,
158    {
159        self.map_err(|e| surf::Error::new(e.status(), e.into_inner().context(cx)))
160    }
161
162    fn with_context<C, F>(self, f: F) -> Self
163    where
164        C: std::fmt::Display + Send + Sync + 'static,
165        F: FnOnce() -> C,
166    {
167        self.map_err(|e| surf::Error::new(e.status(), e.into_inner().context(f())))
168    }
169}