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}