diff --git a/src/libcore/iter/adapters/mod.rs b/src/libcore/iter/adapters/mod.rs index c2edcd22f953b..8eae52ffd3277 100644 --- a/src/libcore/iter/adapters/mod.rs +++ b/src/libcore/iter/adapters/mod.rs @@ -2062,3 +2062,138 @@ impl ExactSizeIterator for Inspect #[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for Inspect where F: FnMut(&I::Item) {} + +/// An iterator adapter that produces output as long as the underlying +/// iterator produces `Option::Some` values. +pub(crate) struct OptionShunt { + iter: I, + exited_early: bool, +} + +impl OptionShunt +where + I: Iterator>, +{ + /// Process the given iterator as if it yielded a `T` instead of a + /// `Option`. Any `None` value will stop the inner iterator and + /// the overall result will be a `None`. + pub fn process(iter: I, mut f: F) -> Option + where + F: FnMut(&mut Self) -> U, + { + let mut shunt = OptionShunt::new(iter); + let value = f(shunt.by_ref()); + shunt.reconstruct(value) + } + + fn new(iter: I) -> Self { + OptionShunt { + iter, + exited_early: false, + } + } + + /// Consume the adapter and rebuild a `Option` value. + fn reconstruct(self, val: U) -> Option { + if self.exited_early { + None + } else { + Some(val) + } + } +} + +impl Iterator for OptionShunt +where + I: Iterator>, +{ + type Item = T; + + fn next(&mut self) -> Option { + match self.iter.next() { + Some(Some(v)) => Some(v), + Some(None) => { + self.exited_early = true; + None + } + None => None, + } + } + + fn size_hint(&self) -> (usize, Option) { + if self.exited_early { + (0, Some(0)) + } else { + let (_, upper) = self.iter.size_hint(); + (0, upper) + } + } +} + +/// An iterator adapter that produces output as long as the underlying +/// iterator produces `Result::Ok` values. +/// +/// If an error is encountered, the iterator stops and the error is +/// stored. The error may be recovered later via `reconstruct`. +pub(crate) struct ResultShunt { + iter: I, + error: Option, +} + +impl ResultShunt + where I: Iterator> +{ + /// Process the given iterator as if it yielded a `T` instead of a + /// `Result`. Any errors will stop the inner iterator and + /// the overall result will be an error. + pub fn process(iter: I, mut f: F) -> Result + where F: FnMut(&mut Self) -> U + { + let mut shunt = ResultShunt::new(iter); + let value = f(shunt.by_ref()); + shunt.reconstruct(value) + } + + fn new(iter: I) -> Self { + ResultShunt { + iter, + error: None, + } + } + + /// Consume the adapter and rebuild a `Result` value. This should + /// *always* be called, otherwise any potential error would be + /// lost. + fn reconstruct(self, val: U) -> Result { + match self.error { + None => Ok(val), + Some(e) => Err(e), + } + } +} + +impl Iterator for ResultShunt + where I: Iterator> +{ + type Item = T; + + fn next(&mut self) -> Option { + match self.iter.next() { + Some(Ok(v)) => Some(v), + Some(Err(e)) => { + self.error = Some(e); + None + } + None => None, + } + } + + fn size_hint(&self) -> (usize, Option) { + if self.error.is_some() { + (0, Some(0)) + } else { + let (_, upper) = self.iter.size_hint(); + (0, upper) + } + } +} diff --git a/src/libcore/iter/mod.rs b/src/libcore/iter/mod.rs index 6eccb9d1ea86d..4a7d7f96b9b04 100644 --- a/src/libcore/iter/mod.rs +++ b/src/libcore/iter/mod.rs @@ -360,7 +360,7 @@ pub use self::adapters::Flatten; #[stable(feature = "iter_copied", since = "1.36.0")] pub use self::adapters::Copied; -pub(crate) use self::adapters::TrustedRandomAccess; +pub(crate) use self::adapters::{TrustedRandomAccess, OptionShunt, ResultShunt}; mod range; mod sources; diff --git a/src/libcore/iter/traits/accum.rs b/src/libcore/iter/traits/accum.rs index adfb639bae341..01b64fb08acf7 100644 --- a/src/libcore/iter/traits/accum.rs +++ b/src/libcore/iter/traits/accum.rs @@ -1,5 +1,6 @@ use crate::ops::{Mul, Add}; use crate::num::Wrapping; +use crate::iter::adapters::{OptionShunt, ResultShunt}; /// Trait to represent types that can be created by summing up an iterator. /// @@ -114,74 +115,6 @@ macro_rules! float_sum_product { integer_sum_product! { i8 i16 i32 i64 i128 isize u8 u16 u32 u64 u128 usize } float_sum_product! { f32 f64 } -/// An iterator adapter that produces output as long as the underlying -/// iterator produces `Result::Ok` values. -/// -/// If an error is encountered, the iterator stops and the error is -/// stored. The error may be recovered later via `reconstruct`. -struct ResultShunt { - iter: I, - error: Option, -} - -impl ResultShunt - where I: Iterator> -{ - /// Process the given iterator as if it yielded a `T` instead of a - /// `Result`. Any errors will stop the inner iterator and - /// the overall result will be an error. - pub fn process(iter: I, mut f: F) -> Result - where F: FnMut(&mut Self) -> U - { - let mut shunt = ResultShunt::new(iter); - let value = f(shunt.by_ref()); - shunt.reconstruct(value) - } - - fn new(iter: I) -> Self { - ResultShunt { - iter, - error: None, - } - } - - /// Consume the adapter and rebuild a `Result` value. This should - /// *always* be called, otherwise any potential error would be - /// lost. - fn reconstruct(self, val: U) -> Result { - match self.error { - None => Ok(val), - Some(e) => Err(e), - } - } -} - -impl Iterator for ResultShunt - where I: Iterator> -{ - type Item = T; - - fn next(&mut self) -> Option { - match self.iter.next() { - Some(Ok(v)) => Some(v), - Some(Err(e)) => { - self.error = Some(e); - None - } - None => None, - } - } - - fn size_hint(&self) -> (usize, Option) { - if self.error.is_some() { - (0, Some(0)) - } else { - let (_, upper) = self.iter.size_hint(); - (0, upper) - } - } -} - #[stable(feature = "iter_arith_traits_result", since="1.16.0")] impl Sum> for Result where T: Sum, @@ -224,73 +157,6 @@ impl Product> for Result } } -/// An iterator adapter that produces output as long as the underlying -/// iterator produces `Option::Some` values. -struct OptionShunt { - iter: I, - exited_early: bool, -} - -impl OptionShunt -where - I: Iterator>, -{ - /// Process the given iterator as if it yielded a `T` instead of a - /// `Option`. Any `None` value will stop the inner iterator and - /// the overall result will be a `None`. - pub fn process(iter: I, mut f: F) -> Option - where - F: FnMut(&mut Self) -> U, - { - let mut shunt = OptionShunt::new(iter); - let value = f(shunt.by_ref()); - shunt.reconstruct(value) - } - - fn new(iter: I) -> Self { - OptionShunt { - iter, - exited_early: false, - } - } - - /// Consume the adapter and rebuild a `Option` value. - fn reconstruct(self, val: U) -> Option { - if self.exited_early { - None - } else { - Some(val) - } - } -} - -impl Iterator for OptionShunt -where - I: Iterator>, -{ - type Item = T; - - fn next(&mut self) -> Option { - match self.iter.next() { - Some(Some(v)) => Some(v), - Some(None) => { - self.exited_early = true; - None - } - None => None, - } - } - - fn size_hint(&self) -> (usize, Option) { - if self.exited_early { - (0, Some(0)) - } else { - let (_, upper) = self.iter.size_hint(); - (0, upper) - } - } -} - #[stable(feature = "iter_arith_traits_option", since = "1.37.0")] impl Sum> for Option where diff --git a/src/libcore/option.rs b/src/libcore/option.rs index abc8883d3985f..70a87cfe5a78a 100644 --- a/src/libcore/option.rs +++ b/src/libcore/option.rs @@ -135,7 +135,7 @@ #![stable(feature = "rust1", since = "1.0.0")] -use crate::iter::{FromIterator, FusedIterator, TrustedLen}; +use crate::iter::{FromIterator, FusedIterator, TrustedLen, OptionShunt}; use crate::{convert, fmt, hint, mem, ops::{self, Deref, DerefMut}}; use crate::pin::Pin; @@ -1499,45 +1499,7 @@ impl> FromIterator> for Option { // FIXME(#11084): This could be replaced with Iterator::scan when this // performance bug is closed. - struct Adapter { - iter: Iter, - found_none: bool, - } - - impl>> Iterator for Adapter { - type Item = T; - - #[inline] - fn next(&mut self) -> Option { - match self.iter.next() { - Some(Some(value)) => Some(value), - Some(None) => { - self.found_none = true; - None - } - None => None, - } - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - if self.found_none { - (0, Some(0)) - } else { - let (_, upper) = self.iter.size_hint(); - (0, upper) - } - } - } - - let mut adapter = Adapter { iter: iter.into_iter(), found_none: false }; - let v: V = FromIterator::from_iter(adapter.by_ref()); - - if adapter.found_none { - None - } else { - Some(v) - } + OptionShunt::process(iter.into_iter(), |i| i.collect()) } } diff --git a/src/libcore/result.rs b/src/libcore/result.rs index cb6bc058730d1..559877ddd5a1c 100644 --- a/src/libcore/result.rs +++ b/src/libcore/result.rs @@ -231,7 +231,7 @@ #![stable(feature = "rust1", since = "1.0.0")] use crate::fmt; -use crate::iter::{FromIterator, FusedIterator, TrustedLen}; +use crate::iter::{FromIterator, FusedIterator, TrustedLen, ResultShunt}; use crate::ops::{self, Deref, DerefMut}; /// `Result` is a type that represents either success ([`Ok`]) or failure ([`Err`]). @@ -1343,39 +1343,7 @@ impl> FromIterator> for Result { // FIXME(#11084): This could be replaced with Iterator::scan when this // performance bug is closed. - struct Adapter { - iter: Iter, - err: Option, - } - - impl>> Iterator for Adapter { - type Item = T; - - #[inline] - fn next(&mut self) -> Option { - match self.iter.next() { - Some(Ok(value)) => Some(value), - Some(Err(err)) => { - self.err = Some(err); - None - } - None => None, - } - } - - fn size_hint(&self) -> (usize, Option) { - let (_min, max) = self.iter.size_hint(); - (0, max) - } - } - - let mut adapter = Adapter { iter: iter.into_iter(), err: None }; - let v: V = FromIterator::from_iter(adapter.by_ref()); - - match adapter.err { - Some(err) => Err(err), - None => Ok(v), - } + ResultShunt::process(iter.into_iter(), |i| i.collect()) } }