rs-graph 0.14.1

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.

pub mod maxflow;

pub mod graph;
pub use self::graph::read as read_graph;

use std::error;
use std::fmt;
use std::io;
use std::str::{FromStr, SplitWhitespace};

/// Error when reading a file in DIMACS format.
#[derive(Debug)]
pub enum DimacsError {
    Io(io::Error),
    Format { line: usize, msg: String },
    Data { line: usize, msg: String },
}

impl From<io::Error> for DimacsError {
    fn from(err: io::Error) -> Self {
        DimacsError::Io(err)
    }
}

impl fmt::Display for DimacsError {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        use self::DimacsError::*;
        match self {
            Io(err) => err.fmt(fmt),
            Format { line, msg } => write!(fmt, "Format error on line {}: {}", line, msg),
            Data { line, msg } => write!(fmt, "Data error on line {}: {}", line, msg),
        }
    }
}

impl error::Error for DimacsError {
    fn cause(&self) -> Option<&error::Error> {
        match self {
            DimacsError::Io(err) => Some(err),
            _ => None,
        }
    }
}

/// 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 {
            line: self.line,
            msg: "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 {
            line: self.line,
            msg: "expected number".to_string(),
        })).parse()
            .or_else(|e| {
                Err(DimacsError::Format {
                    line: self.line,
                    msg: 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 {
                line: self.line,
                msg: 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 {
        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(())
}