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 ≎ 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 {}