<commit_before>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Interfaces to the operating system provided random number
//! generators.

use rand::Rng;
use ops::Drop;

#[cfg(unix)]
use rand::reader::ReaderRng;
#[cfg(unix)]
use io::File;

#[cfg(windows)]
use cast;
#[cfg(windows)]
use libc::{c_long, DWORD, BYTE};
#[cfg(windows)]
type HCRYPTPROV = c_long;
// the extern functions imported from the runtime on Windows are
// implemented so that they either succeed or abort(), so we can just
// assume they work when we call them.

/// A random number generator that retrieves randomness straight from
/// the operating system. Platform sources:
///
/// - Unix-like systems (Linux, Android, Mac OSX): read directly from
///   `/dev/urandom`.
/// - Windows: calls `CryptGenRandom`, using the default cryptographic
///   service provider with the `PROV_RSA_FULL` type.
///
/// This does not block.
#[cfg(unix)]
pub struct OSRng {
    priv inner: ReaderRng<File>
}
/// A random number generator that retrieves randomness straight from
/// the operating system. Platform sources:
///
/// - Unix-like systems (Linux, Android, Mac OSX): read directly from
///   `/dev/urandom`.
/// - Windows: calls `CryptGenRandom`, using the default cryptographic
///   service provider with the `PROV_RSA_FULL` type.
///
/// This does not block.
#[cfg(windows)]
pub struct OSRng {
    priv hcryptprov: HCRYPTPROV
}

impl OSRng {
    /// Create a new `OSRng`.
    #[cfg(unix)]
    pub fn new() -> OSRng {
        use path::Path;
        let reader = File::open(&Path::new("/dev/urandom"));
        let reader = reader.expect("Error opening /dev/urandom");
        let reader_rng = ReaderRng::new(reader);

        OSRng { inner: reader_rng }
    }

    /// Create a new `OSRng`.
    #[cfg(windows)]
    pub fn new() -> OSRng {
        extern { fn rust_win32_rand_acquire(phProv: *mut HCRYPTPROV); }

        let mut hcp = 0;
        unsafe {rust_win32_rand_acquire(&mut hcp)};

        OSRng { hcryptprov: hcp }
    }
}

#[cfg(unix)]
impl Rng for OSRng {
    fn next_u32(&mut self) -> u32 {
        self.inner.next_u32()
    }
    fn next_u64(&mut self) -> u64 {
        self.inner.next_u64()
    }
    fn fill_bytes(&mut self, v: &mut [u8]) {
        self.inner.fill_bytes(v)
    }
}

#[cfg(windows)]
impl Rng for OSRng {
    fn next_u32(&mut self) -> u32 {
        let mut v = [0u8, .. 4];
        self.fill_bytes(v);
        unsafe { cast::transmute(v) }
    }
    fn next_u64(&mut self) -> u64 {
        let mut v = [0u8, .. 8];
        self.fill_bytes(v);
        unsafe { cast::transmute(v) }
    }
    fn fill_bytes(&mut self, v: &mut [u8]) {
        use container::Container;
        use vec::MutableVector;

        extern {
            fn rust_win32_rand_gen(hProv: HCRYPTPROV, dwLen: DWORD,
                                   pbBuffer: *mut BYTE);
        }

        unsafe {rust_win32_rand_gen(self.hcryptprov, v.len() as DWORD, v.as_mut_ptr())}
    }
}

impl Drop for OSRng {
    #[cfg(unix)]
    fn drop(&mut self) {
        // ensure that OSRng is not implicitly copyable on all
        // platforms, for consistency.
    }

    #[cfg(windows)]
    fn drop(&mut self) {
        extern { fn rust_win32_rand_release(hProv: HCRYPTPROV); }

        unsafe {rust_win32_rand_release(self.hcryptprov)}
    }
}

#[cfg(test)]
mod test {
    use prelude::*;
    use super::*;
    use rand::Rng;
    use task;

    #[test]
    fn test_os_rng() {
        let mut r = OSRng::new();

        r.next_u32();
        r.next_u64();

        let mut v = [0u8, .. 1000];
        r.fill_bytes(v);
    }

    #[test]
    fn test_os_rng_tasks() {

        let mut chans = ~[];
        for _ in range(0, 20) {
            let (p, c) = Chan::new();
            chans.push(c);
            do task::spawn {
                // wait until all the tasks are ready to go.
                p.recv();

                // deschedule to attempt to interleave things as much
                // as possible (XXX: is this a good test?)
                let mut r = OSRng::new();
                task::deschedule();
                let mut v = [0u8, .. 1000];

                for _ in range(0, 100) {
                    r.next_u32();
                    task::deschedule();
                    r.next_u64();
                    task::deschedule();
                    r.fill_bytes(v);
                    task::deschedule();
                }
            }
        }

        // start all the tasks
        for c in chans.iter() {
            c.send(())
        }
    }
}
<commit_msg>Removing do keyword from libstd and librustc<commit_after>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Interfaces to the operating system provided random number
//! generators.

use rand::Rng;
use ops::Drop;

#[cfg(unix)]
use rand::reader::ReaderRng;
#[cfg(unix)]
use io::File;

#[cfg(windows)]
use cast;
#[cfg(windows)]
use libc::{c_long, DWORD, BYTE};
#[cfg(windows)]
type HCRYPTPROV = c_long;
// the extern functions imported from the runtime on Windows are
// implemented so that they either succeed or abort(), so we can just
// assume they work when we call them.

/// A random number generator that retrieves randomness straight from
/// the operating system. Platform sources:
///
/// - Unix-like systems (Linux, Android, Mac OSX): read directly from
///   `/dev/urandom`.
/// - Windows: calls `CryptGenRandom`, using the default cryptographic
///   service provider with the `PROV_RSA_FULL` type.
///
/// This does not block.
#[cfg(unix)]
pub struct OSRng {
    priv inner: ReaderRng<File>
}
/// A random number generator that retrieves randomness straight from
/// the operating system. Platform sources:
///
/// - Unix-like systems (Linux, Android, Mac OSX): read directly from
///   `/dev/urandom`.
/// - Windows: calls `CryptGenRandom`, using the default cryptographic
///   service provider with the `PROV_RSA_FULL` type.
///
/// This does not block.
#[cfg(windows)]
pub struct OSRng {
    priv hcryptprov: HCRYPTPROV
}

impl OSRng {
    /// Create a new `OSRng`.
    #[cfg(unix)]
    pub fn new() -> OSRng {
        use path::Path;
        let reader = File::open(&Path::new("/dev/urandom"));
        let reader = reader.expect("Error opening /dev/urandom");
        let reader_rng = ReaderRng::new(reader);

        OSRng { inner: reader_rng }
    }

    /// Create a new `OSRng`.
    #[cfg(windows)]
    pub fn new() -> OSRng {
        extern { fn rust_win32_rand_acquire(phProv: *mut HCRYPTPROV); }

        let mut hcp = 0;
        unsafe {rust_win32_rand_acquire(&mut hcp)};

        OSRng { hcryptprov: hcp }
    }
}

#[cfg(unix)]
impl Rng for OSRng {
    fn next_u32(&mut self) -> u32 {
        self.inner.next_u32()
    }
    fn next_u64(&mut self) -> u64 {
        self.inner.next_u64()
    }
    fn fill_bytes(&mut self, v: &mut [u8]) {
        self.inner.fill_bytes(v)
    }
}

#[cfg(windows)]
impl Rng for OSRng {
    fn next_u32(&mut self) -> u32 {
        let mut v = [0u8, .. 4];
        self.fill_bytes(v);
        unsafe { cast::transmute(v) }
    }
    fn next_u64(&mut self) -> u64 {
        let mut v = [0u8, .. 8];
        self.fill_bytes(v);
        unsafe { cast::transmute(v) }
    }
    fn fill_bytes(&mut self, v: &mut [u8]) {
        use container::Container;
        use vec::MutableVector;

        extern {
            fn rust_win32_rand_gen(hProv: HCRYPTPROV, dwLen: DWORD,
                                   pbBuffer: *mut BYTE);
        }

        unsafe {rust_win32_rand_gen(self.hcryptprov, v.len() as DWORD, v.as_mut_ptr())}
    }
}

impl Drop for OSRng {
    #[cfg(unix)]
    fn drop(&mut self) {
        // ensure that OSRng is not implicitly copyable on all
        // platforms, for consistency.
    }

    #[cfg(windows)]
    fn drop(&mut self) {
        extern { fn rust_win32_rand_release(hProv: HCRYPTPROV); }

        unsafe {rust_win32_rand_release(self.hcryptprov)}
    }
}

#[cfg(test)]
mod test {
    use prelude::*;
    use super::*;
    use rand::Rng;
    use task;

    #[test]
    fn test_os_rng() {
        let mut r = OSRng::new();

        r.next_u32();
        r.next_u64();

        let mut v = [0u8, .. 1000];
        r.fill_bytes(v);
    }

    #[test]
    fn test_os_rng_tasks() {

        let mut chans = ~[];
        for _ in range(0, 20) {
            let (p, c) = Chan::new();
            chans.push(c);
            task::spawn(proc() {
                // wait until all the tasks are ready to go.
                p.recv();

                // deschedule to attempt to interleave things as much
                // as possible (XXX: is this a good test?)
                let mut r = OSRng::new();
                task::deschedule();
                let mut v = [0u8, .. 1000];

                for _ in range(0, 100) {
                    r.next_u32();
                    task::deschedule();
                    r.next_u64();
                    task::deschedule();
                    r.fill_bytes(v);
                    task::deschedule();
                }
            })
        }

        // start all the tasks
        for c in chans.iter() {
            c.send(())
        }
    }
}
<|endoftext|>


<commit_before>extern crate rand;

use std::{fmt, iter, thread, time};

use rand::Rng;

#[derive(Debug, Clone, Copy, PartialEq)]
enum Cell {
    Dead,
    Alive,
}

impl fmt::Display for Cell {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let ch = match *self {
            Cell::Dead => ' ',
            Cell::Alive => '█',
        };
        write!(f, "{}", ch)
    }
}

struct Grid {
    width: usize,
    height: usize,
    buf: Box<[Cell]>,
}

impl Grid {
    /// width, height and percentage
    pub fn new(w: usize, h: usize, p: f32) -> Self {
        let mut rng = rand::thread_rng();
        let buf_size = h * w;
        let live_cnt = ((buf_size as f32) * (p / 100.0)) as usize;
        let dead_cnt = buf_size - live_cnt;

        let mut buf = iter::repeat(Cell::Alive)
            .take(live_cnt)
            .chain(iter::repeat(Cell::Dead).take(dead_cnt))
            .collect::<Vec<Cell>>()
            .into_boxed_slice();

        rng.shuffle(&mut buf);

        Self {
            buf,
            width: w,
            height: h,
        }
    }

    pub fn display(&self) {
        (0..self.width).for_each(|_| print!("-"));
        println!("");

        self.buf.chunks(self.width).for_each(|l| {
            l.iter().for_each(|c| print!("{}", c));
            println!("");
        });

        (0..self.width).for_each(|_| print!("-"));
        println!("");
    }

    fn get_neigh(&self, idx: usize) -> [Cell; 8] {
        let l_edge = idx % self.width == 0;
        let r_edge = idx % self.width == self.width - 1;
        let t_edge = idx / self.width == 0;
        let b_edge = idx / self.width == self.height - 1;

        let l = if !l_edge {
            idx - 1
        } else {
            idx + self.width - 1
        };

        let r = if !r_edge {
            idx + 1
        } else {
            idx + 1 - self.width
        };

        let u = if !t_edge {
            idx - self.width
        } else {
            idx + (self.width * (self.height - 1))
        };

        let d = if !b_edge {
            idx + self.width
        } else {
            idx % self.width
        };

        let ru = if !t_edge {
            r - self.width
        } else {
            r + (self.width * (self.height - 1))
        };

        let rd = if !b_edge {
            r + self.width
        } else {
            r % self.width
        };

        let lu = if !t_edge {
            l - self.width
        } else {
            l + (self.width * (self.height - 1))
        };

        let ld = if !b_edge {
            l + self.width
        } else {
            l % self.width
        };

        //println!("{} {:?}", idx,  [l, r, u, d, ru, rd, lu, ld]);
        [
            self.buf[l],
            self.buf[r],
            self.buf[u],
            self.buf[d],
            self.buf[ru],
            self.buf[rd],
            self.buf[lu],
            self.buf[ld],
        ]
    }

    fn step(&mut self) {
        let counts: Vec<_> = (0..self.buf.len())
            .map(|idx| {
                self.get_neigh(idx)
                    .iter()
                    .filter(|&c| *c == Cell::Alive)
                    .count()
            })
            .collect();

        for (c, cnt) in self.buf.iter_mut().zip(counts) {
            *c = match (*c, cnt) {
                (Cell::Alive, cnt) if cnt < 2 => Cell::Dead,
                (Cell::Alive, cnt) if cnt < 4 => Cell::Alive,
                (Cell::Alive, cnt) if cnt >= 4 => Cell::Dead,
                (Cell::Dead, cnt) if cnt == 3 => Cell::Alive,
                _ => *c,
            }
        }
    }
}

fn main() {
    let mut g = Grid::new(100, 50, 15.0);

    g.display();
    loop {
        thread::sleep(time::Duration::from_millis(100));
        g.step();
        g.display();
    }
}
<commit_msg>Update in one iteration<commit_after>extern crate rand;

use std::{fmt, iter, thread, time};

use rand::Rng;

#[derive(Debug, Clone, Copy, PartialEq)]
enum Cell {
    Dead,
    Alive,
}

impl fmt::Display for Cell {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let ch = match *self {
            Cell::Dead => ' ',
            Cell::Alive => '█',
        };
        write!(f, "{}", ch)
    }
}

impl Cell {
    fn next(self, cnt: usize) -> Cell {
        match (self, cnt) {
            (Cell::Alive, cnt) if cnt < 2 => Cell::Dead,
            (Cell::Alive, cnt) if cnt < 4 => Cell::Alive,
            (Cell::Alive, cnt) if cnt >= 4 => Cell::Dead,
            (Cell::Dead, cnt) if cnt == 3 => Cell::Alive,
            _ => self,
        }
    }
}

struct Grid {
    width: usize,
    height: usize,
    buf: Box<[Cell]>,
}

impl Grid {
    /// width, height and percentage
    pub fn new(w: usize, h: usize, p: f32) -> Self {
        let mut rng = rand::thread_rng();
        let buf_size = h * w;
        let live_cnt = ((buf_size as f32) * (p / 100.0)) as usize;
        let dead_cnt = buf_size - live_cnt;

        let mut buf = iter::repeat(Cell::Alive)
            .take(live_cnt)
            .chain(iter::repeat(Cell::Dead).take(dead_cnt))
            .collect::<Vec<Cell>>()
            .into_boxed_slice();

        rng.shuffle(&mut buf);

        Self {
            buf,
            width: w,
            height: h,
        }
    }

    pub fn display(&self) {
        (0..self.width).for_each(|_| print!("-"));
        println!("");

        self.buf.chunks(self.width).for_each(|l| {
            l.iter().for_each(|c| print!("{}", c));
            println!("");
        });

        (0..self.width).for_each(|_| print!("-"));
        println!("");
    }

    fn get_neigh(&self, idx: usize) -> [Cell; 8] {
        let l_edge = idx % self.width == 0;
        let r_edge = idx % self.width == self.width - 1;
        let t_edge = idx / self.width == 0;
        let b_edge = idx / self.width == self.height - 1;

        let l = if !l_edge {
            idx - 1
        } else {
            idx + self.width - 1
        };

        let r = if !r_edge {
            idx + 1
        } else {
            idx + 1 - self.width
        };

        let u = if !t_edge {
            idx - self.width
        } else {
            idx + (self.width * (self.height - 1))
        };

        let d = if !b_edge {
            idx + self.width
        } else {
            idx % self.width
        };

        let ru = if !t_edge {
            r - self.width
        } else {
            r + (self.width * (self.height - 1))
        };

        let rd = if !b_edge {
            r + self.width
        } else {
            r % self.width
        };

        let lu = if !t_edge {
            l - self.width
        } else {
            l + (self.width * (self.height - 1))
        };

        let ld = if !b_edge {
            l + self.width
        } else {
            l % self.width
        };

        //println!("{} {:?}", idx,  [l, r, u, d, ru, rd, lu, ld]);
        [
            self.buf[l],
            self.buf[r],
            self.buf[u],
            self.buf[d],
            self.buf[ru],
            self.buf[rd],
            self.buf[lu],
            self.buf[ld],
        ]
    }

    fn step(&mut self) {
        self.buf = self.buf
            .iter()
            .enumerate()
            .map(|(idx, c)| {
                let cnt = self.get_neigh(idx)
                    .iter()
                    .filter(|&cc| *cc == Cell::Alive)
                    .count();

                c.next(cnt)
            })
            .collect::<Vec<Cell>>()
            .into_boxed_slice();
    }
}

fn main() {
    let mut g = Grid::new(100, 50, 15.0);

    g.display();
    loop {
        thread::sleep(time::Duration::from_millis(100));
        g.step();
        g.display();
    }
}
<|endoftext|>


<commit_before>#![feature(net)]
extern crate nickel;
#[macro_use] extern crate nickel_macros;

use std::collections::HashMap;
use std::net::IpAddr;
use nickel::*;
use std::io;

fn main() {

   let mut nickel = Nickel::new();

   nickel.utilize(StaticFilesHandler::new("public/"));

   nickel.utilize(middleware! { |request|
     println!("Request: {:?}", request.origin.uri);
     });

   fn handler<'a>(_: &mut Request, res: Response<'a>) -> MiddlewareResult<'a> {

     let mut data = HashMap::<&str, &str>::new();
     data.insert("title", "nickel-bootstrap");
     data.insert("message", "hello from nickel bootstrap!");
     Ok(Halt(try!(res.render("templates/index.mustache", &data))))

   }

   nickel.get("**", middleware!(@handler));

   nickel.listen(IpAddr::new_v4(127,0,0,1), 6767);
}
<commit_msg>removed unused include<commit_after>#![feature(net)]
extern crate nickel;
#[macro_use] extern crate nickel_macros;

use std::collections::HashMap;
use std::net::IpAddr;
use nickel::*;

fn main() {

   let mut nickel = Nickel::new();

   nickel.utilize(StaticFilesHandler::new("public/"));

   nickel.utilize(middleware! { |request|
     println!("Request: {:?}", request.origin.uri);
     });

   fn handler<'a>(_: &mut Request, res: Response<'a>) -> MiddlewareResult<'a> {

     let mut data = HashMap::<&str, &str>::new();
     data.insert("title", "nickel-bootstrap");
     data.insert("message", "hello from nickel bootstrap!");
     Ok(Halt(try!(res.render("templates/index.mustache", &data))))

   }

   nickel.get("**", middleware!(@handler));

   nickel.listen(IpAddr::new_v4(127,0,0,1), 6767);
}
<|endoftext|>


<commit_before>
#[macro_use]
extern crate clap;
use clap::{Arg, App};

use std::io::{self, Read};
use std::fs::File;
use std::path::{Path, PathBuf};
use std::ffi::OsStr;
use std::error::Error;
use std::env;

use std::collections::HashSet;
use std::collections::HashMap;

extern crate petgraph;
use petgraph::Graph;
use petgraph::prelude::NodeIndex;

extern crate walkdir;
use walkdir::WalkDir;

#[macro_use]
extern crate lazy_static;
extern crate regex;

use regex::Regex;

mod path_utils;

mod dot_writer;

mod file_node;
use file_node::FileNode;

// -----------------------------------------------------------------------------

#[derive(Debug)]
enum IncludeStatus {
    Relative, // e.g. <vector>
    Absolute, // e.g. /usr/include/c++/4.8/vector
    FailedLookup, // Failed to resolve an absolute file path.
}

#[derive(Debug)]
struct Include {
    path: PathBuf,
    is_system_include: bool,
    status: IncludeStatus,
}

impl Include {
    fn new_relative(name: &str, is_sys: bool) -> Include {
        Include {
            path: PathBuf::from(name),
            is_system_include: is_sys,
            status: IncludeStatus::Relative,
        }
    }

    fn as_absolute(&self, absolute_path: &Path) -> Include {
        Include {
            path: PathBuf::from(absolute_path),
            is_system_include: self.is_system_include,
            status: IncludeStatus::Absolute,
        }
    }

    fn as_failed_lookup(&self) -> Include {
        Include {
            path: PathBuf::from(&self.path),
            is_system_include: self.is_system_include,
            status: IncludeStatus::FailedLookup,
        }
    }
}

// ----------------------------------------------------------------------------

// Convert a relative include path (e.g. <Windows.h>) into an absolute path.
fn find_absolute_include_path(include: &Include,
                              parent_file: &Path,
                              system_search_paths: &[PathBuf])
                              -> Include {

    let local_dir = parent_file.parent().unwrap(); // strip the file name

    let normalized_path = path_utils::normalize_path_separators(&include.path);

    match path_utils::convert_to_absolute_path(&normalized_path, local_dir, system_search_paths) {
        None => {
            println!("In file {:?}", parent_file);
            println!("Unable to locate include {:?}", &include.path);
            println!("");
            include.as_failed_lookup()
        }
        Some(path_buf) => include.as_absolute(path_buf.as_path()),
    }
}

// -----------------------------------------------------------------------------

// Return a list of #include statements found in the file
fn scan_file_for_includes(file: &Path) -> Result<Vec<Include>, io::Error> {
    let mut f = File::open(file)?;
    let mut text = String::new();
    f.read_to_string(&mut text)?;

    let mut includes = Vec::new();

    // Use a regex to search for '#include ...' lines.
    // The second (...) capture group isolates just the text, not the "" or <> symbols.
    lazy_static! {
        static ref RE: Regex = Regex::new(r##"#include ([<|"])(.*)[>|"]"##).unwrap();
    }

    // cap.at(1) is an angle brace or double quote, to determine user or system include.
    // cap.at(2) is the include file name.
    for cap in RE.captures_iter(&text) {
        let is_system_include = cap.at(1).map_or(false, |sym| sym == "<");

        if let Some(include_name) = cap.at(2) {
            includes.push(Include::new_relative(include_name, is_system_include));
        }
    }

    // println!("Found {} includes in {}", includes.len(), &file.display());

    Ok(includes)
}

// -----------------------------------------------------------------------------

// TODO: implement the command line arguments from the original 'cinclude2dot' project.
// --debug       Display various debug info
// --exclude     Specify a regular expression of filenames to ignore
//              For example, ignore your test harnesses.
// --merge       Granularity of the diagram:
//              file - the default, treats each file as separate
//              module - merges .c/.cc/.cpp/.cxx and .h/.hpp/.hxx pairs
//              directory - merges directories into one node
// --groups      Cluster files or modules into directory groups
// --help        Display this help page.
// --include     Followed by a comma separated list of include search paths.
// --paths       Leaves relative paths in displayed filenames.
// --quotetypes  Select for parsing the files included by strip quotes or angle brackets:
//              both - the default, parse all headers.
//              angle - include only "system" headers included by anglebrackets (<>)
//              quote - include only "user" headers included by strip quotes ("")
// --src         Followed by a path to the source code, defaults to current directory

arg_enum! {
    #[derive(Debug)]
    #[allow(non_camel_case_types)]
    enum MergeType {
        file,
        module,
        directory
    }
}

arg_enum! {
    #[derive(Debug)]
    #[allow(non_camel_case_types)]
    enum QuoteTypes {
        both,
        angle,
        quote
    }
}

fn main() {
    // TODO: accept extra include paths.
    let args = App::new("IncludeGraph-rs")
        .version(crate_version!())
        .author(crate_authors!())
        .about("Generates an include graph from a tree of C++ files")
        .arg(Arg::with_name("debug")
            .long("debug")
            .help("Display extra debug info")
            .takes_value(true))
        .arg(Arg::with_name("exclude")
            .long("exclude")
            .help("Specify a regular expression of filenames to ignore. \nRust/RE2 \
                   syntax.\n\tExample: --exclude=\"test_|noisyFile\"")
            .takes_value(true))
        .arg(Arg::with_name("merge")
            .long("merge")
            .help("Granularity of the diagram: \nfile - the default, treats each file as \
                   separate \nmodule - merges .c/.cc/.cpp/.cxx and .h/.hpp/.hxx pairs \
                   \ndirectory - merges directories into one node\n")
            .possible_values(&MergeType::variants())
            .default_value("file")
            .takes_value(true))
        .arg(Arg::with_name("groups")
            .long("groups")
            .help("Cluster files or modules into directory groups")
            .takes_value(true))
        .arg(Arg::with_name("include")
            .long("include")
            .help("Comma separated list of include search paths.")
            .takes_value(true))
        .arg(Arg::with_name("paths")
            .long("paths")
            .help("Leaves relative paths in displayed filenames.")
            .takes_value(true))
        .arg(Arg::with_name("quotetypes")
            .long("quotetypes")
            .help("Select which type of includes to parse:\nboth - the default, parse all \
                   includes. \nangle - parse only \"system\" includes (<>) \nquote - parse only \
                   \"user\" includes (\"\")\n")
            .possible_values(&QuoteTypes::variants())
            .default_value("both")
            .takes_value(true))
        .arg(Arg::with_name("src")
            .help("Path to the source code, defaults to current directory.")
            .multiple(false))
        .get_matches();

    let expand_system_includes = false;

    let root_dir = match args.value_of("src") {
        Some(path) => PathBuf::from(path),
        None => env::current_dir().unwrap()
    };

    if !root_dir.exists() {
        println!("Unable to access directory: {}", root_dir.display());
    }

    // Create a list of default system include paths.
    let mut search_paths = Vec::new();
    if expand_system_includes {
        search_paths.push(PathBuf::from(r"C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\include"));
    }

    // Restrict the file extensions to search.
    let mut extensions = HashSet::new();
    extensions.insert(OsStr::new("c"));
    extensions.insert(OsStr::new("cc"));
    extensions.insert(OsStr::new("cpp"));
    extensions.insert(OsStr::new("cxx"));
    extensions.insert(OsStr::new("h"));
    extensions.insert(OsStr::new("hpp"));
    extensions.insert(OsStr::new("hxx"));

    // Regular expression of files to exclude. Skip if exclude string is empty.
    let exclude_regex = args.value_of("exclude")
        .and_then(|ref regex_str| {
            Regex::new(regex_str)
                .map_err(|err| panic!("Unable to parse exclude regex: {}", err.description()))
                .ok() // Converts successful result to Some(), discarding errors.
        });

    // Collect all the files to scan in a HashSet
    // Note: is_hidden() is currently hiding paths that start with './', so don't use it yet.
    let input_queue = WalkDir::new(root_dir).into_iter()
        //.filter_entry(|e| !path_utils::is_hidden(e))
        .filter_map(|entry| match entry {
            Err(what) => {println!("Error reading directory: {}", what.description()); None},
            Ok(val) => Some(val),
        })
        .map(|entry| PathBuf::from(entry.path()))
        .filter(|ref path| path.extension().map_or(false, |ext| extensions.contains(ext)))
        .filter(|ref path| !path_utils::filename_matches_regex(&exclude_regex, &path))
        .collect::<HashSet<_>>();

    // Graph of all the tracked files
    let mut graph = Graph::<FileNode, bool>::new();
    let mut indices = HashMap::<FileNode, NodeIndex>::new();

    for path_buf in input_queue {
        let parent_file = path_buf.as_path();
        let includes_result = scan_file_for_includes(parent_file);
        match includes_result {
            Ok(includes) => {

                // Convert relative includes to absolute includes
                let user_includes = includes.iter()
                    .filter(|inc| !inc.is_system_include || expand_system_includes)
                    .filter(|inc| !path_utils::name_matches_regex(&exclude_regex, &inc.path))
                    .map(|inc| find_absolute_include_path(inc, parent_file, &search_paths))
                    .collect::<Vec<_>>();

                for inc in user_includes {
                    // Get an existing NodeIndex from the graph, on create a new node.
                    let src_node = FileNode {
                        path: PathBuf::from(&parent_file),
                        is_system: false,
                    };
                    let dst_node = FileNode {
                        path: PathBuf::from(&inc.path),
                        is_system: false,
                    };

                    // These functions should work, but currently create duplicate nodes.
                    let src_node_idx = indices.entry(src_node.clone())
                        .or_insert_with(|| graph.add_node(src_node))
                        .clone();
                    let dst_node_idx = indices.entry(dst_node.clone())
                        .or_insert_with(|| graph.add_node(dst_node))
                        .clone();

                    // println!("Adding edge {:?} -> {:?}", src_node_idx, dst_node_idx);
                    graph.add_edge(src_node_idx, dst_node_idx, true);
                }

                // We still add system includes to the graph, but skip the file lookup.
                if !expand_system_includes {
                    let system_includes: Vec<_> = includes.iter()
                        .filter(|inc| inc.is_system_include && !expand_system_includes)
                        .filter(|inc| !path_utils::name_matches_regex(&exclude_regex, &inc.path))
                        .collect();

                    for inc in system_includes {

                        // Get an existing NodeIndex from the graph, on create a new node.
                        let src_node = FileNode {
                            path: PathBuf::from(&parent_file),
                            is_system: false,
                        };
                        let dst_node = FileNode {
                            path: PathBuf::from(&inc.path),
                            is_system: true,
                        };

                        // These functions should work, but currently create duplicate nodes.
                        let src_node_idx = indices.entry(src_node.clone())
                            .or_insert_with(|| graph.add_node(src_node))
                            .clone();
                        let dst_node_idx = indices.entry(dst_node.clone())
                            .or_insert_with(|| graph.add_node(dst_node))
                            .clone();

                        // println!("Adding edge {:?} -> {:?}", src_node_idx, dst_node_idx);
                        graph.add_edge(src_node_idx, dst_node_idx, true);
                    }

                }
            }
            Err(err) => {
                println!("Unable to process file {:?}: {}", parent_file, err);
            }
        };
    }

    // Write the graph to a dot file.
    let _ = dot_writer::write_dot_with_header("./graph.dot", &graph);

    println!("Now run \"dot -Tpdf graph.dot > graph.pdf\" to render the graph.");
}
<commit_msg>Added optional extra include paths<commit_after>
#[macro_use]
extern crate clap;
use clap::{Arg, App};

use std::io::{self, Read};
use std::fs::File;
use std::path::{Path, PathBuf};
use std::ffi::OsStr;
use std::error::Error;
use std::env;

use std::collections::HashSet;
use std::collections::HashMap;

extern crate petgraph;
use petgraph::Graph;
use petgraph::prelude::NodeIndex;

extern crate walkdir;
use walkdir::WalkDir;

#[macro_use]
extern crate lazy_static;
extern crate regex;

use regex::Regex;

mod path_utils;

mod dot_writer;

mod file_node;
use file_node::FileNode;

// -----------------------------------------------------------------------------

#[derive(Debug)]
enum IncludeStatus {
    Relative, // e.g. <vector>
    Absolute, // e.g. /usr/include/c++/4.8/vector
    FailedLookup, // Failed to resolve an absolute file path.
}

#[derive(Debug)]
struct Include {
    path: PathBuf,
    is_system_include: bool,
    status: IncludeStatus,
}

impl Include {
    fn new_relative(name: &str, is_sys: bool) -> Include {
        Include {
            path: PathBuf::from(name),
            is_system_include: is_sys,
            status: IncludeStatus::Relative,
        }
    }

    fn as_absolute(&self, absolute_path: &Path) -> Include {
        Include {
            path: PathBuf::from(absolute_path),
            is_system_include: self.is_system_include,
            status: IncludeStatus::Absolute,
        }
    }

    fn as_failed_lookup(&self) -> Include {
        Include {
            path: PathBuf::from(&self.path),
            is_system_include: self.is_system_include,
            status: IncludeStatus::FailedLookup,
        }
    }
}

// ----------------------------------------------------------------------------

// Convert a relative include path (e.g. <Windows.h>) into an absolute path.
fn find_absolute_include_path(include: &Include,
                              parent_file: &Path,
                              system_search_paths: &[PathBuf])
                              -> Include {

    let local_dir = parent_file.parent().unwrap(); // strip the file name

    let normalized_path = path_utils::normalize_path_separators(&include.path);

    match path_utils::convert_to_absolute_path(&normalized_path, local_dir, system_search_paths) {
        None => {
            println!("In file {:?}", parent_file);
            println!("Unable to locate include {:?}", &include.path);
            println!("");
            include.as_failed_lookup()
        }
        Some(path_buf) => include.as_absolute(path_buf.as_path()),
    }
}

// -----------------------------------------------------------------------------

// Return a list of #include statements found in the file
fn scan_file_for_includes(file: &Path) -> Result<Vec<Include>, io::Error> {
    let mut f = File::open(file)?;
    let mut text = String::new();
    f.read_to_string(&mut text)?;

    let mut includes = Vec::new();

    // Use a regex to search for '#include ...' lines.
    // The second (...) capture group isolates just the text, not the "" or <> symbols.
    lazy_static! {
        static ref RE: Regex = Regex::new(r##"#include ([<|"])(.*)[>|"]"##).unwrap();
    }

    // cap.at(1) is an angle brace or double quote, to determine user or system include.
    // cap.at(2) is the include file name.
    for cap in RE.captures_iter(&text) {
        let is_system_include = cap.at(1).map_or(false, |sym| sym == "<");

        if let Some(include_name) = cap.at(2) {
            includes.push(Include::new_relative(include_name, is_system_include));
        }
    }

    // println!("Found {} includes in {}", includes.len(), &file.display());

    Ok(includes)
}

// -----------------------------------------------------------------------------

// TODO: implement the command line arguments from the original 'cinclude2dot' project.
// --debug       Display various debug info
// --exclude     Specify a regular expression of filenames to ignore
//              For example, ignore your test harnesses.
// --merge       Granularity of the diagram:
//              file - the default, treats each file as separate
//              module - merges .c/.cc/.cpp/.cxx and .h/.hpp/.hxx pairs
//              directory - merges directories into one node
// --groups      Cluster files or modules into directory groups
// --help        Display this help page.
// --include     Followed by a comma separated list of include search paths.
// --paths       Leaves relative paths in displayed filenames.
// --quotetypes  Select for parsing the files included by strip quotes or angle brackets:
//              both - the default, parse all headers.
//              angle - include only "system" headers included by anglebrackets (<>)
//              quote - include only "user" headers included by strip quotes ("")
// --src         Followed by a path to the source code, defaults to current directory

arg_enum! {
    #[derive(Debug)]
    #[allow(non_camel_case_types)]
    enum MergeType {
        file,
        module,
        directory
    }
}

arg_enum! {
    #[derive(Debug)]
    #[allow(non_camel_case_types)]
    enum QuoteTypes {
        both,
        angle,
        quote
    }
}

fn main() {
    // TODO: accept extra include paths.
    let args = App::new("IncludeGraph-rs")
        .version(crate_version!())
        .author(crate_authors!())
        .about("Generates an include graph from a tree of C++ files")
        .arg(Arg::with_name("debug")
            .long("debug")
            .help("Display extra debug info")
            .takes_value(true))
        .arg(Arg::with_name("exclude")
            .long("exclude")
            .help("Specify a regular expression of filenames to ignore. \nRust/RE2 \
                   syntax.\n\tExample: --exclude=\"test_|noisyFile\"")
            .takes_value(true))
        .arg(Arg::with_name("merge")
            .long("merge")
            .help("Granularity of the diagram: \nfile - the default, treats each file as \
                   separate \nmodule - merges .c/.cc/.cpp/.cxx and .h/.hpp/.hxx pairs \
                   \ndirectory - merges directories into one node\n")
            .possible_values(&MergeType::variants())
            .default_value("file")
            .takes_value(true))
        .arg(Arg::with_name("groups")
            .long("groups")
            .help("Cluster files or modules into directory groups")
            .takes_value(true))
        .arg(Arg::with_name("include")
            .long("include")
            .help("Comma separated list of include search paths.")
            .multiple(true)
            .require_delimiter(true)
            .takes_value(true))
        .arg(Arg::with_name("paths")
            .long("paths")
            .help("Leaves relative paths in displayed filenames.")
            .takes_value(true))
        .arg(Arg::with_name("quotetypes")
            .long("quotetypes")
            .help("Select which type of includes to parse:\nboth - the default, parse all \
                   includes. \nangle - parse only \"system\" includes (<>) \nquote - parse only \
                   \"user\" includes (\"\")\n")
            .possible_values(&QuoteTypes::variants())
            .default_value("both")
            .takes_value(true))
        .arg(Arg::with_name("src")
            .help("Path to the source code, defaults to current directory.")
            .multiple(false))
        .get_matches();

    let expand_system_includes = false;

    let root_dir = match args.value_of("src") {
        Some(path) => PathBuf::from(path),
        None => env::current_dir().unwrap()
    };

    if !root_dir.exists() {
        panic!("Unable to access directory: {}", root_dir.display());
    }
    //println!("Scanning directory: {}", root_dir.display());

    // Collect a list of include paths to search.
    let mut search_paths = Vec::new();
    if let Some(values) = args.values_of("include") {
        for string in values {
            //println!("Using include: {}", &string);
            search_paths.push(PathBuf::from(string));
        }
    }

    // Add a list of default system include paths.
//    if expand_system_includes {
//        search_paths.push(PathBuf::from(r"C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\include"));
//    }

    // Restrict the file extensions to search.
    let mut extensions = HashSet::new();
    extensions.insert(OsStr::new("c"));
    extensions.insert(OsStr::new("cc"));
    extensions.insert(OsStr::new("cpp"));
    extensions.insert(OsStr::new("cxx"));
    extensions.insert(OsStr::new("h"));
    extensions.insert(OsStr::new("hpp"));
    extensions.insert(OsStr::new("hxx"));

    // Regular expression of files to exclude. Skip if exclude string is empty.
    let exclude_regex = args.value_of("exclude")
        .and_then(|ref regex_str| {
            Regex::new(regex_str)
                .map_err(|err| panic!("Unable to parse exclude regex: {}", err.description()))
                .ok() // Converts successful result to Some(), discarding errors.
        });

    // Collect all the files to scan in a HashSet
    // Note: is_hidden() is currently hiding paths that start with './', so don't use it yet.
    let input_queue = WalkDir::new(root_dir).into_iter()
        //.filter_entry(|e| !path_utils::is_hidden(e))
        .filter_map(|entry| match entry {
            Err(what) => {println!("Error reading directory: {}", what.description()); None},
            Ok(val) => Some(val),
        })
        .map(|entry| PathBuf::from(entry.path()))
        .filter(|ref path| path.extension().map_or(false, |ext| extensions.contains(ext)))
        .filter(|ref path| !path_utils::filename_matches_regex(&exclude_regex, &path))
        .collect::<HashSet<_>>();

    // Graph of all the tracked files
    let mut graph = Graph::<FileNode, bool>::new();
    let mut indices = HashMap::<FileNode, NodeIndex>::new();

    for path_buf in input_queue {
        let parent_file = path_buf.as_path();
        let includes_result = scan_file_for_includes(parent_file);
        match includes_result {
            Ok(includes) => {

                // Convert relative includes to absolute includes
                let user_includes = includes.iter()
                    .filter(|inc| !inc.is_system_include || expand_system_includes)
                    .filter(|inc| !path_utils::name_matches_regex(&exclude_regex, &inc.path))
                    .map(|inc| find_absolute_include_path(inc, parent_file, &search_paths))
                    .collect::<Vec<_>>();

                for inc in user_includes {
                    // Get an existing NodeIndex from the graph, on create a new node.
                    let src_node = FileNode {
                        path: PathBuf::from(&parent_file),
                        is_system: false,
                    };
                    let dst_node = FileNode {
                        path: PathBuf::from(&inc.path),
                        is_system: false,
                    };

                    // These functions should work, but currently create duplicate nodes.
                    let src_node_idx = indices.entry(src_node.clone())
                        .or_insert_with(|| graph.add_node(src_node))
                        .clone();
                    let dst_node_idx = indices.entry(dst_node.clone())
                        .or_insert_with(|| graph.add_node(dst_node))
                        .clone();

                    // println!("Adding edge {:?} -> {:?}", src_node_idx, dst_node_idx);
                    graph.add_edge(src_node_idx, dst_node_idx, true);
                }

                // We still add system includes to the graph, but skip the file lookup.
                if !expand_system_includes {
                    let system_includes: Vec<_> = includes.iter()
                        .filter(|inc| inc.is_system_include && !expand_system_includes)
                        .filter(|inc| !path_utils::name_matches_regex(&exclude_regex, &inc.path))
                        .collect();

                    for inc in system_includes {

                        // Get an existing NodeIndex from the graph, on create a new node.
                        let src_node = FileNode {
                            path: PathBuf::from(&parent_file),
                            is_system: false,
                        };
                        let dst_node = FileNode {
                            path: PathBuf::from(&inc.path),
                            is_system: true,
                        };

                        // These functions should work, but currently create duplicate nodes.
                        let src_node_idx = indices.entry(src_node.clone())
                            .or_insert_with(|| graph.add_node(src_node))
                            .clone();
                        let dst_node_idx = indices.entry(dst_node.clone())
                            .or_insert_with(|| graph.add_node(dst_node))
                            .clone();

                        // println!("Adding edge {:?} -> {:?}", src_node_idx, dst_node_idx);
                        graph.add_edge(src_node_idx, dst_node_idx, true);
                    }

                }
            }
            Err(err) => {
                println!("Unable to process file {:?}: {}", parent_file, err);
            }
        };
    }

    // Write the graph to a dot file.
    let _ = dot_writer::write_dot_with_header("./graph.dot", &graph);

    println!("Now run \"dot -Tpdf graph.dot > graph.pdf\" to render the graph.");
}
<|endoftext|>


<commit_before>extern crate toml;
extern crate graphviz;

use graphviz as dot;

fn main() {
    println!("Not yet implemented");
}
<commit_msg>Parse Cargo.lock<commit_after>extern crate toml;
extern crate graphviz;

use graphviz as dot;
use std::io::{File};

fn main() {
    let contents =
        File::open(&Path::new("Cargo.lock")).read_to_string();
    match contents {
        Err(e) => {
            println!("Error: {}", e);
            std::os::set_exit_status(1)
        },
        Ok(toml_str) => {
            match toml::Parser::new(toml_str.as_slice()).parse() {
                None => {
                    println!("Cargo.lock is invalid toml");
                    std::os::set_exit_status(1)
                }
                Some(toml) => {
                    println!("Valid toml serialization: {}", toml::Table(toml))
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>use std::io;

fn print_table(table: [char; 9]) {

	println!("+---+---+---+");
	println!("| {} | {} | {} |", table[0], table[1], table[2]);
	println!("+---+---+---+");
	println!("| {} | {} | {} |", table[3], table[4], table[5]);
	println!("+---+---+---+");
	println!("| {} | {} | {} |", table[6], table[7], table[8]);
	println!("+---+---+---+");

}

fn change_player(mut player: char) -> char {
	if player == 'x' { 'o' } else { 'x' }
}

/*
/	We're adding player as second parameter
/	because we want to know who played
/	last move so we wouldn't have to check
/	both times
*/
fn check_table(table: [char; 9], player: char) -> bool {

	if full_table(table) {
		return true;
	}

	if (table[0], table[1], table[2]) == (player, player, player) ||
		(table[3], table[4], table[5]) == (player, player, player) ||
		(table[6], table[7], table[8]) == (player, player, player) ||
		(table[0], table[3], table[6]) == (player, player, player) ||
		(table[1], table[4], table[7]) == (player, player, player) ||
		(table[2], table[5], table[8]) == (player, player, player) ||
		(table[0], table[4], table[8]) == (player, player, player) ||
		(table[2], table[4], table[6]) == (player, player, player)
	{
		return true;
	}

	false

}

fn full_table(table: [char; 9]) -> bool {

	if table[0] != ' ' &&
		table[1] != ' ' &&
		table[2] != ' ' &&
		table[3] != ' ' &&
		table[4] != ' ' &&
		table[5] != ' ' &&
		table[6] != ' ' &&
		table[7] != ' ' &&
		table[8] != ' '
	{
		true
	}
	else
	{
		false
	}

}

fn main() {

	let mut table: [char; 9] = [' '; 9];

	// set x as first player
	let mut player: char = 'x';

	let mut stdin = io::stdin();
	let mut input = String::new();
	let mut field = 0;
	let mut valid: bool = true;
	let mut game_over: bool = false;

	println!("ROX - Tic Tac Toe in Rust");
	println!("Author: Nikola S. (panther99)");

	while !game_over {

		// change player
		player = change_player(player);

		// clears input, prints table and curren player
		input.clear();
		print_table(table);
		println!("Current player: {}", player);
		println!("Choose field (1-9): ");

		// get user input
		io::stdin().read_line(&mut input)
			.expect("Failed to read line");

		// we're shadowing field to usize to use it
		// for indexing array in field checker
		let field: usize = input.trim().parse()
			.expect("Failed to read line");

		// check if user wrote valid field
		if field > 0 && field < 10 {
			if table[field-1] == ' ' {
				table[field-1] = player;
				valid = true;
			} else {
				println!("That field isn't empty!");
				valid = false;
			}
		} else {
			println!("That field doesn't exist!");
			valid = false;
		}

		// do this while field is invalid
        while !valid {

			input.clear();
			print_table(table);
			println!("Choose field (1-9): ");
			io::stdin().read_line(&mut input)
				.expect("Failed to read line");
			let field: usize = input.trim().parse()
				.expect("Failed to read line");

			if field > 0 && field < 10 {
				if table[field-1] == ' ' {
					table[field-1] = player;
					valid = true;
				} else {
					println!("That field isn't empty!");
					valid = false;
				}
			} else {
				println!("That field doesn't exist!");
				valid = false;
			}

        }

		// check if current player won the game
		game_over = check_table(table, player);

    }

	// check if table is full or last player won the game
	if full_table(table) {
		println!("It's a tie!");
	} else {
		println!("Player {} won the game!", player);
	}

}

<commit_msg>Fixed formatting<commit_after>use std::io;

fn print_table(table: [char; 9]) {

	println!("+---+---+---+");
	println!("| {} | {} | {} |", table[0], table[1], table[2]);
	println!("+---+---+---+");
	println!("| {} | {} | {} |", table[3], table[4], table[5]);
	println!("+---+---+---+");
	println!("| {} | {} | {} |", table[6], table[7], table[8]);
	println!("+---+---+---+");

}

fn change_player(mut player: char) -> char {
	if player == 'x' { 'o' } else { 'x' }
}

/*
/	We're adding player as second parameter
/	because we want to know who played
/	last move so we wouldn't have to check
/	both times
*/
fn check_table(table: [char; 9], player: char) -> bool {

	if full_table(table) {
		return true;
	}

	if (table[0], table[1], table[2]) == (player, player, player) ||
		(table[3], table[4], table[5]) == (player, player, player) ||
		(table[6], table[7], table[8]) == (player, player, player) ||
		(table[0], table[3], table[6]) == (player, player, player) ||
		(table[1], table[4], table[7]) == (player, player, player) ||
		(table[2], table[5], table[8]) == (player, player, player) ||
		(table[0], table[4], table[8]) == (player, player, player) ||
		(table[2], table[4], table[6]) == (player, player, player)
	{
		return true;
	}

	false

}

fn full_table(table: [char; 9]) -> bool {

	if table[0] != ' ' &&
		table[1] != ' ' &&
		table[2] != ' ' &&
		table[3] != ' ' &&
		table[4] != ' ' &&
		table[5] != ' ' &&
		table[6] != ' ' &&
		table[7] != ' ' &&
		table[8] != ' '
	{
		true
	}
	else
	{
		false
	}

}

fn main() {

	let mut table: [char; 9] = [' '; 9];

	// set x as first player
	let mut player: char = 'x';

	let mut stdin = io::stdin();
	let mut input = String::new();
	let mut field = 0;
	let mut valid: bool = true;
	let mut game_over: bool = false;

	println!("ROX - Tic Tac Toe in Rust");
	println!("Author: Nikola S. (panther99)");

	while !game_over {

		// change player
		player = change_player(player);

		// clears input, prints table and curren player
		input.clear();
		print_table(table);
		println!("Current player: {}", player);
		println!("Choose field (1-9): ");

		// get user input
		io::stdin().read_line(&mut input)
			.expect("Failed to read line");

		// we're shadowing field to usize to use it
		// for indexing array in field checker
		let field: usize = input.trim().parse()
			.expect("Failed to read line");

		// check if user wrote valid field
		if field > 0 && field < 10 {
			if table[field-1] == ' ' {
				table[field-1] = player;
				valid = true;
			} else {
				println!("That field isn't empty!");
				valid = false;
			}
		} else {
			println!("That field doesn't exist!");
			valid = false;
		}

		// do this while field is invalid
		while !valid {

			input.clear();
			print_table(table);
			println!("Choose field (1-9): ");
			io::stdin().read_line(&mut input)
				.expect("Failed to read line");
			let field: usize = input.trim().parse()
				.expect("Failed to read line");

			if field > 0 && field < 10 {
				if table[field-1] == ' ' {
					table[field-1] = player;
					valid = true;
				} else {
					println!("That field isn't empty!");
					valid = false;
				}
			} else {
				println!("That field doesn't exist!");
				valid = false;
			}

		}

		// check if current player won the game
		game_over = check_table(table, player);

	}

	// check if table is full or last player won the game
	if full_table(table) {
		println!("It's a tie!");
	} else {
		println!("Player {} won the game!", player);
	}

}

<|endoftext|>


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

use clap::{Parser, Subcommand};

#[derive(Parser)]
#[command(author, version, about, long_about = None)]
struct Cli {
    #[command(subcommand)]
    command: Option<Commands>,
}

#[derive(Subcommand)]
enum Commands {
    /// The export command exports DSL files into PlantUML files using Structurizr-CLI
    Export {
        /// A file path for DSL files to be read from
        #[arg(short, long)]
        workspace: PathBuf,

        /// Format that Structurizr-CLI supports
        #[arg(short, long)]
        formatter: String,

        /// A file path for PlantUML files to be exported to
        #[arg(short, long)]
        output: Option<PathBuf>,
    },
    /// The render command renders DSL files into PNG files using a specific formatter
    Render {
        /// Format that Structurizr-CLI supports
        #[arg(short, long)]
        formatter: String,

        /// Input file path for files
        #[arg(short, long)]
        input: PathBuf,
    },
}

fn main() {
    let cli = Cli::parse();

    match cli.command {
        Some(Commands::Export {
            workspace,
            formatter,
            output,
        }) => {
            todo!()
        }
        Some(Commands::Render { input, formatter }) => {
            todo!()
        }
        None => {}
    }
}
<commit_msg>Adding enums for Structurizr supported formatters<commit_after>use std::path::PathBuf;

use clap::{Parser, Subcommand, ValueEnum};

#[derive(Parser)]
#[command(author, version, about, long_about = None)]
struct Cli {
    #[command(subcommand)]
    command: Option<Commands>,
}

#[derive(Copy, Clone, PartialEq, Eq, ValueEnum)]
enum Formatters {
    PlantUML,
    PlantUMLStructurizr,
    PlantUMLC4,
    Mermaid,
    WebSequence,
    Ilograph,
    DOT,
    JSON,
    DSL,
    Theme,
}

#[derive(Subcommand)]
enum Commands {
    /// The export command exports DSL files into PlantUML files using Structurizr-CLI
    Export {
        /// A file path for DSL files to be read from
        #[arg(short, long)]
        workspace: PathBuf,

        /// A format that Structurizr-CLI supports
        #[arg(short, long, value_enum)]
        formatter: Formatters,

        /// A file path for PlantUML files to be exported to
        #[arg(short, long)]
        output: Option<PathBuf>,
    },
    /// The render command renders DSL files into PNG files using a specific formatter
    Render {
        /// A format that Structurizr-CLI supports
        #[arg(short, long, value_enum)]
        formatter: Formatters,

        /// Input file path for files
        #[arg(short, long)]
        input: PathBuf,
    },
}

fn main() {
    let cli = Cli::parse();

    match cli.command {
        Some(Commands::Export {
            workspace,
            formatter,
            output,
        }) => {
            todo!()
        }
        Some(Commands::Render { input, formatter }) => {
            todo!()
        }
        None => {}
    }
}
<|endoftext|>


<commit_before>#![allow(dead_code)]

// `error_chain!` can recurse deeply
#![recursion_limit = "1024"]

#[macro_use] extern crate error_chain;
#[macro_use] extern crate glium;
extern crate rand;

#[cfg(test)]
#[macro_use]
mod test_utils;

mod drawer;
mod errors;
mod graph;
mod map;
mod math;
mod mouse;
mod square;
mod state;
mod visible_graph;

use drawer::Drawer;
use graph::Graph;
use map::{Map, Player};
use math::{apply, compose};
use mouse::Mouse;
use square::SquareGrid;
use state::{MAX_GOOP, Occupied, State};
use visible_graph::GraphPt;

use glium::glutin::{Event, ElementState, MouseButton, VirtualKeyCode};
use glium::Surface;

use std::rc::Rc;
use std::time::{Duration, Instant};

// This only gives access within this module. Make this `pub use errors::*;`
// instead if the types must be accessible from other modules (e.g., within
// a `links` section).
use errors::*;

fn main() {
    if let Err(ref e) = run() {
        use ::std::io::Write;
        let stderr = &mut ::std::io::stderr();
        let errmsg = "Error writing to stderr";

        writeln!(stderr, "error: {}", e).expect(errmsg);

        for e in e.iter().skip(1) {
            writeln!(stderr, "caused by: {}", e).expect(errmsg);
        }

        // The backtrace is not always generated. Try to run this example
        // with `RUST_BACKTRACE=1`.
        if let Some(backtrace) = e.backtrace() {
            writeln!(stderr, "backtrace: {:?}", backtrace).expect(errmsg);
        }

        ::std::process::exit(1);
    }
}

fn run() -> Result<()> {
    use glium::DisplayBuild;

    let display = glium::glutin::WindowBuilder::new()
        .with_title("rbattle".to_string())
        .build_glium()
        .chain_err(|| "unable to open window")?;

    let graph = SquareGrid::new(15, 15);
    let sources = vec![16, 45];
    let colors = vec![(0x9f, 0x20, 0xb1), (0xb1, 0x20, 0x44),
                      (0x20, 0xb1, 0x21), (0x20, 0x67, 0xb1),
                      (0xe0, 0x6f, 0x3a)];
    let map = Rc::new(Map::new(graph, sources, colors));
    let drawer = Drawer::new(&display, &map)
        .chain_err(|| "failed to construct Drawer for map")?;

    let mut state = State::new(map.clone());

    state.nodes[45] = Some(Occupied {
        player: Player(2),
        outflows: map.graph.neighbors(45),
        goop: MAX_GOOP
    });

    state.nodes[30] = Some(Occupied {
        player: Player(2),
        outflows: vec![15],
        goop: 0
    });

    state.nodes[16] = Some(Occupied {
        player: Player(0),
        outflows: map.graph.neighbors(16),
        goop: MAX_GOOP
    });

    state.nodes[17] = Some(Occupied {
        player: Player(1),
        outflows: vec![],
        goop: 2
    });

    let mut mouse = Mouse::new(map.clone());

    loop {
        let mut frame = display.draw();
        frame.clear_color(1.0, 1.0, 1.0, 1.0);
        let status = drawer.draw(&mut frame, &state, &mouse);
        frame.finish()
            .chain_err(|| "drawing finish failed")?;

        let window_to_game = status?;
        let window_to_graph = compose(map.game_to_graph, window_to_game);

        for event in display.poll_events() {
            match event {
                Event::Closed => return Ok(()),
                Event::KeyboardInput(ElementState::Pressed, _,
                                     Some(VirtualKeyCode::Space)) => {
                    state.flow();
                    state.generate_goop();
                }
                Event::MouseMoved(x, y) => {
                    let graph_pos = apply(window_to_graph, [x as f32, y as f32]);
                    mouse.move_to(GraphPt(graph_pos));
                }
                Event::MouseInput(ElementState::Pressed, MouseButton::Left) => {
                    mouse.click();
                }
                Event::MouseInput(ElementState::Released, MouseButton::Left) => {
                    if let Some(action) = mouse.release() {
                        state.take_action(action);
                    }
                }
                _ => ()
            }
        }

    }
}
<commit_msg>Add single-step and free-running modes.<commit_after>#![allow(dead_code)]

// `error_chain!` can recurse deeply
#![recursion_limit = "1024"]

#[macro_use] extern crate error_chain;
#[macro_use] extern crate glium;
extern crate rand;

#[cfg(test)]
#[macro_use]
mod test_utils;

mod drawer;
mod errors;
mod graph;
mod map;
mod math;
mod mouse;
mod square;
mod state;
mod visible_graph;

use drawer::Drawer;
use graph::Graph;
use map::{Map, Player};
use math::{apply, compose};
use mouse::Mouse;
use square::SquareGrid;
use state::{MAX_GOOP, Occupied, State};
use visible_graph::GraphPt;

use glium::glutin::{Event, ElementState, MouseButton, VirtualKeyCode};
use glium::Surface;

use std::rc::Rc;
use std::time::{Duration, Instant};

// This only gives access within this module. Make this `pub use errors::*;`
// instead if the types must be accessible from other modules (e.g., within
// a `links` section).
use errors::*;

fn main() {
    if let Err(ref e) = run() {
        use ::std::io::Write;
        let stderr = &mut ::std::io::stderr();
        let errmsg = "Error writing to stderr";

        writeln!(stderr, "error: {}", e).expect(errmsg);

        for e in e.iter().skip(1) {
            writeln!(stderr, "caused by: {}", e).expect(errmsg);
        }

        // The backtrace is not always generated. Try to run this example
        // with `RUST_BACKTRACE=1`.
        if let Some(backtrace) = e.backtrace() {
            writeln!(stderr, "backtrace: {:?}", backtrace).expect(errmsg);
        }

        ::std::process::exit(1);
    }
}

fn run() -> Result<()> {
    use glium::DisplayBuild;

    let display = glium::glutin::WindowBuilder::new()
        .with_title("rbattle".to_string())
        .build_glium()
        .chain_err(|| "unable to open window")?;

    let graph = SquareGrid::new(15, 15);
    let sources = vec![16, 45];
    let colors = vec![(0x9f, 0x20, 0xb1), (0xb1, 0x20, 0x44),
                      (0x20, 0xb1, 0x21), (0x20, 0x67, 0xb1),
                      (0xe0, 0x6f, 0x3a)];
    let map = Rc::new(Map::new(graph, sources, colors));
    let drawer = Drawer::new(&display, &map)
        .chain_err(|| "failed to construct Drawer for map")?;

    let mut state = State::new(map.clone());

    state.nodes[45] = Some(Occupied {
        player: Player(2),
        outflows: map.graph.neighbors(45),
        goop: MAX_GOOP
    });

    state.nodes[30] = Some(Occupied {
        player: Player(2),
        outflows: vec![15],
        goop: 0
    });

    state.nodes[16] = Some(Occupied {
        player: Player(0),
        outflows: map.graph.neighbors(16),
        goop: MAX_GOOP
    });

    state.nodes[17] = Some(Occupied {
        player: Player(1),
        outflows: vec![],
        goop: 2
    });

    let mut mouse = Mouse::new(map.clone());
    let mut single_step = true;

    loop {
        let mut frame = display.draw();
        frame.clear_color(1.0, 1.0, 1.0, 1.0);
        let status = drawer.draw(&mut frame, &state, &mouse);
        frame.finish()
            .chain_err(|| "drawing finish failed")?;

        let window_to_game = status?;
        let window_to_graph = compose(map.game_to_graph, window_to_game);

        for event in display.poll_events() {
            match event {
                Event::Closed => return Ok(()),
                Event::KeyboardInput(ElementState::Pressed, _,
                                     Some(VirtualKeyCode::Space)) => {
                    single_step = true;
                    state.flow();
                    state.generate_goop();
                }
                Event::KeyboardInput(ElementState::Pressed, _,
                                     Some(VirtualKeyCode::Return)) => {
                    single_step = false;
                }
                Event::MouseMoved(x, y) => {
                    let graph_pos = apply(window_to_graph, [x as f32, y as f32]);
                    mouse.move_to(GraphPt(graph_pos));
                }
                Event::MouseInput(ElementState::Pressed, MouseButton::Left) => {
                    mouse.click();
                }
                Event::MouseInput(ElementState::Released, MouseButton::Left) => {
                    if let Some(action) = mouse.release() {
                        state.take_action(action);
                    }
                }
                _ => ()
            }
        }

        if !single_step {
            state.flow();
            state.generate_goop();
        }
    }
}
<|endoftext|>


<commit_before>extern crate rff;
extern crate clap;
extern crate rayon;

use std::io::{self, Write, BufWriter};
use rff::{stdin, match_and_score};
use rff::interface::Interface;
use clap::{App, Arg};
use rayon::prelude::*;

fn main() {
    let status_code = run();
    std::process::exit(status_code);
}

fn run() -> i32 {
    let matches = App::new("rff").
        version(env!("CARGO_PKG_VERSION")).
        author("Andrew S. <andrew@stwrt.ca>").
        about("A fuzzy finder.").
        arg(
            Arg::with_name("query").
                short("s").
                long("search").
                value_name("QUERY").
                help("Term to search for")
        ).
        arg(
            Arg::with_name("benchmark").
                long("benchmark").
                help("Run rff in benchmark mode")
        ).
        get_matches();

    let has_query = matches.is_present("query");
    let has_benchmark = matches.is_present("benchmark");

    if has_benchmark && !has_query {
        println!("Must specifiy -s/--search with --benchmark");
        return 1
    }

    if has_query {
        let query = matches.value_of("query").unwrap();

        if has_benchmark {
            benchmark(query);
        } else {
            search(query);
        }
    } else {
        interactive();
    }

    return 0
}

fn benchmark(needle: &str) {
    let lines = stdin::slurp();

    // in benchmark mode, we run the match/score/sort loop 100 times
    for _ in 0..100 {
        lines
            .par_iter()
            .filter_map(|line| match_and_score(needle, line))
            .collect::<Vec<_>>()
            .sort_by(|a, b| a.1.partial_cmp(&b.1).unwrap().reverse());
    }
}

fn search(needle: &str) {
    let lines = stdin::slurp();
    let mut lines: Vec<_> = lines
        .par_iter()
        .filter_map(|line| match_and_score(needle, line))
        .collect();

    lines.sort_by(|a, b| a.1.partial_cmp(&b.1).unwrap().reverse());

    let stdout = io::stdout();
    let mut stdout = BufWriter::new(stdout.lock());

    for line in &lines {
        writeln!(stdout, "{}", line.0).unwrap();
    }
}

fn interactive() {
    let lines = stdin::slurp();

    match Interface::new(&lines).run() {
        Ok(result) => println!("{}", result),
        Err(error) => println!("{:?}", error),
    }
}
<commit_msg>Don't print 'Exit' when Ctrl-C'd<commit_after>extern crate rff;
extern crate clap;
extern crate rayon;

use std::io::{self, Write, BufWriter};
use rff::{stdin, match_and_score};
use rff::interface::Interface;
use clap::{App, Arg};
use rayon::prelude::*;

fn main() {
    let status_code = run();
    std::process::exit(status_code);
}

fn run() -> i32 {
    let matches = App::new("rff").
        version(env!("CARGO_PKG_VERSION")).
        author("Andrew S. <andrew@stwrt.ca>").
        about("A fuzzy finder.").
        arg(
            Arg::with_name("query").
                short("s").
                long("search").
                value_name("QUERY").
                help("Term to search for")
        ).
        arg(
            Arg::with_name("benchmark").
                long("benchmark").
                help("Run rff in benchmark mode")
        ).
        get_matches();

    let has_query = matches.is_present("query");
    let has_benchmark = matches.is_present("benchmark");

    if has_benchmark && !has_query {
        println!("Must specifiy -s/--search with --benchmark");
        return 1
    }

    if has_query {
        let query = matches.value_of("query").unwrap();

        if has_benchmark {
            benchmark(query);
        } else {
            search(query);
        }
    } else {
        interactive();
    }

    return 0
}

fn benchmark(needle: &str) {
    let lines = stdin::slurp();

    // in benchmark mode, we run the match/score/sort loop 100 times
    for _ in 0..100 {
        lines
            .par_iter()
            .filter_map(|line| match_and_score(needle, line))
            .collect::<Vec<_>>()
            .sort_by(|a, b| a.1.partial_cmp(&b.1).unwrap().reverse());
    }
}

fn search(needle: &str) {
    let lines = stdin::slurp();
    let mut lines: Vec<_> = lines
        .par_iter()
        .filter_map(|line| match_and_score(needle, line))
        .collect();

    lines.sort_by(|a, b| a.1.partial_cmp(&b.1).unwrap().reverse());

    let stdout = io::stdout();
    let mut stdout = BufWriter::new(stdout.lock());

    for line in &lines {
        writeln!(stdout, "{}", line.0).unwrap();
    }
}

fn interactive() {
    let lines = stdin::slurp();

    match Interface::new(&lines).run() {
        Ok(result) => println!("{}", result),
        Err(rff::interface::Error::Exit) => {},
        Err(error) => { println!("{:?}", error); },
    }
}
<|endoftext|>


<commit_before>extern crate rudit;
extern crate termion;

use std::io::{Write, stdout};
use termion::raw::IntoRawMode;
use termion::event::Key;
use termion::input::TermRead;
use termion::cursor::Goto;
use rudit::gapbuffer::GapBuffer;

fn main() {
    let mut buffer = GapBuffer::new(30);
    let mut stdout = stdout().into_raw_mode().unwrap();
    let mut index = 0;
    let mut cx: u16 = 3;
    let mut cy: u16 = 1;
    write!(stdout,
           "{}{}",
           termion::clear::All,
           termion::cursor::Goto(cx, cy))
            .unwrap();
    stdout.flush().unwrap();
    'main: loop {

        write!(stdout, "{}", termion::clear::CurrentLine).unwrap();

        draw_lines(&mut stdout, &buffer.buffer);
        draw_cursor(&mut stdout, cx, cy);

        stdout.flush().unwrap();

        for c in std::io::stdin().keys() {
            match c.unwrap() {
                Key::Char('\n') => {
                    buffer.insert(index, '\n');
                    cx = 3;
                    cy += 1;
                    index += 1;
                }
                Key::Char(c) => {
                    buffer.insert(index, c);
                    index += 1;
                    cx += 1;
                }
                Key::Left => {
                    if cx > 0 {
                        cx -= 1;
                        index -= 1;
                    }
                }
                Key::Right => {
                    if cx as usize <= buffer.len() {
                        cx += 1;
                        index += 1;
                    }
                }
                Key::Esc => break,
                _ => (),
            }
            continue 'main;
        }
        write!(stdout, "{}", termion::clear::All).unwrap();
        stdout.flush().unwrap();
        break;
    }
}
fn draw_lines(stdout: &mut termion::raw::RawTerminal<std::io::Stdout>, buffer: &Vec<char>) {
    let s: String = buffer.iter().collect();
    for (index, i) in s.split('\n').enumerate() {
        write!(stdout,
               "{}{}{}{}",
               Goto(0, (index + 1) as u16),
               index,
               Goto(3, (index + 1) as u16),
               i)
                .unwrap();
    }
}

fn draw_cursor(stdout: &mut termion::raw::RawTerminal<std::io::Stdout>, cx: u16, cy: u16) {
    write!(stdout, "{}", termion::cursor::Goto(cx, cy)).unwrap();
}
<commit_msg>right cursor movement working<commit_after>extern crate rudit;
extern crate termion;

use std::io::{Write, stdout};
use termion::raw::IntoRawMode;
use termion::event::Key;
use termion::input::TermRead;
use termion::cursor::Goto;
use rudit::gapbuffer::GapBuffer;

fn main() {
    let mut buffer = GapBuffer::new(30);
    let mut stdout = stdout().into_raw_mode().unwrap();
    let mut index = 0;
    let mut cx: u16 = 3;
    let mut cy: u16 = 1;
    // buffer.insert(0, 'a');
    // buffer.insert(1, 'b');
    // buffer.insert(2, '\n');
    // buffer.insert(3, 'c');
    // index = 3;
    // cy = 2;
    write!(stdout,
           "{}{}",
           termion::clear::All,
           termion::cursor::Goto(cx, cy))
        .unwrap();
    stdout.flush().unwrap();
    'main: loop {

        write!(stdout, "{}", termion::clear::CurrentLine).unwrap();

        draw_lines(&mut stdout, &buffer.buffer);
        draw_cursor(&mut stdout, cx, cy);

        stdout.flush().unwrap();

        for c in std::io::stdin().keys() {
            match c.unwrap() {
                Key::Char('\n') => {
                    buffer.insert(index, '\n');
                    cx = 3;
                    cy += 1;
                    index += 1;
                }
                Key::Char(c) => {
                    buffer.insert(index, c);
                    index += 1;
                    cx += 1;
                }
                Key::Up => {
                    cy -= 1;
                }
                Key::Left => {
                    if cx > 3 {
                        cx -= 1;
                        index -= 1;
                    }
                }
                Key::Right => {
                    // inefficient(?)
                    // let mut b = vec!['\0'; buffer.buffer.len()];
                    // for i in 0..buffer.gap_start {
                    //     b[i] = buffer.buffer[i];
                    // }
                    // for i in buffer.gap_end..buffer.buffer.len() {
                    //     b[i - (buffer.gap_end - buffer.gap_start)] = buffer.buffer[i];
                    // }
                    // if b[index] != '\0' {
                    //     cx += 1;
                    //     index += 1;
                    // }

                    // better
                    if buffer.buffer[index] != '\0' ||
                       buffer.buffer[buffer.buffer.len() - index + buffer.gap_start - 1] != '\0' {
                        cx += 1;
                        index += 1;
                    }
                }
                Key::Esc => break,
                _ => (),
            }
            continue 'main;
        }
        write!(stdout, "{}", termion::clear::All).unwrap();
        stdout.flush().unwrap();
        break;
    }
}

fn draw_lines(stdout: &mut termion::raw::RawTerminal<std::io::Stdout>, buffer: &Vec<char>) {
    let s: String = buffer.iter().collect();
    for (index, i) in s.split('\n').enumerate() {
        write!(stdout,
               "{}{}{}{}",
               Goto(0, (index + 1) as u16),
               index,
               Goto(3, (index + 1) as u16),
               i)
            .unwrap();
    }
}

fn draw_cursor(stdout: &mut termion::raw::RawTerminal<std::io::Stdout>, cx: u16, cy: u16) {
    write!(stdout, "{}", termion::cursor::Goto(cx, cy)).unwrap();
}
<|endoftext|>


<commit_before>use fixedbitset::FixedBitSet;
use petgraph::graph::GraphIndex;
use petgraph::visit::{
    EdgeRef, FilterNode, GraphBase, IntoEdges, NodeIndexable, VisitMap, Visitable,
};

use std::iter;

pub enum DfsEvent<G>
where
    G: IntoEdges,
{
    Discover(G::NodeId),
    TreeEdge(G::EdgeRef),
    BackEdge(G::EdgeRef),
    CrossForwardEdge(G::EdgeRef),
    Finish(G::NodeId),
}

struct DfsState<G, F>
where
    G: IntoEdges + Visitable,
    F: FnMut(DfsEvent<G>) -> (),
{
    graph: G,
    discovered: G::Map,
    finished: G::Map,
    visitor: F,
}

impl<G, F> DfsState<G, F>
where
    G: IntoEdges + Visitable,
    F: FnMut(DfsEvent<G>) -> (),
{
    /// https://docs.rs/petgraph/0.4.12/src/petgraph/visit/dfsvisit.rs.html#164-189
    fn go_rec(&mut self, u: G::NodeId) -> () {
        if self.discovered.visit(u) {
            (self.visitor)(DfsEvent::Discover(u));
            for e in self.graph.edges(u) {
                let v = e.target();
                if !self.discovered.is_visited(&v) {
                    (self.visitor)(DfsEvent::TreeEdge(e));
                    self.go_rec(v);
                } else if !self.finished.is_visited(&v) {
                    (self.visitor)(DfsEvent::BackEdge(e));
                } else {
                    (self.visitor)(DfsEvent::CrossForwardEdge(e));
                }
            }
            let first_finish = self.finished.visit(u);
            debug_assert!(first_finish);
            (self.visitor)(DfsEvent::Finish(u));
        }
    }
}

/// Like [`petgraph::visit::depth_first_search`], but with edges.
pub fn depth_first_search<G, F>(graph: G, start: G::NodeId, mut visitor: F) -> ()
where
    G: IntoEdges + Visitable,
    F: FnMut(DfsEvent<G>) -> (),
{
    DfsState {
        graph,
        discovered: graph.visit_map(),
        finished: graph.visit_map(),
        visitor,
    }.go_rec(start);
}

/// Returns the union of all simple paths from `start` to a node in `end_set`,
/// including the nodes in `end_set`.
/// Also returns a topological ordering of this subgraph.
pub fn slice<G, F>(
    graph: G,
    start: G::NodeId,
    end_set: F,
) -> (FixedBitSet, FixedBitSet, Vec<G::NodeId>)
where
    G: IntoEdges + Visitable + NodeIndexable,
    G::NodeId: GraphIndex,
    G::EdgeId: GraphIndex,
    F: FilterNode<G::NodeId>,
{
    let mut ret_nodes = FixedBitSet::with_capacity(graph.node_bound());
    // petgraph doesn't expose `edge_bound` :(
    let mut ret_edges = FixedBitSet::with_capacity(0);
    // we push nodes into this in post-order, then reverse at the end
    let mut ret_topo_order = Vec::new();

    let mut cur_node_stack = vec![start];
    let mut cur_edge_stack = Vec::new();
    depth_first_search(graph, start, |ev| {
        use self::DfsEvent::*;
        match ev {
            TreeEdge(te) => {
                cur_edge_stack.push(te.id());
                cur_node_stack.push(te.target());
                if end_set.include_node(te.target()) {
                    // found a simple path from `start` to `end`
                    ret_nodes.extend(cur_node_stack.iter().map(|n| n.index()));
                    ret_edges.extend(cur_edge_stack.iter().map(|e| e.index()));
                }
            }
            CrossForwardEdge(cfe) => {
                debug_assert!(cur_node_stack.iter().all(|&n| n != cfe.target()));
                debug_assert!(cur_edge_stack.iter().all(|&e| e != cfe.id()));
                debug_assert!(cur_node_stack[0] == start);
                if ret_nodes[cfe.target().index()] {
                    // found a simple path from `start` to a node already in the
                    // slice, which is on a simple path to `end`
                    ret_nodes.extend(cur_node_stack.iter().map(|n| n.index()));
                    ret_edges.extend(cur_edge_stack.iter().map(|e| e.index()));
                    ret_edges.extend(iter::once(cfe.id().index()));
                }
            }
            Finish(f) => {
                let _pop_n = cur_node_stack.pop();
                let _pop_e = cur_edge_stack.pop();
                debug_assert!(_pop_n == Some(f));
                debug_assert!(_pop_e.is_some() == (f != start));
                if ret_nodes[f.index()] {
                    ret_topo_order.push(f);
                }
            }
            _ => (),
        }
    });

    ret_topo_order.reverse();
    (ret_nodes, ret_edges, ret_topo_order)
}

#[cfg(test)]
mod tests {
    use super::*;
    use petgraph::algo;
    use petgraph::prelude::{NodeIndex, StableDiGraph};
    use petgraph::stable_graph;
    use petgraph::visit::IntoEdgeReferences;

    use quickcheck::TestResult;
    use std::collections::HashMap;
    use std::hash::Hash;

    #[quickcheck]
    fn qc_slice(
        mut graph: StableDiGraph<(), ()>,
        start_i: usize,
        end_is: Vec<usize>,
    ) -> TestResult {
        let nodes: Vec<_> = graph.node_indices().collect();
        if nodes.is_empty() {
            return TestResult::discard();
        }
        let start = nodes[start_i % nodes.len()];
        let ends: FixedBitSet = end_is
            .into_iter()
            .map(|end_i| nodes[end_i % nodes.len()].index())
            .collect();
        println!("start: {:?}", start);
        println!("ends: {:?}", ends);
        let (slice_nodes, slice_edges, slice_topo_order) = slice(&graph, start, ends);
        let mut trace_nodes = FixedBitSet::with_capacity(graph.node_bound());
        trace_nodes.extend(slice_topo_order.iter().map(|n| n.index()));
        if trace_nodes != slice_nodes {
            println!("wrong nodes in topo_order:");
            println!(
                "  real: {:?}",
                slice_nodes
                    .ones()
                    .map(|i| NodeIndex::new(i))
                    .collect::<Vec<NodeIndex>>()
            );
            println!("  order: {:?}", slice_topo_order);
            return TestResult::failed();
        }
        graph.retain_nodes(|_, n| slice_nodes[n.index()]);
        graph.retain_edges(|_, e| slice_edges[e.index()]);
        if algo::is_cyclic_directed(&graph) {
            println!("cyclic slice:");
            println!("  slice: {:?}", graph);
            return TestResult::failed();
        }
        if !is_topological_ordering(&graph, &slice_topo_order) {
            println!("bad topological ordering: {:?}", slice_topo_order);
            println!("  slice: {:?}", graph);
            return TestResult::failed();
        }
        TestResult::passed()
    }

    fn is_topological_ordering<G>(graph: G, topo_order: &[G::NodeId]) -> bool
    where
        G: IntoEdgeReferences,
        G::NodeId: Eq + Hash,
    {
        let order_idx: HashMap<_, _> = topo_order
            .into_iter()
            .enumerate()
            .map(|(i, n)| (n, i))
            .collect();
        graph
            .edge_references()
            .all(|e| order_idx[&e.source()] < order_idx[&e.target()])
    }
}
<commit_msg>[ctrl_flow_struct] Add extra graph slice test<commit_after>use fixedbitset::FixedBitSet;
use petgraph::graph::GraphIndex;
use petgraph::visit::{
    EdgeRef, FilterNode, GraphBase, IntoEdges, NodeIndexable, VisitMap, Visitable,
};

use std::iter;

pub enum DfsEvent<G>
where
    G: IntoEdges,
{
    Discover(G::NodeId),
    TreeEdge(G::EdgeRef),
    BackEdge(G::EdgeRef),
    CrossForwardEdge(G::EdgeRef),
    Finish(G::NodeId),
}

struct DfsState<G, F>
where
    G: IntoEdges + Visitable,
    F: FnMut(DfsEvent<G>) -> (),
{
    graph: G,
    discovered: G::Map,
    finished: G::Map,
    visitor: F,
}

impl<G, F> DfsState<G, F>
where
    G: IntoEdges + Visitable,
    F: FnMut(DfsEvent<G>) -> (),
{
    /// https://docs.rs/petgraph/0.4.12/src/petgraph/visit/dfsvisit.rs.html#164-189
    fn go_rec(&mut self, u: G::NodeId) -> () {
        if self.discovered.visit(u) {
            (self.visitor)(DfsEvent::Discover(u));
            for e in self.graph.edges(u) {
                let v = e.target();
                if !self.discovered.is_visited(&v) {
                    (self.visitor)(DfsEvent::TreeEdge(e));
                    self.go_rec(v);
                } else if !self.finished.is_visited(&v) {
                    (self.visitor)(DfsEvent::BackEdge(e));
                } else {
                    (self.visitor)(DfsEvent::CrossForwardEdge(e));
                }
            }
            let first_finish = self.finished.visit(u);
            debug_assert!(first_finish);
            (self.visitor)(DfsEvent::Finish(u));
        }
    }
}

/// Like [`petgraph::visit::depth_first_search`], but with edges.
pub fn depth_first_search<G, F>(graph: G, start: G::NodeId, mut visitor: F) -> ()
where
    G: IntoEdges + Visitable,
    F: FnMut(DfsEvent<G>) -> (),
{
    DfsState {
        graph,
        discovered: graph.visit_map(),
        finished: graph.visit_map(),
        visitor,
    }.go_rec(start);
}

/// Returns the union of all simple paths from `start` to a node in `end_set`,
/// including the nodes in `end_set`.
/// Also returns a topological ordering of this subgraph.
pub fn slice<G, F>(
    graph: G,
    start: G::NodeId,
    end_set: F,
) -> (FixedBitSet, FixedBitSet, Vec<G::NodeId>)
where
    G: IntoEdges + Visitable + NodeIndexable,
    G::NodeId: GraphIndex,
    G::EdgeId: GraphIndex,
    F: FilterNode<G::NodeId>,
{
    let mut ret_nodes = FixedBitSet::with_capacity(graph.node_bound());
    // petgraph doesn't expose `edge_bound` :(
    let mut ret_edges = FixedBitSet::with_capacity(0);
    // we push nodes into this in post-order, then reverse at the end
    let mut ret_topo_order = Vec::new();

    ret_nodes.put(start.index());

    let mut cur_node_stack = vec![start];
    let mut cur_edge_stack = Vec::new();
    depth_first_search(graph, start, |ev| {
        use self::DfsEvent::*;
        match ev {
            TreeEdge(te) => {
                cur_edge_stack.push(te.id());
                cur_node_stack.push(te.target());
                if end_set.include_node(te.target()) {
                    // found a simple path from `start` to `end`
                    ret_nodes.extend(cur_node_stack.iter().map(|n| n.index()));
                    ret_edges.extend(cur_edge_stack.iter().map(|e| e.index()));
                }
            }
            CrossForwardEdge(cfe) => {
                debug_assert!(cur_node_stack.iter().all(|&n| n != cfe.target()));
                debug_assert!(cur_edge_stack.iter().all(|&e| e != cfe.id()));
                debug_assert!(cur_node_stack[0] == start);
                if ret_nodes[cfe.target().index()] {
                    // found a simple path from `start` to a node already in the
                    // slice, which is on a simple path to `end`
                    ret_nodes.extend(cur_node_stack.iter().map(|n| n.index()));
                    ret_edges.extend(cur_edge_stack.iter().map(|e| e.index()));
                    ret_edges.extend(iter::once(cfe.id().index()));
                }
            }
            Finish(f) => {
                let _pop_n = cur_node_stack.pop();
                let _pop_e = cur_edge_stack.pop();
                debug_assert!(_pop_n == Some(f));
                debug_assert!(_pop_e.is_some() == (f != start));
                if ret_nodes[f.index()] {
                    ret_topo_order.push(f);
                }
            }
            _ => (),
        }
    });

    ret_topo_order.reverse();
    (ret_nodes, ret_edges, ret_topo_order)
}

#[cfg(test)]
mod tests {
    use super::*;
    use petgraph::algo;
    use petgraph::prelude::{EdgeIndex, NodeIndex, Outgoing, StableDiGraph};
    use petgraph::stable_graph;
    use petgraph::visit::IntoEdgeReferences;

    use quickcheck::TestResult;
    use std::collections::HashMap;
    use std::hash::Hash;
    use std::iter;

    /// Tests that `slice` returns an acyclic graph and a topological ordering.
    #[quickcheck]
    fn qc_slice(
        mut graph: StableDiGraph<(), ()>,
        start_i: usize,
        end_is: Vec<usize>,
    ) -> TestResult {
        let nodes: Vec<_> = graph.node_indices().collect();
        if nodes.is_empty() {
            return TestResult::discard();
        }
        let start = nodes[start_i % nodes.len()];
        let ends: FixedBitSet = end_is
            .into_iter()
            .map(|end_i| nodes[end_i % nodes.len()].index())
            .collect();
        println!("start: {:?}", start);
        println!("ends: {:?}", ends);
        let (slice_nodes, slice_edges, slice_topo_order) = slice(&graph, start, ends);
        let mut trace_nodes = FixedBitSet::with_capacity(graph.node_bound());
        trace_nodes.extend(slice_topo_order.iter().map(|n| n.index()));
        if trace_nodes != slice_nodes {
            println!("wrong nodes in topo_order:");
            println!(
                "  real: {:?}",
                slice_nodes
                    .ones()
                    .map(|i| NodeIndex::new(i))
                    .collect::<Vec<NodeIndex>>()
            );
            println!("  order: {:?}", slice_topo_order);
            return TestResult::failed();
        }
        graph.retain_nodes(|_, n| slice_nodes[n.index()]);
        graph.retain_edges(|_, e| slice_edges[e.index()]);
        if algo::is_cyclic_directed(&graph) {
            println!("cyclic slice:");
            println!("  slice: {:?}", graph);
            return TestResult::failed();
        }
        if !is_topological_ordering(&graph, &slice_topo_order) {
            println!("bad topological ordering: {:?}", slice_topo_order);
            println!("  slice: {:?}", graph);
            return TestResult::failed();
        }
        TestResult::passed()
    }

    /// Tests that `slice`ing a connected rooted acyclic graph is a no-op.
    #[quickcheck]
    fn qc_slice_acyclic(mut graph: StableDiGraph<(), ()>, root_i: usize) -> TestResult {
        let nodes: Vec<_> = graph.node_indices().collect();
        if nodes.is_empty() {
            return TestResult::discard();
        }
        let root = nodes[root_i % nodes.len()];
        let mut reachable = FixedBitSet::with_capacity(graph.node_bound());
        let mut back_edges = FixedBitSet::with_capacity(0);
        depth_first_search(&graph, root, |ev| {
            use super::DfsEvent::*;
            match ev {
                Discover(n) => reachable.set(n.index(), true),
                BackEdge(e) => back_edges.extend(iter::once(e.id().index())),
                _ => (),
            }
        });
        graph.retain_nodes(|_, n| reachable[n.index()]);
        graph.retain_edges(|_, e| !back_edges[e.index()]);
        println!("graph: {:?}", graph);
        println!("root: {:?}", root);
        assert!(!algo::is_cyclic_directed(&graph));
        let (slice_nodes, slice_edges, _) = slice(&graph, root, |n| {
            graph.edges_directed(n, Outgoing).next().is_none()
        });
        println!("slice_nodes: {:?}", slice_nodes.ones().collect::<Vec<_>>());
        println!(
            "slice_edges: {:?}",
            slice_edges
                .ones()
                .map(|ei| graph.edge_endpoints(EdgeIndex::new(ei)).unwrap())
                .collect::<Vec<_>>()
        );
        TestResult::from_bool(
            graph.node_indices().all(|n| slice_nodes[n.index()])
                && graph.edge_indices().all(|e| slice_edges[e.index()]),
        )
    }

    fn is_topological_ordering<G>(graph: G, topo_order: &[G::NodeId]) -> bool
    where
        G: IntoEdgeReferences,
        G::NodeId: Eq + Hash,
    {
        let order_idx: HashMap<_, _> = topo_order
            .into_iter()
            .enumerate()
            .map(|(i, n)| (n, i))
            .collect();
        graph
            .edge_references()
            .all(|e| order_idx[&e.source()] < order_idx[&e.target()])
    }
}
<|endoftext|>