use std::io::{Read, Chars, CharsError, BufReader};
use std::io;
use std::fs::File;
use std::path::Path;
use std::str::FromStr;
use std::fmt::{Debug, Display};
use std::fmt;
use std::any::Any;
use std::error::Error;
#[derive(Debug)]
pub enum ScanError<F: FromStr> {
Parse(F::Err),
Io(CharsError),
EndOfFile
}
impl<F> fmt::Display for ScanError<F> where
F: FromStr + Debug,
<F as FromStr>::Err: Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
ScanError::Parse(ref err) => write!(f, "Parse error: {}", err),
ScanError::Io(ref err) => write!(f, "IO error: {}", err),
ScanError::EndOfFile => write!(f, "End of File Error"),
}
}
}
impl<F: FromStr> From<io::CharsError> for ScanError<F> {
fn from(e: io::CharsError) -> ScanError<F> { ScanError::Io(e) }
}
impl<F: FromStr> From<io::Error> for ScanError<F> {
fn from(e: io::Error) -> ScanError<F> { ScanError::Io(CharsError::Other(e)) }
}
impl<F> Error for ScanError<F> where
F: FromStr + Debug,
<F as FromStr>::Err: Error + Any {
fn description(&self) -> &str {
match *self {
ScanError::Parse(ref err) => err.description(),
ScanError::Io(ref err) => Error::description(err),
ScanError::EndOfFile => &"End of File reached before next token"
}
}
fn cause(&self) -> Option<&Error> {
match *self {
ScanError::Parse(ref err) => Some(err),
ScanError::Io(ref err) => Some(err),
ScanError::EndOfFile => None,
}
}
}
pub trait Scan {
fn next_str(&mut self) -> Option<Result<String, CharsError>>;
fn next<F: FromStr>(&mut self) -> Result<F,ScanError<F>> {
self.next_str().map(|res| res
.map_err(|io_err| ScanError::Io(io_err))
.and_then(|s| s.parse::<F>()
.map_err(|fmt_err| ScanError::Parse(fmt_err))
)
).unwrap_or(Err(ScanError::EndOfFile))
}
}
#[derive(Debug)]
pub struct Scanner<I, F> {
chars: I,
ignore: F,
}
fn is_white(c: &char) -> bool {
*c == ' ' || *c == '\t' || *c == '\n' || *c == '\r'
}
impl<R: Read, F: Fn(&char) -> bool> Scanner<Chars<R>, F> {
pub fn custom(reader: R, f: F) -> Scanner<Chars<R>, F> {
Scanner{ chars: reader.chars(), ignore: f }
}
}
impl<R: Read> Scanner<Chars<R>, fn(&char) -> bool> {
pub fn new(reader: R) -> Scanner<Chars<R>, fn(&char) -> bool> {
Scanner::custom(reader, is_white)
}
}
impl<I, F> Scan for Scanner<I, F> where
I: Iterator<Item = Result<char,CharsError>>,
F: Fn(&char) -> bool {
fn next_str(&mut self) -> Option<Result<String, CharsError>> {
let mut out = String::new();
loop {
match self.chars.next() {
None => {
if out.len() > 0 {
return Some(Ok(out));
}
else {
return None;
}
},
Some(res) => {
match res {
Ok(c) => {
if (self.ignore)(&c) && out.len() > 0 {
return Some(Ok(out));
}
else if !(self.ignore)(&c) {
out.push(c);
}
}
Err(e) => {
return Some(Err(e));
}
}
},
}
}
}
}
pub fn from_path<P: AsRef<Path>>(path: P) ->
io::Result<Scanner<Chars<BufReader<File>>, fn(&char) -> bool>> {
let file = try!(File::open(path));
Ok(Scanner::new(BufReader::new(file)))
}
pub fn from_stdin() -> Scanner<Chars<io::Stdin>, fn(&char) -> bool> {
Scanner::new(io::stdin())
}