iter.rs 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  1. //
  2. // imag - the personal information management suite for the commandline
  3. // Copyright (C) 2016 the imag contributors
  4. //
  5. // This library is free software; you can redistribute it and/or
  6. // modify it under the terms of the GNU Lesser General Public
  7. // License as published by the Free Software Foundation; version
  8. // 2.1 of the License.
  9. //
  10. // This library is distributed in the hope that it will be useful,
  11. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  13. // Lesser General Public License for more details.
  14. //
  15. // You should have received a copy of the GNU Lesser General Public
  16. // License along with this library; if not, write to the Free Software
  17. // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  18. //
  19. use std::error::Error;
  20. /// An iterator that maps `f` over the `Error` elements of `iter`, similar to `std::iter::Map`.
  21. ///
  22. /// This `struct` is created by the `on_err()` method on `TraceIterator`. See its
  23. /// documentation for more information.
  24. #[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
  25. #[derive(Clone)]
  26. pub struct OnErr<I, F>{
  27. iter: I,
  28. f: F
  29. }
  30. impl<I, F, T, E> Iterator for OnErr<I, F> where
  31. I: Iterator<Item = Result<T, E>>,
  32. F: FnMut(&E)
  33. {
  34. type Item = Result<T, E>;
  35. #[inline]
  36. fn next(&mut self) -> Option<Self::Item> {
  37. self.iter.next().map(|r| r.map_err(|e| { (self.f)(&e); e }))
  38. }
  39. #[inline]
  40. fn size_hint(&self) -> (usize, Option<usize>) {
  41. self.iter.size_hint()
  42. }
  43. }
  44. impl<I, F> ExactSizeIterator for OnErr<I, F> where
  45. I: ExactSizeIterator,
  46. OnErr<I, F>: Iterator
  47. {
  48. }
  49. impl<I, F, T, E> DoubleEndedIterator for OnErr<I, F> where
  50. I: DoubleEndedIterator<Item = Result<T, E>>,
  51. F: FnMut(&E)
  52. {
  53. #[inline]
  54. fn next_back(&mut self) -> Option<Self::Item> {
  55. self.iter.next_back().map(|r| r.map_err(|e| { (self.f)(&e); e }))
  56. }
  57. }
  58. /// An iterator that unwraps the `Ok` items of `iter`, while passing the `Err` items to its
  59. /// closure `f`.
  60. ///
  61. /// This `struct` is created by the `unwrap_with()` method on `TraceIterator`. See its
  62. /// documentation for more information.
  63. #[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
  64. #[derive(Clone)]
  65. pub struct UnwrapWith<I, F>{
  66. iter: I,
  67. f: F
  68. }
  69. impl<I, F, T, E> Iterator for UnwrapWith<I, F> where
  70. I: Iterator<Item = Result<T, E>>,
  71. F: FnMut(E)
  72. {
  73. type Item = T;
  74. #[inline]
  75. fn next(&mut self) -> Option<Self::Item> {
  76. loop {
  77. match self.iter.next() {
  78. Some(Err(e)) => {
  79. (self.f)(e);
  80. },
  81. Some(Ok(item)) => return Some(item),
  82. None => return None,
  83. }
  84. }
  85. }
  86. #[inline]
  87. fn size_hint(&self) -> (usize, Option<usize>) {
  88. let (_, upper) = self.iter.size_hint();
  89. (0, upper)
  90. }
  91. }
  92. impl<I, F, T, E> DoubleEndedIterator for UnwrapWith<I, F> where
  93. I: DoubleEndedIterator<Item = Result<T, E>>,
  94. F: FnMut(E)
  95. {
  96. #[inline]
  97. fn next_back(&mut self) -> Option<Self::Item> {
  98. loop {
  99. match self.iter.next_back() {
  100. Some(Err(e)) => {
  101. (self.f)(e);
  102. },
  103. Some(Ok(item)) => return Some(item),
  104. None => return None,
  105. }
  106. }
  107. }
  108. }
  109. /// This trait provides methods that make it easier to work with iterators that yield a `Result`.
  110. pub trait TraceIterator<T, E> : Iterator<Item = Result<T, E>> + Sized {
  111. /// Creates an iterator that yields the item in each `Ok` item, while filtering out the `Err`
  112. /// items. Each filtered `Err` will be trace-logged with [`::trace::trace_error`].
  113. ///
  114. /// As with all iterators, the processing is lazy. If you do not use the result of this method,
  115. /// nothing will be passed to `::trace::trace_error`, no matter how many `Err` items might
  116. /// be present.
  117. #[inline]
  118. fn trace_unwrap(self) -> UnwrapWith<Self, fn(E)> where E: Error {
  119. #[inline]
  120. fn trace_error<E: Error>(err: E) {
  121. ::trace::trace_error(&err);
  122. }
  123. self.unwrap_with(trace_error)
  124. }
  125. /// Takes a closure and creates an iterator that will call that closure for each `Err` element.
  126. /// The resulting iterator will yield the exact same items as the original iterator. A close
  127. /// analogue from the standard library would be `Iterator::inspect`.
  128. ///
  129. /// As with all iterators, the processing is lazy. The result of this method must be evaluated
  130. /// for the closure to be called.
  131. #[inline]
  132. fn on_err<F>(self, f: F) -> OnErr<Self, F> where F: FnMut(&E) {
  133. OnErr { iter: self, f: f }
  134. }
  135. /// Takes a closure and creates an iterator that will yield the items inside all `Ok` items
  136. /// yielded by the original iterator. All `Err` items will be filtered out, and the contents
  137. /// of each `Err` will be passed to the closure.
  138. ///
  139. /// As with all iterators, the processing is lazy. The result of this method must be evaluated
  140. /// for the closure to be called.
  141. #[inline]
  142. fn unwrap_with<F>(self, f: F) -> UnwrapWith<Self, F>
  143. where F: FnMut(E)
  144. {
  145. UnwrapWith { iter: self, f: f }
  146. }
  147. }
  148. impl<I, T, E> TraceIterator<T, E> for I where
  149. I: Iterator<Item = Result<T, E>>
  150. {}
  151. #[cfg(test)]
  152. mod test {
  153. use super::TraceIterator;
  154. #[derive(Copy, Clone, Eq, PartialEq, Debug)]
  155. struct TestError(i32);
  156. #[test]
  157. fn test_unwrap_with() {
  158. let original = vec![Ok(1), Err(TestError(2)), Ok(3), Err(TestError(4))];
  159. let mut errs = vec![];
  160. let oks = original
  161. .into_iter()
  162. .unwrap_with(|e|errs.push(e))
  163. .collect::<Vec<_>>();
  164. assert_eq!(&oks, &[1, 3]);
  165. assert_eq!(&errs, &[TestError(2), TestError(4)]);
  166. }
  167. #[test]
  168. fn test_unwrap_with_backward() {
  169. let original = vec![Ok(1), Err(TestError(2)), Ok(3), Err(TestError(4))];
  170. let mut errs = vec![];
  171. let oks = original
  172. .into_iter()
  173. .rev()
  174. .unwrap_with(|e|errs.push(e))
  175. .collect::<Vec<_>>();
  176. assert_eq!(&oks, &[3, 1]);
  177. assert_eq!(&errs, &[TestError(4), TestError(2)]);
  178. }
  179. #[test]
  180. fn test_on_err() {
  181. let original = vec![Ok(1), Err(TestError(2)), Ok(3), Err(TestError(4))];
  182. let mut errs = vec![];
  183. let result = original
  184. .into_iter()
  185. .on_err(|e|errs.push(e.clone()))
  186. .collect::<Vec<_>>();
  187. assert_eq!(&result, &[Ok(1), Err(TestError(2)), Ok(3), Err(TestError(4))]);
  188. assert_eq!(&errs, &[TestError(2), TestError(4)]);
  189. }
  190. #[test]
  191. fn test_on_err_backward() {
  192. let original = vec![Ok(1), Err(TestError(2)), Ok(3), Err(TestError(4))];
  193. let mut errs = vec![];
  194. let result = original
  195. .into_iter()
  196. .rev()
  197. .on_err(|e|errs.push(e.clone()))
  198. .collect::<Vec<_>>();
  199. assert_eq!(&result, &[Err(TestError(4)), Ok(3), Err(TestError(2)), Ok(1)]);
  200. assert_eq!(&errs, &[TestError(4), TestError(2)]);
  201. }
  202. }