// Collecting and aggregating iterator values // // Copyright (C) 2014-2021 Ryan Specialty Group, LLC. // // This file is part of TAME. // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see . //! A [`FromIterator`] that can fail, //! along with a [`try_collect`](TryCollect::try_collect) that is //! analogous to [`collect`](Iterator::collect). //! //! Rust's built-in [`Iterator::collect`] is a powerful abstraction that is //! able to remove a considerable amount of boilerplate and explicit //! composition, //! but it cannot handle failures. //! These traits attempt to stay as faithful as possible to the Rust //! standard library while permitting (and expecting) failures to occur. //! //! See the [parent module](super) for more information. use super::TrippableIterator; use std::convert::Infallible; /// Conversion from an [`Iterator`] that may fail in a controlled way. /// /// If the conversion cannot fail, /// use Rust's built-in [`FromIterator`] instead; /// [`TryFromIterator`] is implemented automatically anything /// implementing [`FromIterator`]. pub trait TryFromIterator: Sized { /// Conversation failure. type Error; /// Attempts to create a value from an iterator, /// failing in a controlled manner. /// /// This is generally called through [`TryCollect::try_collect`]. /// /// See the [module-level documentation](super) for more information. fn try_from_iter>( iter: I, ) -> Result; } impl TryFromIterator for T where T: FromIterator, { type Error = Infallible; /// Create a value from an iterator. /// /// This is an automatic implementation for anything implementing /// [`FromIterator`] and cannot fail; /// it directly invokes [`FromIterator::from_iter`]. fn try_from_iter>( iter: I, ) -> Result { Ok(FromIterator::from_iter(iter)) } } /// Augment [`Iterator`]s with a [`try_collect`](TryCollect::try_collect) /// method, /// which is analogous to [`Iterator::collect`]. /// /// Where [`Iterator::collect`] uses [`FromIterator`], /// `try_collect` uses [`TryFromIterator`]. pub trait TryCollect: Iterator + Sized { /// Attempts to transform an iterator into a collection, /// which may fail in a controlled manner under certain /// circumstances. /// /// If this operation is infailliable for all relevant types, /// use [`Iterator::collect`] instead. /// /// See the [module-level documentation](super) for more information. #[inline] fn try_collect>( self, ) -> Result { TryFromIterator::try_from_iter(self) } /// Attempts to transform a [`Result`](Result) iterator into a /// collection of [`TryFromIterator`](TryFromIterator), /// which may fail in a controlled manner on either the source /// iterator or the transformation. /// /// Ideally, this method would not have to exist. /// However, /// at the time of writing, /// `iter.while_ok(TryCollect::try_collect)` fails to compile, /// requiring instead a more verbose closure. /// This function exists purely to improve readability and reduce /// boilerplate, /// but at the expense of a somewhat confusing return type. /// /// The outer [`Result`] represents the the source iterator, /// in the sense of [`TrippableIterator::while_ok`]. /// The inner [`Result`] represents the result of the /// [`try_collect`](TryCollect::try_collect) operation. /// Since these two errors types are expected to be unrelated to /// one-another /// (after all, [`TrippableIterator`] exists precisely to decouple /// the downstream iterators from upstream failures), /// there is no obvious and correct conversion, /// and so it is left up to the caller. /// Often, /// this call is simply suffixed with `??`, /// leaving the containing function's return type to manage the /// conversion via [`Into`]. #[inline] fn try_collect_ok>( mut self, ) -> Result, E> where Self: Iterator>, { // At the time of writing, // `self.while_ok(TryCollect::try_collect)` does not compile, // stating that `FnOnce` is "not general enough" and appearing // immune to any attempts to generalize lifetimes using // higher-rank trait bounds (HRTBs). self.while_ok(|iter| TryCollect::try_collect(iter)) } } impl TryCollect for I {}