I'm trying to implement a simple interpreter in Rust, for which I have created a Tokens
struct, which takes source characters and produces either a Token
or a ScanError
inside a Result
:
pub struct Tokens<'src> {
chars: Chars<'src>,
}
impl<'src> Iterator for Tokens<'src> {
type Item = Result<Token, ScanError>;
fn next(&mut self) -> Option<Result<Token, ScanError>> {
// ...
}
}
Since Result
implements FromIterator
, it is simple to collect the result to either the first ScanError
or a vector of Token
s:
fn scan_tokens(source: &str) -> Result<Vec<Token>, ScanError> {
let iter = Tokens {
chars: source.chars(),
};
iter.collect()
}
In the case of multiple errors I really want to return every error:
fn scan_tokens(source: &str) -> Result<Vec<Token>, Vec<ScanError>> {
// what goes here?
}
It isn't possible as far as I know to implement my own version of FromIterator
because neither that trait or Result
are local to my crate. Can anyone suggest a clean way of doing this?
I have written an implementation using partition
on the iterator, then unwrapping each Result
, below, but it's not fun to read and doesn't feel like good use of iterators:
type T = Vec<Result<Token, ScanError>>;
fn scan_tokens(source: &str) -> Result<Vec<Token>, Vec<ScanError>> {
let iter = Tokens {
chars: source.chars(),
};
let (tokens_results, error_results): (T, T) = iter.partition(|result| result.is_ok());
let errors: Vec<ScanError> = error_results
.into_iter()
.map(|result| result.unwrap_err())
.collect();
if errors.len() > 0 {
return Err(errors);
}
Ok(tokens_results
.into_iter()
.map(|result| result.unwrap())
.collect())
}