trie_rs/try_collect.rs
1//! Try to collect from an iterator; operation may fail.
2//!
3//! Any type can that be `collect()`ed can be `try_collect()`ed without fail.
4//!
5//! # Usage
6//!
7//! The simplest usage is like this.
8//!
9//! ```
10//! use trie_rs::try_collect::*;
11//! let bytes: Vec<u8> = vec![72, 105];
12//! let s: String = bytes.into_iter().try_collect().unwrap();
13//! assert_eq!(s, "Hi");
14//! ```
15//!
16//! # Motivation
17//!
18//! I really wanted to be able to turn a `Iterator<Item = u8>` into a String
19//! more easily, so that one could accumulate trie entries as `Vec<u8>`s or as
20//! `String`s. This is made complicated by the fact that [String] does not have
21//! a `FromIterator<u8>` implementation, and the method it does have
22//! `from_utf8()` is fallible; it returns a `Result`.
23//!
24//! Thus [TryFromIterator] is simply a fallible version of
25//! [std::iter::FromIterator]. And `try_collect()` is `collect()` fallible
26//! cousin as well.
27//!
28//! # Technical Note
29//!
30//! `TryFromIterator<A, M>` accepts a generic type `M` marker parameter. In
31//! general usage, the caller will simply pass along a generic `M` type.
32//!
33//! The reason it exists is so we can specify a blanket implementation of
34//! [TryFromIterator] for all [std::iter::FromIterator]s, and we can also
35//! specify one for [String].
36//!
37//! Without this marker type, it's not possible to have a blanket and
38//! specialized implementation of the trait.
39//!
40use std::fmt::Debug;
41use std::iter::FromIterator;
42
43/// Try to collect from an iterator; operation may fail.
44pub trait TryCollect: Iterator {
45 /// Use this iterator to collect into a container `C`, may fail.
46 fn try_collect<C, M>(self) -> Result<C, C::Error>
47 where
48 C: TryFromIterator<Self::Item, M>,
49 Self: Sized,
50 {
51 C::try_from_iter(self)
52 }
53}
54
55impl<T> TryCollect for T where T: Iterator + ?Sized {}
56
57/// Try to create an object from an iterator.
58pub trait TryFromIterator<A, Marker> {
59 /// Error type of [TryFromIterator::try_from_iter].
60 type Error: Debug;
61 /// Try to turn the given iterator into `Self`.
62 fn try_from_iter<T>(iter: T) -> Result<Self, Self::Error>
63 where
64 Self: Sized,
65 T: IntoIterator<Item = A>;
66}
67
68#[derive(Debug, Clone)]
69/// Marker type for blanket [TryFromIterator] implementation.
70#[doc(hidden)]
71pub struct Collect;
72
73impl<S, A> TryFromIterator<A, Collect> for S
74where
75 S: FromIterator<A>,
76{
77 type Error = ();
78 fn try_from_iter<T>(iter: T) -> Result<Self, Self::Error>
79 where
80 Self: Sized,
81 T: IntoIterator<Item = A>,
82 {
83 Ok(FromIterator::from_iter(iter))
84 }
85}
86
87#[derive(Debug, Clone)]
88/// Marker type for String [TryFromIterator] implementation.
89#[doc(hidden)]
90pub struct StringCollect;
91
92impl TryFromIterator<u8, StringCollect> for String {
93 type Error = std::string::FromUtf8Error;
94 fn try_from_iter<T>(iter: T) -> Result<Self, Self::Error>
95 where
96 Self: Sized,
97 T: IntoIterator<Item = u8>,
98 {
99 String::from_utf8(iter.into_iter().collect())
100 }
101}