use std::str::{FromStr, SplitWhitespace};
use std::io;
use std::fmt;
use std::error;
pub mod maxflow;
pub mod graph;
pub use self::graph::read as read_graph;
quick_error! {
#[derive(Debug)]
pub enum DimacsError {
Format(line: usize, msg: String) {
description("format error")
display("Format error in line {}: {}", line, msg)
}
Data(line: usize, msg: String) {
description("data error")
display("Data error line {}: {}", line, msg)
}
Builder(err: Box<error::Error>) {
from()
cause(&**err)
description(err.description())
display("Builder error: {}", err)
}
IoError(err: io::Error) {
from()
cause(err)
description(err.description())
display("I/O error: {}", err)
}
}
}
pub struct Tokens<'a> {
it: SplitWhitespace<'a>,
pub line: usize,
}
impl<'a> Iterator for Tokens<'a> {
type Item = &'a str;
fn next(&mut self) -> Option<&'a str> {
self.it.next()
}
}
impl<'a> Tokens<'a> {
fn str(&mut self) -> Result<&'a str, DimacsError> {
self.it
.next()
.ok_or_else(|| DimacsError::Format(self.line, "expected token".to_string()))
}
fn number<T>(&mut self) -> Result<T, DimacsError>
where T: FromStr,
T::Err: fmt::Display
{
try!(self.it
.next()
.ok_or_else(|| DimacsError::Format(self.line, "expected number".to_string())))
.parse()
.or_else(|e| Err(DimacsError::Format(self.line, format!("{}", e))))
}
fn end(&mut self) -> Result<(), DimacsError> {
if let Some(s) = self.it.next() {
Err(DimacsError::Format(self.line, format!("unexpected token at end of line: {}", s)))
} else {
Ok(())
}
}
}
pub fn read_dimacs<R, F>(fin: &mut R, f: &mut F) -> Result<(), DimacsError>
where R: io::BufRead,
F: FnMut(char, &mut Tokens) -> Result<(), DimacsError>
{
let mut nline = 0;
let mut line = String::new();
while try!({
line.clear();
fin.read_line(&mut line)
}) > 0 {
nline += 1;
let mut it = line.chars();
while let Some(c) = it.next() {
match c {
_ if char::is_whitespace(c) => continue,
'c' | '\n' => break,
_ => {
let mut tok = Tokens {
it: it.as_str().split_whitespace(),
line: nline,
};
try!(f(c, &mut tok));
break;
}
}
}
}
Ok(())
}