rs-graph 0.6.3

A library for graph algorithms and combinatorial optimization
Documentation
// Copyright (c) 2015, 2016, 2017 Frank Fischer <frank-fischer@shadow-soft.de>
//
// This program is free software: you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see  <http://www.gnu.org/licenses/>
//

//! Reading files in DIMACS format.

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;

/// Error when reading a file in DIMACS format.
quick_error! {
    #[derive(Debug)]
    pub enum DimacsError {
        /// Invalid content of the file.
        Format(line: usize, msg: String) {
            description("format error")
            display("Format error in line {}: {}", line, msg)
        }
        /// Inconsistent data in the file.
        Data(line: usize, msg: String) {
            description("data error")
            display("Data error line {}: {}", line, msg)
        }
        /// A builder error,
        Builder(err: Box<error::Error>) {
            from()
            cause(&**err)
            description(err.description())
            display("Builder error: {}", err)
        }
        /// An IO error.
        IoError(err: io::Error) {
            from()
            cause(err)
            description(err.description())
            display("I/O error: {}", err)
        }
    }
}

/// Iterates over the tokens in a line.
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> {
    /// Returns the next token as `&str`.
    fn str(&mut self) -> Result<&'a str, DimacsError> {
        self.it
            .next()
            .ok_or_else(|| DimacsError::Format(self.line, "expected token".to_string()))
    }

    /// Returns the next token converted to a number.
    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))))
    }

    /// Ensures that there is no next token.
    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(())
        }
    }
}

/// Read a DIMACS file.
///
/// - `fin` is the buffered reader with the file content
/// - `f` is callback called once for each non-comment line with
///   `(c,toks)`, where `c` is the descripter of the line and `toks`
///   an iterator over the tokens
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(())
}