<commit_before>// Copyright (C) 2017 Élisabeth HENRY.
//
// This file is part of Crowbook.
//
// Crowbook is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation, either version 2.1 of the License, or
// (at your option) any later version.
//
// Caribon 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 Lesser General Public License for more details.
//
// You should have received ba copy of the GNU Lesser General Public License
// along with Crowbook.  If not, see <http://www.gnu.org/licenses/>.

use error::Result;

use crowbook_text_processing::escape;

#[cfg(feature="syntect")]
use syntect;

/// Wrapper around syntect, so it can be more easily optionally compiled.
#[cfg(feature="syntect")]
pub struct Syntax {
    syntax_set: syntect::parsing::SyntaxSet,
    theme: syntect::highlighting::Theme,
}

#[cfg(not(feature="syntect"))]
pub struct Syntax {}

#[cfg(feature="syntect")]
impl Syntax {
    /// Creates a new Syntax wrapper
    pub fn new(theme_name: &str) -> Syntax {
        let mut theme_set = syntect::highlighting::ThemeSet::load_defaults();
        let theme = match theme_set.themes.remove(theme_name) {
            Some(theme) => theme,
            None => {
                error!("{}", lformat!("could not set syntect theme to {theme}, defaulting to \"InspiredGithub\"",
                                           theme = theme_name));
                info!("{}", lformat!("valid theme names are: {themes}",
                                          themes = theme_set.themes
                                          .keys()
                                          .map(|s| s.to_owned())
                                          .collect::<Vec<_>>()
                                          .join(", ")));
                theme_set.themes.remove("InspiredGitHub").unwrap()
            }
        };
        Syntax {
            syntax_set: syntect::parsing::SyntaxSet::load_defaults_nonewlines(),
            theme: theme,
        }
    }

    /// Convert a string containing code to HTML
    pub fn to_html(&self, code: &str, language: &str) -> Result<String> {
        let language = strip_language(language);
        let syntax = self.syntax_set.find_syntax_by_token(language)
            .unwrap_or_else(|| self.syntax_set.find_syntax_plain_text());
        let mut h = syntect::easy::HighlightLines::new(syntax, &self.theme);
        let regions = h.highlight(code);
        Ok(format!("
{}
",
                   syntect::html::styles_to_coloured_html(&regions[..],
                                                          syntect::html::IncludeBackground::No)))
    }

    pub fn to_tex(&self, code: &str, language: &str) -> Result<String> {
        let language = strip_language(language);
        use latex::insert_breaks;
        use syntect::highlighting::{BLACK, FONT_STYLE_BOLD, FONT_STYLE_ITALIC, FONT_STYLE_UNDERLINE};
        let syntax = self.syntax_set.find_syntax_by_token(language)
            .unwrap_or_else(|| self.syntax_set.find_syntax_plain_text());
        let mut h = syntect::easy::HighlightLines::new(syntax, &self.theme);
        let regions = h.highlight(code);

        let mut result = String::with_capacity(code.len());
        for (style, text) in regions {
            let mut content = escape::tex(text).into_owned();
            content = insert_breaks(&content);
            content = content.replace('\n', "\\\\{}\n")
                .replace(' ', "\\hphantom{ }\\allowbreak{}");
            content = format!("\\texttt{{{}}}", content);
            if style.foreground != BLACK {
                let r = style.foreground.r as f32 / 255.0;
                let g = style.foreground.g as f32 / 255.0;
                let b = style.foreground.b as f32 / 255.0;
                content = format!("\\textcolor[rgb]{{{r}, {g}, {b}}}{{{text}}}",
                                  r = r,
                                  g = g,
                                  b = b,
                                  text = content);
            }
            if style.font_style.contains(FONT_STYLE_BOLD) {
                content = format!("\\textbf{{{}}}", content);
            }
            if style.font_style.contains(FONT_STYLE_ITALIC) {
                content = format!("\\emph{{{}}}", content);
            }
            if style.font_style.contains(FONT_STYLE_UNDERLINE) {
                content = format!("\\underline{{{}}}", content);
            }
            result.push_str(&content);
        }
        Ok(format!("{{\\sloppy {}}}", result))
    }
}

/// Strip language name of possible other infos, e.g. "rust,ignore" -> "rust"
/// Currently only ',' is done
fn strip_language(language: &str) -> &str {
    let splits: Vec<_> = language
        .split(|c: char| match c {
            ',' => true,
            _ => false
        })
        .collect();
    splits[0].trim()
}

#[cfg(not(feature="syntect"))]
impl Syntax {
    pub fn new( _: &str) -> Syntax {
        error!("{}", lformat!("crowbook was compiled without syntect support, syntax highlighting will be disabled"));
        Syntax {}
    }

    pub fn to_html(&self, code: &str, language: &str) -> Result<String> {
        Ok(format!("
{code}
",
                code = escape::html(code),
                lang = language))
    }

    pub fn to_tex(&self, code: &str, _: &str) -> Result<String> {
        Ok(format!("\\begin{{spverbatim}}{}\\end{{spverbatim}}\n",
                code))
    }
}
<commit_msg>Avoid using deprecated consts from syntect<commit_after>// Copyright (C) 2017 Élisabeth HENRY.
//
// This file is part of Crowbook.
//
// Crowbook is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation, either version 2.1 of the License, or
// (at your option) any later version.
//
// Caribon 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 Lesser General Public License for more details.
//
// You should have received ba copy of the GNU Lesser General Public License
// along with Crowbook.  If not, see <http://www.gnu.org/licenses/>.

use error::Result;

use crowbook_text_processing::escape;

#[cfg(feature="syntect")]
use syntect;

/// Wrapper around syntect, so it can be more easily optionally compiled.
#[cfg(feature="syntect")]
pub struct Syntax {
    syntax_set: syntect::parsing::SyntaxSet,
    theme: syntect::highlighting::Theme,
}

#[cfg(not(feature="syntect"))]
pub struct Syntax {}

#[cfg(feature="syntect")]
impl Syntax {
    /// Creates a new Syntax wrapper
    pub fn new(theme_name: &str) -> Syntax {
        let mut theme_set = syntect::highlighting::ThemeSet::load_defaults();
        let theme = match theme_set.themes.remove(theme_name) {
            Some(theme) => theme,
            None => {
                error!("{}", lformat!("could not set syntect theme to {theme}, defaulting to \"InspiredGithub\"",
                                           theme = theme_name));
                info!("{}", lformat!("valid theme names are: {themes}",
                                          themes = theme_set.themes
                                          .keys()
                                          .map(|s| s.to_owned())
                                          .collect::<Vec<_>>()
                                          .join(", ")));
                theme_set.themes.remove("InspiredGitHub").unwrap()
            }
        };
        Syntax {
            syntax_set: syntect::parsing::SyntaxSet::load_defaults_nonewlines(),
            theme: theme,
        }
    }

    /// Convert a string containing code to HTML
    pub fn to_html(&self, code: &str, language: &str) -> Result<String> {
        let language = strip_language(language);
        let syntax = self.syntax_set.find_syntax_by_token(language)
            .unwrap_or_else(|| self.syntax_set.find_syntax_plain_text());
        let mut h = syntect::easy::HighlightLines::new(syntax, &self.theme);
        let regions = h.highlight(code);
        Ok(format!("
{}
",
                   syntect::html::styles_to_coloured_html(&regions[..],
                                                          syntect::html::IncludeBackground::No)))
    }

    pub fn to_tex(&self, code: &str, language: &str) -> Result<String> {
        let language = strip_language(language);
        use latex::insert_breaks;
        use syntect::highlighting::{Color, FontStyle};
        let syntax = self.syntax_set.find_syntax_by_token(language)
            .unwrap_or_else(|| self.syntax_set.find_syntax_plain_text());
        let mut h = syntect::easy::HighlightLines::new(syntax, &self.theme);
        let regions = h.highlight(code);

        let mut result = String::with_capacity(code.len());
        for (style, text) in regions {
            let mut content = escape::tex(text).into_owned();
            content = insert_breaks(&content);
            content = content.replace('\n', "\\\\{}\n")
                .replace(' ', "\\hphantom{ }\\allowbreak{}");
            content = format!("\\texttt{{{}}}", content);
            if style.foreground != Color::BLACK {
                let r = style.foreground.r as f32 / 255.0;
                let g = style.foreground.g as f32 / 255.0;
                let b = style.foreground.b as f32 / 255.0;
                content = format!("\\textcolor[rgb]{{{r}, {g}, {b}}}{{{text}}}",
                                  r = r,
                                  g = g,
                                  b = b,
                                  text = content);
            }
            if style.font_style.contains(FontStyle::BOLD) {
                content = format!("\\textbf{{{}}}", content);
            }
            if style.font_style.contains(FontStyle::ITALIC) {
                content = format!("\\emph{{{}}}", content);
            }
            if style.font_style.contains(FontStyle::UNDERLINE) {
                content = format!("\\underline{{{}}}", content);
            }
            result.push_str(&content);
        }
        Ok(format!("{{\\sloppy {}}}", result))
    }
}

/// Strip language name of possible other infos, e.g. "rust,ignore" -> "rust"
/// Currently only ',' is done
fn strip_language(language: &str) -> &str {
    let splits: Vec<_> = language
        .split(|c: char| match c {
            ',' => true,
            _ => false
        })
        .collect();
    splits[0].trim()
}

#[cfg(not(feature="syntect"))]
impl Syntax {
    pub fn new( _: &str) -> Syntax {
        error!("{}", lformat!("crowbook was compiled without syntect support, syntax highlighting will be disabled"));
        Syntax {}
    }

    pub fn to_html(&self, code: &str, language: &str) -> Result<String> {
        Ok(format!("
{code}
",
                code = escape::html(code),
                lang = language))
    }

    pub fn to_tex(&self, code: &str, _: &str) -> Result<String> {
        Ok(format!("\\begin{{spverbatim}}{}\\end{{spverbatim}}\n",
                code))
    }
}
<|endoftext|>


<commit_before>#![allow(dead_code)]

use std::net::TcpStream;
use std::io::Read;
use std::io::Write;
use std::str::FromStr;
use std::thread;
use std::sync::mpsc;

use regex::Regex;

// A small subset of IRC command types
#[derive(Debug)]
enum Command {
    ReplyWelcome,
    Pass,
    Nick,
    Join,
    Privmsg,
    Ping,
    Pong,
    Unknown
}

impl Command {
    fn as_str(&self) -> &'static str {
        match *self {
            Command::ReplyWelcome => "RPL_WELCOME",
            Command::Pass => "PASS",
            Command::Nick => "NICK",
            Command::Join => "JOIN",
            Command::Privmsg => "PRIVMSG",
            Command::Ping => "PING",
            Command::Pong => "PONG",
            _ => ""
        }
    }

    fn from_string(command: &str) -> Command {
        match command {
            "001"|"RPL_WELCOME"     =>  Command::ReplyWelcome,
            "PRIVMSG"               =>  Command::Privmsg,
            "PING"                  =>  Command::Ping,
            _                       =>  Command::Unknown
        }
    }
}

// A representation of an IRC message
#[derive(Debug)]
struct IrcMessage {
    prefix: Option<String>,
    command: Command,
    params: Option<Vec<String>>
}

impl IrcMessage {
    fn from_string(msg: String) -> Option<IrcMessage> {
        // Parse a UTF-8 string into our own IRC message structure

        // Dissect the message to identify its prefix (if present), its command (if present), and its
        // arguments (if present)
        //@todo probably a bad idea to have written this regex, google "irc regex" and replace this
        let re = Regex::new(r"(^:(?P<prefix>([:alnum:]|[:punct:])+) )?((?P<command>([:alnum:])+)? ?)(?P<params>.*?)\r").unwrap();
        let cap = re.captures(&msg).unwrap();

        let prefix = cap.name("prefix");
        let command = cap.name("command");
        let params = cap.name("params");

        // Populate an IrcMessage struct with the fields, splitting up the parameters (if present)
        // into a list of Strings
        Some(IrcMessage {
            prefix: match prefix {
                Some(prefix) => Some(FromStr::from_str(prefix).unwrap()),
                None => None
            },

            command: match command {
                Some(command) => Command::from_string(command),
                _ =>  return None // our regex couldn't parse a command; the command is mandatory
            },

            params: match params {
                Some(params) => {
                    // Tokenize the parameters.
                    // Tokenizing them is nontrivial, because of the TRAILING parameter pattern.
                    // So we use regex.
                    //@TODO this regex fails if any middle parameter has a colon in it
                    //@TODO or if the trailing parameter has a \r without a following \n
                    //@todo probably a bad idea to have written this regex, google "irc regex" and replace this
                    let re = Regex::new(r"^(?P<middles>[^:]+)?(:(?P<trailing>[^\r\n]+))?").unwrap();
                    let cap = re.captures(params).unwrap();

                    let middles = cap.name("middles");
                    let trailing = cap.name("trailing");

                    let mut paramvec = Vec::new();

                    match middles {
                        Some(middles)   => {
                            for middle in middles.trim().split(" ") {
                                paramvec.push(FromStr::from_str(middle).unwrap());
                            }
                        },
                        _               => ()
                    }

                    match trailing {
                        Some(trailing)  => { paramvec.push(FromStr::from_str(trailing).unwrap()) },
                        _               => ()
                    };

                    Some(paramvec)
                },
                None => None
            }
        })
    }

    // Assumes that the last parameter is the trailing parameter
    fn into_string(self) -> String {
        let mut result = String::new();

        if self.prefix.is_some() {
            result.push_str(":");
            result.push_str(&self.prefix.unwrap());
            result.push_str(" ");
        }

        result.push_str(&self.command.as_str());
        result.push_str(" ");

        if self.params.is_some() {
            // C-style... is there a better way to identify the last element?
            let params = self.params.unwrap();
            let iter = params.iter();
            let num_params = iter.clone().count();
            let mut param_on = 0;

            for param in iter {
                param_on = param_on + 1;
                if param_on == num_params {
                    result.push_str(":");
                }
                result.push_str(&param);
                if param_on != num_params {
                    result.push_str(" ");
                }
            }
        }

        result.push_str("\r\n");

        result
    }
}

pub struct IrcConnection {
    join_handle: thread::JoinHandle<()>,
    rx_privmsg: mpsc::Receiver<Vec<String>>,
    tx_kill: mpsc::Sender<()>
}

impl IrcConnection {
    pub fn spawn(server: String, pass: String, nick: String, channel: String) -> Result<IrcConnection, ()> {
        // Establish a TCP stream with our target server
        let stream = match TcpStream::connect(&server[..]) {
            Ok(stream) => stream,
            Err(_) => return Err(())
        };

        // Create two application-local channels: one for passing received privmsgs to our user app,
        // and one for listening from our user app for a kill command
        let (tx_privmsg, rx_privmsg) = mpsc::channel();
        let (tx_kill, rx_kill) = mpsc::channel();

        // We're going to spawn a thread that services an IRC connection - we contain all of the
        // information that thread will need in an "internal" IRC connection struct and give it
        // ownership of that struct
        let irc_connection_internal = IrcConnectionInternal { tcp_stream: stream, server: server, pass: pass, nick: nick, channel: channel };

        // Spawn an IRC connection servicing thread. This thread maintains an IRC connection and
        // passes chat messages (privmsgs) through one of its channels
        let join_handle = thread::spawn(move|| {
            // Send the server our credentials
            //@todo implement log in failure recovery
            match irc_connection_internal.send_credentials() {
                Ok(_) => (),
                Err(_) => panic!("Unable to send credentials!")
            }

            match irc_connection_internal.send_join() {
                Ok(_) => (),
                Err(_) => panic!("Unable to join target channel!")
            }

            loop {
                // Check for kill signal; kill this thread if received
                match rx_kill.try_recv() {
                    Ok(()) => return,
                    Err(_) => ()
                }

                let m = irc_connection_internal.get_message();
                println!("\t\t::prefix:: {:?} ::command:: {:?}: ::params::{:?}", m.prefix, m.command, m.params);
                match m.command {
                    // as a bot, all we really care about is:
                    // did the server ping us? if so, pong it
                    // did another client send a message? if so, pass it to our user
                    Command::Ping => {
                        match irc_connection_internal.send_pong() {
                            Ok(_) => (),
                            Err(_) => panic!("Unable to send pong!")
                        }
                    },
                    Command::Privmsg => {
                        match m.params {
                            Some(params) => {
                                for x in params.iter() {
                                    println!("\t {}", x);
                                }

                                if params.len() > 0 {
                                    match tx_privmsg.send(params) {
                                        Ok(_) => (),
                                        Err(err) => println!("Error sending received IRC message to user\
                                                              app: {}", err)
                                    };
                                }
                            },
                            _ => ()
                        }
                    }
                    _ => ()
                }
            }
        });

        Ok( IrcConnection { join_handle: join_handle, rx_privmsg: rx_privmsg, tx_kill: tx_kill } )
    }

    pub fn join(self) {
        self.join_handle.join();
    }

    pub fn receive_privmsg(&self) -> Vec<String> {
        self.rx_privmsg.recv().unwrap()
    }

    pub fn kill(&self) {
        self.tx_kill.send(());
    }
}

struct IrcConnectionInternal {
    tcp_stream: TcpStream,

    server: String,
    pass: String,
    nick: String,
    channel: String,
}

impl IrcConnectionInternal {
    // Get a message from an IRC channel.
    //@todo make this nonblocking - any way to do this without function-local static?
    fn get_message(&self) -> IrcMessage {
        loop {
            // Receive a message from the server as raw bytes.
            // We'll convert it to a String once we've received the whole thing, to simplify parsing
            let mut response: Vec<u8> = Vec::new();

            // Read from the TCP stream until we get CRLF (which signals the termination of an IRC message)
            // or the socket read fails
            loop {
                let mut read_byte: Vec<u8> = Vec::with_capacity(1);

                let read_result = (&(self.tcp_stream)).take(1).read_to_end(&mut read_byte);
                match read_result {
                    Result::Ok(_) => {
                        response.push(*(read_byte.get(0).unwrap())); //@todo handle None
                        if last_two_are_crlf(&response) {
                            break;
                        }
                    },
                    Result::Err(error)      => {
                        println!("Stream read error: {:?}", error);
                        break;
                    }
                }
            }

            // Convert our raw byte vector into a String for easier, native processing
            //@TODO Better handle invalid messages
            let msg_str = String::from_utf8(response).unwrap();

            println!("IN  <--\t{}", msg_str);

            match IrcMessage::from_string(msg_str) {
                Some(msg) => return msg,
                _ => () // the string we received couldn't be parsed as a valid IRC message
            }
        }
    }

    // Consider making a Message serializer...
    fn send_message(&self, message: IrcMessage) -> Result<(), ()> {
        let message_string = message.into_string();

        println!("OUT -->\t{}", message_string);

        match (&(self.tcp_stream)).write_all(message_string.as_bytes()) {
            Ok(_) => Ok(()),
            Err(_) => Err(())
        }
    }

    fn send_credentials(&self) -> Result<(), ()> {
        let pass_message = IrcMessage { prefix: None, command: Command::Pass, params: Some(vec![self.pass.clone()]) };
        let nick_message = IrcMessage { prefix: None, command: Command::Nick, params: Some(vec![self.nick.clone()]) };

        try!(self.send_message(pass_message));
        try!(self.send_message(nick_message));

        Ok(())
    }

    fn send_join(&self) -> Result<(), ()> {
        let join_message = IrcMessage { prefix: None, command: Command::Join, params: Some(vec![self.channel.clone()]) };

        try!(self.send_message(join_message));

        Ok(())
    }

    fn send_pong(&self) -> Result<(), ()> {
        let pong_message = IrcMessage { prefix: None, command: Command::Pong, params: None };

        try!(self.send_message(pong_message));

        Ok(())
    }
}

fn last_two_are_crlf(myvec: &Vec<u8>) -> bool {
    let myvec_len = myvec.len();

    if myvec_len < 2 {
        return false;
    }

    match (myvec[myvec_len-2], myvec[myvec_len-1]) {
        (b'\r', b'\n')  => true,
        _               => false
    }
}<commit_msg>Cleanly output parsed IRC messages<commit_after>#![allow(dead_code)]

use std::net::TcpStream;
use std::io::Read;
use std::io::Write;
use std::str::FromStr;
use std::thread;
use std::sync::mpsc;

use regex::Regex;

// A small subset of IRC command types
#[derive(Debug)]
enum Command {
    ReplyWelcome,
    Pass,
    Nick,
    Join,
    Privmsg,
    Ping,
    Pong,
    Unknown
}

impl Command {
    fn as_str(&self) -> &'static str {
        match *self {
            Command::ReplyWelcome => "RPL_WELCOME",
            Command::Pass => "PASS",
            Command::Nick => "NICK",
            Command::Join => "JOIN",
            Command::Privmsg => "PRIVMSG",
            Command::Ping => "PING",
            Command::Pong => "PONG",
            _ => ""
        }
    }

    fn from_string(command: &str) -> Command {
        match command {
            "001"|"RPL_WELCOME"     =>  Command::ReplyWelcome,
            "PRIVMSG"               =>  Command::Privmsg,
            "PING"                  =>  Command::Ping,
            _                       =>  Command::Unknown
        }
    }
}

// A representation of an IRC message
#[derive(Debug)]
struct IrcMessage {
    prefix: Option<String>,
    command: Command,
    params: Option<Vec<String>>
}

impl IrcMessage {
    fn from_string(msg: String) -> Option<IrcMessage> {
        // Parse a UTF-8 string into our own IRC message structure

        // Dissect the message to identify its prefix (if present), its command (if present), and its
        // arguments (if present)
        //@todo probably a bad idea to have written this regex, google "irc regex" and replace this
        let re = Regex::new(r"(^:(?P<prefix>([:alnum:]|[:punct:])+) )?((?P<command>([:alnum:])+)? ?)(?P<params>.*?)\r").unwrap();
        let cap = re.captures(&msg).unwrap();

        let prefix = cap.name("prefix");
        let command = cap.name("command");
        let params = cap.name("params");

        // Populate an IrcMessage struct with the fields, splitting up the parameters (if present)
        // into a list of Strings
        Some(IrcMessage {
            prefix: match prefix {
                Some(prefix) => Some(FromStr::from_str(prefix).unwrap()),
                None => None
            },

            command: match command {
                Some(command) => Command::from_string(command),
                _ =>  return None // our regex couldn't parse a command; the command is mandatory
            },

            params: match params {
                Some(params) => {
                    // Tokenize the parameters.
                    // Tokenizing them is nontrivial, because of the TRAILING parameter pattern.
                    // So we use regex.
                    //@TODO this regex fails if any middle parameter has a colon in it
                    //@TODO or if the trailing parameter has a \r without a following \n
                    //@todo probably a bad idea to have written this regex, google "irc regex" and replace this
                    let re = Regex::new(r"^(?P<middles>[^:]+)?(:(?P<trailing>[^\r\n]+))?").unwrap();
                    let cap = re.captures(params).unwrap();

                    let middles = cap.name("middles");
                    let trailing = cap.name("trailing");

                    let mut paramvec = Vec::new();

                    match middles {
                        Some(middles)   => {
                            for middle in middles.trim().split(" ") {
                                paramvec.push(FromStr::from_str(middle).unwrap());
                            }
                        },
                        _               => ()
                    }

                    match trailing {
                        Some(trailing)  => { paramvec.push(FromStr::from_str(trailing).unwrap()) },
                        _               => ()
                    };

                    Some(paramvec)
                },
                None => None
            }
        })
    }

    // Assumes that the last parameter is the trailing parameter
    fn into_string(self) -> String {
        let mut result = String::new();

        if self.prefix.is_some() {
            result.push_str(":");
            result.push_str(&self.prefix.unwrap());
            result.push_str(" ");
        }

        result.push_str(&self.command.as_str());
        result.push_str(" ");

        if self.params.is_some() {
            // C-style... is there a better way to identify the last element?
            let params = self.params.unwrap();
            let iter = params.iter();
            let num_params = iter.clone().count();
            let mut param_on = 0;

            for param in iter {
                param_on = param_on + 1;
                if param_on == num_params {
                    result.push_str(":");
                }
                result.push_str(&param);
                if param_on != num_params {
                    result.push_str(" ");
                }
            }
        }

        result.push_str("\r\n");

        result
    }
}

pub struct IrcConnection {
    join_handle: thread::JoinHandle<()>,
    rx_privmsg: mpsc::Receiver<Vec<String>>,
    tx_kill: mpsc::Sender<()>
}

impl IrcConnection {
    pub fn spawn(server: String, pass: String, nick: String, channel: String) -> Result<IrcConnection, ()> {
        // Establish a TCP stream with our target server
        let stream = match TcpStream::connect(&server[..]) {
            Ok(stream) => stream,
            Err(_) => return Err(())
        };

        // Create two application-local channels: one for passing received privmsgs to our user app,
        // and one for listening from our user app for a kill command
        let (tx_privmsg, rx_privmsg) = mpsc::channel();
        let (tx_kill, rx_kill) = mpsc::channel();

        // We're going to spawn a thread that services an IRC connection - we contain all of the
        // information that thread will need in an "internal" IRC connection struct and give it
        // ownership of that struct
        let irc_connection_internal = IrcConnectionInternal { tcp_stream: stream, server: server, pass: pass, nick: nick, channel: channel };

        // Spawn an IRC connection servicing thread. This thread maintains an IRC connection and
        // passes chat messages (privmsgs) through one of its channels
        let join_handle = thread::spawn(move|| {
            // Send the server our credentials
            //@todo implement log in failure recovery
            match irc_connection_internal.send_credentials() {
                Ok(_) => (),
                Err(_) => panic!("Unable to send credentials!")
            }

            match irc_connection_internal.send_join() {
                Ok(_) => (),
                Err(_) => panic!("Unable to join target channel!")
            }

            loop {
                // Check for kill signal; kill this thread if received
                match rx_kill.try_recv() {
                    Ok(()) => return,
                    Err(_) => ()
                }

                let m = irc_connection_internal.get_message();
                println!("\t\t::prefix:: {:?} ::command:: {:?}: ::params::{:?}\n", m.prefix, m.command, m.params);
                match m.command {
                    // as a bot, all we really care about is:
                    // did the server ping us? if so, pong it
                    // did another client send a message? if so, pass it to our user
                    Command::Ping => {
                        match irc_connection_internal.send_pong() {
                            Ok(_) => (),
                            Err(_) => panic!("Unable to send pong!")
                        }
                    },
                    Command::Privmsg => {
                        match m.params {
                            Some(params) => {
                                for x in params.iter() {
                                    println!("\t {}", x);
                                }

                                if params.len() > 0 {
                                    match tx_privmsg.send(params) {
                                        Ok(_) => (),
                                        Err(err) => println!("Error sending received IRC message to user\
                                                              app: {}", err)
                                    };
                                }
                            },
                            _ => ()
                        }
                    }
                    _ => ()
                }
            }
        });

        Ok( IrcConnection { join_handle: join_handle, rx_privmsg: rx_privmsg, tx_kill: tx_kill } )
    }

    pub fn join(self) {
        self.join_handle.join();
    }

    pub fn receive_privmsg(&self) -> Vec<String> {
        self.rx_privmsg.recv().unwrap()
    }

    pub fn kill(&self) {
        self.tx_kill.send(());
    }
}

struct IrcConnectionInternal {
    tcp_stream: TcpStream,

    server: String,
    pass: String,
    nick: String,
    channel: String,
}

impl IrcConnectionInternal {
    // Get a message from an IRC channel.
    //@todo make this nonblocking - any way to do this without function-local static?
    fn get_message(&self) -> IrcMessage {
        loop {
            // Receive a message from the server as raw bytes.
            // We'll convert it to a String once we've received the whole thing, to simplify parsing
            let mut response: Vec<u8> = Vec::new();

            // Read from the TCP stream until we get CRLF (which signals the termination of an IRC message)
            // or the socket read fails
            loop {
                let mut read_byte: Vec<u8> = Vec::with_capacity(1);

                let read_result = (&(self.tcp_stream)).take(1).read_to_end(&mut read_byte);
                match read_result {
                    Result::Ok(_) => {
                        response.push(*(read_byte.get(0).unwrap())); //@todo handle None
                        if last_two_are_crlf(&response) {
                            break;
                        }
                    },
                    Result::Err(error)      => {
                        println!("Stream read error: {:?}", error);
                        break;
                    }
                }
            }

            // Convert our raw byte vector into a String for easier, native processing
            //@TODO Better handle invalid messages
            let msg_str = String::from_utf8(response).unwrap();

            println!("IN  <--\t{}", msg_str);

            match IrcMessage::from_string(msg_str) {
                Some(msg) => return msg,
                _ => () // the string we received couldn't be parsed as a valid IRC message
            }
        }
    }

    // Consider making a Message serializer...
    fn send_message(&self, message: IrcMessage) -> Result<(), ()> {
        let message_string = message.into_string();

        println!("OUT -->\t{}", message_string);

        match (&(self.tcp_stream)).write_all(message_string.as_bytes()) {
            Ok(_) => Ok(()),
            Err(_) => Err(())
        }
    }

    fn send_credentials(&self) -> Result<(), ()> {
        let pass_message = IrcMessage { prefix: None, command: Command::Pass, params: Some(vec![self.pass.clone()]) };
        let nick_message = IrcMessage { prefix: None, command: Command::Nick, params: Some(vec![self.nick.clone()]) };

        try!(self.send_message(pass_message));
        try!(self.send_message(nick_message));

        Ok(())
    }

    fn send_join(&self) -> Result<(), ()> {
        let join_message = IrcMessage { prefix: None, command: Command::Join, params: Some(vec![self.channel.clone()]) };

        try!(self.send_message(join_message));

        Ok(())
    }

    fn send_pong(&self) -> Result<(), ()> {
        let pong_message = IrcMessage { prefix: None, command: Command::Pong, params: None };

        try!(self.send_message(pong_message));

        Ok(())
    }
}

fn last_two_are_crlf(myvec: &Vec<u8>) -> bool {
    let myvec_len = myvec.len();

    if myvec_len < 2 {
        return false;
    }

    match (myvec[myvec_len-2], myvec[myvec_len-1]) {
        (b'\r', b'\n')  => true,
        _               => false
    }
}<|endoftext|>


<commit_before>use lazy_static::lazy_static;
use std::env;
use std::path::PathBuf;

lazy_static! {
    pub static ref CARGO_TARGET_DIR: PathBuf = {
        match env::var_os("CARGO_TARGET_DIR") {
            Some(v) => v.into(),
            None => "target".into(),
        }
    };
    pub static ref TARGET_LIB: PathBuf = {
        if let Some(path) = option_env!("TARGET_LIBS") {
            path.into()
        } else {
            let mut dir = CARGO_TARGET_DIR.clone();
            if let Some(target) = env::var_os("CARGO_BUILD_TARGET") {
                dir.push(target);
            }
            dir.push(env!("PROFILE"));
            dir
        }
    };
}

#[must_use]
pub fn is_rustc_test_suite() -> bool {
    option_env!("RUSTC_TEST_SUITE").is_some()
}
<commit_msg>Fix run-pass tests when CARGO_TARGET_DIR is not set<commit_after>use cargo_metadata::MetadataCommand;
use lazy_static::lazy_static;
use std::env;
use std::path::PathBuf;

lazy_static! {
    pub static ref CARGO_TARGET_DIR: PathBuf = {
        match env::var_os("CARGO_TARGET_DIR") {
            Some(v) => v.into(),
            None => MetadataCommand::new().exec().unwrap().target_directory,
        }
    };
    pub static ref TARGET_LIB: PathBuf = {
        if let Some(path) = option_env!("TARGET_LIBS") {
            path.into()
        } else {
            let mut dir = CARGO_TARGET_DIR.clone();
            if let Some(target) = env::var_os("CARGO_BUILD_TARGET") {
                dir.push(target);
            }
            dir.push(env!("PROFILE"));
            dir
        }
    };
}

#[must_use]
pub fn is_rustc_test_suite() -> bool {
    option_env!("RUSTC_TEST_SUITE").is_some()
}
<|endoftext|>


<commit_before>//! **UnionFind** is a disjoint-set data structure.

use std::num;

/// **UnionFind\<K\>** is a disjoint-set data structure. It tracks set membership of *n* elements
/// indexed from *0* to *n - 1*. The scalar type is **K** which must be an unsigned integer type.
///
/// http://en.wikipedia.org/wiki/Disjoint-set_data_structure
///
/// Too awesome not to quote:
///
/// “The amortized time per operation is **O(α(n))** where **α(n)** is the
/// inverse of **f(x) = A(x, x)** with **A** being the extremely fast-growing Ackermann function.”
#[derive(Show, Clone)]
pub struct UnionFind<K> where K: num::UnsignedInt
{
    // For element at index *i*, store the index of its representative; the reprsentative itself
    // stores its own index. This forms equivalence classes which are the disjoint sets, each
    // with a unique representative.
    parent: Vec<K>,
    // It is a balancing tree structure,
    // so the ranks are logarithmic in the size of the container -- a byte is more than enough.
    //
    // Rank is separated out both to save space and to save cache in when searching in the parent
    // vector.
    rank: Vec<u8>,
}

#[inline]
fn to_uint<K: num::UnsignedInt>(x: K) -> uint { x.to_uint().unwrap() }

#[inline]
unsafe fn get_unchecked<K>(xs: &[K], index: uint) -> &K
{
    debug_assert!(index < xs.len());
    xs.get_unchecked(index)
}

impl<K> UnionFind<K> where K: num::UnsignedInt
{
    /// Create a new **UnionFind** of **n** disjoint sets.
    pub fn new(n: uint) -> Self
    {
        let mut parent = Vec::with_capacity(n);
        let mut rank = Vec::with_capacity(n);

        let mut i: K = num::Int::zero();
        // unroll the first iteration to avoid wraparound in i for K=u8, n=256.
        rank.push(0);
        parent.push(i);
        for _ in range(1, n) {
            i = i + num::Int::one();
            rank.push(0);
            parent.push(i);
        }
        UnionFind{parent: parent, rank: rank}
    }

    /// Return the representative for **x**.
    ///
    /// **Panics** if **x** is out of bounds.
    pub fn find(&self, x: K) -> K
    {
        assert!(to_uint(x) < self.parent.len());
        unsafe {
            let mut x = x;
            loop {
                // Use unchecked indexing because we can trust the internal set ids.
                let xparent = *get_unchecked(&*self.parent, to_uint(x));
                if xparent == x {
                    break
                }
                x = xparent;
            }
            x
        }
    }

    /// Return the representative for **x**.
    ///
    /// Write back the found representative, flattening the internal
    /// datastructure in the process and quicken future lookups.
    ///
    /// **Panics** if **x** is out of bounds.
    pub fn find_mut(&mut self, x: K) -> K
    {
        assert!(to_uint(x) < self.parent.len());
        unsafe {
            self.find_mut_recursive(x)
        }
    }

    unsafe fn find_mut_recursive(&mut self, x: K) -> K
    {
        let xparent = *get_unchecked(&*self.parent, to_uint(x));
        if xparent != x {
            let xrep = self.find_mut_recursive(xparent);
            let xparent = self.parent.get_unchecked_mut(to_uint(x));
            *xparent = xrep;
            *xparent
        } else {
            xparent
        }
    }

    /// Unify the two sets containing **x** and **y**.
    ///
    /// Return **false** if the sets were already the same, **true** if they were unified.
    ///
    /// **Panics** if **x** or **y** is out of bounds.
    pub fn union(&mut self, x: K, y: K) -> bool
    {
        if x == y {
            return false
        }
        let xrep = self.find_mut(x);
        let yrep = self.find_mut(y);

        if xrep == yrep {
            return false
        }

        let xrepu = to_uint(xrep);
        let yrepu = to_uint(yrep);
        let xrank = self.rank[xrepu];
        let yrank = self.rank[yrepu];

        // The rank corresponds roughly to the depth of the treeset, so put the
        // smaller set below the larger
        if xrank < yrank {
            self.parent[xrepu] = yrep;
        } else if xrank > yrank {
            self.parent[yrepu] = xrep;
        } else {
            // put y below x when equal.
            self.parent[yrepu] = xrep;
            self.rank[xrepu] += 1;
        }
        true
    }
}
<commit_msg>UnionFind: Doc fix and ::new(0) fix.<commit_after>//! **UnionFind** is a disjoint-set data structure.

use std::num;

/// **UnionFind\<K\>** is a disjoint-set data structure. It tracks set membership of *n* elements
/// indexed from *0* to *n - 1*. The scalar type is **K** which must be an unsigned integer type.
///
/// http://en.wikipedia.org/wiki/Disjoint-set_data_structure
///
/// Too awesome not to quote:
///
/// “The amortized time per operation is **O(α(n))** where **α(n)** is the
/// inverse of **f(x) = A(x, x)** with **A** being the extremely fast-growing Ackermann function.”
#[derive(Show, Clone)]
pub struct UnionFind<K> where K: num::UnsignedInt
{
    // For element at index *i*, store the index of its parent; the representative itself
    // stores its own index. This forms equivalence classes which are the disjoint sets, each
    // with a unique representative.
    parent: Vec<K>,
    // It is a balancing tree structure,
    // so the ranks are logarithmic in the size of the container -- a byte is more than enough.
    //
    // Rank is separated out both to save space and to save cache in when searching in the parent
    // vector.
    rank: Vec<u8>,
}

#[inline]
fn to_uint<K: num::UnsignedInt>(x: K) -> uint { x.to_uint().unwrap() }

#[inline]
unsafe fn get_unchecked<K>(xs: &[K], index: uint) -> &K
{
    debug_assert!(index < xs.len());
    xs.get_unchecked(index)
}

impl<K> UnionFind<K> where K: num::UnsignedInt
{
    /// Create a new **UnionFind** of **n** disjoint sets.
    pub fn new(n: uint) -> Self
    {
        let mut parent = Vec::with_capacity(n);
        let mut rank = Vec::with_capacity(n);

        for _ in range(0, n) {
            rank.push(0)
        }

        // unroll the first iteration to avoid wraparound in i for K=u8, n=256.
        let mut i: K = num::Int::zero();
        if n > 0 {
            parent.push(i);
        }
        for _ in range(1, n) {
            i = i + num::Int::one();
            parent.push(i);
        }
        UnionFind{parent: parent, rank: rank}
    }

    /// Return the representative for **x**.
    ///
    /// **Panics** if **x** is out of bounds.
    pub fn find(&self, x: K) -> K
    {
        assert!(to_uint(x) < self.parent.len());
        unsafe {
            let mut x = x;
            loop {
                // Use unchecked indexing because we can trust the internal set ids.
                let xparent = *get_unchecked(&*self.parent, to_uint(x));
                if xparent == x {
                    break
                }
                x = xparent;
            }
            x
        }
    }

    /// Return the representative for **x**.
    ///
    /// Write back the found representative, flattening the internal
    /// datastructure in the process and quicken future lookups.
    ///
    /// **Panics** if **x** is out of bounds.
    pub fn find_mut(&mut self, x: K) -> K
    {
        assert!(to_uint(x) < self.parent.len());
        unsafe {
            self.find_mut_recursive(x)
        }
    }

    unsafe fn find_mut_recursive(&mut self, x: K) -> K
    {
        let xparent = *get_unchecked(&*self.parent, to_uint(x));
        if xparent != x {
            let xrep = self.find_mut_recursive(xparent);
            let xparent = self.parent.get_unchecked_mut(to_uint(x));
            *xparent = xrep;
            *xparent
        } else {
            xparent
        }
    }

    /// Unify the two sets containing **x** and **y**.
    ///
    /// Return **false** if the sets were already the same, **true** if they were unified.
    ///
    /// **Panics** if **x** or **y** is out of bounds.
    pub fn union(&mut self, x: K, y: K) -> bool
    {
        if x == y {
            return false
        }
        let xrep = self.find_mut(x);
        let yrep = self.find_mut(y);

        if xrep == yrep {
            return false
        }

        let xrepu = to_uint(xrep);
        let yrepu = to_uint(yrep);
        let xrank = self.rank[xrepu];
        let yrank = self.rank[yrepu];

        // The rank corresponds roughly to the depth of the treeset, so put the
        // smaller set below the larger
        if xrank < yrank {
            self.parent[xrepu] = yrep;
        } else if xrank > yrank {
            self.parent[yrepu] = xrep;
        } else {
            // put y below x when equal.
            self.parent[yrepu] = xrep;
            self.rank[xrepu] += 1;
        }
        true
    }
}
<|endoftext|>


<commit_before>use std::fmt::{Display, Formatter, Error};

use assembler::Assemble;
use disassembler::Disassemble;

use definitions::{GenDefinition};

#[allow(non_camel_case_types)]
#[derive(Clone,Copy,Debug)]
pub enum Arch {
    X86,
    X86_64,
    Arm,
    Arm64,
    Thumb,
    Mips
}

/// The trait that has to be implemented for running the synthetizer
pub trait Native: GenDefinition + Assemble + Disassemble { }
impl<T> Native for T where T: GenDefinition + Assemble + Disassemble {}

#[derive(Clone, Debug)]
pub struct Opnd {
    pub len: Option<u32>,
    pub text: String
}

#[derive(Clone, Debug)]
pub struct Instruction {
    pub mnemonic: String,
    pub opnds: Vec<Opnd>,
}

impl Opnd {
    pub fn new(text: &str, len: Option<u32>) -> Opnd {
        Opnd { text: text.to_owned(), len: len }
    }
    pub fn text(&self) -> &str { &self.text }
}

impl Instruction {
    pub fn new(mnemonic: &str, opnds: &[(&str, Option<u32>)]) -> Instruction
    {
        Instruction {
            mnemonic: mnemonic.to_owned(),
            opnds: opnds.into_iter()
                .map(
                    |&(s, len)|
                    Opnd::new(s, len))
                .collect()
        }
    }

    pub fn to_text(&self) -> String {
        let opnds: String = self.opnds.iter()
            .map(|s| s.text())
            .collect::<Vec<&str>>()
            .join(",");
        format!("{} {}", self.mnemonic, opnds)
    }

    pub fn assemble<T: Assemble>(&self) -> Option<Vec<u8>> {
        let s = self.to_text();
        T::assemble(&s)
    }

    pub fn get_opnds(&self) -> &[Opnd] { &self.opnds }
    pub fn get_mnemonic(&self) -> &str { &self.mnemonic }
}

impl Display for Instruction {
    fn fmt(&self, formatter: &mut Formatter) -> Result<(), Error> {
        let _ = formatter.write_str(&self.mnemonic);
        let _ = formatter.write_str(" ");
        for opnd in &self.opnds {
            let _ = formatter.write_str(opnd.text());
        }
        Ok(())
    }
}
<commit_msg>adding PartialEq to Opnd and Instruction<commit_after>use std::fmt::{Display, Formatter, Error};

use assembler::Assemble;
use disassembler::Disassemble;

use definitions::{GenDefinition};

#[allow(non_camel_case_types)]
#[derive(Clone,Copy,Debug)]
pub enum Arch {
    X86,
    X86_64,
    Arm,
    Arm64,
    Thumb,
    Mips
}

/// The trait that has to be implemented for running the synthetizer
pub trait Native: GenDefinition + Assemble + Disassemble { }
impl<T> Native for T where T: GenDefinition + Assemble + Disassemble {}

#[derive(Clone,Debug,PartialEq)]
pub struct Opnd {
    pub len: Option<u32>,
    pub text: String
}

#[derive(Clone,Debug,PartialEq)]
pub struct Instruction {
    pub mnemonic: String,
    pub opnds: Vec<Opnd>,
}

impl Opnd {
    pub fn new(text: &str, len: Option<u32>) -> Opnd {
        Opnd { text: text.to_owned(), len: len }
    }
    pub fn text(&self) -> &str { &self.text }
}

impl Instruction {
    pub fn new(mnemonic: &str, opnds: &[(&str, Option<u32>)]) -> Instruction
    {
        Instruction {
            mnemonic: mnemonic.to_owned(),
            opnds: opnds.into_iter()
                .map(
                    |&(s, len)|
                    Opnd::new(s, len))
                .collect()
        }
    }

    pub fn to_text(&self) -> String {
        let opnds: String = self.opnds.iter()
            .map(|s| s.text())
            .collect::<Vec<&str>>()
            .join(",");
        format!("{} {}", self.mnemonic, opnds)
    }

    pub fn assemble<T: Assemble>(&self) -> Option<Vec<u8>> {
        let s = self.to_text();
        T::assemble(&s)
    }

    pub fn get_opnds(&self) -> &[Opnd] { &self.opnds }
    pub fn get_mnemonic(&self) -> &str { &self.mnemonic }
}

impl Display for Instruction {
    fn fmt(&self, formatter: &mut Formatter) -> Result<(), Error> {
        let _ = formatter.write_str(&self.mnemonic);
        let _ = formatter.write_str(" ");
        for opnd in &self.opnds {
            let _ = formatter.write_str(opnd.text());
        }
        Ok(())
    }
}
<|endoftext|>


<commit_before>use std::slice;

use std::marker;

pub trait ModuleStruct<'a> {
	fn init_module(&mut self);
}

struct TorchBackend {}
struct Parameter {}

pub struct Module<'a> {
	pub _name: &'a str,
	_backend : TorchBackend,
//	_buffers: HashTable<&str, Tensor>
//	_backward_hooks:
//	_forward_hooks:
	_params: Vec<&'a str>,
    _modulesp: Vec<*mut Module<'a>>,
	training: bool,
}
pub struct ModuleIter<'module, 'iter> {
	mod_iter: slice::IterMut<'iter, *mut Module<'module> >,
//	 _marker: marker::PhantomData<&'module Module<'module>>,
}

impl <'a>Module<'a> {
	pub fn new() -> Module<'a> {
		Module {_name: "", _backend: TorchBackend {}, _params: Vec::new(),
		_modulesp: Vec::new(), training: true }
	}
	#[inline]
    fn as_mut_ptr(&mut self) -> *mut Module<'a> {
        self as *mut Module<'a>
    }
    pub fn add_module(&mut self, module: &mut ModIntf<'a>) {
    	self._modulesp.push(module.delegate().as_mut_ptr())

    }
	pub fn modules_iter<'b>(&mut self) -> ModuleIter<'a, 'b> {
		ModuleIter {mod_iter: self._modulesp.iter_mut()}  //_marker: marker::PhantomData } }
	}
}

pub trait ModIntf<'a> {
	fn delegate(&mut self) -> &mut Module<'a>;
	fn forward(&mut self /* Tensor */ ) /* -> Tensor */;
}

#[derive(ModParse)]
pub struct Linear<'a> {
	delegate: Module<'a> ,
	in_features: u32,
}

impl <'a>Linear<'a> {
	pub fn new(/* args: LinearArgs */) -> Linear<'a> {
		let mut t = Linear {delegate: Module::new(), in_features: 0 };
		t.init_module();
		t
	}
}

impl <'a> ModIntf<'a> for Linear<'a>  {
	fn delegate(&mut self) -> &mut Module<'a> {
		&mut self.delegate
	}
	fn forward(&mut self/* Tensor */) /* -> Tensor */ {

	}
}

<commit_msg>create iterator that converts pointers back to mutable references<commit_after>use std::slice;

use std::marker;

pub trait ModuleStruct<'a> {
	fn init_module(&mut self);
}

struct TorchBackend {}
struct Parameter {}

pub struct Module<'a> {
	pub _name: &'a str,
	_backend : TorchBackend,
//	_buffers: HashTable<&str, Tensor>
//	_backward_hooks:
//	_forward_hooks:
	_params: Vec<&'a str>,
    _modulesp: Vec<*mut Module<'a>>,
	training: bool,
}
pub struct ModuleIterMut<'a, T: 'a> {
	mod_iter: slice::IterMut<'a, *mut T>,
//	 _marker: marker::PhantomData<&'module Module<'module>>,
}

impl <'a>Iterator for ModuleIterMut<'a, Module<'a>> {
	type Item = &'a mut Module<'a>;
	fn next(&mut self) -> Option<Self::Item> {
		if let Some(t) = self.mod_iter.next() {
			Some(unsafe { &mut **t as Self::Item })
		} else {
			None
		}
	}
}

impl <'a>Module<'a> {
	pub fn new() -> Module<'a> {
		Module {_name: "", _backend: TorchBackend {}, _params: Vec::new(),
		_modulesp: Vec::new(), training: true }
	}
	#[inline]
    fn as_mut_ptr(&mut self) -> *mut Module<'a> {
        self as *mut Module<'a>
    }
    pub fn add_module(&mut self, module: &mut ModIntf<'a>) {
    	self._modulesp.push(module.delegate().as_mut_ptr())

    }
	pub fn modules_iter_mut(&mut self) -> ModuleIterMut<Module<'a> > {
		ModuleIterMut {mod_iter: self._modulesp.iter_mut()}  //_marker: marker::PhantomData } }
	}
}

pub trait ModIntf<'a> {
	fn delegate(&mut self) -> &mut Module<'a>;
	fn forward(&mut self /* Tensor */ ) /* -> Tensor */;
}

#[derive(ModParse)]
pub struct Linear<'a> {
	delegate: Module<'a> ,
	in_features: u32,
}

impl <'a>Linear<'a> {
	pub fn new(/* args: LinearArgs */) -> Linear<'a> {
		let mut t = Linear {delegate: Module::new(), in_features: 0 };
		t.init_module();
		t
	}
}

impl <'a> ModIntf<'a> for Linear<'a>  {
	fn delegate(&mut self) -> &mut Module<'a> {
		&mut self.delegate
	}
	fn forward(&mut self/* Tensor */) /* -> Tensor */ {

	}
}

<|endoftext|>


<commit_before>/* Cymbalum, Molecular Simulation in Rust - Copyright (C) 2015 Guillaume Fraux
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/
 */

//! Various internal utilities, which do not have there own module

mod bcount;
pub use self::bcount::Bc;

mod xyz;
pub use self::xyz::universe_from_xyz;
<commit_msg>Silent a warning about unused function<commit_after>/* Cymbalum, Molecular Simulation in Rust - Copyright (C) 2015 Guillaume Fraux
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/
 */

//! Various internal utilities, which do not have there own module

mod bcount;
pub use self::bcount::Bc;

#[cfg(test)]
mod xyz;
#[cfg(test)]
pub use self::xyz::universe_from_xyz;
<|endoftext|>


<commit_before>use crate::syntax::Atom::{self, *};
use proc_macro2::{Literal, Span, TokenStream};
use quote::ToTokens;
use std::cmp::Ordering;
use std::collections::BTreeSet;
use std::fmt::{self, Display};
use std::str::FromStr;
use std::u64;
use syn::{Error, Expr, Lit, Result, Token, UnOp};

pub struct DiscriminantSet {
    repr: Option<Atom>,
    values: BTreeSet<Discriminant>,
    previous: Option<Discriminant>,
}

#[derive(Copy, Clone, Eq, PartialEq)]
pub struct Discriminant {
    negative: bool,
    magnitude: u64,
}

impl DiscriminantSet {
    pub fn new(repr: Option<Atom>) -> Self {
        DiscriminantSet {
            repr,
            values: BTreeSet::new(),
            previous: None,
        }
    }

    pub fn insert(&mut self, expr: &Expr) -> Result<Discriminant> {
        let (discriminant, repr) = expr_to_discriminant(expr)?;
        match (self.repr, repr) {
            (None, Some(new_repr)) => {
                if let Some(limits) = Limits::of(new_repr) {
                    for &past in &self.values {
                        if limits.min <= past && past <= limits.max {
                            continue;
                        }
                        let msg = format!(
                            "discriminant value `{}` is outside the limits of {}",
                            past, new_repr,
                        );
                        return Err(Error::new(Span::call_site(), msg));
                    }
                }
                self.repr = Some(new_repr);
            }
            (Some(prev), Some(repr)) if prev != repr => {
                let msg = format!("expected {}, found {}", prev, repr);
                return Err(Error::new(Span::call_site(), msg));
            }
            _ => {}
        }
        insert(self, discriminant)
    }

    pub fn insert_next(&mut self) -> Result<Discriminant> {
        let discriminant = match self.previous {
            None => Discriminant::zero(),
            Some(mut discriminant) if discriminant.negative => {
                discriminant.magnitude -= 1;
                if discriminant.magnitude == 0 {
                    discriminant.negative = false;
                }
                discriminant
            }
            Some(mut discriminant) => {
                if discriminant.magnitude == u64::MAX {
                    let msg = format!("discriminant overflow on value after {}", u64::MAX);
                    return Err(Error::new(Span::call_site(), msg));
                }
                discriminant.magnitude += 1;
                discriminant
            }
        };
        insert(self, discriminant)
    }

    pub fn inferred_repr(&self) -> Result<Atom> {
        if let Some(repr) = self.repr {
            return Ok(repr);
        }
        if self.values.is_empty() {
            return Ok(U8);
        }
        let min = *self.values.iter().next().unwrap();
        let max = *self.values.iter().next_back().unwrap();
        for limits in &LIMITS {
            if limits.min <= min && max <= limits.max {
                return Ok(limits.repr);
            }
        }
        let msg = "these discriminant values do not fit in any supported enum repr type";
        Err(Error::new(Span::call_site(), msg))
    }
}

fn expr_to_discriminant(expr: &Expr) -> Result<(Discriminant, Option<Atom>)> {
    match expr {
        Expr::Lit(expr) => {
            if let Lit::Int(lit) = &expr.lit {
                let discriminant = lit.base10_parse::<Discriminant>()?;
                let repr = parse_int_suffix(lit.suffix())?;
                return Ok((discriminant, repr));
            }
        }
        Expr::Unary(unary) => {
            if let UnOp::Neg(_) = unary.op {
                let (mut discriminant, repr) = expr_to_discriminant(&unary.expr)?;
                discriminant.negative ^= true;
                return Ok((discriminant, repr));
            }
        }
        _ => {}
    }
    Err(Error::new_spanned(
        expr,
        "enums with non-integer literal discriminants are not supported yet",
    ))
}

fn insert(set: &mut DiscriminantSet, discriminant: Discriminant) -> Result<Discriminant> {
    if let Some(expected_repr) = set.repr {
        if let Some(limits) = Limits::of(expected_repr) {
            if discriminant < limits.min || limits.max < discriminant {
                let msg = format!(
                    "discriminant value `{}` is outside the limits of {}",
                    discriminant, expected_repr,
                );
                return Err(Error::new(Span::call_site(), msg));
            }
        }
    }
    set.values.insert(discriminant);
    set.previous = Some(discriminant);
    Ok(discriminant)
}

impl Discriminant {
    const fn zero() -> Self {
        Discriminant {
            negative: false,
            magnitude: 0,
        }
    }

    const fn pos(u: u64) -> Self {
        Discriminant {
            negative: false,
            magnitude: u,
        }
    }

    const fn neg(i: i64) -> Self {
        Discriminant {
            negative: i < 0,
            // This is `i.abs() as u64` but without overflow on MIN. Uses the
            // fact that MIN.wrapping_abs() wraps back to MIN whose binary
            // representation is 1<<63, and thus the `as u64` conversion
            // produces 1<<63 too which happens to be the correct unsigned
            // magnitude.
            magnitude: i.wrapping_abs() as u64,
        }
    }
}

impl Display for Discriminant {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        if self.negative {
            f.write_str("-")?;
        }
        Display::fmt(&self.magnitude, f)
    }
}

impl ToTokens for Discriminant {
    fn to_tokens(&self, tokens: &mut TokenStream) {
        if self.negative {
            Token![-](Span::call_site()).to_tokens(tokens);
        }
        Literal::u64_unsuffixed(self.magnitude).to_tokens(tokens);
    }
}

impl FromStr for Discriminant {
    type Err = Error;

    fn from_str(mut s: &str) -> Result<Self> {
        let negative = s.starts_with('-');
        if negative {
            s = &s[1..];
        }
        match s.parse::<u64>() {
            Ok(magnitude) => Ok(Discriminant {
                negative,
                magnitude,
            }),
            Err(_) => Err(Error::new(
                Span::call_site(),
                "discriminant value outside of supported range",
            )),
        }
    }
}

impl Ord for Discriminant {
    fn cmp(&self, other: &Self) -> Ordering {
        match (self.negative, other.negative) {
            (true, true) => self.magnitude.cmp(&other.magnitude).reverse(),
            (true, false) => Ordering::Less, // negative < positive
            (false, true) => Ordering::Greater, // positive > negative
            (false, false) => self.magnitude.cmp(&other.magnitude),
        }
    }
}

impl PartialOrd for Discriminant {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

fn parse_int_suffix(suffix: &str) -> Result<Option<Atom>> {
    if suffix.is_empty() {
        return Ok(None);
    }
    if let Some(atom) = Atom::from_str(suffix) {
        match atom {
            U8 | U16 | U32 | U64 | Usize | I8 | I16 | I32 | I64 | Isize => return Ok(Some(atom)),
            _ => {}
        }
    }
    let msg = format!("unrecognized integer suffix: `{}`", suffix);
    Err(Error::new(Span::call_site(), msg))
}

#[derive(Copy, Clone)]
struct Limits {
    repr: Atom,
    min: Discriminant,
    max: Discriminant,
}

impl Limits {
    fn of(repr: Atom) -> Option<Limits> {
        for limits in &LIMITS {
            if limits.repr == repr {
                return Some(*limits);
            }
        }
        None
    }
}

const LIMITS: [Limits; 8] = [
    Limits {
        repr: U8,
        min: Discriminant::zero(),
        max: Discriminant::pos(std::u8::MAX as u64),
    },
    Limits {
        repr: I8,
        min: Discriminant::neg(std::i8::MIN as i64),
        max: Discriminant::pos(std::i8::MAX as u64),
    },
    Limits {
        repr: U16,
        min: Discriminant::zero(),
        max: Discriminant::pos(std::u16::MAX as u64),
    },
    Limits {
        repr: I16,
        min: Discriminant::neg(std::i16::MIN as i64),
        max: Discriminant::pos(std::i16::MAX as u64),
    },
    Limits {
        repr: U32,
        min: Discriminant::zero(),
        max: Discriminant::pos(std::u32::MAX as u64),
    },
    Limits {
        repr: I32,
        min: Discriminant::neg(std::i32::MIN as i64),
        max: Discriminant::pos(std::i32::MAX as u64),
    },
    Limits {
        repr: U64,
        min: Discriminant::zero(),
        max: Discriminant::pos(std::u64::MAX),
    },
    Limits {
        repr: I64,
        min: Discriminant::neg(std::i64::MIN),
        max: Discriminant::pos(std::i64::MAX as u64),
    },
];
<commit_msg>Neg/Pos enum for discriminant sign<commit_after>use crate::syntax::Atom::{self, *};
use proc_macro2::{Literal, Span, TokenStream};
use quote::ToTokens;
use std::cmp::Ordering;
use std::collections::BTreeSet;
use std::fmt::{self, Display};
use std::str::FromStr;
use std::u64;
use syn::{Error, Expr, Lit, Result, Token, UnOp};

pub struct DiscriminantSet {
    repr: Option<Atom>,
    values: BTreeSet<Discriminant>,
    previous: Option<Discriminant>,
}

#[derive(Copy, Clone, Eq, PartialEq)]
pub struct Discriminant {
    sign: Sign,
    magnitude: u64,
}

#[derive(Copy, Clone, Eq, PartialEq)]
enum Sign {
    Negative,
    Positive,
}

impl DiscriminantSet {
    pub fn new(repr: Option<Atom>) -> Self {
        DiscriminantSet {
            repr,
            values: BTreeSet::new(),
            previous: None,
        }
    }

    pub fn insert(&mut self, expr: &Expr) -> Result<Discriminant> {
        let (discriminant, repr) = expr_to_discriminant(expr)?;
        match (self.repr, repr) {
            (None, Some(new_repr)) => {
                if let Some(limits) = Limits::of(new_repr) {
                    for &past in &self.values {
                        if limits.min <= past && past <= limits.max {
                            continue;
                        }
                        let msg = format!(
                            "discriminant value `{}` is outside the limits of {}",
                            past, new_repr,
                        );
                        return Err(Error::new(Span::call_site(), msg));
                    }
                }
                self.repr = Some(new_repr);
            }
            (Some(prev), Some(repr)) if prev != repr => {
                let msg = format!("expected {}, found {}", prev, repr);
                return Err(Error::new(Span::call_site(), msg));
            }
            _ => {}
        }
        insert(self, discriminant)
    }

    pub fn insert_next(&mut self) -> Result<Discriminant> {
        let discriminant = match self.previous {
            None => Discriminant::zero(),
            Some(mut discriminant) => match discriminant.sign {
                Sign::Negative => {
                    discriminant.magnitude -= 1;
                    if discriminant.magnitude == 0 {
                        discriminant.sign = Sign::Positive;
                    }
                    discriminant
                }
                Sign::Positive => {
                    if discriminant.magnitude == u64::MAX {
                        let msg = format!("discriminant overflow on value after {}", u64::MAX);
                        return Err(Error::new(Span::call_site(), msg));
                    }
                    discriminant.magnitude += 1;
                    discriminant
                }
            },
        };
        insert(self, discriminant)
    }

    pub fn inferred_repr(&self) -> Result<Atom> {
        if let Some(repr) = self.repr {
            return Ok(repr);
        }
        if self.values.is_empty() {
            return Ok(U8);
        }
        let min = *self.values.iter().next().unwrap();
        let max = *self.values.iter().next_back().unwrap();
        for limits in &LIMITS {
            if limits.min <= min && max <= limits.max {
                return Ok(limits.repr);
            }
        }
        let msg = "these discriminant values do not fit in any supported enum repr type";
        Err(Error::new(Span::call_site(), msg))
    }
}

fn expr_to_discriminant(expr: &Expr) -> Result<(Discriminant, Option<Atom>)> {
    match expr {
        Expr::Lit(expr) => {
            if let Lit::Int(lit) = &expr.lit {
                let discriminant = lit.base10_parse::<Discriminant>()?;
                let repr = parse_int_suffix(lit.suffix())?;
                return Ok((discriminant, repr));
            }
        }
        Expr::Unary(unary) => {
            if let UnOp::Neg(_) = unary.op {
                let (mut discriminant, repr) = expr_to_discriminant(&unary.expr)?;
                discriminant.sign = match discriminant.sign {
                    Sign::Positive => Sign::Negative,
                    Sign::Negative => Sign::Positive,
                };
                return Ok((discriminant, repr));
            }
        }
        _ => {}
    }
    Err(Error::new_spanned(
        expr,
        "enums with non-integer literal discriminants are not supported yet",
    ))
}

fn insert(set: &mut DiscriminantSet, discriminant: Discriminant) -> Result<Discriminant> {
    if let Some(expected_repr) = set.repr {
        if let Some(limits) = Limits::of(expected_repr) {
            if discriminant < limits.min || limits.max < discriminant {
                let msg = format!(
                    "discriminant value `{}` is outside the limits of {}",
                    discriminant, expected_repr,
                );
                return Err(Error::new(Span::call_site(), msg));
            }
        }
    }
    set.values.insert(discriminant);
    set.previous = Some(discriminant);
    Ok(discriminant)
}

impl Discriminant {
    const fn zero() -> Self {
        Discriminant {
            sign: Sign::Positive,
            magnitude: 0,
        }
    }

    const fn pos(u: u64) -> Self {
        Discriminant {
            sign: Sign::Positive,
            magnitude: u,
        }
    }

    const fn neg(i: i64) -> Self {
        Discriminant {
            sign: if i < 0 {
                Sign::Negative
            } else {
                Sign::Positive
            },
            // This is `i.abs() as u64` but without overflow on MIN. Uses the
            // fact that MIN.wrapping_abs() wraps back to MIN whose binary
            // representation is 1<<63, and thus the `as u64` conversion
            // produces 1<<63 too which happens to be the correct unsigned
            // magnitude.
            magnitude: i.wrapping_abs() as u64,
        }
    }
}

impl Display for Discriminant {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        if self.sign == Sign::Negative {
            f.write_str("-")?;
        }
        Display::fmt(&self.magnitude, f)
    }
}

impl ToTokens for Discriminant {
    fn to_tokens(&self, tokens: &mut TokenStream) {
        if self.sign == Sign::Negative {
            Token![-](Span::call_site()).to_tokens(tokens);
        }
        Literal::u64_unsuffixed(self.magnitude).to_tokens(tokens);
    }
}

impl FromStr for Discriminant {
    type Err = Error;

    fn from_str(mut s: &str) -> Result<Self> {
        let sign = if s.starts_with('-') {
            s = &s[1..];
            Sign::Negative
        } else {
            Sign::Positive
        };
        match s.parse::<u64>() {
            Ok(magnitude) => Ok(Discriminant { sign, magnitude }),
            Err(_) => Err(Error::new(
                Span::call_site(),
                "discriminant value outside of supported range",
            )),
        }
    }
}

impl Ord for Discriminant {
    fn cmp(&self, other: &Self) -> Ordering {
        use self::Sign::{Negative, Positive};
        match (self.sign, other.sign) {
            (Negative, Negative) => self.magnitude.cmp(&other.magnitude).reverse(),
            (Negative, Positive) => Ordering::Less, // negative < positive
            (Positive, Negative) => Ordering::Greater, // positive > negative
            (Positive, Positive) => self.magnitude.cmp(&other.magnitude),
        }
    }
}

impl PartialOrd for Discriminant {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

fn parse_int_suffix(suffix: &str) -> Result<Option<Atom>> {
    if suffix.is_empty() {
        return Ok(None);
    }
    if let Some(atom) = Atom::from_str(suffix) {
        match atom {
            U8 | U16 | U32 | U64 | Usize | I8 | I16 | I32 | I64 | Isize => return Ok(Some(atom)),
            _ => {}
        }
    }
    let msg = format!("unrecognized integer suffix: `{}`", suffix);
    Err(Error::new(Span::call_site(), msg))
}

#[derive(Copy, Clone)]
struct Limits {
    repr: Atom,
    min: Discriminant,
    max: Discriminant,
}

impl Limits {
    fn of(repr: Atom) -> Option<Limits> {
        for limits in &LIMITS {
            if limits.repr == repr {
                return Some(*limits);
            }
        }
        None
    }
}

const LIMITS: [Limits; 8] = [
    Limits {
        repr: U8,
        min: Discriminant::zero(),
        max: Discriminant::pos(std::u8::MAX as u64),
    },
    Limits {
        repr: I8,
        min: Discriminant::neg(std::i8::MIN as i64),
        max: Discriminant::pos(std::i8::MAX as u64),
    },
    Limits {
        repr: U16,
        min: Discriminant::zero(),
        max: Discriminant::pos(std::u16::MAX as u64),
    },
    Limits {
        repr: I16,
        min: Discriminant::neg(std::i16::MIN as i64),
        max: Discriminant::pos(std::i16::MAX as u64),
    },
    Limits {
        repr: U32,
        min: Discriminant::zero(),
        max: Discriminant::pos(std::u32::MAX as u64),
    },
    Limits {
        repr: I32,
        min: Discriminant::neg(std::i32::MIN as i64),
        max: Discriminant::pos(std::i32::MAX as u64),
    },
    Limits {
        repr: U64,
        min: Discriminant::zero(),
        max: Discriminant::pos(std::u64::MAX),
    },
    Limits {
        repr: I64,
        min: Discriminant::neg(std::i64::MIN),
        max: Discriminant::pos(std::i64::MAX as u64),
    },
];
<|endoftext|>


<commit_before>use ::items::*;
use ::errors::*;

use self::ErrorKind::*;

use ::std::iter::Enumerate;
use ::std::str::Lines;

pub struct DimacsParser<'a> {
	lines: Enumerate<Lines<'a>>,
	line : usize
}

impl<'a> DimacsParser<'a> {
	#[inline]
	pub fn from_str(input: &'a str) -> DimacsParser<'a> {
		DimacsParser{
			lines: input.lines().enumerate(),
			line : 0
		}
	}

	fn mk_err(&self, kind: ErrorKind) -> DimacsError {
		DimacsError::new(self.line, kind)
	}

	#[inline]
	pub(super)
	fn err(&self, kind: ErrorKind) -> Result<DimacsItem> {
		Err(self.mk_err(kind))
	}

	fn parse_comment(&mut self, content: &str) -> Result<DimacsItem> {
		match content.find(char::is_whitespace) {
			Some(pos) => {
				let (head, tail) = content.split_at(pos);
				if head != "c" {
					debug_assert!(false); // this should never happen!
					self.err(InvalidStartOfLine)
				}
				else {
					Ok(DimacsItem::Comment(Comment::from_str(&tail[1..])))
				}
			},
			None => {
				Ok(DimacsItem::Comment(Comment::from_str("")))
			}
		}
	}

	fn expect<I: Iterator<Item=&'a str>>(&mut self, expected: &str, args: &mut I) -> Result<()> {
		match args.next() {
			Some(arg) => match arg == expected {
				true  => Ok(()),
				false => Err(self.mk_err(UnexpectedToken))
			},
			None => Err(self.mk_err(UnexpectedEndOfLine))
		}
	}

	fn parse_i64<I: Iterator<Item=&'a str>>(&mut self, args: &mut I) -> Result<i64> {
		match args.next() {
			Some(arg) => {
				arg.parse::<i64>().map_err(|_| self.mk_err(InvalidInteger))
			},
			None      => Err(self.mk_err(UnexpectedEndOfLine))
		}
	}

	fn parse_u64<I: Iterator<Item=&'a str>>(&mut self, args: &mut I) -> Result<u64> {
		let v = self.parse_i64(args)?;
		match v.is_negative() {
			true => Err(self.mk_err(UnexpectedNegativeInteger)),
			_    => Ok(v as u64)
		}
	}

	fn parse_config<I: Iterator<Item=&'a str>>(&mut self, mut args: I) -> Result<DimacsItem> {
		self.expect("p", &mut args)?;
		self.expect("cnf", &mut args)?;

		let nv = self.parse_u64(&mut args).map_err(|e|
			if e == self.mk_err(InvalidInteger) { self.mk_err(InvalidConfigNumVars) } else {e} )?;
		let nc = self.parse_u64(&mut args).map_err(|e|
			if e == self.mk_err(InvalidInteger) { self.mk_err(InvalidConfigNumClauses) } else {e} )?;

		if let Some(_) = args.next() {
			self.err(TooManyArgsForConfig)
		}
		else {
			Ok(DimacsItem::Config(Config::new(nv, nc)))
		}
	}

	fn parse_clause<I: Iterator<Item=&'a str>>(&mut self, mut args: I) -> Result<DimacsItem> {
		let mut lits = Vec::new();
		loop {
			match self.parse_i64(&mut args) {
				Ok(val) => lits.push(Lit::from_i64(val)),
				Err(e)  => match e.kind {
					UnexpectedEndOfLine => break,
					kind                => return self.err(kind)
				}
			}
		}
		match lits.pop() {
			Some(last) =>
				match last == Lit::from_i64(0) {
					true => Ok(DimacsItem::Clause(Clause::from_vec(lits))),
					_    => self.err(MissingZeroLiteralAtEndOfClause)
				},
			None => self.err(TooFewArgsForClause)
		}
	}

	fn parse_line(&mut self, line: usize, content: &'a str) -> Option<(usize, Result<DimacsItem>)> {
		self.line = line + 1;
		match content.chars().next() {
			Some(c) =>
				Some((line,
					match c {
						'c'        => self.parse_comment(content),
						'p'        => self.parse_config(content.split_whitespace()),
						'-'        |
						'1'...'9'  => self.parse_clause(content.split_whitespace()),
						_          => self.err(InvalidStartOfLine)
					}
				)
			),
			None => self.next_line_and_item() // empty line!
		}
	}

	fn next_item(&mut self) -> Option<Result<DimacsItem>> {
		match self.next_line_and_item() {
			Some((_, item)) => Some(item),
			None               => None
		}
	}

	fn next_line_and_item(&mut self) -> Option<(usize, Result<DimacsItem>)> {
		match self.lines.next() {
			Some((line, content)) => self.parse_line(line, content.trim_left()),
			None                  => None
		}
	}
}

impl<'a> Iterator for DimacsParser<'a> {
	type Item = Result<DimacsItem>;

	#[inline]
	fn next(&mut self) -> Option<Self::Item> {
		self.next_item()
	}
}

#[cfg(test)]
mod tests {
	use super::*;

	fn mk_comment(content: &str) -> Result<DimacsItem> {
		Ok(DimacsItem::Comment(Comment::from_str(content)))
	}

	fn mk_config(num_vars: u64, num_clauses: u64) -> Result<DimacsItem> {
		Ok(DimacsItem::Config(Config::new(num_vars, num_clauses)))
	}

	fn mk_clause(lits: &[i64]) -> Result<DimacsItem> {
		Ok(DimacsItem::Clause(
			Clause::from_vec(
				lits.into_iter().map(|&val| Lit::from_i64(val)).collect())))
	}

	fn mk_error(line: usize, kind: ErrorKind) -> Result<DimacsItem> {
		Err(DimacsError::new(line, kind))
	}

	fn assert_items(content: &str, expected_items: &[Result<DimacsItem>]) {
		let mut parsed_items = DimacsParser::from_str(content);
		for item in expected_items {
			assert_eq!(parsed_items.next().unwrap(), *item);
		}
		assert_eq!(parsed_items.next(), None);
	}

	#[test]
	fn valid_01() {
		assert_items(
			r"
				c This is a simplified DIMACS input file for testing purposes.
				c Such input files may start with line comments, starting with 'c'.
				c Next follows a configuration line stating the number of variables
				c and clauses used to represent this SAT instance.
				c Afterwards there is information about a clause within the SAT
				c instance for every line starting with a number and ending with '0'.
				p cnf 5 3
				 1  2  3  0
				-1  2  0
				 1 -3 -4  5  0
			",
			&[
				mk_comment("This is a simplified DIMACS input file for testing purposes."),
				mk_comment("Such input files may start with line comments, starting with 'c'."),
				mk_comment("Next follows a configuration line stating the number of variables"),
				mk_comment("and clauses used to represent this SAT instance."),
				mk_comment("Afterwards there is information about a clause within the SAT"),
				mk_comment("instance for every line starting with a number and ending with '0'."),
				mk_config(5, 3),
				mk_clause(&[ 1,  2,  3   ]),
				mk_clause(&[-1,  2       ]),
				mk_clause(&[ 1, -3, -4, 5])
			]
		)
	}

	#[test]
	fn err_multiple_configs() {
		assert_items(
			r"p cnf 5 3
			  p cnf 42 2
			",
			&[
				mk_config(5, 3),
				mk_error(2, MultipleConfigs)
			]
		)
	}

	#[test]
	fn err_missing_configs() {
		assert_items(
			r"c This is an entry comment
			  -1 0
			",
			&[
				mk_comment("This is an entry comment"),
				mk_error(2, MissingConfig),
			]
		)
	}

	#[test]
	fn err_invalid_start_of_line_01() {
		assert_items(
			r"foo",
			&[
				mk_error(1, InvalidStartOfLine),
			]
		)
	}

	#[test]
	fn err_invalid_start_of_line_02() {
		assert_items(
			r"c foo bar baz
			  c lirum larum lel
			  p cnf 42 1337
			  -1	-2	-3	-4 0
			   1     2   3   4 0
			   0
			",
			&[
				mk_comment("foo bar baz"),
				mk_comment("lirum larum lel  "),
				mk_config(42, 1337),
				mk_clause(&[-1, -2, -3, -4]),
				mk_clause(&[ 1,  2,  3,  4]),
				mk_error(6, InvalidStartOfLine),
			]
		)
	}

	#[test]
	fn err_var_out_of_bounds() {
		assert_items(
			r"p cnf 5 10
			  1000 0
			",
			&[
				mk_config(5, 10),
				mk_error(2, VarOutOfBounds),
			]
		)
	}

	#[test]
	fn err_too_many_clauses() {
		assert_items(
			r"p cnf 9 3
			  -1  2  3 0
			   2 -3  4 0
			   3  4 -5 0
			   4 -5  6 0
			   5  6 -7 0
			",
			&[
				mk_config(9, 3),
				mk_clause(&[-1,  2,  3]),
				mk_clause(&[ 2, -3,  4]),
				mk_clause(&[ 3,  4, -5]),
				mk_error(5, TooManyClauses),
				mk_error(6, TooManyClauses),
			]
		)
	}

	fn read_file_to_string(path: &str) -> String {
		use std::io::prelude::*;
		use std::fs::File;

		let mut f = File::open(path).expect("bench file not found");
		let mut s = String::new();

		f.read_to_string(&mut s).expect("encountered problems writing bench file to string");
		s
	}

	fn test_file(path: &str) {
		let input = read_file_to_string(path);
		assert!(
			DimacsParser::from_str(input.as_str()).all(
				|item| {
					if let Err(error) = item {
						println!("{:?}", error);
						false
					}
					else {
						true
					}
				}
			)
		);
	}

	#[test]
	fn aim_100_1_6_no_1() {
		test_file("bench/aim-100-1_6-no-1.cnf")
	}

	#[test]
	fn aim_50_1_6_yes1_4() {
		test_file("bench/aim-50-1_6-yes1-4.cnf")
	}

	#[test]
	fn par_8_1_c() {
		test_file("bench/par-8-1-c.cnf")
	}

	#[test]
	fn bf0432_007() {
		test_file("bench/bf0432-007.cnf")
	}

	#[test]
	fn zebra_v155_c1135() {
		test_file("bench/zebra-v155-c1135.cnf")
	}
}

#[cfg(all(feature = "bench", test))]
mod benches {
	use super::*;

	use test::{Bencher, black_box};

	fn read_file_to_string(path: &str) -> String {
		use std::io::prelude::*;
		use std::fs::File;

		let mut f = File::open(path).expect("bench file not found");
		let mut s = String::new();

		f.read_to_string(&mut s).expect("encountered problems writing bench file to string");
		s
	}

	fn bench_file(bencher: &mut Bencher, path: &str) {
		let input = read_file_to_string(path);
		bencher.iter(|| {
			let items = DimacsParser::from_str(input.as_str()).collect::<Vec<_>>();
			black_box(items);
		});
	}

	#[bench]
	fn aim_100_1_6_no_1(bencher: &mut Bencher) {
		bench_file(bencher, "bench/aim-100-1_6-no-1.cnf")
	}

	#[bench]
	fn aim_100_1_6_yes_1_4(bencher: &mut Bencher) {
		bench_file(bencher, "bench/aim-50-1_6-yes1-4.cnf")
	}

	#[bench]
	fn bf0432_007(bencher: &mut Bencher) {
		bench_file(bencher, "bench/bf0432-007.cnf")
	}

	#[bench]
	fn zebra_v155_c1135(bencher: &mut Bencher) {
		bench_file(bencher, "bench/zebra-v155-c1135.cnf")
	}

	#[bench]
	fn par_8_1_c(bencher: &mut Bencher) {
		bench_file(bencher, "bench/par-8-1-c.cnf")
	}
}
<commit_msg>refactored parser a bit<commit_after>use ::items::*;
use ::errors::*;

use self::ErrorKind::*;

use ::std::iter::Enumerate;
use ::std::str::Lines;

pub struct DimacsParser<'a> {
	lines: Enumerate<Lines<'a>>,
	line : usize
}

impl<'a> DimacsParser<'a> {
	#[inline]
	pub fn from_str(input: &'a str) -> DimacsParser<'a> {
		DimacsParser{
			lines: input.lines().enumerate(),
			line : 0
		}
	}

	fn mk_err(&self, kind: ErrorKind) -> DimacsError {
		DimacsError::new(self.line, kind)
	}

	#[inline]
	pub(super)
	fn err(&self, kind: ErrorKind) -> Result<DimacsItem> {
		Err(self.mk_err(kind))
	}

	fn parse_comment(&mut self, content: &str) -> Result<DimacsItem> {
		match content.find(char::is_whitespace) {
			Some(pos) => {
				let (head, tail) = content.split_at(pos);
				if head != "c" {
					debug_assert!(false); // this should never happen!
					self.err(InvalidStartOfLine)
				}
				else {
					Ok(DimacsItem::Comment(Comment::from_str(&tail[1..])))
				}
			},
			None => {
				Ok(DimacsItem::Comment(Comment::from_str("")))
			}
		}
	}

	fn expect<I: Iterator<Item=&'a str>>(&mut self, expected: &str, args: &mut I) -> Result<()> {
		match args.next() {
			Some(arg) => match arg == expected {
				true  => Ok(()),
				false => Err(self.mk_err(UnexpectedToken))
			},
			None => Err(self.mk_err(UnexpectedEndOfLine))
		}
	}

	fn parse_i64<I: Iterator<Item=&'a str>>(&mut self, args: &mut I) -> Result<i64> {
		match args.next() {
			Some(arg) => {
				arg.parse::<i64>().map_err(|_| self.mk_err(InvalidInteger))
			},
			None      => Err(self.mk_err(UnexpectedEndOfLine))
		}
	}

	fn parse_u64<I: Iterator<Item=&'a str>>(&mut self, args: &mut I) -> Result<u64> {
		let v = self.parse_i64(args)?;
		match v.is_negative() {
			true => Err(self.mk_err(UnexpectedNegativeInteger)),
			_    => Ok(v as u64)
		}
	}

	fn parse_config<I: Iterator<Item=&'a str>>(&mut self, mut args: I) -> Result<DimacsItem> {
		self.expect("p", &mut args)?;
		self.expect("cnf", &mut args)?;

		let nv = self.parse_u64(&mut args).map_err(|e|
			if e == self.mk_err(InvalidInteger) { self.mk_err(InvalidConfigNumVars) } else {e} )?;
		let nc = self.parse_u64(&mut args).map_err(|e|
			if e == self.mk_err(InvalidInteger) { self.mk_err(InvalidConfigNumClauses) } else {e} )?;

		if let Some(_) = args.next() {
			self.err(TooManyArgsForConfig)
		}
		else {
			Ok(DimacsItem::Config(Config::new(nv, nc)))
		}
	}

	fn parse_clause<I: Iterator<Item=&'a str>>(&mut self, mut args: I) -> Result<DimacsItem> {
		let mut lits = Vec::new();
		loop {
			match self.parse_i64(&mut args) {
				Ok(val) => lits.push(Lit::from_i64(val)),
				Err(e)  => match e.kind {
					UnexpectedEndOfLine => break,
					kind                => return self.err(kind)
				}
			}
		}
		match lits.pop() {
			Some(last) =>
				match last == Lit::from_i64(0) {
					true => Ok(DimacsItem::Clause(Clause::from_vec(lits))),
					_    => self.err(MissingZeroLiteralAtEndOfClause)
				},
			None => self.err(TooFewArgsForClause)
		}
	}

	fn parse_line(&mut self, line: usize, content: &'a str) -> Option<Result<DimacsItem>> {
		self.line = line + 1;
		match content.chars().next() {
			Some(c) => Some(
				match c {
					'c'        => self.parse_comment(content),
					'p'        => self.parse_config(content.split_whitespace()),
					'-'        |
					'1'...'9'  => self.parse_clause(content.split_whitespace()),
					_          => self.err(InvalidStartOfLine)
				}
			),
			None => self.next() // empty line!
		}
	}
}

impl<'a> Iterator for DimacsParser<'a> {
	type Item = Result<DimacsItem>;

	#[inline]
	fn next(&mut self) -> Option<Self::Item> {
		match self.lines.next() {
			Some((line, content)) => self.parse_line(line, content.trim_left()),
			None                  => None
		}
	}
}

#[cfg(test)]
mod tests {
	use super::*;

	fn mk_comment(content: &str) -> Result<DimacsItem> {
		Ok(DimacsItem::Comment(Comment::from_str(content)))
	}

	fn mk_config(num_vars: u64, num_clauses: u64) -> Result<DimacsItem> {
		Ok(DimacsItem::Config(Config::new(num_vars, num_clauses)))
	}

	fn mk_clause(lits: &[i64]) -> Result<DimacsItem> {
		Ok(DimacsItem::Clause(
			Clause::from_vec(
				lits.into_iter().map(|&val| Lit::from_i64(val)).collect())))
	}

	fn mk_error(line: usize, kind: ErrorKind) -> Result<DimacsItem> {
		Err(DimacsError::new(line, kind))
	}

	fn assert_items(content: &str, expected_items: &[Result<DimacsItem>]) {
		let mut parsed_items = DimacsParser::from_str(content);
		for item in expected_items {
			assert_eq!(parsed_items.next().unwrap(), *item);
		}
		assert_eq!(parsed_items.next(), None);
	}

	#[test]
	fn valid_01() {
		assert_items(
			r"
				c This is a simplified DIMACS input file for testing purposes.
				c Such input files may start with line comments, starting with 'c'.
				c Next follows a configuration line stating the number of variables
				c and clauses used to represent this SAT instance.
				c Afterwards there is information about a clause within the SAT
				c instance for every line starting with a number and ending with '0'.
				p cnf 5 3
				 1  2  3  0
				-1  2  0
				 1 -3 -4  5  0
			",
			&[
				mk_comment("This is a simplified DIMACS input file for testing purposes."),
				mk_comment("Such input files may start with line comments, starting with 'c'."),
				mk_comment("Next follows a configuration line stating the number of variables"),
				mk_comment("and clauses used to represent this SAT instance."),
				mk_comment("Afterwards there is information about a clause within the SAT"),
				mk_comment("instance for every line starting with a number and ending with '0'."),
				mk_config(5, 3),
				mk_clause(&[ 1,  2,  3   ]),
				mk_clause(&[-1,  2       ]),
				mk_clause(&[ 1, -3, -4, 5])
			]
		)
	}

	#[test]
	fn err_multiple_configs() {
		assert_items(
			r"p cnf 5 3
			  p cnf 42 2
			",
			&[
				mk_config(5, 3),
				mk_error(2, MultipleConfigs)
			]
		)
	}

	#[test]
	fn err_missing_configs() {
		assert_items(
			r"c This is an entry comment
			  -1 0
			",
			&[
				mk_comment("This is an entry comment"),
				mk_error(2, MissingConfig),
			]
		)
	}

	#[test]
	fn err_invalid_start_of_line_01() {
		assert_items(
			r"foo",
			&[
				mk_error(1, InvalidStartOfLine),
			]
		)
	}

	#[test]
	fn err_invalid_start_of_line_02() {
		assert_items(
			r"c foo bar baz
			  c lirum larum lel
			  p cnf 42 1337
			  -1	-2	-3	-4 0
			   1     2   3   4 0
			   0
			",
			&[
				mk_comment("foo bar baz"),
				mk_comment("lirum larum lel  "),
				mk_config(42, 1337),
				mk_clause(&[-1, -2, -3, -4]),
				mk_clause(&[ 1,  2,  3,  4]),
				mk_error(6, InvalidStartOfLine),
			]
		)
	}

	#[test]
	fn err_var_out_of_bounds() {
		assert_items(
			r"p cnf 5 10
			  1000 0
			",
			&[
				mk_config(5, 10),
				mk_error(2, VarOutOfBounds),
			]
		)
	}

	#[test]
	fn err_too_many_clauses() {
		assert_items(
			r"p cnf 9 3
			  -1  2  3 0
			   2 -3  4 0
			   3  4 -5 0
			   4 -5  6 0
			   5  6 -7 0
			",
			&[
				mk_config(9, 3),
				mk_clause(&[-1,  2,  3]),
				mk_clause(&[ 2, -3,  4]),
				mk_clause(&[ 3,  4, -5]),
				mk_error(5, TooManyClauses),
				mk_error(6, TooManyClauses),
			]
		)
	}

	fn read_file_to_string(path: &str) -> String {
		use std::io::prelude::*;
		use std::fs::File;

		let mut f = File::open(path).expect("bench file not found");
		let mut s = String::new();

		f.read_to_string(&mut s).expect("encountered problems writing bench file to string");
		s
	}

	fn test_file(path: &str) {
		let input = read_file_to_string(path);
		assert!(
			DimacsParser::from_str(input.as_str()).all(
				|item| {
					if let Err(error) = item {
						println!("{:?}", error);
						false
					}
					else {
						true
					}
				}
			)
		);
	}

	#[test]
	fn aim_100_1_6_no_1() {
		test_file("bench/aim-100-1_6-no-1.cnf")
	}

	#[test]
	fn aim_50_1_6_yes1_4() {
		test_file("bench/aim-50-1_6-yes1-4.cnf")
	}

	#[test]
	fn par_8_1_c() {
		test_file("bench/par-8-1-c.cnf")
	}

	#[test]
	fn bf0432_007() {
		test_file("bench/bf0432-007.cnf")
	}

	#[test]
	fn zebra_v155_c1135() {
		test_file("bench/zebra-v155-c1135.cnf")
	}
}

#[cfg(all(feature = "bench", test))]
mod benches {
	use super::*;

	use test::{Bencher, black_box};

	fn read_file_to_string(path: &str) -> String {
		use std::io::prelude::*;
		use std::fs::File;

		let mut f = File::open(path).expect("bench file not found");
		let mut s = String::new();

		f.read_to_string(&mut s).expect("encountered problems writing bench file to string");
		s
	}

	fn bench_file(bencher: &mut Bencher, path: &str) {
		let input = read_file_to_string(path);
		bencher.iter(|| {
			let items = DimacsParser::from_str(input.as_str()).collect::<Vec<_>>();
			black_box(items);
		});
	}

	#[bench]
	fn aim_100_1_6_no_1(bencher: &mut Bencher) {
		bench_file(bencher, "bench/aim-100-1_6-no-1.cnf")
	}

	#[bench]
	fn aim_100_1_6_yes_1_4(bencher: &mut Bencher) {
		bench_file(bencher, "bench/aim-50-1_6-yes1-4.cnf")
	}

	#[bench]
	fn bf0432_007(bencher: &mut Bencher) {
		bench_file(bencher, "bench/bf0432-007.cnf")
	}

	#[bench]
	fn zebra_v155_c1135(bencher: &mut Bencher) {
		bench_file(bencher, "bench/zebra-v155-c1135.cnf")
	}

	#[bench]
	fn par_8_1_c(bencher: &mut Bencher) {
		bench_file(bencher, "bench/par-8-1-c.cnf")
	}
}
<|endoftext|>