bumpalo/collections/
collect_in.rs

1#[cfg(feature = "boxed")]
2use crate::boxed::Box;
3use crate::collections::{String, Vec};
4use crate::Bump;
5
6/// A trait for types that support being constructed from an iterator, parameterized by an allocator.
7pub trait FromIteratorIn<A> {
8    /// The allocator type
9    type Alloc;
10
11    /// Similar to [`FromIterator::from_iter`][from_iter], but with a given allocator.
12    ///
13    /// [from_iter]: https://doc.rust-lang.org/std/iter/trait.FromIterator.html#tymethod.from_iter
14    ///
15    /// ```
16    /// # use bumpalo::collections::{FromIteratorIn, Vec};
17    /// # use bumpalo::Bump;
18    /// #
19    /// let five_fives = std::iter::repeat(5).take(5);
20    /// let bump = Bump::new();
21    ///
22    /// let v = Vec::from_iter_in(five_fives, &bump);
23    ///
24    /// assert_eq!(v, [5, 5, 5, 5, 5]);
25    /// ```
26    fn from_iter_in<I>(iter: I, alloc: Self::Alloc) -> Self
27    where
28        I: IntoIterator<Item = A>;
29}
30
31#[cfg(feature = "boxed")]
32impl<'bump, T> FromIteratorIn<T> for Box<'bump, [T]> {
33    type Alloc = &'bump Bump;
34
35    fn from_iter_in<I>(iter: I, alloc: Self::Alloc) -> Self
36    where
37        I: IntoIterator<Item = T>,
38    {
39        Box::from_iter_in(iter, alloc)
40    }
41}
42
43impl<'bump, T> FromIteratorIn<T> for Vec<'bump, T> {
44    type Alloc = &'bump Bump;
45
46    fn from_iter_in<I>(iter: I, alloc: Self::Alloc) -> Self
47    where
48        I: IntoIterator<Item = T>,
49    {
50        Vec::from_iter_in(iter, alloc)
51    }
52}
53
54impl<T, V: FromIteratorIn<T>> FromIteratorIn<Option<T>> for Option<V> {
55    type Alloc = V::Alloc;
56    fn from_iter_in<I>(iter: I, alloc: Self::Alloc) -> Self
57    where
58        I: IntoIterator<Item = Option<T>>,
59    {
60        iter.into_iter()
61            .map(|x| x.ok_or(()))
62            .collect_in::<Result<_, _>>(alloc)
63            .ok()
64    }
65}
66
67impl<T, E, V: FromIteratorIn<T>> FromIteratorIn<Result<T, E>> for Result<V, E> {
68    type Alloc = V::Alloc;
69    /// Takes each element in the `Iterator`: if it is an `Err`, no further
70    /// elements are taken, and the `Err` is returned. Should no `Err` occur, a
71    /// container with the values of each `Result` is returned.
72    ///
73    /// Here is an example which increments every integer in a vector,
74    /// checking for overflow:
75    ///
76    /// ```
77    /// # use bumpalo::collections::{FromIteratorIn, CollectIn, Vec, String};
78    /// # use bumpalo::Bump;
79    /// #
80    /// let bump = Bump::new();
81    ///
82    /// let v = vec![1, 2, u32::MAX];
83    /// let res: Result<Vec<u32>, &'static str> = v.iter().take(2).map(|x: &u32|
84    ///     x.checked_add(1).ok_or("Overflow!")
85    /// ).collect_in(&bump);
86    /// assert_eq!(res, Ok(bumpalo::vec![in &bump; 2, 3]));
87    ///
88    /// let res: Result<Vec<u32>, &'static str> = v.iter().map(|x: &u32|
89    ///     x.checked_add(1).ok_or("Overflow!")
90    /// ).collect_in(&bump);
91    /// assert_eq!(res, Err("Overflow!"));
92    /// ```
93    fn from_iter_in<I>(iter: I, alloc: Self::Alloc) -> Self
94    where
95        I: IntoIterator<Item = Result<T, E>>,
96    {
97        let mut iter = iter.into_iter();
98        let mut error = None;
99        let container = core::iter::from_fn(|| match iter.next() {
100            Some(Ok(x)) => Some(x),
101            Some(Err(e)) => {
102                error = Some(e);
103                None
104            }
105            None => None,
106        })
107        .collect_in(alloc);
108
109        match error {
110            Some(e) => Err(e),
111            None => Ok(container),
112        }
113    }
114}
115
116impl<'bump> FromIteratorIn<char> for String<'bump> {
117    type Alloc = &'bump Bump;
118
119    fn from_iter_in<I>(iter: I, alloc: Self::Alloc) -> Self
120    where
121        I: IntoIterator<Item = char>,
122    {
123        String::from_iter_in(iter, alloc)
124    }
125}
126
127/// Extension trait for iterators, in order to allow allocator-parameterized collections to be constructed more easily.
128pub trait CollectIn: Iterator + Sized {
129    /// Collect all items from an iterator, into a collection parameterized by an allocator.
130    /// Similar to [`Iterator::collect`][collect].
131    ///
132    /// [collect]: https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.collect
133    ///
134    /// ```
135    /// # use bumpalo::collections::{FromIteratorIn, CollectIn, Vec, String};
136    /// # use bumpalo::Bump;
137    /// #
138    /// let bump = Bump::new();
139    ///
140    /// let str = "hello, world!".to_owned();
141    /// let bump_str: String = str.chars().collect_in(&bump);
142    /// assert_eq!(&bump_str, &str);
143    ///
144    /// let nums: Vec<i32> = (0..=3).collect_in::<Vec<_>>(&bump);
145    /// assert_eq!(&nums, &[0,1,2,3]);
146    /// ```
147    fn collect_in<C: FromIteratorIn<Self::Item>>(self, alloc: C::Alloc) -> C {
148        C::from_iter_in(self, alloc)
149    }
150}
151
152impl<I: Iterator> CollectIn for I {}