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