use typle::typle; // How to convert `Iterator` to `Result<(Vec>, Vec>), E>` // for any tuple size, generalizing the 2-tuple case described in // https://users.rust-lang.org/t/unzip-with-error-handling/110250 // That is, implement the following `TryUnzip` trait for `Iterator>`. pub trait TryUnzip { type Output; type Error; fn try_unzip(self) -> Result; } // typle` does not work when the tuple types are only associated types because // associated types cannot distinguish implementations. The implementations for // each tuple length conflict because they are all on the same type (in this // case `Iterator`): https://github.com/rust-lang/rust/issues/20400 // #[typle(Tuple for 2..=3)] // impl TryUnzip for I // where // I: Iterator>, // T: Tuple, // { // type Output = typle_for!(i in .. => Vec>); // type Error = E; // // fn try_unzip(self) -> Result { // let mut vecs = typle_for!(i in .. => Vec::new()); // for result in self { // let t = result?; // for typle_index!(i) in 0..T::LEN { // vecs[[i]].push(t[[i]]); // } // } // Ok(vecs) // } // } // If the trait can be modified, then we can use a generic type for the tuple // type instead of an associated type: pub trait TryUnzipModified { type Error; fn try_unzip(self) -> Result; } #[typle(Tuple for 2..=3)] impl TryUnzipModified Vec>)> for I where I: Iterator>, T: Tuple, { type Error = E; fn try_unzip(self) -> Result Vec>), Self::Error> { #[typle_attr_if(T::LEN == 0, allow(unused_mut))] let mut vecs = typle_for!(.. => Vec::new()); for result in self { #[typle_attr_if(T::LEN == 0, allow(clippy::let_unit_value, unused_variables))] let t = result?; for typle_index!(i) in 0..T::LEN { vecs[[i]].push(t[[i]]); } } Ok(vecs) } } // A solution that does not modify the original trait is to add a new trait with // an associated method, implement it on the tuple type, and call it from an // impl for the original trait. Note that the typle impl uses the input // types as generic parameters to select the implementation and uses associated // types for any interface types constructed using typle macros. pub trait TryUnzipTuple { type Output; fn try_unzip(iter: I) -> Result where I: Iterator>; } #[typle(Tuple for 2..=3)] impl TryUnzipTuple for T where T: Tuple, { type Output = typle_for!(i in .. => Vec>); fn try_unzip(iter: I) -> Result where I: Iterator>, { #[typle_attr_if(T::LEN == 0, allow(unused_mut))] let mut vecs = typle_for!(.. => Vec::new()); for result in iter { #[typle_attr_if(T::LEN == 0, allow(clippy::let_unit_value, unused_variables))] let t = result?; for typle_index!(i) in 0..T::LEN { vecs[[i]].push(t[[i]]); } } Ok(vecs) } } impl TryUnzip for I where I: Iterator>, T: TryUnzipTuple, { type Output = >::Output; type Error = E; fn try_unzip(self) -> Result { >::try_unzip(self) } }