use crate::alloc::TryVec; use crate::error::OutOfMemory; use std_alloc::boxed::Box; /// Extension trait for an `Iterator` to fallibly collect into a container. pub trait TryCollect: Iterator { /// Attempts to collect the iterator `self` into `B`. /// /// Same as [`Iterator::collect`] except returns OOM instead of aborting. fn try_collect(self) -> Result where B: TryFromIterator, Self: Sized, { B::try_from_iter(self) } } impl TryCollect for I {} /// Analogue of [`FromIterator`] in the standard library, but used with /// [`TryCollect::try_collect`] instead. pub trait TryFromIterator: Sized { /// Creates an instance of this collection from the `iter` provided. /// /// Does not abort on OOM but instead returns an error. fn try_from_iter(iter: I) -> Result where I: Iterator; } impl TryFromIterator for TryVec { fn try_from_iter(iter: I) -> Result where I: Iterator, { let mut result = TryVec::with_capacity(iter.size_hint().0)?; for item in iter { result.push(item)?; } Ok(result) } } impl TryFromIterator for Box<[T]> { fn try_from_iter(iter: I) -> Result where I: Iterator, { let vec = TryVec::try_from_iter(iter)?; vec.into_boxed_slice() } } impl TryFromIterator, E> for TryVec where E: From, { fn try_from_iter(iter: I) -> Result where I: Iterator>, { let mut result = TryVec::with_capacity(iter.size_hint().0)?; for item in iter { result.push(item?)?; } Ok(result) } } impl TryFromIterator, E> for Box<[T]> where E: From, { fn try_from_iter(iter: I) -> Result where I: Iterator>, { let vec = iter.try_collect::, E>()?; Ok(vec.into_boxed_slice()?) } } /// Analogue of [`Extend`] except handles OOM conditions. pub trait TryExtend { /// Extends `self` with the items from `iter`. /// /// Returns an error if allocation fails while adding items to `self`. If an /// OOM happens then some items from `iter` may have been added to `self` /// already. On OOM no further items from the iterator will be consumed. fn try_extend(&mut self, iter: I) -> Result<(), OutOfMemory> where I: IntoIterator; } impl TryExtend for TryVec { fn try_extend(&mut self, iter: I) -> Result<(), OutOfMemory> where I: IntoIterator, { let iter = iter.into_iter(); self.reserve(iter.size_hint().0)?; for item in iter { self.push(item)?; } Ok(()) } } #[cfg(test)] mod tests { use super::{Box, TryCollect, TryExtend, TryVec}; use crate::error::{OutOfMemory, Result}; #[test] fn test_vec_collect() -> Result<(), OutOfMemory> { let v: TryVec = (0..10).try_collect()?; assert_eq!(&*v, &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]); Ok(()) } #[test] fn test_box_collect() -> Result<(), OutOfMemory> { let v: Box<[i32]> = (0..10).try_collect()?; assert_eq!(&*v, &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]); Ok(()) } #[test] fn test_vec_result_collect() -> Result<()> { let v: Result> = [].into_iter().try_collect(); assert!(v?.is_empty()); let v: Result> = [Ok(1), Ok(2)].into_iter().try_collect(); assert_eq!(&*v?, &[1, 2]); let v: Result> = [Ok(1), Err(crate::format_err!("hi"))] .into_iter() .try_collect(); assert!(v.is_err()); let v: Result> = [Err(crate::format_err!("hi")), Ok(1)] .into_iter() .try_collect(); assert!(v.is_err()); Ok(()) } #[test] fn test_box_result_collect() -> Result<()> { let v: Result> = [].into_iter().try_collect(); assert!(v?.is_empty()); let v: Result> = [Ok(1), Ok(2)].into_iter().try_collect(); assert_eq!(&*v?, &[1, 2]); let v: Result> = [Ok(1), Err(crate::format_err!("hi"))] .into_iter() .try_collect(); assert!(v.is_err()); let v: Result> = [Err(crate::format_err!("hi")), Ok(1)] .into_iter() .try_collect(); assert!(v.is_err()); Ok(()) } #[test] fn test_try_extend() -> Result<(), OutOfMemory> { let mut vec = TryVec::new(); vec.try_extend([1, 2, 3].iter().cloned())?; assert_eq!(&*vec, &[1, 2, 3]); vec.try_extend([])?; assert_eq!(&*vec, &[1, 2, 3]); Ok(()) } }