<commit_before>#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub struct Posn {
    pub offset: u32,
    pub line: u32,
    pub column: u32
}

impl Posn {
    pub fn origin() -> Posn {
        Posn {
            offset: 0,
            line: 0,
            column: 0
        }
    }
}

#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub struct Span {
    pub start: Posn,
    pub end: Posn
}

pub trait TrackingRef {
    fn tracking_ref(&self) -> &Option;
}

pub trait TrackingMut: TrackingRef {
    fn tracking_mut(&mut self) -> &mut Option;
}

impl<'a, T: TrackingRef> TrackingRef for &'a T {
    fn tracking_ref(&self) -> &Option { (*self).tracking_ref() }
}

impl TrackingRef for Option {
    fn tracking_ref(&self) -> &Option { self }
}

impl TrackingMut for Option {
    fn tracking_mut(&mut self) -> &mut Option { self }
}

pub trait Untrack {
    fn untrack(&mut self);
}

impl<T> Untrack for Box<T>
  where T: Untrack
{
    fn untrack(&mut self) {
        (**self).untrack();
    }
}

impl<T> Untrack for Option<T>
  where T: Untrack
{
    fn untrack(&mut self) {
        match *self {
            Some(ref mut x) => { x.untrack(); }
            None => { }
        }
    }
}

impl<T> Untrack for Vec<T>
  where T: Untrack
{
    fn untrack(&mut self) {
        for x in self {
            x.untrack();
        }
    }
}

pub fn span<T, U>(left: &T, right: &U) -> Option
  where T: TrackingRef,
        U: TrackingRef
{
    match (*left.tracking_ref(), *right.tracking_ref()) {
        (Some(l), Some(r)) => Some(Span { start: l.start, end: r.end }),
        _ => None
    }
}
<commit_msg>Custom debug formatters for locations.<commit_after>use std::fmt::{Debug, Formatter, Result};

#[derive(Clone, Copy, Eq, PartialEq)]
pub struct Posn {
    pub offset: u32,
    pub line: u32,
    pub column: u32
}

impl Posn {
    pub fn origin() -> Posn {
        Posn {
            offset: 0,
            line: 0,
            column: 0
        }
    }
}

impl Debug for Posn {
    fn fmt(&self, fmt: &mut Formatter) -> Result {
        fmt.write_fmt(format_args!("{}:{}", self.line + 1, self.column + 1))
    }
}

#[derive(Clone, Copy, Eq, PartialEq)]
pub struct Span {
    pub start: Posn,
    pub end: Posn
}

impl Debug for Span {
    fn fmt(&self, fmt: &mut Formatter) -> Result {
        fmt.write_fmt(format_args!("{:?}..{:?}", self.start, self.end))
    }
}

pub trait TrackingRef {
    fn tracking_ref(&self) -> &Option;
}

pub trait TrackingMut: TrackingRef {
    fn tracking_mut(&mut self) -> &mut Option;
}

impl<'a, T: TrackingRef> TrackingRef for &'a T {
    fn tracking_ref(&self) -> &Option { (*self).tracking_ref() }
}

impl TrackingRef for Option {
    fn tracking_ref(&self) -> &Option { self }
}

impl TrackingMut for Option {
    fn tracking_mut(&mut self) -> &mut Option { self }
}

pub trait Untrack {
    fn untrack(&mut self);
}

impl<T> Untrack for Box<T>
  where T: Untrack
{
    fn untrack(&mut self) {
        (**self).untrack();
    }
}

impl<T> Untrack for Option<T>
  where T: Untrack
{
    fn untrack(&mut self) {
        match *self {
            Some(ref mut x) => { x.untrack(); }
            None => { }
        }
    }
}

impl<T> Untrack for Vec<T>
  where T: Untrack
{
    fn untrack(&mut self) {
        for x in self {
            x.untrack();
        }
    }
}

pub fn span<T, U>(left: &T, right: &U) -> Option
  where T: TrackingRef,
        U: TrackingRef
{
    match (*left.tracking_ref(), *right.tracking_ref()) {
        (Some(l), Some(r)) => Some(Span { start: l.start, end: r.end }),
        _ => None
    }
}
<|endoftext|>


<commit_before>#[cfg(feature = "parallel")]
extern crate rayon;
#[cfg(feature = "parallel")]
use rayon::prelude::*;

use std::env;
use std::process::Command;
use std::process::Stdio;
use std::path::{Path, PathBuf};
use std::ffi::OsString;

fn x86_triple(os: &str) -> &'static str {
    match os {
        "darwin" => "-fmacho32",
        "windows" => "-fwin32",
        _ => "-felf32"
    }
}

fn x86_64_triple(os: &str) -> &'static str {
    match os {
        "darwin" => "-fmacho64",
        "windows" => "-fwin64",
        _ => "-felf64"
    }
}

fn parse_triple(trip: &str) -> &'static str {
    let parts = trip.split('-').collect::<Vec<_>>();
    // ARCH-VENDOR-OS-ENVIRONMENT
    // or ARCH-VENDOR-OS
    // we don't care about environ so doesn't matter if triple doesn't have it
    if parts.len() < 3 {
        return ""
    }

    match parts[0] {
        "x86_64" => x86_64_triple(parts[2]),
        "x86" | "i386" | "i586" | "i686" => x86_triple(parts[2]),
        _ => ""
    }
}

/// # Example
///
/// ```no_run
/// nasm_rs::compile_library("libfoo.a", &["foo.s", "bar.s"]);
/// ```
pub fn compile_library(output: &str, files: &[&str]) {
    compile_library_args(output, files, &[]);
}

/// # Example
///
/// ```no_run
/// nasm_rs::compile_library_args("libfoo.a", &["foo.s", "bar.s"], &["-Fdwarf"]);
/// ```
pub fn compile_library_args<P: AsRef<Path>>(output: &str, files: &[P], args: &[&str]) {
    let mut b = Build::new();
    for file in files {
        b.file(file);
    }
    for arg in args {
        b.flag(arg);
    }
    b.compile(output);
}

pub struct Build {
    files: Vec<PathBuf>,
    flags: Vec<String>,
    target: Option<String>,
    out_dir: Option<PathBuf>,
    archiver: Option<PathBuf>,
    nasm: Option<PathBuf>,
    debug: bool,
}

impl Build {
    pub fn new() -> Self {
        Self {
            files: Vec::new(),
            flags: Vec::new(),
            archiver: None,
            out_dir: None,
            nasm: None,
            target: None,
            debug: env::var("DEBUG").ok().map_or(false, |d| d != "false"),
        }
    }

    /// Add a file which will be compiled
    ///
    /// e.g. `"foo.s"`
    pub fn file<P: AsRef<Path>>(&mut self, p: P) -> &mut Self {
        self.files.push(p.as_ref().to_owned());
        self
    }

    /// Set multiple files
    pub fn files<P: AsRef<Path>, I: IntoIterator<Item=P>>(&mut self, files: I) -> &mut Self {
        for file in files {
            self.file(file);
        }
        self
    }

    /// Add a directory to the `-I` include path
    pub fn include<P: AsRef<Path>>(&mut self, dir: P) -> &mut Self {
        let mut flag = format!("-I{}", dir.as_ref().display());
        // nasm requires trailing slash, but `Path` may omit it.
        if !flag.ends_with("/") {
            flag += "/";
        }
        self.flags.push(flag);
        self
    }

    /// Pre-define a macro with an optional value
    pub fn define<'a, V: Into<Option<&'a str>>>(&mut self, var: &str, val: V) -> &mut Self {
        let val = val.into();
        let flag = if let Some(val) = val {
            format!("-D{}={}", var, val)
        } else {
            format!("-D{}", var)
        };
        self.flags.push(flag);
        self
    }

    /// Configures whether the assembler will generate debug information.
    ///
    /// This option is automatically scraped from the `DEBUG` environment
    /// variable by build scripts (only enabled when the profile is "debug"), so
    /// it's not required to call this function.
    pub fn debug(&mut self, enable: bool) -> &mut Self {
        self.debug = enable;
        self
    }

    /// Add an arbitrary flag to the invocation of the assembler
    ///
    /// e.g. `"-Fdwarf"`
    pub fn flag(&mut self, flag: &str) -> &mut Self {
        self.flags.push(flag.to_owned());
        self
    }

    /// Configures the target this configuration will be compiling for.
    ///
    /// This option is automatically scraped from the `TARGET` environment
    /// variable by build scripts, so it's not required to call this function.
    pub fn target(&mut self, target: &str) -> &mut Self {
        self.target = Some(target.to_owned());
        self
    }

    /// Configures the output directory where all object files and static libraries will be located.
    ///
    /// This option is automatically scraped from the OUT_DIR environment variable by build scripts,
    /// so it's not required to call this function.
    pub fn out_dir<P: AsRef<Path>>(&mut self, out_dir: P) -> &mut Self {
        self.out_dir = Some(out_dir.as_ref().to_owned());
        self
    }

    /// Configures the tool used to assemble archives.
    ///
    /// This option is automatically determined from the target platform or a
    /// number of environment variables, so it's not required to call this
    /// function.
    pub fn archiver<P: AsRef<Path>>(&mut self, archiver: P) -> &mut Self {
        self.archiver = Some(archiver.as_ref().to_owned());
        self
    }

    /// Configures path to `nasm` command
    pub fn nasm<P: AsRef<Path>>(&mut self, nasm: P) -> &mut Self {
        self.nasm = Some(nasm.as_ref().to_owned());
        self
    }

    /// Run the compiler, generating the file output
    ///
    /// The name output should be the base name of the library,
    /// without file extension, and without "lib" prefix.
    ///
    /// The output file will have target-specific name,
    /// such as `lib*.a` (non-MSVC) or `*.lib` (MSVC).
    pub fn compile(&mut self, lib_name: &str) {
        // Trim name for backwards comatibility
        let lib_name = if lib_name.starts_with("lib") && lib_name.ends_with(".a") {
            &lib_name[3..lib_name.len() - 2]
        } else {
            lib_name.trim_right_matches(".lib")
        };

        let target = self.get_target();
        let output = if target.ends_with("-msvc") {
            format!("{}.lib", lib_name)
        } else {
            format!("lib{}.a", lib_name)
        };

        let dst = &self.get_out_dir();
        let objects = self.compile_objects();
        self.archive(&dst, &output, &objects[..]);

        println!("cargo:rustc-flags=-L {}",
                 dst.display());
    }

    /// Run the compiler, generating .o files
    ///
    /// The files can be linked in a separate step, e.g. passed to `cc`
    pub fn compile_objects(&mut self) -> Vec<PathBuf> {
        let target = self.get_target();

        let nasm = self.find_nasm();
        let args = self.get_args(&target);

        let src = &PathBuf::from(env::var_os("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR must be set"));
        let dst = &self.get_out_dir();

        self.make_iter().map(|file| {
            self.compile_file(&nasm, file.as_ref(), &args, src, dst)
        }).collect::<Vec<_>>()
    }

    fn get_args(&self, target: &str) -> Vec<&str> {
        let mut args = vec![parse_triple(&target)];

        if self.debug {
            args.push("-g");
        }

        for arg in &self.flags {
            args.push(arg);
        }

        args
    }

    #[cfg(feature = "parallel")]
    fn make_iter(&self) -> rayon::slice::Iter<PathBuf> {
        self.files.par_iter()
    }

    #[cfg(not(feature = "parallel"))]
    fn make_iter(&self) -> std::slice::Iter<PathBuf> {
        self.files.iter()
    }

    fn compile_file(&self, nasm: &Path, file: &Path, new_args: &[&str], src: &Path, dst: &Path) -> PathBuf {
        let obj = dst.join(file).with_extension("o");
        let mut cmd = Command::new(nasm);
        cmd.args(&new_args[..]);
        std::fs::create_dir_all(&obj.parent().unwrap()).unwrap();

        run(cmd.arg(src.join(file)).arg("-o").arg(&obj));
        obj
    }

    fn archive(&self, out_dir: &Path, lib: &str, objs: &[PathBuf]) {
        let ar = if cfg!(target_env = "msvc") {
            self.archiver.clone().unwrap_or_else(|| "lib".into())
        } else {
            self.archiver.clone()
            .or_else(|| env::var_os("AR").map(|a| a.into()))
            .unwrap_or_else(|| "ar".into())
        };
        if cfg!(target_env = "msvc") {
            let mut out_param = OsString::new();
            out_param.push("/OUT:");
            out_param.push(out_dir.join(lib).as_os_str());
            run(Command::new(ar).arg(out_param).args(objs));
        } else {
            run(Command::new(ar).arg("crus").arg(out_dir.join(lib)).args(objs));
        }
    }

    fn get_out_dir(&self) -> PathBuf {
        self.out_dir.clone()
            .unwrap_or_else(|| PathBuf::from(env::var_os("OUT_DIR").expect("OUT_DIR must be set")))
    }

    fn get_target(&self) -> String {
        self.target.clone()
            .unwrap_or_else(|| env::var("TARGET").expect("TARGET must be set"))
    }

    fn find_nasm(&mut self) -> PathBuf {
        match self.nasm.clone() {
            Some(path) => path,
            None => {
                let nasm_path = PathBuf::from("nasm");
                match is_nasm_new_enough(&nasm_path) {
                    Ok(_) => nasm_path,
                    Err(version) => {
                        panic!("This version of NASM is too old: {}", version);
                    },
                }
            },
        }
    }
}

fn get_output(cmd: &mut Command) -> Result<String, String> {
    let out = cmd.output().map_err(|e| e.to_string())?;
    if out.status.success() {
        Ok(String::from_utf8_lossy(&out.stdout).to_string())
    } else {
        Err(String::from_utf8_lossy(&out.stderr))?
    }
}

/// Returns version string if nasm is too old,
/// or error message string if it's unusable.
fn is_nasm_new_enough(nasm_path: &Path) -> Result<(), String> {
    match get_output(Command::new(nasm_path).arg("-v")) {
        Ok(version) => {
            if version.contains("NASM version 0.") {
                Err(version)?
            } else {
                Ok(())
            }
        },
        Err(err) => Err(err)?,
    }
}

fn run(cmd: &mut Command) {
    println!("running: {:?}", cmd);

    let status = match cmd.stdout(Stdio::inherit()).stderr(Stdio::inherit()).status() {
        Ok(status) => status,

        Err(e) => panic!("failed to spawn process: {}", e),
    };

    if !status.success() {
        panic!("nonzero exit status: {}", status);
    }
}

#[test]
fn test_build() {
    let mut build = Build::new();
    build.file("test");
    build.archiver("ar");
    build.include("./");
    build.include("dir");
    build.define("foo", Some("1"));
    build.define("bar", None);
    build.flag("-test");
    build.target("i686-unknown-linux-musl");
    build.out_dir("/tmp");

    assert_eq!(build.get_args("i686-unknown-linux-musl"), &["-felf32", "-I./", "-Idir/", "-Dfoo=1", "-Dbar", "-test"]);
}
<commit_msg>Update trim_right_matches usage<commit_after>#[cfg(feature = "parallel")]
extern crate rayon;
#[cfg(feature = "parallel")]
use rayon::prelude::*;

use std::env;
use std::process::Command;
use std::process::Stdio;
use std::path::{Path, PathBuf};
use std::ffi::OsString;

fn x86_triple(os: &str) -> &'static str {
    match os {
        "darwin" => "-fmacho32",
        "windows" => "-fwin32",
        _ => "-felf32"
    }
}

fn x86_64_triple(os: &str) -> &'static str {
    match os {
        "darwin" => "-fmacho64",
        "windows" => "-fwin64",
        _ => "-felf64"
    }
}

fn parse_triple(trip: &str) -> &'static str {
    let parts = trip.split('-').collect::<Vec<_>>();
    // ARCH-VENDOR-OS-ENVIRONMENT
    // or ARCH-VENDOR-OS
    // we don't care about environ so doesn't matter if triple doesn't have it
    if parts.len() < 3 {
        return ""
    }

    match parts[0] {
        "x86_64" => x86_64_triple(parts[2]),
        "x86" | "i386" | "i586" | "i686" => x86_triple(parts[2]),
        _ => ""
    }
}

/// # Example
///
/// ```no_run
/// nasm_rs::compile_library("libfoo.a", &["foo.s", "bar.s"]);
/// ```
pub fn compile_library(output: &str, files: &[&str]) {
    compile_library_args(output, files, &[]);
}

/// # Example
///
/// ```no_run
/// nasm_rs::compile_library_args("libfoo.a", &["foo.s", "bar.s"], &["-Fdwarf"]);
/// ```
pub fn compile_library_args<P: AsRef<Path>>(output: &str, files: &[P], args: &[&str]) {
    let mut b = Build::new();
    for file in files {
        b.file(file);
    }
    for arg in args {
        b.flag(arg);
    }
    b.compile(output);
}

pub struct Build {
    files: Vec<PathBuf>,
    flags: Vec<String>,
    target: Option<String>,
    out_dir: Option<PathBuf>,
    archiver: Option<PathBuf>,
    nasm: Option<PathBuf>,
    debug: bool,
}

impl Build {
    pub fn new() -> Self {
        Self {
            files: Vec::new(),
            flags: Vec::new(),
            archiver: None,
            out_dir: None,
            nasm: None,
            target: None,
            debug: env::var("DEBUG").ok().map_or(false, |d| d != "false"),
        }
    }

    /// Add a file which will be compiled
    ///
    /// e.g. `"foo.s"`
    pub fn file<P: AsRef<Path>>(&mut self, p: P) -> &mut Self {
        self.files.push(p.as_ref().to_owned());
        self
    }

    /// Set multiple files
    pub fn files<P: AsRef<Path>, I: IntoIterator<Item=P>>(&mut self, files: I) -> &mut Self {
        for file in files {
            self.file(file);
        }
        self
    }

    /// Add a directory to the `-I` include path
    pub fn include<P: AsRef<Path>>(&mut self, dir: P) -> &mut Self {
        let mut flag = format!("-I{}", dir.as_ref().display());
        // nasm requires trailing slash, but `Path` may omit it.
        if !flag.ends_with("/") {
            flag += "/";
        }
        self.flags.push(flag);
        self
    }

    /// Pre-define a macro with an optional value
    pub fn define<'a, V: Into<Option<&'a str>>>(&mut self, var: &str, val: V) -> &mut Self {
        let val = val.into();
        let flag = if let Some(val) = val {
            format!("-D{}={}", var, val)
        } else {
            format!("-D{}", var)
        };
        self.flags.push(flag);
        self
    }

    /// Configures whether the assembler will generate debug information.
    ///
    /// This option is automatically scraped from the `DEBUG` environment
    /// variable by build scripts (only enabled when the profile is "debug"), so
    /// it's not required to call this function.
    pub fn debug(&mut self, enable: bool) -> &mut Self {
        self.debug = enable;
        self
    }

    /// Add an arbitrary flag to the invocation of the assembler
    ///
    /// e.g. `"-Fdwarf"`
    pub fn flag(&mut self, flag: &str) -> &mut Self {
        self.flags.push(flag.to_owned());
        self
    }

    /// Configures the target this configuration will be compiling for.
    ///
    /// This option is automatically scraped from the `TARGET` environment
    /// variable by build scripts, so it's not required to call this function.
    pub fn target(&mut self, target: &str) -> &mut Self {
        self.target = Some(target.to_owned());
        self
    }

    /// Configures the output directory where all object files and static libraries will be located.
    ///
    /// This option is automatically scraped from the OUT_DIR environment variable by build scripts,
    /// so it's not required to call this function.
    pub fn out_dir<P: AsRef<Path>>(&mut self, out_dir: P) -> &mut Self {
        self.out_dir = Some(out_dir.as_ref().to_owned());
        self
    }

    /// Configures the tool used to assemble archives.
    ///
    /// This option is automatically determined from the target platform or a
    /// number of environment variables, so it's not required to call this
    /// function.
    pub fn archiver<P: AsRef<Path>>(&mut self, archiver: P) -> &mut Self {
        self.archiver = Some(archiver.as_ref().to_owned());
        self
    }

    /// Configures path to `nasm` command
    pub fn nasm<P: AsRef<Path>>(&mut self, nasm: P) -> &mut Self {
        self.nasm = Some(nasm.as_ref().to_owned());
        self
    }

    /// Run the compiler, generating the file output
    ///
    /// The name output should be the base name of the library,
    /// without file extension, and without "lib" prefix.
    ///
    /// The output file will have target-specific name,
    /// such as `lib*.a` (non-MSVC) or `*.lib` (MSVC).
    pub fn compile(&mut self, lib_name: &str) {
        // Trim name for backwards comatibility
        let lib_name = if lib_name.starts_with("lib") && lib_name.ends_with(".a") {
            &lib_name[3..lib_name.len() - 2]
        } else {
            lib_name.trim_end_matches(".lib")
        };

        let target = self.get_target();
        let output = if target.ends_with("-msvc") {
            format!("{}.lib", lib_name)
        } else {
            format!("lib{}.a", lib_name)
        };

        let dst = &self.get_out_dir();
        let objects = self.compile_objects();
        self.archive(&dst, &output, &objects[..]);

        println!("cargo:rustc-flags=-L {}",
                 dst.display());
    }

    /// Run the compiler, generating .o files
    ///
    /// The files can be linked in a separate step, e.g. passed to `cc`
    pub fn compile_objects(&mut self) -> Vec<PathBuf> {
        let target = self.get_target();

        let nasm = self.find_nasm();
        let args = self.get_args(&target);

        let src = &PathBuf::from(env::var_os("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR must be set"));
        let dst = &self.get_out_dir();

        self.make_iter().map(|file| {
            self.compile_file(&nasm, file.as_ref(), &args, src, dst)
        }).collect::<Vec<_>>()
    }

    fn get_args(&self, target: &str) -> Vec<&str> {
        let mut args = vec![parse_triple(&target)];

        if self.debug {
            args.push("-g");
        }

        for arg in &self.flags {
            args.push(arg);
        }

        args
    }

    #[cfg(feature = "parallel")]
    fn make_iter(&self) -> rayon::slice::Iter<PathBuf> {
        self.files.par_iter()
    }

    #[cfg(not(feature = "parallel"))]
    fn make_iter(&self) -> std::slice::Iter<PathBuf> {
        self.files.iter()
    }

    fn compile_file(&self, nasm: &Path, file: &Path, new_args: &[&str], src: &Path, dst: &Path) -> PathBuf {
        let obj = dst.join(file).with_extension("o");
        let mut cmd = Command::new(nasm);
        cmd.args(&new_args[..]);
        std::fs::create_dir_all(&obj.parent().unwrap()).unwrap();

        run(cmd.arg(src.join(file)).arg("-o").arg(&obj));
        obj
    }

    fn archive(&self, out_dir: &Path, lib: &str, objs: &[PathBuf]) {
        let ar = if cfg!(target_env = "msvc") {
            self.archiver.clone().unwrap_or_else(|| "lib".into())
        } else {
            self.archiver.clone()
            .or_else(|| env::var_os("AR").map(|a| a.into()))
            .unwrap_or_else(|| "ar".into())
        };
        if cfg!(target_env = "msvc") {
            let mut out_param = OsString::new();
            out_param.push("/OUT:");
            out_param.push(out_dir.join(lib).as_os_str());
            run(Command::new(ar).arg(out_param).args(objs));
        } else {
            run(Command::new(ar).arg("crus").arg(out_dir.join(lib)).args(objs));
        }
    }

    fn get_out_dir(&self) -> PathBuf {
        self.out_dir.clone()
            .unwrap_or_else(|| PathBuf::from(env::var_os("OUT_DIR").expect("OUT_DIR must be set")))
    }

    fn get_target(&self) -> String {
        self.target.clone()
            .unwrap_or_else(|| env::var("TARGET").expect("TARGET must be set"))
    }

    fn find_nasm(&mut self) -> PathBuf {
        match self.nasm.clone() {
            Some(path) => path,
            None => {
                let nasm_path = PathBuf::from("nasm");
                match is_nasm_new_enough(&nasm_path) {
                    Ok(_) => nasm_path,
                    Err(version) => {
                        panic!("This version of NASM is too old: {}", version);
                    },
                }
            },
        }
    }
}

fn get_output(cmd: &mut Command) -> Result<String, String> {
    let out = cmd.output().map_err(|e| e.to_string())?;
    if out.status.success() {
        Ok(String::from_utf8_lossy(&out.stdout).to_string())
    } else {
        Err(String::from_utf8_lossy(&out.stderr))?
    }
}

/// Returns version string if nasm is too old,
/// or error message string if it's unusable.
fn is_nasm_new_enough(nasm_path: &Path) -> Result<(), String> {
    match get_output(Command::new(nasm_path).arg("-v")) {
        Ok(version) => {
            if version.contains("NASM version 0.") {
                Err(version)?
            } else {
                Ok(())
            }
        },
        Err(err) => Err(err)?,
    }
}

fn run(cmd: &mut Command) {
    println!("running: {:?}", cmd);

    let status = match cmd.stdout(Stdio::inherit()).stderr(Stdio::inherit()).status() {
        Ok(status) => status,

        Err(e) => panic!("failed to spawn process: {}", e),
    };

    if !status.success() {
        panic!("nonzero exit status: {}", status);
    }
}

#[test]
fn test_build() {
    let mut build = Build::new();
    build.file("test");
    build.archiver("ar");
    build.include("./");
    build.include("dir");
    build.define("foo", Some("1"));
    build.define("bar", None);
    build.flag("-test");
    build.target("i686-unknown-linux-musl");
    build.out_dir("/tmp");

    assert_eq!(build.get_args("i686-unknown-linux-musl"), &["-felf32", "-I./", "-Idir/", "-Dfoo=1", "-Dbar", "-test"]);
}
<|endoftext|>


<commit_before>pub trait DOMNode {
    type ChildrenType: DOMChildren;
    fn children(&self) -> &Self::ChildrenType;
}
impl<'a, T: DOMNode> DOMNode for &'a T {
    type ChildrenType = T::ChildrenType;
    fn children(&self) -> &Self::ChildrenType { (*self).children() }
}

const NONE_REF: &'static () = &();

impl DOMNode for String {
    type ChildrenType = ();
    fn children(&self) -> &Self::ChildrenType { NONE_REF }
}

impl<'a> DOMNode for &'a str {
    type ChildrenType = ();
    fn children(&self) -> &Self::ChildrenType { NONE_REF }
}

pub mod tags {
    use super::{DOMNode, DOMChildren};

    macro_rules! impl_tags {
        ($($tagname:ident,)*) => { $(
            pub struct $tagname<C: DOMChildren>(pub C);
            impl<C: DOMChildren> DOMNode for $tagname<C> {
                type ChildrenType = C;
                fn children(&self) -> &Self::ChildrenType { &self.0 }
            }
        )* }
    }

    impl_tags!(
        A, B, Big, BlockQuote, Body, Br, Center, Del, Div, Em,
        Font, Head, H1, H2, H3, H4, H5, H6, HR, I, Img, Ins,
        Li, Ol, P, Pre, S, Small, Span, Strong, Sub, Sup,
        Table, TD, TH, Title, TR, TT, U, UL,
    );
}

/// Processor that can fold over all the children of a `DOMNode`
pub trait DOMChildrenProcessor {
    /// Accumulator
    type Acc;

    /// Folding function
    fn get_processor<T: DOMChildren>() -> fn(&mut Self::Acc, &T) -> ();
}

pub trait DOMChildren {
    fn process_all
(&self, acc: &mut P::Acc) -> ();
}

impl DOMChildren for () {
    fn process_all
(&self, _acc: &mut P::Acc) -> () {}
}

impl<T: DOMNode> DOMChildren for T {
    fn process_all
(&self, acc: &mut P::Acc) -> () {
        P::get_processor()(acc, self);
    }
}

impl<T: DOMChildren> DOMChildren for [T] {
    fn process_all
(&self, acc: &mut P::Acc) -> () {
        for x in self {
            x.process_all::
(acc);
        }
    }
}

macro_rules! array_impls {
    ($($len:expr,)*) => { $(
        impl<T: DOMChildren> DOMChildren for [T; $len] {
            fn process_all
(&self, acc: &mut P::Acc) -> () {
                for x in self {
                    x.process_all::
(acc);
                }
            }
        }
    )* }
}

array_impls!(
    0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
    17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
);

// Credit to @shepmaster for structure of recursive tuple macro
macro_rules! tuple_impls {
    () => {};

    // Copywrite @shepmaster
    (($idx:tt => $typ:ident), $( ($nidx:tt => $ntyp:ident), )*) => {
        /*
         * Invoke recursive reversal of list that ends in the macro expansion implementation
         * of the reversed list
        */
        tuple_impls!([($idx, $typ);] $( ($nidx => $ntyp), )*);
        tuple_impls!($( ($nidx => $ntyp), )*); // invoke macro on tail
    };

    /*
     * ([accumulatedList], listToReverse); recursively calls tuple_impls until the list to reverse
     + is empty (see next pattern)
    */
    ([$(($accIdx: tt, $accTyp: ident);)+]  ($idx:tt => $typ:ident), $( ($nidx:tt => $ntyp:ident), )*) => {
      tuple_impls!([($idx, $typ); $(($accIdx, $accTyp); )*] $( ($nidx => $ntyp), ) *);
    };

    // Finally expand into the implementation
    ([($idx:tt, $typ:ident); $( ($nidx:tt, $ntyp:ident); )*]) => {
        impl<$typ, $( $ntyp ),*> DOMChildren for ($typ, $( $ntyp ),*)
            where $typ: DOMChildren,
                  $( $ntyp: DOMChildren),*
        {
            fn process_all
(&self, acc: &mut P::Acc) -> ()
                    where P: DOMChildrenProcessor {
                &self.$idx.process_all::
(acc);
                $(
                    &self.$nidx.process_all::
(acc);
                )*
            }
        }
    }
}

tuple_impls!(
    (9 => J),
    (8 => I),
    (7 => H),
    (6 => G),
    (5 => F),
    (4 => E),
    (3 => D),
    (2 => C),
    (1 => B),
    (0 => A),
);

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

    struct BogusOne;
    impl DOMNode for BogusOne {
        type ChildrenType = ();
        fn children(&self) -> &Self::ChildrenType { NONE_REF }
    }

    struct BogusTwo;
    impl DOMNode for BogusTwo {
        type ChildrenType = ();
        fn children(&self) -> &Self::ChildrenType { NONE_REF }
    }

    struct ChildCounter;
    impl DOMChildrenProcessor for ChildCounter {
        type Acc = usize;

        fn get_processor<T: DOMChildren>() -> fn(&mut Self::Acc, &T) -> () {
            fn incr<T: DOMChildren>(state: &mut usize, _level: &T) {
                *state += 1;
            }
            incr
        }
    }

    #[test]
    fn counts_children() {
        let mut count = 0;
        (BogusOne, &BogusOne, &BogusTwo).process_all::<ChildCounter>(&mut count);
        assert_eq!(3, count);

        count = 0;
        (BogusOne, (BogusOne,), BogusOne).process_all::<ChildCounter>(&mut count);
        assert_eq!(3, count);

        count = 0;
        [BogusOne, BogusOne, BogusOne].process_all::<ChildCounter>(&mut count);
        assert_eq!(3, count);

        count = 0;
        (BogusOne, BogusOne,
            [BogusOne, BogusOne, BogusOne],
            [(BogusOne)],
            [(), (), ()],
            [&BogusTwo, &BogusTwo, &BogusTwo],
        ).process_all::<ChildCounter>(&mut count);
        assert_eq!(9, count);

        let div = Div ((
            BogusOne,
            BogusOne,
            BogusTwo,
            Table ((
                "something",
                "something else".to_string(),
                TH (()),
                TR (()),
                TR (()),
            )),
        ));

        count = 0;
        div.process_all::<ChildCounter>(&mut count);
        assert_eq!(1, count);

        let div_children = div.children();

        count = 0;
        div_children.process_all::<ChildCounter>(&mut count);
        assert_eq!(4, count);
    }
}
<commit_msg>Add HTML string builder<commit_after>pub trait DOMNode {
    type ChildrenType: DOMChildren;
    fn children(&self) -> &Self::ChildrenType;
    fn tagname(&self) -> &str;
}
impl<'a, T: DOMNode> DOMNode for &'a T {
    type ChildrenType = T::ChildrenType;
    fn children(&self) -> &Self::ChildrenType { (*self).children() }
    fn tagname(&self) -> &str { (*self).tagname() }
}

const NONE_REF: &'static () = &();

impl DOMNode for String {
    type ChildrenType = ();
    fn children(&self) -> &Self::ChildrenType { NONE_REF }
    fn tagname(&self) -> &str { "text_tag" }
}

impl<'a> DOMNode for &'a str {
    type ChildrenType = ();
    fn children(&self) -> &Self::ChildrenType { NONE_REF }
    fn tagname(&self) -> &str { "text_tag" }
}

pub mod tags {
    use super::{DOMNode, DOMChildren};

    macro_rules! impl_tags {
        ($($tagname:ident,)*) => { $(
            pub struct $tagname<C: DOMChildren>(pub C);
            impl<C: DOMChildren> DOMNode for $tagname<C> {
                type ChildrenType = C;
                fn children(&self) -> &Self::ChildrenType { &self.0 }
                fn tagname(&self) -> &str { stringify!($tagname) }
            }
        )* }
    }

    impl_tags!(
        A, B, Big, BlockQuote, Body, Br, Center, Del, Div, Em,
        Font, Head, H1, H2, H3, H4, H5, H6, HR, I, Img, Ins,
        Li, Ol, P, Pre, S, Small, Span, Strong, Sub, Sup,
        Table, TD, TH, Title, TR, TT, U, UL,
    );
}

/// Processor of a `DOMNode`
pub trait DOMNodeProcessor {
    /// Accumulator
    type Acc;

    /// Folding function
    fn get_processor<T: DOMNode>() -> fn(&mut Self::Acc, &T) -> ();
}

pub trait DOMChildren {
    fn process_all
(&self, acc: &mut P::Acc) -> ();
}

impl DOMChildren for () {
    fn process_all
(&self, _acc: &mut P::Acc) -> () {}
}

impl<T: DOMNode> DOMChildren for T {
    fn process_all
(&self, acc: &mut P::Acc) -> () {
        P::get_processor()(acc, self);
    }
}

impl<T: DOMChildren> DOMChildren for [T] {
    fn process_all
(&self, acc: &mut P::Acc) -> () {
        for x in self {
            x.process_all::
(acc);
        }
    }
}

macro_rules! array_impls {
    ($($len:expr,)*) => { $(
        impl<T: DOMChildren> DOMChildren for [T; $len] {
            fn process_all
(&self, acc: &mut P::Acc) -> () {
                for x in self {
                    x.process_all::
(acc);
                }
            }
        }
    )* }
}

array_impls!(
    0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
    17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
);

// Credit to @shepmaster for structure of recursive tuple macro
macro_rules! tuple_impls {
    () => {};

    // Copywrite @shepmaster
    (($idx:tt => $typ:ident), $( ($nidx:tt => $ntyp:ident), )*) => {
        /*
         * Invoke recursive reversal of list that ends in the macro expansion implementation
         * of the reversed list
        */
        tuple_impls!([($idx, $typ);] $( ($nidx => $ntyp), )*);
        tuple_impls!($( ($nidx => $ntyp), )*); // invoke macro on tail
    };

    /*
     * ([accumulatedList], listToReverse); recursively calls tuple_impls until the list to reverse
     + is empty (see next pattern)
    */
    ([$(($accIdx: tt, $accTyp: ident);)+]  ($idx:tt => $typ:ident), $( ($nidx:tt => $ntyp:ident), )*) => {
      tuple_impls!([($idx, $typ); $(($accIdx, $accTyp); )*] $( ($nidx => $ntyp), ) *);
    };

    // Finally expand into the implementation
    ([($idx:tt, $typ:ident); $( ($nidx:tt, $ntyp:ident); )*]) => {
        impl<$typ, $( $ntyp ),*> DOMChildren for ($typ, $( $ntyp ),*)
            where $typ: DOMChildren,
                  $( $ntyp: DOMChildren),*
        {
            fn process_all
(&self, acc: &mut P::Acc) -> ()
                    where P: DOMNodeProcessor {
                &self.$idx.process_all::
(acc);
                $(
                    &self.$nidx.process_all::
(acc);
                )*
            }
        }
    }
}

tuple_impls!(
    (9 => J),
    (8 => I),
    (7 => H),
    (6 => G),
    (5 => F),
    (4 => E),
    (3 => D),
    (2 => C),
    (1 => B),
    (0 => A),
);

pub mod html_string {
    use super::{DOMNode, DOMChildren, DOMNodeProcessor};

    pub struct HtmlStringBuilder;
    impl DOMNodeProcessor for HtmlStringBuilder {
        type Acc = String;

        fn get_processor<T: DOMNode>() -> fn(&mut Self::Acc, &T) -> () {
            fn add_node<T: DOMNode>(string: &mut String, node: &T) {
                string.push_str("<");
                string.push_str(node.tagname());
                string.push_str(">");

                node.children().process_all::<HtmlStringBuilder>(string);

                string.push_str("</");
                string.push_str(node.tagname());
                string.push_str(">");
            }
            add_node
        }
    }
}

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

    struct BogusOne;
    impl DOMNode for BogusOne {
        type ChildrenType = ();
        fn children(&self) -> &Self::ChildrenType { NONE_REF }
        fn tagname(&self) -> &str { "bogus_tag_one" }
    }

    struct BogusTwo;
    impl DOMNode for BogusTwo {
        type ChildrenType = ();
        fn children(&self) -> &Self::ChildrenType { NONE_REF }
        fn tagname(&self) -> &str { "bogus_tag_two" }
    }

    struct ChildCounter;
    impl DOMNodeProcessor for ChildCounter {
        type Acc = usize;

        fn get_processor<T: DOMNode>() -> fn(&mut Self::Acc, &T) -> () {
            fn incr<T: DOMNode>(count: &mut usize, _node: &T) {
                *count += 1;
            }
            incr
        }
    }

    static HTML_SAMPLE:
        Div<(BogusOne, BogusOne, BogusTwo, Table<(&'static str, TH<()>, TR<()>, TR<()>)>)> =

    Div ((
        BogusOne,
        BogusOne,
        BogusTwo,
        Table ((
            "something",
            TH (()),
            TR (()),
            TR (()),
        )),
    ));

    #[test]
    fn counts_children() {
        let mut count = 0;
        (BogusOne, &BogusOne, &BogusTwo).process_all::<ChildCounter>(&mut count);
        assert_eq!(3, count);

        count = 0;
        (BogusOne, (BogusOne,), BogusOne).process_all::<ChildCounter>(&mut count);
        assert_eq!(3, count);

        count = 0;
        [BogusOne, BogusOne, BogusOne].process_all::<ChildCounter>(&mut count);
        assert_eq!(3, count);

        count = 0;
        (BogusOne, BogusOne,
            [BogusOne, BogusOne, BogusOne],
            [(BogusOne)],
            [(), (), ()],
            [&BogusTwo, &BogusTwo, &BogusTwo],
        ).process_all::<ChildCounter>(&mut count);
        assert_eq!(9, count);

        count = 0;
        HTML_SAMPLE.process_all::<ChildCounter>(&mut count);
        assert_eq!(1, count);

        let div_children = HTML_SAMPLE.children();

        count = 0;
        div_children.process_all::<ChildCounter>(&mut count);
        assert_eq!(4, count);
    }

    #[test]
    fn builds_string() {
        let mut string = String::new();
        HTML_SAMPLE.process_all::<HtmlStringBuilder>(&mut string);
        assert_eq!(
            r#"

                <bogus_tag_one></bogus_tag_one>
                <bogus_tag_one></bogus_tag_one>
                <bogus_tag_two></bogus_tag_two>

                    <text_tag></text_tag>

            "#.chars().filter(|c| !c.is_whitespace()).collect::<String>(),
            string.to_lowercase()
        );
    }
}
<|endoftext|>


<commit_before>#[macro_export]
macro_rules! query_map {
($conn:ident, $query:expr, $params:expr, $T:ident, $($member:ident),* ) => {
		{
			let stmt = $conn.prepare($query)
					.unwrap();

			let result = stmt.query($params).unwrap()
				.map(|row:postgres::Row| $T {
						$( $member: row.get(stringify!($member)) ),*
					});
			result.collect::<Vec<$T>>()
		}
	}
}

<commit_msg>added support for custom mapping<commit_after>#[macro_export]
macro_rules! query_map {
	($conn:ident, $query:expr, $params:expr, $T:ident{ $($member:ident),* }) => {
		{
			let stmt = $conn.prepare($query)
					.unwrap();

			let result = stmt.query($params).unwrap()
				.map(|row:postgres::Row| $T {
						$( $member: row.get(stringify!($member)) ),*
					});
			result.collect::<Vec<$T>>()
		}
	};

	($conn:ident, $query:expr, $params:expr, $T:ident{ $($member:ident => $key:expr),* }) => {
		{
			let stmt = $conn.prepare($query)
					.unwrap();

			let result = stmt.query($params).unwrap()
				.map(|row:postgres::Row| $T {
						$( $member: row.get($key) ),*
					});
			result.collect::<Vec<$T>>()
		}
	}
}

<|endoftext|>


<commit_before>#![feature(custom_derive, plugin)]
#![plugin(serde_macros)]

extern crate serde;
extern crate serde_json;

use serde::Deserialize;
use std::fmt;
use std::io::{self, Read};
use std::convert;
use std::collections::HashMap;
use std::net::{
    TcpListener,
    TcpStream,
};
use std::sync::{
    self,
    Mutex,
};
use std::sync::mpsc::{
    channel,
    sync_channel,
    Sender,
    SyncSender,
    Receiver,
};
use std::thread;

#[derive(Debug)]
pub enum Error {
    Io(io::Error),
    Json(serde_json::Error),
    Sender,
    Unimplemented,
    Impossible
}

impl convert::From<serde_json::Error> for Error {
    fn from(err: serde_json::Error) -> Error {
        match err {
            serde_json::Error::IoError(err) => Error::Io(err),
            err => Error::Json(err),
        }
    }
}

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

impl<T> convert::From<sync::mpsc::SendError<T>> for Error {
    fn from(_: sync::mpsc::SendError<T>) -> Error {
        Error::Sender
    }
}

pub type Result<T> = std::result::Result<T, Error>;

pub fn handle_conn<F, Request, Reply>(
    mut stream: TcpStream,
    f: F) -> Result<()>
    where Request: fmt::Debug + serde::de::Deserialize,
          Reply: fmt::Debug + serde::ser::Serialize,
          F: 'static + Serve<Request, Reply>
{
    let read_stream = try!(stream.try_clone());
    let mut de = serde_json::Deserializer::new(read_stream.bytes());
    let request_packet: Packet<Request> = try!(Packet::deserialize(&mut de));
    let reply = try!(f.serve(&request_packet.message));
    let reply_packet = Packet{
        id: request_packet.id,
        message: reply,
    };
    try!(serde_json::to_writer(&mut stream, &reply_packet));
    Ok(())
}

pub fn serve<F, Request, Reply>(listener: TcpListener, f: F) -> Error
    where Request: fmt::Debug + serde::de::Deserialize,
          Reply: fmt::Debug + serde::ser::Serialize,
          F: 'static + Serve<Request, Reply>,
{
    for conn in listener.incoming() {
        let conn = match conn {
            Err(err) => return convert::From::from(err),
            Ok(c) => c,
        };
        let f = f.clone();
        thread::spawn(move || {
            if let Err(err) = handle_conn(conn, f) {
                println!("error handling connection: {:?}", err);
            }
        });
    }
    Error::Impossible
}

pub trait Serve<Request, Reply> : Sync + Send + Clone {
    fn serve(&self, request: &Request) -> io::Result<Reply>;
}

#[derive(Debug, Clone, Serialize, Deserialize)]
struct Packet<T> {
    id: u64,
    message: T,
}

struct Handle<T> {
    id: u64,
    sender: Sender<T>,
}

enum ReceiverMessage<Reply> {
    Handle(Handle<Reply>),
    Packet(Packet<Reply>),
}

fn receiver<Reply>(messages: Receiver<ReceiverMessage<Reply>>) -> Result<()> {
    let mut ready_handles: HashMap<u64, Handle<Reply>> = HashMap::new();
    for message in messages.into_iter() {
        match message {
            ReceiverMessage::Handle(handle) => {
                ready_handles.insert(handle.id, handle);
            },
            ReceiverMessage::Packet(packet) => {
                let handle = ready_handles.remove(&packet.id).unwrap();
                try!(handle.sender.send(packet.message));
            }
        }
    }
    Ok(())
}

fn reader<T, F>(mut stream: TcpStream, decode: F, tx: SyncSender<T>)
    where F: Send + 'static + Fn(&mut TcpStream) -> Result<T>,
          T: Send + 'static
{
    use serde_json::Error::SyntaxError;
    use serde_json::ErrorCode::EOFWhileParsingValue;
    loop {
        match decode(&mut stream) {
            Ok(t) => tx.send(t).unwrap(),
            Err(Error::Json(SyntaxError(EOFWhileParsingValue, _, _))) => break,
            Err(err) => panic!("unexpected error while parsing!: {:?}", err),
        }
    }
}

fn increment(cur_id: &mut u64) -> u64 {
    let id = *cur_id;
    *cur_id += 1;
    id
}

struct SyncedClientState{
    next_id: u64,
    stream: TcpStream,
}

pub struct Client<Reply> {
    synced_state: Mutex<SyncedClientState>,
    handles_tx: SyncSender<ReceiverMessage<Reply>>,
    reader_guard: thread::JoinHandle<()>,
}

impl<Reply> Client<Reply>
    where Reply: serde::de::Deserialize + Send + 'static
{
    pub fn new(stream: TcpStream) -> Result<Self> {
        let (handles_tx, receiver_rx) = sync_channel(0);
        let decode = |mut stream: &mut TcpStream| {
            let packet = try!(serde_json::from_reader(&mut stream));
            Ok(ReceiverMessage::Packet(packet))
        };
        let read_stream = try!(stream.try_clone());
        let reader_handles_tx = handles_tx.clone();
        let guard = thread::spawn(move || reader(read_stream, decode, reader_handles_tx));
        thread::spawn(move || receiver(receiver_rx));
        Ok(Client{
            synced_state: Mutex::new(SyncedClientState{
                next_id: 0,
                stream: stream,
            }),
            reader_guard: guard,
            handles_tx: handles_tx,
        })
    }

    pub fn rpc<Request>(&self, request: &Request) -> Result<Reply>
        where Request: serde::ser::Serialize + Clone + Send + 'static
    {
        let (tx, rx) = channel();
        let mut state = self.synced_state.lock().unwrap();
        let id = increment(&mut state.next_id);
        try!(self.handles_tx.send(ReceiverMessage::Handle(Handle{
            id: id,
            sender: tx,
        })));
        try!(serde_json::to_writer(&mut state.stream, &Packet{
            id: id,
            message: request.clone(),
        }));
        Ok(rx.recv().unwrap())
    }

    pub fn join(self) {
        self.reader_guard.join().unwrap();
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use std::thread;
    use std::net::{TcpStream, TcpListener};
    use std::io;

    fn pair() -> (TcpStream, TcpListener) {
        let addr = "127.0.0.1:9000";
        // Do this one first so that we don't get connection refused :)
        let listener = TcpListener::bind(addr).unwrap();
        (TcpStream::connect(addr).unwrap(), listener)
    }

    #[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
    enum Request {
        Increment
    }

    #[derive(Debug, PartialEq, Serialize, Deserialize)]
    enum Reply {
        Increment
    }

    #[derive(Clone)]
    struct Server;

    impl Serve<Request, Reply> for Server {
        fn serve(&self, _: &Request) -> io::Result<Reply> {
            Ok(Reply::Increment)
        }
    }

    #[test]
    fn test() {
        let (client_stream, server_streams) = pair();
        thread::spawn(|| serve(server_streams, Server));
        let client = Client::new(client_stream).unwrap();
        assert_eq!(Reply::Increment, client.rpc(&Request::Increment).unwrap());
        client.join();
    }
}
<commit_msg>A number of improvements<commit_after>#![feature(custom_derive, plugin)]
#![plugin(serde_macros)]

extern crate serde;
extern crate serde_json;

use serde::Deserialize;
use std::fmt;
use std::io::{self, Read};
use std::convert;
use std::collections::HashMap;
use std::net::{
    self,
    TcpListener,
    TcpStream,
};
use std::sync::{
    self,
    Mutex,
    Arc,
};
use std::sync::mpsc::{
    channel,
    sync_channel,
    Sender,
    SyncSender,
    Receiver,
};
use std::time;
use std::thread;

#[derive(Debug)]
pub enum Error {
    Io(io::Error),
    Json(serde_json::Error),
    Sender,
    Unimplemented,
    Impossible
}

impl convert::From<serde_json::Error> for Error {
    fn from(err: serde_json::Error) -> Error {
        match err {
            serde_json::Error::IoError(err) => Error::Io(err),
            err => Error::Json(err),
        }
    }
}

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

impl<T> convert::From<sync::mpsc::SendError<T>> for Error {
    fn from(_: sync::mpsc::SendError<T>) -> Error {
        Error::Sender
    }
}

pub type Result<T> = std::result::Result<T, Error>;

pub fn handle_conn<F, Request, Reply>(mut stream: TcpStream, f: Arc<F>) -> Result<()>
    where Request: fmt::Debug + serde::de::Deserialize,
          Reply: fmt::Debug + serde::ser::Serialize,
          F: Serve<Request, Reply>
{
    let read_stream = try!(stream.try_clone());
    let mut de = serde_json::Deserializer::new(read_stream.bytes());
    loop {
        println!("read");
        let request_packet: Packet<Request> = try!(Packet::deserialize(&mut de));
        match request_packet {
            Packet::Shutdown => break,
            Packet::Message(id, message) => {
                let reply = try!(f.serve(&message));
                let reply_packet = Packet::Message(id, reply);
                println!("write");
                try!(serde_json::to_writer(&mut stream, &reply_packet));
            },
        }
    }
    Ok(())
}

pub fn serve<F, Request, Reply>(listener: TcpListener, f: Arc<F>) -> Error
    where Request: fmt::Debug + serde::de::Deserialize,
          Reply: fmt::Debug + serde::ser::Serialize,
          F: 'static + Serve<Request, Reply>,
{
    for conn in listener.incoming() {
        let conn = match conn {
            Err(err) => return convert::From::from(err),
            Ok(c) => c,
        };
        let f = f.clone();
        thread::spawn(move || {
            if let Err(err) = handle_conn(conn, f) {
                println!("error handling connection: {:?}", err);
            }
        });
    }
    Error::Impossible
}

pub trait Serve<Request, Reply>: Send + Sync {
    fn serve(&self, request: &Request) -> io::Result<Reply>;
}

#[derive(Debug, Clone, Serialize, Deserialize)]
enum Packet<T> {
    Message(u64, T),
    Shutdown,
}

struct Handle<T> {
    id: u64,
    sender: Sender<T>,
}

enum ReceiverMessage<Reply> {
    Handle(Handle<Reply>),
    Packet(Packet<Reply>),
    Shutdown,
}

fn receiver<Reply>(messages: Receiver<ReceiverMessage<Reply>>) -> Result<()> {
    let mut ready_handles: HashMap<u64, Handle<Reply>> = HashMap::new();
    for message in messages.into_iter() {
        match message {
            ReceiverMessage::Handle(handle) => {
                ready_handles.insert(handle.id, handle);
            },
            ReceiverMessage::Packet(Packet::Shutdown) => break,
            ReceiverMessage::Packet(Packet::Message(id, message)) => {
                let handle = ready_handles.remove(&id).unwrap();
                try!(handle.sender.send(message));
            }
            ReceiverMessage::Shutdown => break,
        }
    }
    Ok(())
}

fn reader<Reply>(stream: TcpStream, tx: SyncSender<ReceiverMessage<Reply>>)
    where Reply: serde::Deserialize
{
    use serde_json::Error::SyntaxError;
    use serde_json::ErrorCode::EOFWhileParsingValue;
    let mut de = serde_json::Deserializer::new(stream.bytes());
    loop {
        match Packet::deserialize(&mut de) {
            Ok(packet) =>{
                println!("send!");
                tx.send(ReceiverMessage::Packet(packet)).unwrap();
            },
            // TODO: This shutdown logic is janky.. What's the right way to do this?
            Err(SyntaxError(EOFWhileParsingValue, _, _)) => break,
            Err(SyntaxError(ExpectedValue, _, _)) => break,
            Err(err) => panic!("unexpected error while parsing!: {:?}", err),
        }
    }
}

fn increment(cur_id: &mut u64) -> u64 {
    let id = *cur_id;
    *cur_id += 1;
    id
}

struct SyncedClientState{
    next_id: u64,
    stream: TcpStream,
}

pub struct Client<Reply> {
    synced_state: Mutex<SyncedClientState>,
    handles_tx: SyncSender<ReceiverMessage<Reply>>,
    reader_guard: thread::JoinHandle<()>,
}

impl<Reply> Client<Reply>
    where Reply: serde::de::Deserialize + Send + 'static
{
    pub fn new(stream: TcpStream) -> Result<Self> {
        let (handles_tx, receiver_rx) = sync_channel(0);
        let read_stream = try!(stream.try_clone());
        try!(read_stream.set_read_timeout(Some(time::Duration::from_millis(50))));
        let reader_handles_tx = handles_tx.clone();
        let guard = thread::spawn(move || reader(read_stream, reader_handles_tx));
        thread::spawn(move || receiver(receiver_rx));
        Ok(Client{
            synced_state: Mutex::new(SyncedClientState{
                next_id: 0,
                stream: stream,
            }),
            reader_guard: guard,
            handles_tx: handles_tx,
        })
    }

    pub fn rpc<Request>(&self, request: &Request) -> Result<Reply>
        where Request: serde::ser::Serialize + Clone + Send + 'static
    {
        let (tx, rx) = channel();
        let mut state = self.synced_state.lock().unwrap();
        let id = increment(&mut state.next_id);
        try!(self.handles_tx.send(ReceiverMessage::Handle(Handle{
            id: id,
            sender: tx,
        })));
        let packet = Packet::Message(id, request.clone());
        try!(serde_json::to_writer(&mut state.stream, &packet));
        Ok(rx.recv().unwrap())
    }

    pub fn join<Request: serde::Serialize>(self) -> Result<()> {
        let mut state = self.synced_state.lock().unwrap();
        let packet: Packet<Request> = Packet::Shutdown;
        try!(serde_json::to_writer(&mut state.stream, &packet));
        try!(state.stream.shutdown(net::Shutdown::Both));
        self.reader_guard.join().unwrap();
        Ok(())
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use std::io;
    use std::net::{TcpStream, TcpListener};
    use std::sync::{Arc, Mutex};
    use std::thread;

    fn pair() -> (TcpStream, TcpListener) {
        let addr = "127.0.0.1:9000";
        // Do this one first so that we don't get connection refused :)
        let listener = TcpListener::bind(addr).unwrap();
        (TcpStream::connect(addr).unwrap(), listener)
    }

    #[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
    enum Request {
        Increment
    }

    #[derive(Debug, PartialEq, Serialize, Deserialize)]
    enum Reply {
        Increment(u64)
    }

    struct Server {
        counter: Mutex<u64>,
    }

    impl Serve<Request, Reply> for Server {
        fn serve(&self, _: &Request) -> io::Result<Reply> {
            let mut counter = self.counter.lock().unwrap();
            let reply = Reply::Increment(*counter);
            *counter += 1;
            Ok(reply)
        }
    }

    impl Server {
        fn count(&self) -> u64 {
            *self.counter.lock().unwrap()
        }
    }

    #[test]
    fn test() {
        let (client_stream, server_streams) = pair();
        let server = Arc::new(Server{counter: Mutex::new(0)});
        let thread_server = server.clone();
        thread::spawn(move || serve(server_streams, thread_server));
        let client = Client::new(client_stream).unwrap();
        assert_eq!(Reply::Increment(0), client.rpc(&Request::Increment).unwrap());
        assert_eq!(1, server.count());
        assert_eq!(Reply::Increment(1), client.rpc(&Request::Increment).unwrap());
        assert_eq!(2, server.count());
        client.join::<Request>().unwrap();
    }
}
<|endoftext|>


<commit_before>#![crate_name="gm2"]
#![allow(dead_code)]

#[macro_use]
extern crate glium;
extern crate cgmath;
extern crate image;

pub mod render;
pub mod camera;
pub mod input;
pub mod geometry;
pub mod game {
    pub mod simple;
}
pub mod spring;
pub mod audio;

pub type Color = [f32; 4];

pub type Vec2i = cgmath::Vector2<i32>;
pub type Vec3i = cgmath::Vector3<i32>;

pub type Vec3 = cgmath::Vector3<f64>;
pub type Vec3f = cgmath::Vector3<f32>;

pub type Vec4 = cgmath::Vector4<f64>;

pub type Mat3 = cgmath::Matrix3<f64>;
pub type Mat4 = cgmath::Matrix4<f64>;

pub fn round_down(f:f64) -> i32 {
    if f < 0.0 {
        f as i32 - 1
    } else {
        f as i32
    }
}

pub fn round_down_v3(v:Vec3) -> Vec3i {
    Vec3i::new(round_down(v.x), round_down(v.y), round_down(v.z))
}<commit_msg>Added usize<commit_after>#![crate_name="gm2"]
#![allow(dead_code)]

#[macro_use]
extern crate glium;
extern crate cgmath;
extern crate image;

pub mod render;
pub mod camera;
pub mod input;
pub mod geometry;
pub mod game {
    pub mod simple;
}
pub mod spring;
pub mod audio;

pub type Color = [f32; 4];

pub type Vec2i = cgmath::Vector2<i32>;
pub type Vec2Size = cgmath::Vector2<usize>;
pub type Vec3i = cgmath::Vector3<i32>;

pub type Vec3 = cgmath::Vector3<f64>;
pub type Vec3f = cgmath::Vector3<f32>;

pub type Vec4 = cgmath::Vector4<f64>;

pub type Mat3 = cgmath::Matrix3<f64>;
pub type Mat4 = cgmath::Matrix4<f64>;

pub fn round_down(f:f64) -> i32 {
    if f < 0.0 {
        f as i32 - 1
    } else {
        f as i32
    }
}

pub fn round_down_v3(v:Vec3) -> Vec3i {
    Vec3i::new(round_down(v.x), round_down(v.y), round_down(v.z))
}<|endoftext|>


<commit_before>use std::ops::{Deref, DerefMut};
use std::mem;
use std::collections::HashMap;

#[derive(Debug)]
pub enum GraphProperty {
    Int(i64),
    Float(f64),
    String(String),
}

use edge::{Edge,EdgeProxy};
use graph::TraversableToVertex;

/*
* storing in & out edges seperately should cut down on the number of "things" i have to traverse
* if a vertex has 10k edges (5k in and out 5k out) then doing something like*   g(v).outV()
* should be ok
*/
#[derive(Debug)]
pub struct Vertex {
    pub id: i64,
    pub properties: HashMap<String, GraphProperty>,
    // pointers on both sides, yay
    pub out_edges: Vec<*mut Edge>,
    pub in_edges:  Vec<*mut Edge>,
}

impl Vertex {
    pub fn new(id: i64) -> Box<Vertex> {
        let mut props  = HashMap::new();
        Box::new(Vertex{id:id,
                        properties: props,
                        out_edges: Vec::new(),
                        in_edges: Vec::new()})
    }

	pub fn outE() -> Vec<Edge> {
		let mut result = Vec::new();
		result
	}

	pub fn inE() -> Vec<Edge> {
		let mut result = Vec::new();
		result
	}

}

pub struct VertexProxy {
    pub id: i64,
    pub v: *mut Vertex,
}

impl VertexProxy {

	pub fn new(v: *mut Vertex) {

	}

    pub fn add_edge(&mut self, to_vertex: &mut VertexProxy) -> EdgeProxy {
        let in_vertex: &mut Vertex;
        let out_vertex: &mut Vertex;

        unsafe {
            in_vertex =  &mut *(self.v);
            out_vertex = &mut *(to_vertex.v);
        }

        // create the edge
        let e = Box::new(Edge{from_vertex: self.v, to_vertex: to_vertex.v});

        // keep it on the heap but manage it myself
        let edge: *mut Edge = unsafe { mem::transmute(e) };

        in_vertex.out_edges.push(edge);
        out_vertex.in_edges.push(edge);
        EdgeProxy{edge:edge}
    }

    pub fn set_property(&mut self, field: String, value: GraphProperty) {
        self.properties.insert(field, value);
    }

    pub fn get_property(&self, field:String) -> Option<&GraphProperty> {
        self.properties.get(&field)
    }

    pub fn query(self) {
        unimplemented!()
    }

}

impl TraversableToVertex for VertexProxy {
	/* basic traversal operations
	   cannot be chained
	   look at traversal.rs for breadth first chaining
	*/

	/* returns all the outV vertex proxies
	   mainly for internal use
	*/
	fn outV(&self) -> Vec<VertexProxy> {
		let mut result = Vec::new();
		unsafe {
			for &x in self.out_edges.iter() {
				let edge: &Edge = &*x;
				let vertex: &Vertex = &*(edge.to_vertex);

				let proxy = VertexProxy{id:vertex.id, v:edge.to_vertex};
				result.push(proxy);
			}
			result
		}
	}
	fn inV(&self) -> Vec<VertexProxy> {
		let mut result = Vec::new();
		unsafe {
			for &x in self.in_edges.iter() {
				let edge: &Edge = &*x;
				let vertex: &Vertex = &*(edge.from_vertex);

				let proxy = VertexProxy{id:vertex.id, v:edge.from_vertex};
				result.push(proxy);
			}
			result
		}
	}
//	fn inE(&self) -> Vec<EdgeProxy> {
//		let mut result = Vec::new();
//
//		result
//	}
//	fn outE(&self) -> Vec<EdgeProxy> {
//		let mut result = Vec::new();
//
//		result
//	}

}

impl Deref for VertexProxy {
    type Target = Vertex;

    fn deref<'a>(&'a self) -> &'a Vertex {
        unsafe {
            &*(self.v)
        }
    }
}

impl DerefMut for VertexProxy {
    fn deref_mut<'a>(&'a mut self) -> &'a mut Vertex {
        unsafe {
            &mut *(self.v)
        }
    }
}

<commit_msg>removed dead code<commit_after>use std::ops::{Deref, DerefMut};
use std::mem;
use std::collections::HashMap;

#[derive(Debug)]
pub enum GraphProperty {
    Int(i64),
    Float(f64),
    String(String),
}

use edge::{Edge,EdgeProxy};
use graph::TraversableToVertex;

/*
* storing in & out edges seperately should cut down on the number of "things" i have to traverse
* if a vertex has 10k edges (5k in and out 5k out) then doing something like*   g(v).outV()
* should be ok
*/
#[derive(Debug)]
pub struct Vertex {
    pub id: i64,
    pub properties: HashMap<String, GraphProperty>,
    // pointers on both sides, yay
    pub out_edges: Vec<*mut Edge>,
    pub in_edges:  Vec<*mut Edge>,
}

impl Vertex {
    pub fn new(id: i64) -> Box<Vertex> {
        let mut props  = HashMap::new();
        Box::new(Vertex{id:id,
                        properties: props,
                        out_edges: Vec::new(),
                        in_edges: Vec::new()})
    }

	pub fn outE() -> Vec<EdgeProxy> {
		let mut result = Vec::new();
		result
	}

	pub fn inE() -> Vec<EdgeProxy> {
		let mut result = Vec::new();
		result
	}

}

pub struct VertexProxy {
    pub id: i64,
    pub v: *mut Vertex,
}

impl VertexProxy {

	pub fn new(v: *mut Vertex) {

	}

    pub fn add_edge(&mut self, to_vertex: &mut VertexProxy) -> EdgeProxy {
        let in_vertex: &mut Vertex;
        let out_vertex: &mut Vertex;

        unsafe {
            in_vertex =  &mut *(self.v);
            out_vertex = &mut *(to_vertex.v);
        }

        // create the edge
        let e = Box::new(Edge{from_vertex: self.v, to_vertex: to_vertex.v});

        // keep it on the heap but manage it myself
        let edge: *mut Edge = unsafe { mem::transmute(e) };

        in_vertex.out_edges.push(edge);
        out_vertex.in_edges.push(edge);
        EdgeProxy{edge:edge}
    }

    pub fn set_property(&mut self, field: String, value: GraphProperty) {
        self.properties.insert(field, value);
    }

    pub fn get_property(&self, field:String) -> Option<&GraphProperty> {
        self.properties.get(&field)
    }

    pub fn query(self) {
        unimplemented!()
    }

}

impl TraversableToVertex for VertexProxy {
	/* basic traversal operations
	   cannot be chained
	   look at traversal.rs for breadth first chaining
	*/

	/* returns all the outV vertex proxies
	   mainly for internal use
	*/
	fn outV(&self) -> Vec<VertexProxy> {
		let mut result = Vec::new();
		unsafe {
			for &x in self.out_edges.iter() {
				let edge: &Edge = &*x;
				let vertex: &Vertex = &*(edge.to_vertex);

				let proxy = VertexProxy{id:vertex.id, v:edge.to_vertex};
				result.push(proxy);
			}
			result
		}
	}
	fn inV(&self) -> Vec<VertexProxy> {
		let mut result = Vec::new();
		unsafe {
			for &x in self.in_edges.iter() {
				let edge: &Edge = &*x;
				let vertex: &Vertex = &*(edge.from_vertex);

				let proxy = VertexProxy{id:vertex.id, v:edge.from_vertex};
				result.push(proxy);
			}
			result
		}
	}

}

impl Deref for VertexProxy {
    type Target = Vertex;

    fn deref<'a>(&'a self) -> &'a Vertex {
        unsafe {
            &*(self.v)
        }
    }
}

impl DerefMut for VertexProxy {
    fn deref_mut<'a>(&'a mut self) -> &'a mut Vertex {
        unsafe {
            &mut *(self.v)
        }
    }
}

<|endoftext|>


<commit_before>pub mod lines;

#[macro_use]
extern crate nom;

extern crate regex;
extern crate memmap;
extern crate memchr;
extern crate ascii;

use std::path::Path;
use std::cmp;
use std::fmt;

use memmap::{Mmap, Protection};
use memchr::memchr;

// Why is it called partialEq?
#[derive(Debug, PartialEq, Default, Clone)]
pub struct Count {
    pub code: u32,
    pub comment: u32,
    pub blank: u32,
    pub lines: u32,
}

impl Count {
    pub fn merge(&mut self, o: &Count) {
        self.code += o.code;
        self.comment += o.comment;
        self.blank += o.blank;
        self.lines += o.lines;
    }
}

pub enum LineConfig<'a> {
    Multi {
        single_start: &'a str,
        multi_start: &'a str,
        multi_end: &'a str,
    },
    Single {
        single_start: &'a str,
    },
}

// Do any languages actually use utf8 chars as comment chars?
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, Clone)]
pub enum Lang {
    C,
    CCppHeader,
    Rust,
    Ruby,
    Haskell,
    Perl,
    BourneShell,
    Make,
    INI,
    Assembly,
    Yacc,
    Awk,
    Unrecognized,
}

impl fmt::Display for Lang {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let s = match *self {
            Lang::C => "C",
            Lang::CCppHeader => "C/C++ Header",
            Lang::Rust => "Rust",
            Lang::Ruby => "Ruby",
            Lang::Haskell => "Haskell",
            Lang::Perl => "Perl",
            Lang::BourneShell => "Bourne Shell",
            Lang::Make => "Make",
            Lang::INI => "INI",
            Lang::Assembly => "Assembly",
            Lang::Yacc => "Yacc",
            Lang::Awk => "Awk",
            Lang::Unrecognized => "Unrecognized",
        };
        f.pad(s)
    }
}

pub fn lang_from_ext(filepath: &str) -> Lang {
    let path = Path::new(filepath);
    let ext = match path.extension() {
        Some(os_str) => os_str.to_str().unwrap().to_lowercase(),
        None => path.file_name().unwrap().to_str().unwrap().to_lowercase(),
    };

    match &*ext {
        "c" => Lang::C,
        "h" | "hh" | "hpp" | "hxx" => Lang::CCppHeader,
        "rs" => Lang::Rust,
        "hs" => Lang::Haskell,
        "pl" => Lang::Perl,
        "rb" => Lang::Ruby,
        "makefile" | "mk" => Lang::Make,
        "ini" => Lang::INI,
        "s" | "asm" => Lang::Assembly,
        "y" => Lang::Yacc,
        "awk" => Lang::Awk,

        // TODO(cgag): What's the correct extension? Any? Pragma?
        "sh" => Lang::BourneShell,
        // Probably dumb to just default to C.
        _ => Lang::Unrecognized,
    }
}

pub fn counter_config_for_lang<'a>(lang: &Lang) -> LineConfig<'a> {
    enum CT<'a> {
        Single(&'a str),
        Multi(&'a str, &'a str, &'a str),
    }
    // use self::ConfigTuple::*;

    let c_style = CT::Multi("//", "/*", "*/");
    let sh_style = CT::Single("#");

    let ctuple = match *lang {
        Lang::Haskell => CT::Multi("--", "{-", "-}"),
        Lang::Perl => CT::Multi("#", "=pod", "=cut"),
        Lang::INI => CT::Single(";"),
        // TODO(cgag): Well, some architectures use ;, @, |, etc.
        // Need a way to specify more than one possible comment char.
        Lang::Assembly => CT::Multi("#", "/*", "*/"),
        Lang::BourneShell | Lang::Ruby | Lang::Make | Lang::Awk => sh_style,
        // TODO(cgag): not 100% that yacc belongs here.
        Lang::C | Lang::CCppHeader | Lang::Rust | Lang::Yacc => c_style,
        // Default to C style
        Lang::Unrecognized => c_style,
    };

    match ctuple {
        CT::Multi(single, start, end) => {
            LineConfig::Multi {
                single_start: single,
                multi_start: start,
                multi_end: end,
            }
        }
        CT::Single(single) => LineConfig::Single { single_start: single },
    }
}

struct AsciiLines<'a> {
    buf: &'a [u8],
    pos: usize,
}

struct Ascii<'a>(&'a [u8]);
impl<'a> Ascii<'a> {
    fn lines(&self) -> AsciiLines {
        AsciiLines {
            buf: self.0,
            pos: 0,
        }
    }
}

// Appears to work, now we just neeed
impl<'a> Iterator for AsciiLines<'a> {
    type Item = &'a [u8];

    fn next(&mut self) -> Option<&'a [u8]> {
        match memchr(b'\n', &self.buf[self.pos..self.buf.len()]) {
            Some(n) => {
                let start = self.pos;
                self.pos = self.pos + n + 1;
                // - 1 to drop \n char
                Some(&self.buf[start..(self.pos - 1)])
            }
            None => {
                if self.pos == self.buf.len() {
                    return None;
                }
                let start = self.pos;
                self.pos = self.buf.len();
                Some(&self.buf[start..self.pos])
            }
        }
    }
}

pub fn count(filepath: &str) -> Count {
    let lang = lang_from_ext(filepath);
    let config = counter_config_for_lang(&lang);
    match config {
        LineConfig::Single { single_start: single } => count_mmap_unsafe_single(filepath, single),
        LineConfig::Multi { single_start: single, multi_start, multi_end } => {
            count_mmap_unsafe_multi(filepath, single, multi_start, multi_end)
        }
    }
}

pub fn count_mmap_unsafe_single(filepath: &str, single_start: &str) -> Count {
    let fmmap = match Mmap::open_path(filepath, Protection::Read) {
        Ok(mmap) => mmap,
        Err(e) => {
            println!("mmap err for {}: {}", filepath, e);
            return Count::default();
        }
    };
    let bytes: &[u8] = unsafe { fmmap.as_slice() };

    let mut lines = 0;
    let mut code = 0;
    let mut comments = 0;
    let mut blanks = 0;

    let a = Ascii(bytes);
    for byte_line in a.lines() {
        let line = unsafe { std::str::from_utf8_unchecked(byte_line) };
        lines += 1;

        let trimmed = line.trim_left();
        if trimmed.is_empty() {
            blanks += 1;
        } else if trimmed.starts_with(single_start) {
            comments += 1;
        } else {
            code += 1;
        }
    }

    Count {
        code: code,
        comment: comments,
        blank: blanks,
        lines: lines,
    }
}

pub fn count_mmap_unsafe_multi(filepath: &str,
                               single_start: &str,
                               multi_start: &str,
                               multi_end: &str)
                               -> Count {

    let single_line_start = single_start;
    let multiline_start = multi_start;
    let multiline_end = multi_end;

    let fmmap = match Mmap::open_path(filepath, Protection::Read) {
        Ok(mmap) => mmap,
        Err(e) => {
            println!("mmap err for {}: {}", filepath, e);
            return Count::default();
        }
    };
    let bytes: &[u8] = unsafe { fmmap.as_slice() };

    let mut lines = 0;
    let mut code = 0;
    let mut comments = 0;
    let mut blanks = 0;

    let mut in_comment = false;

    let a = Ascii(bytes);
    for byte_line in a.lines() {
        let line = unsafe { std::str::from_utf8_unchecked(byte_line) };
        lines += 1;

        let trimmed = line.trim_left();
        if trimmed.is_empty() {
            blanks += 1;
            continue;
        };

        if !in_comment && trimmed.starts_with(single_line_start) {
            comments += 1;
            continue;
        }

        if !(trimmed.contains(multiline_start) || trimmed.contains(multiline_end)) {
            if in_comment {
                comments += 1;
            } else {
                code += 1;
            }
            continue;
        }

        let mut pos = 0;
        let mut found_code = false;

        let start_len = multiline_start.len();
        let end_len = multiline_end.len();

        'outer: while pos < trimmed.len() {
            // TODO(cgag): must be a less stupid way to do this
            for i in pos..(pos + cmp::max(start_len, end_len) + 1) {
                if !trimmed.is_char_boundary(i) {
                    pos += 1;
                    continue 'outer;
                }
            }

            if pos + start_len <= trimmed.len() &&
               &trimmed[pos..pos + start_len] == multiline_start {
                pos += start_len;
                in_comment = true;
            } else if pos + end_len <= trimmed.len() && &trimmed[pos..pos + end_len] == multiline_end {
                pos += end_len;
                in_comment = false;
            } else if !in_comment {
                found_code = true;
                pos += 1;
            } else {
                pos += 1;
            }
        }

        if found_code {
            code += 1;
        } else {
            comments += 1;
        }
    }

    Count {
        code: code,
        comment: comments,
        blank: blanks,
        lines: lines,
    }
}
<commit_msg>add to_s for strings, delegate to it in Display<commit_after>pub mod lines;

#[macro_use]
extern crate nom;

extern crate regex;
extern crate memmap;
extern crate memchr;
extern crate ascii;

use std::path::Path;
use std::cmp;
use std::fmt;

use memmap::{Mmap, Protection};
use memchr::memchr;

// Why is it called partialEq?
#[derive(Debug, PartialEq, Default, Clone)]
pub struct Count {
    pub code: u32,
    pub comment: u32,
    pub blank: u32,
    pub lines: u32,
}

impl Count {
    pub fn merge(&mut self, o: &Count) {
        self.code += o.code;
        self.comment += o.comment;
        self.blank += o.blank;
        self.lines += o.lines;
    }
}

pub enum LineConfig<'a> {
    Multi {
        single_start: &'a str,
        multi_start: &'a str,
        multi_end: &'a str,
    },
    Single {
        single_start: &'a str,
    },
}

// Do any languages actually use utf8 chars as comment chars?
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, Clone)]
pub enum Lang {
    C,
    CCppHeader,
    Rust,
    Ruby,
    Haskell,
    Perl,
    BourneShell,
    Make,
    INI,
    Assembly,
    Yacc,
    Awk,
    Unrecognized,
}

impl Lang {
    pub fn to_s(&self) -> &str {
        match *self {
            Lang::C => "C",
            Lang::CCppHeader => "C/C++ Header",
            Lang::Rust => "Rust",
            Lang::Ruby => "Ruby",
            Lang::Haskell => "Haskell",
            Lang::Perl => "Perl",
            Lang::BourneShell => "Bourne Shell",
            Lang::Make => "Make",
            Lang::INI => "INI",
            Lang::Assembly => "Assembly",
            Lang::Yacc => "Yacc",
            Lang::Awk => "Awk",
            Lang::Unrecognized => "Unrecognized",
        }
    }
}

impl fmt::Display for Lang {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.pad(self.to_s())
    }
}

pub fn lang_from_ext(filepath: &str) -> Lang {
    let path = Path::new(filepath);
    let ext = match path.extension() {
        Some(os_str) => os_str.to_str().unwrap().to_lowercase(),
        None => path.file_name().unwrap().to_str().unwrap().to_lowercase(),
    };

    match &*ext {
        "c" => Lang::C,
        "h" | "hh" | "hpp" | "hxx" => Lang::CCppHeader,
        "rs" => Lang::Rust,
        "hs" => Lang::Haskell,
        "pl" => Lang::Perl,
        "rb" => Lang::Ruby,
        "makefile" | "mk" => Lang::Make,
        "ini" => Lang::INI,
        "s" | "asm" => Lang::Assembly,
        "y" => Lang::Yacc,
        "awk" => Lang::Awk,

        // TODO(cgag): What's the correct extension? Any? Pragma?
        "sh" => Lang::BourneShell,
        // Probably dumb to just default to C.
        _ => Lang::Unrecognized,
    }
}

pub fn counter_config_for_lang<'a>(lang: &Lang) -> LineConfig<'a> {
    enum CT<'a> {
        Single(&'a str),
        Multi(&'a str, &'a str, &'a str),
    }
    // use self::ConfigTuple::*;

    let c_style = CT::Multi("//", "/*", "*/");
    let sh_style = CT::Single("#");

    let ctuple = match *lang {
        Lang::Haskell => CT::Multi("--", "{-", "-}"),
        Lang::Perl => CT::Multi("#", "=pod", "=cut"),
        Lang::INI => CT::Single(";"),
        // TODO(cgag): Well, some architectures use ;, @, |, etc.
        // Need a way to specify more than one possible comment char.
        Lang::Assembly => CT::Multi("#", "/*", "*/"),
        Lang::BourneShell | Lang::Ruby | Lang::Make | Lang::Awk => sh_style,
        // TODO(cgag): not 100% that yacc belongs here.
        Lang::C | Lang::CCppHeader | Lang::Rust | Lang::Yacc => c_style,
        // Default to C style
        Lang::Unrecognized => c_style,
    };

    match ctuple {
        CT::Multi(single, start, end) => {
            LineConfig::Multi {
                single_start: single,
                multi_start: start,
                multi_end: end,
            }
        }
        CT::Single(single) => LineConfig::Single { single_start: single },
    }
}

struct AsciiLines<'a> {
    buf: &'a [u8],
    pos: usize,
}

struct Ascii<'a>(&'a [u8]);
impl<'a> Ascii<'a> {
    fn lines(&self) -> AsciiLines {
        AsciiLines {
            buf: self.0,
            pos: 0,
        }
    }
}

// Appears to work, now we just neeed
impl<'a> Iterator for AsciiLines<'a> {
    type Item = &'a [u8];

    fn next(&mut self) -> Option<&'a [u8]> {
        match memchr(b'\n', &self.buf[self.pos..self.buf.len()]) {
            Some(n) => {
                let start = self.pos;
                self.pos = self.pos + n + 1;
                // - 1 to drop \n char
                Some(&self.buf[start..(self.pos - 1)])
            }
            None => {
                if self.pos == self.buf.len() {
                    return None;
                }
                let start = self.pos;
                self.pos = self.buf.len();
                Some(&self.buf[start..self.pos])
            }
        }
    }
}

pub fn count(filepath: &str) -> Count {
    let lang = lang_from_ext(filepath);
    let config = counter_config_for_lang(&lang);
    match config {
        LineConfig::Single { single_start: single } => count_mmap_unsafe_single(filepath, single),
        LineConfig::Multi { single_start: single, multi_start, multi_end } => {
            count_mmap_unsafe_multi(filepath, single, multi_start, multi_end)
        }
    }
}

pub fn count_mmap_unsafe_single(filepath: &str, single_start: &str) -> Count {
    let fmmap = match Mmap::open_path(filepath, Protection::Read) {
        Ok(mmap) => mmap,
        Err(e) => {
            println!("mmap err for {}: {}", filepath, e);
            return Count::default();
        }
    };
    let bytes: &[u8] = unsafe { fmmap.as_slice() };

    let mut lines = 0;
    let mut code = 0;
    let mut comments = 0;
    let mut blanks = 0;

    let a = Ascii(bytes);
    for byte_line in a.lines() {
        let line = unsafe { std::str::from_utf8_unchecked(byte_line) };
        lines += 1;

        let trimmed = line.trim_left();
        if trimmed.is_empty() {
            blanks += 1;
        } else if trimmed.starts_with(single_start) {
            comments += 1;
        } else {
            code += 1;
        }
    }

    Count {
        code: code,
        comment: comments,
        blank: blanks,
        lines: lines,
    }
}

pub fn count_mmap_unsafe_multi(filepath: &str,
                               single_start: &str,
                               multi_start: &str,
                               multi_end: &str)
                               -> Count {

    let single_line_start = single_start;
    let multiline_start = multi_start;
    let multiline_end = multi_end;

    let fmmap = match Mmap::open_path(filepath, Protection::Read) {
        Ok(mmap) => mmap,
        Err(e) => {
            println!("mmap err for {}: {}", filepath, e);
            return Count::default();
        }
    };
    let bytes: &[u8] = unsafe { fmmap.as_slice() };

    let mut lines = 0;
    let mut code = 0;
    let mut comments = 0;
    let mut blanks = 0;

    let mut in_comment = false;

    let a = Ascii(bytes);
    for byte_line in a.lines() {
        let line = unsafe { std::str::from_utf8_unchecked(byte_line) };
        lines += 1;

        let trimmed = line.trim_left();
        if trimmed.is_empty() {
            blanks += 1;
            continue;
        };

        if !in_comment && trimmed.starts_with(single_line_start) {
            comments += 1;
            continue;
        }

        if !(trimmed.contains(multiline_start) || trimmed.contains(multiline_end)) {
            if in_comment {
                comments += 1;
            } else {
                code += 1;
            }
            continue;
        }

        let mut pos = 0;
        let mut found_code = false;

        let start_len = multiline_start.len();
        let end_len = multiline_end.len();

        'outer: while pos < trimmed.len() {
            // TODO(cgag): must be a less stupid way to do this
            for i in pos..(pos + cmp::max(start_len, end_len) + 1) {
                if !trimmed.is_char_boundary(i) {
                    pos += 1;
                    continue 'outer;
                }
            }

            if pos + start_len <= trimmed.len() &&
               &trimmed[pos..pos + start_len] == multiline_start {
                pos += start_len;
                in_comment = true;
            } else if pos + end_len <= trimmed.len() && &trimmed[pos..pos + end_len] == multiline_end {
                pos += end_len;
                in_comment = false;
            } else if !in_comment {
                found_code = true;
                pos += 1;
            } else {
                pos += 1;
            }
        }

        if found_code {
            code += 1;
        } else {
            comments += 1;
        }
    }

    Count {
        code: code,
        comment: comments,
        blank: blanks,
        lines: lines,
    }
}
<|endoftext|>


<commit_before>extern crate dns_lookup;
#[macro_use]
extern crate lazy_static;
extern crate params;
extern crate regex;

use params::{Map, Value};
use std::collections::BTreeMap;

mod validators {
    pub mod accepted;
    pub mod active_url;
    pub mod alpha;
    pub mod alpha_dash;
    pub mod alpha_numeric;
    pub mod array;
    pub mod between;
    pub mod boolean;
    pub mod confirmed;
    pub mod different;
    pub mod email;
    pub mod same;
}

#[derive(Debug,Clone)]
pub enum Rule {
    /// The field under validation must be `yes`, `on`, `1`, or `true`.
    /// This is useful for validating "Terms of Service" acceptance.
    ///
    /// On success, will transform the input to a boolean `true`.
    Accepted,
    /// The field under validation, if present, must be an active domain name.
    ActiveUrl,
    /// The field under validation must be entirely alphabetic characters.
    ///
    /// This validator accepts Latin and international (Unicode) input.
    Alpha,
    /// The field under validation may have alpha-numeric characters,
    /// as well as dashes and underscores.
    ///
    /// This validator accepts Latin and international (Unicode) input.
    AlphaDash,
    /// The field under validation must be entirely alpha-numeric characters.
    ///
    /// This validator accepts Latin and international (Unicode) input.
    AlphaNumeric,
    /// The field under validation, if present, must be an array.
    Array,
    /// The field under validation, if present, must have a size between the given min and max.
    /// Strings, numerics, and files are evaluated in the same fashion as the `Size` rule.
    Between(isize, isize),
    /// The field under validation, if present, must be able to be cast as a boolean.
    /// Accepted input are `true`, `false`, `1`, `0`, `"1"`, and `"0"`.
    ///
    /// On success, will transform the input to a boolean `true` or `false`.
    Boolean,
    /// The field under validation must have a matching field of `foo_confirmation`.
    /// For example, if the field under validation is `password`,
    /// a matching `password_confirmation` field must be present in the input.
    Confirmed,
    /// The field under validation must have a different value than `field`.
    Different(String),
    /// The field under validation, if present,
    /// must be numeric and must have an exact length of value.
    Digits(usize),
    /// The field under validation, if present, must have a length between the given min and max.
    DigitsBetween(usize, usize),
    /// When working with arrays, the field under validation must not have any duplicate values
    /// if it is present.
    Distinct,
    /// The field under validation, if present, must be formatted as an e-mail address.
    Email,
    /// The field under validation must not be empty when it is present.
    Filled,
    /// The field under validation, if present, must be included in the given list of values.
    In(Vec<Value>),
    /// The field under validation, if present, must exist in `anotherfield`'s values.
    InArray(String),
    /// The field under validation, if present, must be an integer.
    Integer,
    /// The field under validation, if present, must be an IP address.
    IpAddress,
    /// The field under validation, if present, must be a valid JSON string.
    Json,
    /// The field under validation, if present, must be less than or equal to a maximum value.
    /// Strings, numerics, and files are evaluated in the same fashion as the `Size` rule.
    Max(isize),
    /// The field under validation, if present, must have a minimum value.
    /// Strings, numerics, and files are evaluated in the same fashion as the `Size` rule.
    Min(isize),
    /// The field under validation must not be included in the given list of values.
    NotIn(Vec<Value>),
    /// The field under validation must not exist in `anotherfield`'s values.
    NotInArray(String),
    /// The field under validation, if present, must be numeric.
    Numeric,
    /// The field under validation must be present in the input data but can be empty.
    Present,
    /// The field under validation, if present, must match the given regular expression.
    Regex(String),
    /// The field under validation must be present in the input data and not empty.
    /// A field is considered "empty" if one of the following conditions are true:
    ///
    /// The value is null.
    ///
    /// The value is an empty string.
    ///
    /// The value is an empty array or empty object.
    Required,
    /// The field under validation must be present if the `anotherfield` field
    /// is equal to any `value`.
    RequiredIf(String, Value),
    /// The field under validation must be present unless the `anotherfield` field
    /// is equal to any `value`.
    RequiredUnless(String, Value),
    /// The field under validation must be present only if
    /// any of the other specified fields are present.
    RequiredWith(Vec<String>),
    /// The field under validation must be present only if
    /// all of the other specified fields are present.
    RequiredWithAll(Vec<String>),
    /// The field under validation must be present only when
    /// any of the other specified fields are not present.
    RequiredWithout(Vec<String>),
    /// The field under validation must be present only when
    /// all of the other specified fields are not present.
    RequiredWithoutAll(Vec<String>),
    /// The given field must match the field under validation.
    Same(String),
    /// The field under validation must have a size matching the given value.
    ///
    /// For string data, value corresponds to the number of characters.
    ///
    /// For numeric data, value corresponds to a given integer value.
    ///
    /// For files, size corresponds to the file size in kilobytes.
    Size(isize),
    /// The field under validation, if present, must be a string.
    String,
    /// The field under validation, if present, must be formatted as a valid URL,
    /// but does not need to resolve to a real website.
    Url,
}

pub fn validate(rules: BTreeMap<&str, Vec<Rule>>,
                values: Map)
                -> Result<Map, BTreeMap<&str, Vec<String>>> {
    let mut new_values = values;
    let mut errors = BTreeMap::new();

    for (field, ruleset) in &rules {
        let mut current_errors = Vec::new();
        for rule in ruleset {
            let result = match *rule {
                Rule::Accepted => validators::accepted::validate_accepted(&new_values, field),
                Rule::ActiveUrl => validators::active_url::validate_active_url(&new_values, field),
                Rule::Alpha => validators::alpha::validate_alpha(&new_values, field),
                Rule::AlphaDash => validators::alpha_dash::validate_alpha_dash(&new_values, field),
                Rule::AlphaNumeric => {
                    validators::alpha_numeric::validate_alpha_numeric(&new_values, field)
                }
                Rule::Array => validators::array::validate_array(&new_values, field),
                Rule::Between(min, max) => {
                    validators::between::validate_between(&new_values, field, min, max)
                }
                Rule::Boolean => validators::boolean::validate_boolean(&new_values, field),
                Rule::Confirmed => validators::confirmed::validate_confirmed(&new_values, field),
                Rule::Different(ref other) => {
                    validators::different::validate_different(&new_values, field, other)
                }
                Rule::Email => validators::email::validate_email(&new_values, field),
                Rule::Same(ref other) => validators::same::validate_same(&new_values, field, other),
                _ => {
                    panic!(format!("Unrecognized validation rule {:?} for field {:?}",
                                   rule,
                                   field));
                }
            };
            match result {
                Ok(Some(res)) => {
                    new_values.assign(field, res).ok();
                }
                Ok(None) => (),
                Err(err) => {
                    current_errors.push(err);
                }
            };
        }
        if !current_errors.is_empty() {
            errors.insert(*field, current_errors);
        }
    }

    if errors.is_empty() {
        Ok(new_values)
    } else {
        Err(errors)
    }
}
<commit_msg>Update descriptions<commit_after>extern crate dns_lookup;
#[macro_use]
extern crate lazy_static;
extern crate params;
extern crate regex;

use params::{Map, Value};
use std::collections::BTreeMap;

mod validators {
    pub mod accepted;
    pub mod active_url;
    pub mod alpha;
    pub mod alpha_dash;
    pub mod alpha_numeric;
    pub mod array;
    pub mod between;
    pub mod boolean;
    pub mod confirmed;
    pub mod different;
    pub mod email;
    pub mod same;
}

#[derive(Debug,Clone)]
pub enum Rule {
    /// The field under validation must be `yes`, `on`, `1`, or `true`.
    /// This is useful for validating "Terms of Service" acceptance.
    ///
    /// On success, will transform the input to a boolean `true`.
    Accepted,
    /// The field under validation, if present, must be an active domain name.
    ActiveUrl,
    /// The field under validation must be entirely alphabetic characters.
    ///
    /// This validator accepts Latin and international (Unicode) input.
    Alpha,
    /// The field under validation may have alpha-numeric characters,
    /// as well as dashes and underscores.
    ///
    /// This validator accepts Latin and international (Unicode) input.
    AlphaDash,
    /// The field under validation must be entirely alpha-numeric characters.
    ///
    /// This validator accepts Latin and international (Unicode) input.
    AlphaNumeric,
    /// The field under validation, if present, must be an array.
    Array,
    /// The field under validation, if present, must have a size between the given min and max.
    /// Strings, numerics, and files are evaluated in the same fashion as the `Size` rule.
    Between(isize, isize),
    /// The field under validation, if present, must be able to be cast as a boolean.
    /// Accepted input are `true`, `false`, `1`, `0`, `"1"`, and `"0"`.
    ///
    /// On success, will transform the input to a boolean `true` or `false`.
    Boolean,
    /// The field under validation must have a matching field of `foo_confirmation`.
    /// For example, if the field under validation is `password`,
    /// a matching `password_confirmation` field must be present in the input.
    Confirmed,
    /// The field under validation must have a different value than `field`.
    Different(String),
    /// The field under validation, if present,
    /// must be numeric and must have an exact length of value.
    ///
    /// On success, will transform positive string input to U64 and
    /// negative string input to I64.
    Digits(usize),
    /// The field under validation, if present, must have a length between the given min and max.
    ///
    /// On success, will transform positive string input to U64 and
    /// negative string input to I64.
    DigitsBetween(usize, usize),
    /// When working with arrays, the field under validation must not have any duplicate values
    /// if it is present.
    Distinct,
    /// The field under validation, if present, must be formatted as an e-mail address.
    Email,
    /// The field under validation must not be empty when it is present.
    Filled,
    /// The field under validation, if present, must be included in the given list of values.
    In(Vec<Value>),
    /// The field under validation, if present, must exist in `anotherfield`'s values.
    InArray(String),
    /// The field under validation, if present, must be an integer.
    ///
    /// On success, will transform positive string input to U64 and
    /// negative string input to I64.
    Integer,
    /// The field under validation, if present, must be an IP address.
    IpAddress,
    /// The field under validation, if present, must be a valid JSON string.
    Json,
    /// The field under validation, if present, must be less than or equal to a maximum value.
    /// Strings, numerics, and files are evaluated in the same fashion as the `Size` rule.
    Max(isize),
    /// The field under validation, if present, must have a minimum value.
    /// Strings, numerics, and files are evaluated in the same fashion as the `Size` rule.
    Min(isize),
    /// The field under validation must not be included in the given list of values.
    NotIn(Vec<Value>),
    /// The field under validation must not exist in `anotherfield`'s values.
    NotInArray(String),
    /// The field under validation, if present, must be numeric.
    ///
    /// On success, will transform positive string input to U64 and
    /// negative string input to I64.
    Numeric,
    /// The field under validation must be present in the input data but can be empty.
    Present,
    /// The field under validation, if present, must match the given regular expression.
    Regex(String),
    /// The field under validation must be present in the input data and not empty.
    /// A field is considered "empty" if one of the following conditions are true:
    ///
    /// The value is null.
    ///
    /// The value is an empty string.
    ///
    /// The value is an empty array or empty object.
    Required,
    /// The field under validation must be present if the `anotherfield` field
    /// is equal to any `value`.
    RequiredIf(String, Value),
    /// The field under validation must be present unless the `anotherfield` field
    /// is equal to any `value`.
    RequiredUnless(String, Value),
    /// The field under validation must be present only if
    /// any of the other specified fields are present.
    RequiredWith(Vec<String>),
    /// The field under validation must be present only if
    /// all of the other specified fields are present.
    RequiredWithAll(Vec<String>),
    /// The field under validation must be present only when
    /// any of the other specified fields are not present.
    RequiredWithout(Vec<String>),
    /// The field under validation must be present only when
    /// all of the other specified fields are not present.
    RequiredWithoutAll(Vec<String>),
    /// The given field must match the field under validation.
    Same(String),
    /// The field under validation must have a size matching the given value.
    ///
    /// For string data, value corresponds to the number of characters.
    ///
    /// For numeric data, value corresponds to a given integer value.
    ///
    /// For files, size corresponds to the file size in kilobytes.
    Size(isize),
    /// The field under validation, if present, must be a string.
    String,
    /// The field under validation, if present, must be formatted as a valid URL,
    /// but does not need to resolve to a real website.
    Url,
}

pub fn validate(rules: BTreeMap<&str, Vec<Rule>>,
                values: Map)
                -> Result<Map, BTreeMap<&str, Vec<String>>> {
    let mut new_values = values;
    let mut errors = BTreeMap::new();

    for (field, ruleset) in &rules {
        let mut current_errors = Vec::new();
        for rule in ruleset {
            let result = match *rule {
                Rule::Accepted => validators::accepted::validate_accepted(&new_values, field),
                Rule::ActiveUrl => validators::active_url::validate_active_url(&new_values, field),
                Rule::Alpha => validators::alpha::validate_alpha(&new_values, field),
                Rule::AlphaDash => validators::alpha_dash::validate_alpha_dash(&new_values, field),
                Rule::AlphaNumeric => {
                    validators::alpha_numeric::validate_alpha_numeric(&new_values, field)
                }
                Rule::Array => validators::array::validate_array(&new_values, field),
                Rule::Between(min, max) => {
                    validators::between::validate_between(&new_values, field, min, max)
                }
                Rule::Boolean => validators::boolean::validate_boolean(&new_values, field),
                Rule::Confirmed => validators::confirmed::validate_confirmed(&new_values, field),
                Rule::Different(ref other) => {
                    validators::different::validate_different(&new_values, field, other)
                }
                Rule::Email => validators::email::validate_email(&new_values, field),
                Rule::Same(ref other) => validators::same::validate_same(&new_values, field, other),
                _ => {
                    panic!(format!("Unrecognized validation rule {:?} for field {:?}",
                                   rule,
                                   field));
                }
            };
            match result {
                Ok(Some(res)) => {
                    new_values.assign(field, res).ok();
                }
                Ok(None) => (),
                Err(err) => {
                    current_errors.push(err);
                }
            };
        }
        if !current_errors.is_empty() {
            errors.insert(*field, current_errors);
        }
    }

    if errors.is_empty() {
        Ok(new_values)
    } else {
        Err(errors)
    }
}
<|endoftext|>