<commit_before>use ::cssparser;
use ::libc;

use ::glib::translate::*;

use parsers::ParseError;
use error::*;

// There are two quirks here:
//
// First, we need to expose the Color algebraic type *and* a parse
// error to C, but we can't repr(C) them plainly.  So, we define a
// ColorKind enum and a ColorSpec struct that can both be represented
// in C.
//
// Second, the C code in librsvg expects ARGB colors passed around as
// guint32.  However, in Rust we'd prefer to use cssparser's RGBA
// structure, which has explicit fields for red/green/blue/alpha.
// We'll do those conversions here, for the benefit of the C code, and
// then just wait until the C code gradually disappears.

// Keep this in sync with rsvg-css.h:RsvgCssColorKind
#[repr(C)]
#[derive(Clone, Copy, PartialEq, Debug)]
pub enum ColorKind {
    Inherit,
    CurrentColor,
    ARGB,
    ParseError
}

// Keep this in sync with rsvg-css.h:RsvgCssColorSpec
#[repr(C)]
#[derive(Clone, Copy, PartialEq, Debug)]
pub struct ColorSpec {
    kind: ColorKind,
    argb: u32
}

// Keep in sync with rsvg-css.h:AllowInherit
#[repr(C)]
#[derive(PartialEq, Debug)]
pub enum AllowInherit {
    No,
    Yes
}

// Keep in sync with rsvg-css.h:AllowCurrentColor
#[repr(C)]
#[derive(PartialEq, Debug)]
pub enum AllowCurrentColor {
    No,
    Yes
}

// This is the Rust version of the above
#[derive(Clone, Copy, PartialEq, Debug)]
pub enum Color {
    Inherit,
    CurrentColor,
    RGBA (cssparser::RGBA)
}

impl Color {
    pub fn parse (s: &str, allow_inherit: AllowInherit, allow_current_color: AllowCurrentColor) -> Result<Color, AttributeError> {
        if s == "inherit" {
            if allow_inherit == AllowInherit::Yes {
                Ok (Color::Inherit)
            } else {
                Err (AttributeError::Value ("inherit is not allowed here".to_string ()))
            }
        } else {
            match cssparser::Color::parse (&mut cssparser::Parser::new (s)) {
                Ok (cssparser::Color::CurrentColor) => {
                    if allow_current_color == AllowCurrentColor::Yes {
                        Ok (Color::CurrentColor)
                    } else {
                        Err (AttributeError::Value ("currentColor is not allowed here".to_string ()))
                    }
                },

                Ok (csscolor) => Ok (Color::from (csscolor)),

                _ => Err (AttributeError::Parse (ParseError::new ("invalid syntax for color")))
            }
        }
    }
}

impl From<cssparser::Color> for Color {
    fn from (c: cssparser::Color) -> Color {
        match c {
            cssparser::Color::CurrentColor => Color::CurrentColor,
            cssparser::Color::RGBA (rgba) => Color::RGBA (rgba)
        }
    }
}

impl From<Result<Color, AttributeError>> for ColorSpec {
    fn from (result: Result<Color, AttributeError>) -> ColorSpec {
        match result {
            Ok (Color::Inherit) =>
                ColorSpec {
                    kind: ColorKind::Inherit,
                    argb: 0
                },

            Ok (Color::CurrentColor) =>
                ColorSpec {
                    kind: ColorKind::CurrentColor,
                    argb: 0
                },

            Ok (Color::RGBA (rgba)) =>
                ColorSpec {
                    kind: ColorKind::ARGB,
                    argb: ((rgba.alpha as u32) << 24 |
                           (rgba.red as u32)   << 16 |
                           (rgba.green as u32) << 8  |
                           (rgba.blue as u32))
                },

            _ =>
                ColorSpec {
                    kind: ColorKind::ParseError,
                    argb: 0
                }
        }
    }
}

#[no_mangle]
pub extern fn rsvg_css_parse_color (string: *const libc::c_char,
                                    allow_inherit: AllowInherit,
                                    allow_current_color: AllowCurrentColor) -> ColorSpec {
    let s = unsafe { String::from_glib_none (string) };

    ColorSpec::from (Color::parse (&s, allow_inherit, allow_current_color))
}

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

    fn parse (s: &str) -> ColorSpec {
        // ColorSpec::from (Color::parse (s, AllowInherit::Yes, AllowCurrentColor::Yes))
        rsvg_css_parse_color (s.to_glib_none ().0, AllowInherit::Yes, AllowCurrentColor::Yes)
    }

    #[test]
    fn parses_hash_hex_colors () {
        assert_eq! (parse ("#AB10fa20"), ColorSpec { kind: ColorKind::ARGB, argb: 0x20ab10fa });
        assert_eq! (parse ("#10fa20"),   ColorSpec { kind: ColorKind::ARGB, argb: 0xff10fa20 });
        assert_eq! (parse ("#abcd"),     ColorSpec { kind: ColorKind::ARGB, argb: 0xddaabbcc });
        assert_eq! (parse ("#123"),      ColorSpec { kind: ColorKind::ARGB, argb: 0xff112233 });
    }

    #[test]
    fn parses_color_keywords () {
        assert_eq! (parse ("red"),  ColorSpec { kind: ColorKind::ARGB, argb: 0xffff0000 });
        assert_eq! (parse ("lime"), ColorSpec { kind: ColorKind::ARGB, argb: 0xff00ff00 });
        assert_eq! (parse ("blue"), ColorSpec { kind: ColorKind::ARGB, argb: 0xff0000ff });
    }

    #[test]
    fn parses_color_functions () {
        assert_eq! (parse ("rgb(255, 0, 0)"), ColorSpec { kind: ColorKind::ARGB, argb: 0xffff0000 });
        assert_eq! (parse ("rgb(0, 255, 0)"), ColorSpec { kind: ColorKind::ARGB, argb: 0xff00ff00 });
        assert_eq! (parse ("rgb(0, 0, 255)"), ColorSpec { kind: ColorKind::ARGB, argb: 0xff0000ff });
    }

    #[test]
    fn parses_current_color () {
        assert_eq! (parse ("currentColor"), ColorSpec { kind: ColorKind::CurrentColor, argb: 0 });
    }

    fn make_error () -> ColorSpec {
        ColorSpec {
            kind: ColorKind::ParseError,
            argb: 0
        }
    }

    #[test]
    fn invalid_hash_hex_colors_yield_error () {
        assert_eq! (parse ("#"), make_error ());
        assert_eq! (parse ("#xyz"), make_error ());
        assert_eq! (parse ("#112233gg"), make_error ());
    }

    #[test]
    fn invalid_colors_yield_error () {
        assert_eq! (parse (""), make_error ());
        assert_eq! (parse ("foo"), make_error ());
        assert_eq! (parse ("rgb(chilaquil)"), make_error ());
        assert_eq! (parse ("rgb(1, 2, 3, 4, 5)"), make_error ());
    }

    #[test]
    fn yields_error_on_disallowed_current_color () {
        assert_eq! (ColorSpec::from (Color::parse ("currentColor", AllowInherit::Yes, AllowCurrentColor::No)),
                    make_error ());
    }

    #[test]
    fn yields_error_on_disallowed_inherit () {
        assert_eq! (ColorSpec::from (Color::parse ("inherit", AllowInherit::No, AllowCurrentColor::Yes)),
                    make_error ());
    }
}
<commit_msg>Color::from_color_spec() - Turn a ColorSpec from C back into a Result<Color><commit_after>use ::cssparser;
use ::libc;

use ::glib::translate::*;

use parsers::ParseError;
use error::*;

// There are two quirks here:
//
// First, we need to expose the Color algebraic type *and* a parse
// error to C, but we can't repr(C) them plainly.  So, we define a
// ColorKind enum and a ColorSpec struct that can both be represented
// in C.
//
// Second, the C code in librsvg expects ARGB colors passed around as
// guint32.  However, in Rust we'd prefer to use cssparser's RGBA
// structure, which has explicit fields for red/green/blue/alpha.
// We'll do those conversions here, for the benefit of the C code, and
// then just wait until the C code gradually disappears.

// Keep this in sync with rsvg-css.h:RsvgCssColorKind
#[repr(C)]
#[derive(Clone, Copy, PartialEq, Debug)]
pub enum ColorKind {
    Inherit,
    CurrentColor,
    ARGB,
    ParseError
}

// Keep this in sync with rsvg-css.h:RsvgCssColorSpec
#[repr(C)]
#[derive(Clone, Copy, PartialEq, Debug)]
pub struct ColorSpec {
    kind: ColorKind,
    argb: u32
}

// Keep in sync with rsvg-css.h:AllowInherit
#[repr(C)]
#[derive(PartialEq, Debug)]
pub enum AllowInherit {
    No,
    Yes
}

// Keep in sync with rsvg-css.h:AllowCurrentColor
#[repr(C)]
#[derive(PartialEq, Debug)]
pub enum AllowCurrentColor {
    No,
    Yes
}

// This is the Rust version of the above
#[derive(Clone, Copy, PartialEq, Debug)]
pub enum Color {
    Inherit,
    CurrentColor,
    RGBA (cssparser::RGBA)
}

impl Color {
    pub fn parse (s: &str, allow_inherit: AllowInherit, allow_current_color: AllowCurrentColor) -> Result<Color, AttributeError> {
        if s == "inherit" {
            if allow_inherit == AllowInherit::Yes {
                Ok (Color::Inherit)
            } else {
                Err (AttributeError::Value ("inherit is not allowed here".to_string ()))
            }
        } else {
            match cssparser::Color::parse (&mut cssparser::Parser::new (s)) {
                Ok (cssparser::Color::CurrentColor) => {
                    if allow_current_color == AllowCurrentColor::Yes {
                        Ok (Color::CurrentColor)
                    } else {
                        Err (AttributeError::Value ("currentColor is not allowed here".to_string ()))
                    }
                },

                Ok (csscolor) => Ok (Color::from (csscolor)),

                _ => Err (AttributeError::Parse (ParseError::new ("invalid syntax for color")))
            }
        }
    }

    pub fn from_color_spec (spec: &ColorSpec) -> Result <Color, AttributeError> {
        match *spec {
            ColorSpec { kind: ColorKind::Inherit, .. }      => Ok (Color::Inherit),

            ColorSpec { kind: ColorKind::CurrentColor, .. } => Ok (Color::CurrentColor),

            ColorSpec { kind: ColorKind::ARGB, argb } => Ok (Color::RGBA (rgba_from_argb (argb))),

            ColorSpec { kind: ColorKind::ParseError, .. } => Err (AttributeError::Parse (ParseError::new ("parse error")))
        }
    }
}

fn rgba_from_argb (argb: u32) -> cssparser::RGBA {
    cssparser::RGBA::new (((argb & 0x00ff0000) >> 16) as u8,
                          ((argb & 0x0000ff00) >> 8) as u8,
                          ((argb & 0x000000ff) as u8),
                          ((argb & 0xff000000) >> 24) as u8)
}

impl From<cssparser::Color> for Color {
    fn from (c: cssparser::Color) -> Color {
        match c {
            cssparser::Color::CurrentColor => Color::CurrentColor,
            cssparser::Color::RGBA (rgba) => Color::RGBA (rgba)
        }
    }
}

impl From<Result<Color, AttributeError>> for ColorSpec {
    fn from (result: Result<Color, AttributeError>) -> ColorSpec {
        match result {
            Ok (Color::Inherit) =>
                ColorSpec {
                    kind: ColorKind::Inherit,
                    argb: 0
                },

            Ok (Color::CurrentColor) =>
                ColorSpec {
                    kind: ColorKind::CurrentColor,
                    argb: 0
                },

            Ok (Color::RGBA (rgba)) =>
                ColorSpec {
                    kind: ColorKind::ARGB,
                    argb: ((rgba.alpha as u32) << 24 |
                           (rgba.red as u32)   << 16 |
                           (rgba.green as u32) << 8  |
                           (rgba.blue as u32))
                },

            _ =>
                ColorSpec {
                    kind: ColorKind::ParseError,
                    argb: 0
                }
        }
    }
}

#[no_mangle]
pub extern fn rsvg_css_parse_color (string: *const libc::c_char,
                                    allow_inherit: AllowInherit,
                                    allow_current_color: AllowCurrentColor) -> ColorSpec {
    let s = unsafe { String::from_glib_none (string) };

    ColorSpec::from (Color::parse (&s, allow_inherit, allow_current_color))
}

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

    fn parse (s: &str) -> ColorSpec {
        // ColorSpec::from (Color::parse (s, AllowInherit::Yes, AllowCurrentColor::Yes))
        rsvg_css_parse_color (s.to_glib_none ().0, AllowInherit::Yes, AllowCurrentColor::Yes)
    }

    #[test]
    fn parses_hash_hex_colors () {
        assert_eq! (parse ("#AB10fa20"), ColorSpec { kind: ColorKind::ARGB, argb: 0x20ab10fa });
        assert_eq! (parse ("#10fa20"),   ColorSpec { kind: ColorKind::ARGB, argb: 0xff10fa20 });
        assert_eq! (parse ("#abcd"),     ColorSpec { kind: ColorKind::ARGB, argb: 0xddaabbcc });
        assert_eq! (parse ("#123"),      ColorSpec { kind: ColorKind::ARGB, argb: 0xff112233 });
    }

    #[test]
    fn parses_color_keywords () {
        assert_eq! (parse ("red"),  ColorSpec { kind: ColorKind::ARGB, argb: 0xffff0000 });
        assert_eq! (parse ("lime"), ColorSpec { kind: ColorKind::ARGB, argb: 0xff00ff00 });
        assert_eq! (parse ("blue"), ColorSpec { kind: ColorKind::ARGB, argb: 0xff0000ff });
    }

    #[test]
    fn parses_color_functions () {
        assert_eq! (parse ("rgb(255, 0, 0)"), ColorSpec { kind: ColorKind::ARGB, argb: 0xffff0000 });
        assert_eq! (parse ("rgb(0, 255, 0)"), ColorSpec { kind: ColorKind::ARGB, argb: 0xff00ff00 });
        assert_eq! (parse ("rgb(0, 0, 255)"), ColorSpec { kind: ColorKind::ARGB, argb: 0xff0000ff });
    }

    #[test]
    fn parses_current_color () {
        assert_eq! (parse ("currentColor"), ColorSpec { kind: ColorKind::CurrentColor, argb: 0 });
    }

    fn make_error () -> ColorSpec {
        ColorSpec {
            kind: ColorKind::ParseError,
            argb: 0
        }
    }

    #[test]
    fn invalid_hash_hex_colors_yield_error () {
        assert_eq! (parse ("#"), make_error ());
        assert_eq! (parse ("#xyz"), make_error ());
        assert_eq! (parse ("#112233gg"), make_error ());
    }

    #[test]
    fn invalid_colors_yield_error () {
        assert_eq! (parse (""), make_error ());
        assert_eq! (parse ("foo"), make_error ());
        assert_eq! (parse ("rgb(chilaquil)"), make_error ());
        assert_eq! (parse ("rgb(1, 2, 3, 4, 5)"), make_error ());
    }

    #[test]
    fn yields_error_on_disallowed_current_color () {
        assert_eq! (ColorSpec::from (Color::parse ("currentColor", AllowInherit::Yes, AllowCurrentColor::No)),
                    make_error ());
    }

    #[test]
    fn yields_error_on_disallowed_inherit () {
        assert_eq! (ColorSpec::from (Color::parse ("inherit", AllowInherit::No, AllowCurrentColor::Yes)),
                    make_error ());
    }

    fn test_roundtrip (s: &str) {
        let result = Color::parse (s, AllowInherit::Yes, AllowCurrentColor::Yes);
        let result2 = result.clone ();
        let spec = ColorSpec::from (result2);

        if result.is_ok () {
            assert_eq! (Color::from_color_spec (&spec), result);
        } else {
            assert! (Color::from_color_spec (&spec).is_err ());
        }
    }

    #[test]
    fn roundtrips () {
        test_roundtrip ("inherit");
        test_roundtrip ("currentColor");
        test_roundtrip ("#aabbccdd");
        test_roundtrip ("papadzul");
    }
}
<|endoftext|>


<commit_before>// extern crate bindgen;
#[cfg(target_env = "msvc")]
extern crate cc;
extern crate pkg_config;
extern crate num_cpus;

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

// Automatically write bindings to libsass
//#[allow(dead_code)]
//fn write_bindings() {
//    let bindings = bindgen::Builder::default()
//        .header("libsass/include/sass.h")
//        .clang_arg("-Ilibsass/include")
//        // To avoid a test failing
//        .blacklist_type("max_align_t")
//        // we do static linking so it should be fine
//        // https://github.com/rust-lang/rust/issues/36927
//        .rustified_enum(".*")
//        .generate()
//        .expect("Unable to generate bindings");
//
//    // Write the bindings to the $OUT_DIR/bindings.rs file.
//    let out_path = PathBuf::from("src");
//    bindings
//        .write_to_file(out_path.join("bindings.rs"))
//        .expect("Couldn't write bindings!");
//}

macro_rules! t {
    ($e:expr) => (match $e {
        Ok(n) => n,
        Err(e) => panic!("\n{} failed with {}\n", stringify!($e), e),
    })
}

fn cp_r(dir: &Path, dest: &Path) {
    for entry in t!(fs::read_dir(dir)) {
        let entry = t!(entry);
        let path = entry.path();
        let dst = dest.join(path.file_name().unwrap());
        if t!(fs::metadata(&path)).is_file() {
            t!(fs::copy(path, dst));
        } else {
            t!(fs::create_dir_all(&dst));
            cp_r(&path, &dst);
        }
    }
}

fn get_libsass_folder() -> PathBuf {
    env::current_dir().unwrap().join("libsass")
}

// linux/unix
#[cfg(not(target_env = "msvc"))]
fn compile() {
    let target = env::var("TARGET").expect("TARGET not found");
    let src = get_libsass_folder();
    let dest = PathBuf::from(env::var_os("OUT_DIR").unwrap());
    let build = dest.join("build");
    t!(fs::create_dir_all(&build));
    cp_r(&src, &build);
    let is_bsd = target.contains("dragonfly")
        || target.contains("freebsd")
        || target.contains("netbsd")
        || target.contains("openbsd");
    let libprobe = | lib: &str | -> bool {
        Command::new("ld")
            .arg("-o/dev/null")
            .arg(format!("-l{}",lib))
            .stderr(Stdio::null())
            .status()
            .expect("linker not found")
            .success()
    };

    let jobs = env::var("MAKE_LIBSASS_JOBS").unwrap_or(num_cpus::get().to_string());
    let r = Command::new(if is_bsd { "gmake" } else { "make" })
        .current_dir(&build)
        .args(&["--jobs", &jobs])
        .output()
        .expect("error running make");

    if !r.status.success() {
        let err = String::from_utf8_lossy(&r.stderr);
        let out = String::from_utf8_lossy(&r.stdout);
        panic!("Build error:\nSTDERR:{}\nSTDOUT:{}", err, out);
    }

    println!(
        "cargo:rustc-link-search=native={}",
        build.join("lib").display()
    );
    println!("cargo:rustc-link-lib=static=sass");

    if libprobe("c++_shared") {
        println!("cargo:rustc-link-lib=dylib=c++_shared");
    }
    else if libprobe("c++") {
        println!("cargo:rustc-link-lib=dylib=c++");
    }
    else if libprobe("stdc++") {
        println!("cargo:rustc-link-lib=dylib=libc++");
    }
    else {
        panic!("no c++ library found");
    }

}

// windows
#[cfg(target_env = "msvc")]
fn compile() {
    let src = get_libsass_folder();
    let target = env::var("TARGET").expect("TARGET not found in environment");
    let msvc_platform = if target.contains("x86_64") {
        "Win64"
    } else {
        "Win32"
    };
    let dest = PathBuf::from(env::var_os("OUT_DIR").unwrap());
    let build = dest.join("build");
    t!(fs::create_dir_all(&build));
    cp_r(&src, &build);

    // Find an instance of devenv.exe from Visual Studio IDE in order to upgrade
    // libsass.sln to the current available IDE. Do nothing if no devenv.exe found
    let d = cc::windows_registry::find(target.as_str(), "devenv.exe");
    if let Some(mut d) = d {
        let d = d
            .args(&["/upgrade", "win\\libsass.sln"])
            .current_dir(&build)
            .output()
            .expect("error running devenv");
        if !d.status.success() {
            let err = String::from_utf8_lossy(&d.stderr);
            let out = String::from_utf8_lossy(&d.stdout);
            println!("Upgrade error:\nSTDERR:{}\nSTDOUT:{}", err, out);
        }
    }

    let r = cc::windows_registry::find(target.as_str(), "msbuild.exe")
        .expect("could not find msbuild")
        .args(&[
            "win\\libsass.sln",
            "/p:LIBSASS_STATIC_LIB=1",
            "/p:Configuration=Release",
            "/p:WholeProgramOptimization=false",
            format!("/p:Platform={}", msvc_platform).as_str(),
        ])
        .current_dir(&build)
        .output()
        .expect("error running msbuild");

    if !r.status.success() {
        let err = String::from_utf8_lossy(&r.stderr);
        let out = String::from_utf8_lossy(&r.stdout);
        panic!("Build error:\nSTDERR:{}\nSTDOUT:{}", err, out);
    }

    println!(
        "cargo:rustc-link-search=native={}",
        build.join("win").join("bin").display()
    );
    println!("cargo:rustc-link-lib=static=libsass");
}

fn main() {
    // Uncomment the line below to generate bindings. Doesn't work on CI as it
    // requires additional tooling
    // write_bindings();

    // Is it already built?
    if let Ok(_) = pkg_config::find_library("libsass") {
        return;
    }

    compile();
}
<commit_msg>changed from ld to gcc<commit_after>// extern crate bindgen;
#[cfg(target_env = "msvc")]
extern crate cc;
extern crate pkg_config;
extern crate num_cpus;

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

// Automatically write bindings to libsass
//#[allow(dead_code)]
//fn write_bindings() {
//    let bindings = bindgen::Builder::default()
//        .header("libsass/include/sass.h")
//        .clang_arg("-Ilibsass/include")
//        // To avoid a test failing
//        .blacklist_type("max_align_t")
//        // we do static linking so it should be fine
//        // https://github.com/rust-lang/rust/issues/36927
//        .rustified_enum(".*")
//        .generate()
//        .expect("Unable to generate bindings");
//
//    // Write the bindings to the $OUT_DIR/bindings.rs file.
//    let out_path = PathBuf::from("src");
//    bindings
//        .write_to_file(out_path.join("bindings.rs"))
//        .expect("Couldn't write bindings!");
//}

macro_rules! t {
    ($e:expr) => (match $e {
        Ok(n) => n,
        Err(e) => panic!("\n{} failed with {}\n", stringify!($e), e),
    })
}

fn cp_r(dir: &Path, dest: &Path) {
    for entry in t!(fs::read_dir(dir)) {
        let entry = t!(entry);
        let path = entry.path();
        let dst = dest.join(path.file_name().unwrap());
        if t!(fs::metadata(&path)).is_file() {
            t!(fs::copy(path, dst));
        } else {
            t!(fs::create_dir_all(&dst));
            cp_r(&path, &dst);
        }
    }
}

fn get_libsass_folder() -> PathBuf {
    env::current_dir().unwrap().join("libsass")
}

// linux/unix
#[cfg(not(target_env = "msvc"))]
fn compile() {
    let target = env::var("TARGET").expect("TARGET not found");
    let src = get_libsass_folder();
    let dest = PathBuf::from(env::var_os("OUT_DIR").unwrap());
    let build = dest.join("build");
    t!(fs::create_dir_all(&build));
    cp_r(&src, &build);
    let is_bsd = target.contains("dragonfly")
        || target.contains("freebsd")
        || target.contains("netbsd")
        || target.contains("openbsd");
    let libprobe = | lib: &str | -> bool {
      Command::new("gcc")
        .arg("-xc++")
        .arg("-o/dev/null")
        .arg(format!("-l{}",lib))
        .arg("-shared")
        .stderr(Stdio::null())
        .status()
        .expect("")
        .success()
    };

    let jobs = env::var("MAKE_LIBSASS_JOBS").unwrap_or(num_cpus::get().to_string());
    let r = Command::new(if is_bsd { "gmake" } else { "make" })
        .current_dir(&build)
        .args(&["--jobs", &jobs])
        .output()
        .expect("error running make");

    if !r.status.success() {
        let err = String::from_utf8_lossy(&r.stderr);
        let out = String::from_utf8_lossy(&r.stdout);
        panic!("Build error:\nSTDERR:{}\nSTDOUT:{}", err, out);
    }

    println!(
        "cargo:rustc-link-search=native={}",
        build.join("lib").display()
    );
    println!("cargo:rustc-link-lib=static=sass");

    if libprobe("c++_shared") {
        println!("cargo:rustc-link-lib=dylib=c++_shared");
    }
    else if libprobe("c++") {
        println!("cargo:rustc-link-lib=dylib=c++");
    }
    else if libprobe("stdc++") {
        println!("cargo:rustc-link-lib=dylib=libc++");
    }
    else {
        panic!("no c++ library found");
    }

}

// windows
#[cfg(target_env = "msvc")]
fn compile() {
    let src = get_libsass_folder();
    let target = env::var("TARGET").expect("TARGET not found in environment");
    let msvc_platform = if target.contains("x86_64") {
        "Win64"
    } else {
        "Win32"
    };
    let dest = PathBuf::from(env::var_os("OUT_DIR").unwrap());
    let build = dest.join("build");
    t!(fs::create_dir_all(&build));
    cp_r(&src, &build);

    // Find an instance of devenv.exe from Visual Studio IDE in order to upgrade
    // libsass.sln to the current available IDE. Do nothing if no devenv.exe found
    let d = cc::windows_registry::find(target.as_str(), "devenv.exe");
    if let Some(mut d) = d {
        let d = d
            .args(&["/upgrade", "win\\libsass.sln"])
            .current_dir(&build)
            .output()
            .expect("error running devenv");
        if !d.status.success() {
            let err = String::from_utf8_lossy(&d.stderr);
            let out = String::from_utf8_lossy(&d.stdout);
            println!("Upgrade error:\nSTDERR:{}\nSTDOUT:{}", err, out);
        }
    }

    let r = cc::windows_registry::find(target.as_str(), "msbuild.exe")
        .expect("could not find msbuild")
        .args(&[
            "win\\libsass.sln",
            "/p:LIBSASS_STATIC_LIB=1",
            "/p:Configuration=Release",
            "/p:WholeProgramOptimization=false",
            format!("/p:Platform={}", msvc_platform).as_str(),
        ])
        .current_dir(&build)
        .output()
        .expect("error running msbuild");

    if !r.status.success() {
        let err = String::from_utf8_lossy(&r.stderr);
        let out = String::from_utf8_lossy(&r.stdout);
        panic!("Build error:\nSTDERR:{}\nSTDOUT:{}", err, out);
    }

    println!(
        "cargo:rustc-link-search=native={}",
        build.join("win").join("bin").display()
    );
    println!("cargo:rustc-link-lib=static=libsass");
}

fn main() {
    // Uncomment the line below to generate bindings. Doesn't work on CI as it
    // requires additional tooling
    // write_bindings();

    // Is it already built?
    if let Ok(_) = pkg_config::find_library("libsass") {
        return;
    }

    compile();
}
<|endoftext|>


<commit_before>// Copyright 2016 The Grin Developers
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

extern crate grin_core as core;
extern crate grin_p2p as p2p;
extern crate env_logger;
extern crate futures;
extern crate tokio_core;

use std::net::SocketAddr;
use std::sync::Arc;
use std::time;

use futures::future::Future;
use tokio_core::net::TcpStream;
use tokio_core::reactor::{self, Core};

use core::ser;
use core::core::target::Difficulty;
use p2p::Peer;

// Starts a server and connects a client peer to it to check handshake, followed by a ping/pong exchange to make sure the connection is live.
#[test]
fn peer_handshake() {
  env_logger::init().unwrap();

  let mut evtlp = Core::new().unwrap();
  let handle = evtlp.handle();
  let p2p_conf = p2p::P2PConfig::default();
  let net_adapter = Arc::new(p2p::DummyAdapter{});
  let server = p2p::Server::new(p2p_conf, net_adapter.clone());
  let run_server = server.start(handle.clone());

  let phandle = handle.clone();
  let rhandle = handle.clone();
  let timeout = reactor::Timeout::new(time::Duration::new(1, 0), &handle).unwrap();
  let timeout_send = reactor::Timeout::new(time::Duration::new(2, 0), &handle).unwrap();
  handle.spawn(timeout.map_err(|e| ser::Error::IOErr(e)).and_then(move |_| {
    let p2p_conf = p2p::P2PConfig::default();
    let addr = SocketAddr::new(p2p_conf.host, p2p_conf.port);
    let socket = TcpStream::connect(&addr, &phandle).map_err(|e| ser::Error::IOErr(e));
    socket.and_then(move |socket| {
      Peer::connect(socket, Difficulty::one(), &p2p::handshake::Handshake::new())
		}).and_then(move |(socket, peer)| {
      rhandle.spawn(peer.run(socket, net_adapter.clone()).map_err(|e| {
        panic!("Client run failed: {}", e);
      }));
      peer.send_ping().unwrap();
      timeout_send.map_err(|e| ser::Error::IOErr(e)).map(|_| peer)
		}).and_then(|peer| {
      let (sent, recv) = peer.transmitted_bytes();
      assert!(sent > 0);
      assert!(recv > 0);
      Ok(())
    }).and_then(|_| {
      assert!(server.peer_count() > 0);
      server.stop();
      Ok(())
    })
  }).map_err(|e| {
    panic!("Client connection failed: {}", e);
  }));

  evtlp.run(run_server).unwrap();

}
<commit_msg>Fixed p2p tests.<commit_after>// Copyright 2016 The Grin Developers
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

extern crate grin_core as core;
extern crate grin_p2p as p2p;
extern crate env_logger;
extern crate futures;
extern crate tokio_core;

use std::net::SocketAddr;
use std::sync::Arc;
use std::time;

use futures::future::Future;
use tokio_core::net::TcpStream;
use tokio_core::reactor::{self, Core};

use core::ser;
use core::core::target::Difficulty;
use p2p::Peer;

// Starts a server and connects a client peer to it to check handshake, followed by a ping/pong exchange to make sure the connection is live.
#[test]
fn peer_handshake() {
  env_logger::init().unwrap();

  let mut evtlp = Core::new().unwrap();
  let handle = evtlp.handle();
  let p2p_conf = p2p::P2PConfig::default();
  let net_adapter = Arc::new(p2p::DummyAdapter{});
  let server = p2p::Server::new(p2p::UNKNOWN, p2p_conf, net_adapter.clone());
  let run_server = server.start(handle.clone());
  let my_addr = "127.0.0.1:5000".parse().unwrap();

  let phandle = handle.clone();
  let rhandle = handle.clone();
  let timeout = reactor::Timeout::new(time::Duration::new(1, 0), &handle).unwrap();
  let timeout_send = reactor::Timeout::new(time::Duration::new(2, 0), &handle).unwrap();
  handle.spawn(timeout.map_err(|e| ser::Error::IOErr(e)).and_then(move |_| {
    let p2p_conf = p2p::P2PConfig::default();
    let addr = SocketAddr::new(p2p_conf.host, p2p_conf.port);
    let socket = TcpStream::connect(&addr, &phandle).map_err(|e| ser::Error::IOErr(e));
    socket.and_then(move |socket| {
      Peer::connect(socket, p2p::UNKNOWN, Difficulty::one(), my_addr, &p2p::handshake::Handshake::new())
		}).and_then(move |(socket, peer)| {
      rhandle.spawn(peer.run(socket, net_adapter.clone()).map_err(|e| {
        panic!("Client run failed: {}", e);
      }));
      peer.send_ping().unwrap();
      timeout_send.map_err(|e| ser::Error::IOErr(e)).map(|_| peer)
		}).and_then(|peer| {
      let (sent, recv) = peer.transmitted_bytes();
      assert!(sent > 0);
      assert!(recv > 0);
      Ok(())
    }).and_then(|_| {
      assert!(server.peer_count() > 0);
      server.stop();
      Ok(())
    })
  }).map_err(|e| {
    panic!("Client connection failed: {}", e);
  }));

  evtlp.run(run_server).unwrap();

}
<|endoftext|>


<commit_before><commit_msg>Fix extractor handling of strings<commit_after><|endoftext|>


<commit_before><commit_msg>Simplify memset calls, preparation for replacement<commit_after><|endoftext|>


<commit_before>use syntax::ast;
use syntax::ast::TyKind;
use syntax::attr::AttrMetaMethods;
use syntax::codemap::Span;
use syntax::ext::base::ExtCtxt;
use syntax::ext::build::AstBuilder;
use syntax::parse::token::{str_to_ident, intern_and_get_ident};
use syntax::ptr::P;

fn str_value_of_attr(
    cx: &mut ExtCtxt,
    attr: &ast::Attribute,
    name: &str,
) -> Option<ast::Ident> {
    attr.value_str().map(|value| {
        str_to_ident(&value)
    }).or_else(|| {
        cx.span_err(attr.span(),
            &format!(r#"`{}` must be in the form `#[{}="something"]`"#, name, name));
        None
    })
}

fn single_arg_value_of_attr(
    cx: &mut ExtCtxt,
    attr: &ast::Attribute,
    name: &str,
) -> Option<ast::Ident> {
    let usage_err = || {
        cx.span_err(attr.span(),
            &format!(r#"`{}` must be in the form `#[{}(something)]`"#, name, name));
        None
    };
    // FIXME: This can be cleaned up with slice patterns
    match attr.node.value.node {
        ast::MetaItemKind::List(_, ref items) => {
            if items.len() != 1 {
                return usage_err();
            }
            match items[0].node {
                ast::MetaItemKind::Word(ref value) => Some(str_to_ident(&value)),
                _ => usage_err(),
            }
        }
        _ => usage_err(),
    }
}

pub fn str_value_of_attr_with_name(
    cx: &mut ExtCtxt,
    attrs: &[ast::Attribute],
    name: &str,
) -> Option<ast::Ident> {
    attrs.iter()
        .find(|a| a.check_name(name))
        .and_then(|a| str_value_of_attr(cx, &a, name))
}

pub fn ident_value_of_attr_with_name(
    cx: &mut ExtCtxt,
    attrs: &[ast::Attribute],
    name: &str,
) -> Option<ast::Ident> {
    attrs.iter()
        .find(|a| a.check_name(name))
        .and_then(|a| single_arg_value_of_attr(cx, &a, name))
}

#[cfg(feature = "with-syntex")]
pub fn strip_attributes(krate: ast::Crate) -> ast::Crate {
    use syntax::fold;

    struct StripAttributeFolder;

    impl fold::Folder for StripAttributeFolder {
        fn fold_attribute(&mut self, attr: ast::Attribute) -> Option<ast::Attribute> {
            if attr.check_name("table_name") {
                None
            } else {
                Some(attr)
            }
        }

        fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac {
            fold::noop_fold_mac(mac, self)
        }
    }

    fold::Folder::fold_crate(&mut StripAttributeFolder, krate)
}

pub fn struct_ty(
    cx: &mut ExtCtxt,
    span: Span,
    name: ast::Ident,
    generics: &ast::Generics,
) -> P<ast::Ty> {
    let lifetimes = generics.lifetimes.iter().map(|lt| lt.lifetime).collect();
    let ty_params = generics.ty_params.iter()
        .map(|param| cx.ty_ident(span, param.ident))
        .collect();
    cx.ty_path(cx.path_all(span, false, vec![name], lifetimes, ty_params, Vec::new()))
}

pub fn ty_param_of_option(ty: &ast::Ty) -> Option<&P<ast::Ty>> {
    match ty.node {
        TyKind::Path(_, ref path) => {
            path.segments.first().iter()
                .filter(|s| s.identifier.name.as_str() == intern_and_get_ident("Option"))
                .flat_map(|s| s.parameters.types().first().map(|p| *p))
                .next()
        }
        _ => None,
    }
}

pub fn is_option_ty(ty: &ast::Ty) -> bool {
    ty_param_of_option(ty).is_some()
}
<commit_msg>Strip column name attribute from syntex<commit_after>use syntax::ast;
use syntax::ast::TyKind;
use syntax::attr::AttrMetaMethods;
use syntax::codemap::Span;
use syntax::ext::base::ExtCtxt;
use syntax::ext::build::AstBuilder;
use syntax::parse::token::{str_to_ident, intern_and_get_ident};
use syntax::ptr::P;

fn str_value_of_attr(
    cx: &mut ExtCtxt,
    attr: &ast::Attribute,
    name: &str,
) -> Option<ast::Ident> {
    attr.value_str().map(|value| {
        str_to_ident(&value)
    }).or_else(|| {
        cx.span_err(attr.span(),
            &format!(r#"`{}` must be in the form `#[{}="something"]`"#, name, name));
        None
    })
}

fn single_arg_value_of_attr(
    cx: &mut ExtCtxt,
    attr: &ast::Attribute,
    name: &str,
) -> Option<ast::Ident> {
    let usage_err = || {
        cx.span_err(attr.span(),
            &format!(r#"`{}` must be in the form `#[{}(something)]`"#, name, name));
        None
    };
    // FIXME: This can be cleaned up with slice patterns
    match attr.node.value.node {
        ast::MetaItemKind::List(_, ref items) => {
            if items.len() != 1 {
                return usage_err();
            }
            match items[0].node {
                ast::MetaItemKind::Word(ref value) => Some(str_to_ident(&value)),
                _ => usage_err(),
            }
        }
        _ => usage_err(),
    }
}

pub fn str_value_of_attr_with_name(
    cx: &mut ExtCtxt,
    attrs: &[ast::Attribute],
    name: &str,
) -> Option<ast::Ident> {
    attrs.iter()
        .find(|a| a.check_name(name))
        .and_then(|a| str_value_of_attr(cx, &a, name))
}

pub fn ident_value_of_attr_with_name(
    cx: &mut ExtCtxt,
    attrs: &[ast::Attribute],
    name: &str,
) -> Option<ast::Ident> {
    attrs.iter()
        .find(|a| a.check_name(name))
        .and_then(|a| single_arg_value_of_attr(cx, &a, name))
}

#[cfg(feature = "with-syntex")]
pub fn strip_attributes(krate: ast::Crate) -> ast::Crate {
    use syntax::fold;

    struct StripAttributeFolder;

    impl fold::Folder for StripAttributeFolder {
        fn fold_attribute(&mut self, attr: ast::Attribute) -> Option<ast::Attribute> {
            if attr.check_name("table_name") || attr.check_name("column_name") {
                None
            } else {
                Some(attr)
            }
        }

        fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac {
            fold::noop_fold_mac(mac, self)
        }
    }

    fold::Folder::fold_crate(&mut StripAttributeFolder, krate)
}

pub fn struct_ty(
    cx: &mut ExtCtxt,
    span: Span,
    name: ast::Ident,
    generics: &ast::Generics,
) -> P<ast::Ty> {
    let lifetimes = generics.lifetimes.iter().map(|lt| lt.lifetime).collect();
    let ty_params = generics.ty_params.iter()
        .map(|param| cx.ty_ident(span, param.ident))
        .collect();
    cx.ty_path(cx.path_all(span, false, vec![name], lifetimes, ty_params, Vec::new()))
}

pub fn ty_param_of_option(ty: &ast::Ty) -> Option<&P<ast::Ty>> {
    match ty.node {
        TyKind::Path(_, ref path) => {
            path.segments.first().iter()
                .filter(|s| s.identifier.name.as_str() == intern_and_get_ident("Option"))
                .flat_map(|s| s.parameters.types().first().map(|p| *p))
                .next()
        }
        _ => None,
    }
}

pub fn is_option_ty(ty: &ast::Ty) -> bool {
    ty_param_of_option(ty).is_some()
}
<|endoftext|>


<commit_before><commit_msg>Remove some warnings.<commit_after><|endoftext|>


<commit_before><commit_msg>chore: document the decode 'Error' enum<commit_after><|endoftext|>


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

//! Implementation of cross-process surfaces for Linux. This uses X pixmaps.

use platform::surface::NativeSurfaceMethods;
use texturegl::Texture;

use geom::size::Size2D;
use opengles::glx::{GLXFBConfig, GLXDrawable, GLX_BIND_TO_TEXTURE_RGBA_EXT};
use opengles::glx::{GLX_DEPTH_SIZE, GLX_DRAWABLE_TYPE, GLX_FRONT_EXT, GLX_PIXMAP_BIT, GLX_RGBA};
use opengles::glx::{GLX_TEXTURE_2D_EXT, GLX_TEXTURE_FORMAT_EXT, GLX_TEXTURE_FORMAT_RGBA_EXT};
use opengles::glx::{GLX_TEXTURE_TARGET_EXT, glXChooseVisual, glXCreatePixmap, glXDestroyPixmap};
use opengles::glx::{glXGetProcAddress, glXGetFBConfigAttrib, glXGetFBConfigs};
use opengles::glx::{glXGetVisualFromFBConfig};
use opengles::glx;
use opengles::gl2::NO_ERROR;
use opengles::gl2;
use std::cast;
use std::libc::{c_char, c_int, c_uint, c_void};
use std::ptr;
use xlib::xlib::{Display, Pixmap, XCloseDisplay, XCreateGC, XCreateImage, XCreatePixmap};
use xlib::xlib::{XDefaultScreen, XFreePixmap, XGetGeometry, XOpenDisplay, XPutImage, XRootWindow};
use xlib::xlib::{XVisualInfo, ZPixmap};

/// The display and visual info. This is needed in order to upload on the painting side. This holds
/// a *strong* reference to the display and will close it when done.
///
/// FIXME(pcwalton): Mark nonsendable and noncopyable.
pub struct NativePaintingGraphicsContext {
    display: *Display,
    visual_info: *XVisualInfo,
}

impl NativePaintingGraphicsContext {
    #[fixed_stack_segment]
    pub fn from_metadata(metadata: &NativeGraphicsMetadata) -> NativePaintingGraphicsContext {
        unsafe {
            let display = XOpenDisplay(*metadata);

            // FIXME(pcwalton): It would be more robust to actually have the compositor pass the
            // visual.
            let compositor_visual_info =
                NativeCompositingGraphicsContext::compositor_visual_info(display);

            NativePaintingGraphicsContext {
                display: display,
                visual_info: compositor_visual_info,
            }
        }
    }
}

impl Drop for NativePaintingGraphicsContext {
    #[fixed_stack_segment]
    fn drop(&mut self) {
        unsafe {
            let _ = XCloseDisplay(self.display);
        }
    }
}

/// The display, visual info, and framebuffer configuration. This is needed in order to bind to a
/// texture on the compositor side. This holds only a *weak* reference to the display and does not
/// close it.
///
/// FIXME(pcwalton): Unchecked weak references are bad and can violate memory safety. This is hard
/// to fix because the Display is given to us by the native windowing system, but we should fix it
/// someday.
///
/// FIXME(pcwalton): Mark nonsendable.
pub struct NativeCompositingGraphicsContext {
    display: *Display,
    visual_info: *XVisualInfo,
    framebuffer_configuration: GLXFBConfig,
}

impl NativeCompositingGraphicsContext {
    /// Chooses the compositor visual info using the same algorithm that the compositor uses.
    ///
    /// FIXME(pcwalton): It would be more robust to actually have the compositor pass the visual.
    #[fixed_stack_segment]
    fn compositor_visual_info(display: *Display) -> *XVisualInfo {
        unsafe {
            let glx_display: *glx::Display = cast::transmute(display);
            let screen = XDefaultScreen(display);
            let attributes = [ GLX_RGBA, GLX_DEPTH_SIZE, 24, 0 ];
            let compositor_visual_info = glXChooseVisual(glx_display, screen, &attributes[0]);
            cast::transmute(compositor_visual_info)
        }
    }

    /// Creates a native graphics context from the given X display connection. This uses GLX. Only
    /// the compositor is allowed to call this.
    #[fixed_stack_segment]
    pub fn from_display(display: *Display) -> NativeCompositingGraphicsContext {
        unsafe {
            // FIXME(pcwalton): It would be more robust to actually have the compositor pass the
            // visual.
            let compositor_visual_info =
                NativeCompositingGraphicsContext::compositor_visual_info(display);
            let compositor_visual_id = (*compositor_visual_info).visualid;

            // Choose an FB config.
            let glx_display = cast::transmute(display);
            let screen = XDefaultScreen(display);
            let mut fbconfig_count = 0;
            let fbconfigs = glXGetFBConfigs(glx_display, screen, &mut fbconfig_count);
            let mut fbconfig_index = None;
            for i in range(0, fbconfig_count) {
                let fbconfig = *ptr::offset(fbconfigs, i as int);
                let visual_info = glXGetVisualFromFBConfig(glx_display, fbconfig);
                let visual_info: *XVisualInfo = cast::transmute(visual_info);
                if visual_info == ptr::null() || (*visual_info).visualid != compositor_visual_id {
                    continue
                }

                let mut value = 0;
                glXGetFBConfigAttrib(glx_display, fbconfig, GLX_DRAWABLE_TYPE, &mut value);
                if (value & GLX_PIXMAP_BIT) == 0 {
                    continue
                }

                glXGetFBConfigAttrib(glx_display,
                                     fbconfig,
                                     GLX_BIND_TO_TEXTURE_RGBA_EXT,
                                     &mut value);
                if value == 0 {
                    continue
                }

                fbconfig_index = Some(i);
                break
            }

            let framebuffer_configuration = match fbconfig_index {
                None => fail!("No appropriate framebuffer config found!"),
                Some(index) => *ptr::offset(fbconfigs, index as int),
            };

            NativeCompositingGraphicsContext {
                display: display,
                visual_info: compositor_visual_info,
                framebuffer_configuration: framebuffer_configuration,
            }
        }
    }
}

/// The X display string.
pub type NativeGraphicsMetadata = *c_char;

#[deriving(Eq)]
pub enum NativeSurfaceTransientData {
    NoTransientData,
    RenderTaskTransientData(*Display, *XVisualInfo),
}

pub struct NativeSurface {
    /// The pixmap.
    pixmap: Pixmap,

    /// Whether this pixmap will leak if the destructor runs. This is for debugging purposes.
    will_leak: bool,
}

impl Drop for NativeSurface {
    fn drop(&mut self) {
        if self.will_leak {
            fail!("You should have disposed of the pixmap properly with destroy()! This pixmap \
                   will leak!");
        }
    }
}

impl NativeSurface {
    #[fixed_stack_segment]
    pub fn from_pixmap(pixmap: Pixmap) -> NativeSurface {
        NativeSurface {
            pixmap: pixmap,
            will_leak: true,
        }
    }
}

impl NativeSurfaceMethods for NativeSurface {
    #[fixed_stack_segment]
    fn new(native_context: &NativePaintingGraphicsContext, size: Size2D<i32>, stride: i32)
           -> NativeSurface {
        unsafe {
            // Create the pixmap.
            let screen = XDefaultScreen(native_context.display);
            let window = XRootWindow(native_context.display, screen);

            let pixmap = XCreatePixmap(native_context.display,
                                       window,
                                       size.width as c_uint,
                                       size.height as c_uint,
                                       ((stride / size.width) * 8) as c_uint);

            NativeSurface::from_pixmap(pixmap)
        }
    }

    /// This may only be called on the compositor side.
    #[fixed_stack_segment]
    fn bind_to_texture(&self,
                       native_context: &NativeCompositingGraphicsContext,
                       texture: &Texture,
                       _size: Size2D<int>) {
        unsafe {
            // Create the GLX pixmap.
            //
            // FIXME(pcwalton): RAII for exception safety?
            let pixmap_attributes = [
                GLX_TEXTURE_TARGET_EXT, GLX_TEXTURE_2D_EXT,
                GLX_TEXTURE_FORMAT_EXT, GLX_TEXTURE_FORMAT_RGBA_EXT,
                0
            ];
            let glx_display = cast::transmute(native_context.display);
            let glx_pixmap = glXCreatePixmap(glx_display,
                                             native_context.framebuffer_configuration,
                                             self.pixmap,
                                             &pixmap_attributes[0]);

            let glXBindTexImageEXT: extern "C" fn(*Display, GLXDrawable, c_int, *c_int) =
                cast::transmute(glXGetProcAddress(cast::transmute(&"glXBindTexImageEXT\x00"[0])));
            assert!(glXBindTexImageEXT as *c_void != ptr::null());
            let _bound = texture.bind();
            glXBindTexImageEXT(native_context.display,
                               cast::transmute(glx_pixmap),
                               GLX_FRONT_EXT,
                               ptr::null());
            assert_eq!(gl2::get_error(), NO_ERROR);

            // FIXME(pcwalton): Recycle these for speed?
            glXDestroyPixmap(glx_display, glx_pixmap);
        }
    }

    /// This may only be called on the painting side.
    #[fixed_stack_segment]
    fn upload(&self, graphics_context: &NativePaintingGraphicsContext, data: &[u8]) {
        unsafe {
            // Ensure that we're running on the render task. Take the display.
            let pixmap = self.pixmap;

            // Figure out the width, height, and depth of the pixmap.
            let mut root_window = 0;
            let mut x = 0;
            let mut y = 0;
            let mut width = 0;
            let mut height = 0;
            let mut border_width = 0;
            let mut depth = 0;
            let _ = XGetGeometry(graphics_context.display,
                                 cast::transmute(pixmap),
                                 &mut root_window,
                                 &mut x,
                                 &mut y,
                                 &mut width,
                                 &mut height,
                                 &mut border_width,
                                 &mut depth);

            // Create the image.
            let image = XCreateImage(graphics_context.display,
                                     (*graphics_context.visual_info).visual,
                                     depth,
                                     ZPixmap,
                                     0,
                                     cast::transmute(&data[0]),
                                     width as c_uint,
                                     height as c_uint,
                                     32,
                                     0);

            // Create the X graphics context.
            let gc = XCreateGC(graphics_context.display, pixmap, 0, ptr::null());

            // Draw the image.
            let _ = XPutImage(graphics_context.display,
                              pixmap,
                              gc,
                              image,
                              0,
                              0,
                              0,
                              0,
                              width,
                              height);
        }
    }

    fn get_id(&self) -> int {
        self.pixmap as int
    }

    #[fixed_stack_segment]
    fn destroy(&mut self, graphics_context: &NativePaintingGraphicsContext) {
        unsafe {
            assert!(self.pixmap != 0);
            XFreePixmap(graphics_context.display, self.pixmap);
            self.mark_wont_leak()
        }
    }

    fn mark_will_leak(&mut self) {
        self.will_leak = true
    }

    fn mark_wont_leak(&mut self) {
        self.will_leak = false
    }
}

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

//! Implementation of cross-process surfaces for Linux. This uses X pixmaps.

use platform::surface::NativeSurfaceMethods;
use texturegl::Texture;

use geom::size::Size2D;
use opengles::glx::{GLXFBConfig, GLXDrawable, GLX_BIND_TO_TEXTURE_RGBA_EXT};
use opengles::glx::{GLX_DEPTH_SIZE, GLX_DRAWABLE_TYPE, GLX_FRONT_EXT, GLX_PIXMAP_BIT, GLX_RGBA};
use opengles::glx::{GLX_TEXTURE_2D_EXT, GLX_TEXTURE_FORMAT_EXT, GLX_TEXTURE_FORMAT_RGBA_EXT};
use opengles::glx::{GLX_TEXTURE_TARGET_EXT, glXChooseVisual, glXCreatePixmap, glXDestroyPixmap};
use opengles::glx::{glXGetProcAddress, glXGetFBConfigAttrib, glXGetFBConfigs};
use opengles::glx::{glXGetVisualFromFBConfig};
use opengles::glx;
use opengles::gl2::NO_ERROR;
use opengles::gl2;
use std::cast;
use std::libc::{c_int, c_uint, c_void};
use std::ptr;
use xlib::xlib::{Display, Pixmap, XCloseDisplay, XCreateGC, XCreateImage, XCreatePixmap};
use xlib::xlib::{XDefaultScreen, XFreePixmap, XGetGeometry, XOpenDisplay, XPutImage, XRootWindow};
use xlib::xlib::{XVisualInfo, ZPixmap};

/// The display and visual info. This is needed in order to upload on the painting side. This holds
/// a *strong* reference to the display and will close it when done.
///
/// FIXME(pcwalton): Mark nonsendable and noncopyable.
pub struct NativePaintingGraphicsContext {
    display: *Display,
    visual_info: *XVisualInfo,
}

impl NativePaintingGraphicsContext {
    #[fixed_stack_segment]
    pub fn from_metadata(metadata: &NativeGraphicsMetadata) -> NativePaintingGraphicsContext {
        unsafe {
            let display = XOpenDisplay(metadata.display.to_c_str().with_ref(|c_str| c_str));

            // FIXME(pcwalton): It would be more robust to actually have the compositor pass the
            // visual.
            let compositor_visual_info =
                NativeCompositingGraphicsContext::compositor_visual_info(display);

            NativePaintingGraphicsContext {
                display: display,
                visual_info: compositor_visual_info,
            }
        }
    }
}

impl Drop for NativePaintingGraphicsContext {
    #[fixed_stack_segment]
    fn drop(&mut self) {
        unsafe {
            let _ = XCloseDisplay(self.display);
        }
    }
}

/// The display, visual info, and framebuffer configuration. This is needed in order to bind to a
/// texture on the compositor side. This holds only a *weak* reference to the display and does not
/// close it.
///
/// FIXME(pcwalton): Unchecked weak references are bad and can violate memory safety. This is hard
/// to fix because the Display is given to us by the native windowing system, but we should fix it
/// someday.
///
/// FIXME(pcwalton): Mark nonsendable.
pub struct NativeCompositingGraphicsContext {
    display: *Display,
    visual_info: *XVisualInfo,
    framebuffer_configuration: GLXFBConfig,
}

impl NativeCompositingGraphicsContext {
    /// Chooses the compositor visual info using the same algorithm that the compositor uses.
    ///
    /// FIXME(pcwalton): It would be more robust to actually have the compositor pass the visual.
    #[fixed_stack_segment]
    fn compositor_visual_info(display: *Display) -> *XVisualInfo {
        unsafe {
            let glx_display: *glx::Display = cast::transmute(display);
            let screen = XDefaultScreen(display);
            let attributes = [ GLX_RGBA, GLX_DEPTH_SIZE, 24, 0 ];
            let compositor_visual_info = glXChooseVisual(glx_display, screen, &attributes[0]);
            cast::transmute(compositor_visual_info)
        }
    }

    /// Creates a native graphics context from the given X display connection. This uses GLX. Only
    /// the compositor is allowed to call this.
    #[fixed_stack_segment]
    pub fn from_display(display: *Display) -> NativeCompositingGraphicsContext {
        unsafe {
            // FIXME(pcwalton): It would be more robust to actually have the compositor pass the
            // visual.
            let compositor_visual_info =
                NativeCompositingGraphicsContext::compositor_visual_info(display);
            let compositor_visual_id = (*compositor_visual_info).visualid;

            // Choose an FB config.
            let glx_display = cast::transmute(display);
            let screen = XDefaultScreen(display);
            let mut fbconfig_count = 0;
            let fbconfigs = glXGetFBConfigs(glx_display, screen, &mut fbconfig_count);
            let mut fbconfig_index = None;
            for i in range(0, fbconfig_count) {
                let fbconfig = *ptr::offset(fbconfigs, i as int);
                let visual_info = glXGetVisualFromFBConfig(glx_display, fbconfig);
                let visual_info: *XVisualInfo = cast::transmute(visual_info);
                if visual_info == ptr::null() || (*visual_info).visualid != compositor_visual_id {
                    continue
                }

                let mut value = 0;
                glXGetFBConfigAttrib(glx_display, fbconfig, GLX_DRAWABLE_TYPE, &mut value);
                if (value & GLX_PIXMAP_BIT) == 0 {
                    continue
                }

                glXGetFBConfigAttrib(glx_display,
                                     fbconfig,
                                     GLX_BIND_TO_TEXTURE_RGBA_EXT,
                                     &mut value);
                if value == 0 {
                    continue
                }

                fbconfig_index = Some(i);
                break
            }

            let framebuffer_configuration = match fbconfig_index {
                None => fail!("No appropriate framebuffer config found!"),
                Some(index) => *ptr::offset(fbconfigs, index as int),
            };

            NativeCompositingGraphicsContext {
                display: display,
                visual_info: compositor_visual_info,
                framebuffer_configuration: framebuffer_configuration,
            }
        }
    }
}

/// The X display string.
#[deriving(Clone)]
pub struct NativeGraphicsMetadata {
    display: ~str,
}

impl NativeGraphicsMetadata {
    /// Creates graphics metadata from a metadata descriptor.
    #[fixed_stack_segment]
    pub fn from_descriptor(descriptor: &NativeGraphicsMetadataDescriptor)
                           -> NativeGraphicsMetadata {
        NativeGraphicsMetadata {
            display: descriptor.display.to_str(),
        }
    }
}

/// A sendable form of the X display string.
#[deriving(Clone, Decodable, Encodable)]
pub struct NativeGraphicsMetadataDescriptor {
    display: ~str,
}

impl NativeGraphicsMetadataDescriptor {
    /// Creates a metadata descriptor from metadata.
    #[fixed_stack_segment]
    pub fn from_metadata(metadata: NativeGraphicsMetadata) -> NativeGraphicsMetadataDescriptor {
        NativeGraphicsMetadataDescriptor {
            display: metadata.display.to_str()
        }
    }
}

#[deriving(Eq)]
pub enum NativeSurfaceTransientData {
    NoTransientData,
    RenderTaskTransientData(*Display, *XVisualInfo),
}

#[deriving(Decodable, Encodable)]
pub struct NativeSurface {
    /// The pixmap.
    pixmap: Pixmap,

    /// Whether this pixmap will leak if the destructor runs. This is for debugging purposes.
    will_leak: bool,
}

impl Drop for NativeSurface {
    fn drop(&mut self) {
        if self.will_leak {
            fail!("You should have disposed of the pixmap properly with destroy()! This pixmap \
                   will leak!");
        }
    }
}

impl NativeSurface {
    #[fixed_stack_segment]
    pub fn from_pixmap(pixmap: Pixmap) -> NativeSurface {
        NativeSurface {
            pixmap: pixmap,
            will_leak: true,
        }
    }
}

impl NativeSurfaceMethods for NativeSurface {
    #[fixed_stack_segment]
    fn new(native_context: &NativePaintingGraphicsContext, size: Size2D<i32>, stride: i32)
           -> NativeSurface {
        unsafe {
            // Create the pixmap.
            let screen = XDefaultScreen(native_context.display);
            let window = XRootWindow(native_context.display, screen);

            let pixmap = XCreatePixmap(native_context.display,
                                       window,
                                       size.width as c_uint,
                                       size.height as c_uint,
                                       ((stride / size.width) * 8) as c_uint);

            NativeSurface::from_pixmap(pixmap)
        }
    }

    /// This may only be called on the compositor side.
    #[fixed_stack_segment]
    fn bind_to_texture(&self,
                       native_context: &NativeCompositingGraphicsContext,
                       texture: &Texture,
                       _size: Size2D<int>) {
        unsafe {
            // Create the GLX pixmap.
            //
            // FIXME(pcwalton): RAII for exception safety?
            let pixmap_attributes = [
                GLX_TEXTURE_TARGET_EXT, GLX_TEXTURE_2D_EXT,
                GLX_TEXTURE_FORMAT_EXT, GLX_TEXTURE_FORMAT_RGBA_EXT,
                0
            ];
            let glx_display = cast::transmute(native_context.display);
            let glx_pixmap = glXCreatePixmap(glx_display,
                                             native_context.framebuffer_configuration,
                                             self.pixmap,
                                             &pixmap_attributes[0]);

            let glXBindTexImageEXT: extern "C" fn(*Display, GLXDrawable, c_int, *c_int) =
                cast::transmute(glXGetProcAddress(cast::transmute(&"glXBindTexImageEXT\x00"[0])));
            assert!(glXBindTexImageEXT as *c_void != ptr::null());
            let _bound = texture.bind();
            glXBindTexImageEXT(native_context.display,
                               cast::transmute(glx_pixmap),
                               GLX_FRONT_EXT,
                               ptr::null());
            assert_eq!(gl2::get_error(), NO_ERROR);

            // FIXME(pcwalton): Recycle these for speed?
            glXDestroyPixmap(glx_display, glx_pixmap);
        }
    }

    /// This may only be called on the painting side.
    #[fixed_stack_segment]
    fn upload(&self, graphics_context: &NativePaintingGraphicsContext, data: &[u8]) {
        unsafe {
            // Ensure that we're running on the render task. Take the display.
            let pixmap = self.pixmap;

            // Figure out the width, height, and depth of the pixmap.
            let mut root_window = 0;
            let mut x = 0;
            let mut y = 0;
            let mut width = 0;
            let mut height = 0;
            let mut border_width = 0;
            let mut depth = 0;
            let _ = XGetGeometry(graphics_context.display,
                                 cast::transmute(pixmap),
                                 &mut root_window,
                                 &mut x,
                                 &mut y,
                                 &mut width,
                                 &mut height,
                                 &mut border_width,
                                 &mut depth);

            // Create the image.
            let image = XCreateImage(graphics_context.display,
                                     (*graphics_context.visual_info).visual,
                                     depth,
                                     ZPixmap,
                                     0,
                                     cast::transmute(&data[0]),
                                     width as c_uint,
                                     height as c_uint,
                                     32,
                                     0);

            // Create the X graphics context.
            let gc = XCreateGC(graphics_context.display, pixmap, 0, ptr::null());

            // Draw the image.
            let _ = XPutImage(graphics_context.display,
                              pixmap,
                              gc,
                              image,
                              0,
                              0,
                              0,
                              0,
                              width,
                              height);
        }
    }

    fn get_id(&self) -> int {
        self.pixmap as int
    }

    #[fixed_stack_segment]
    fn destroy(&mut self, graphics_context: &NativePaintingGraphicsContext) {
        unsafe {
            assert!(self.pixmap != 0);
            XFreePixmap(graphics_context.display, self.pixmap);
            self.mark_wont_leak()
        }
    }

    fn mark_will_leak(&mut self) {
        self.will_leak = true
    }

    fn mark_wont_leak(&mut self) {
        self.will_leak = false
    }
}

<|endoftext|>


<commit_before><commit_msg>Fixes to move hashing not recomputing moves when needed<commit_after><|endoftext|>


<commit_before>use crate::actions::{Action, ActionParseError};
use std::borrow::Borrow;
use std::{error, fmt, fs, path, result};
use std::io::{self, BufRead};
use std::str::FromStr;

/// Errors that may occur when querying an agent for its next move.
#[derive(Debug)]
pub enum Error {
  BadAction(ActionParseError),
  Exhausted,
  Wrapped(Box<(dyn error::Error + 'static)>),
}

impl From<ActionParseError> for Error {
  fn from(err: ActionParseError) -> Self {
    Error::BadAction(err)
  }
}

impl From<io::Error> for Error {
  fn from(err: io::Error) -> Self {
    Error::Wrapped(Box::new(err))
  }
}

impl error::Error for Error {
  fn source(&self) -> Option<&(dyn error::Error + 'static)> {
    match self {
      Error::BadAction(e) => Some(e),
      Error::Exhausted => None,
      Error::Wrapped(e) => Some(e.borrow()),
    }
  }
}

impl fmt::Display for Error {
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    write!(f, "{:?}", self)
  }
}

type Result = result::Result<Action, Error>;

/// The interface that Thud-playing agents should implement.
pub trait Agent {
  /// Requests a move for the given game state. This move should be legal to
  /// play on `state`.
  ///
  /// If an agent cannot propose a move (e.g., because it is in a bad internal
  /// state, or it has read the last move from a pre-recorded list), it should
  /// return an error.
  fn propose_move(&mut self, state: &crate::state::State) -> Result;
}

/// An agent that reads Thud moves from stdin. This agent does not lock stdin,
/// making it possible to have two different instances of it take turns reading
/// from stdin.
///
/// A prompt function may be specified, which will result in a prompt string
/// being printed before each move is read.
pub struct StdinAgent<F: Fn(&crate::state::State) -> String> {
  prompt: F,
}

impl<F: Fn(&crate::state::State) -> String> StdinAgent<F> {
  /// Returns an agent that will evaluate `prompt` on the current game state and
  /// print the resulting string each time a move is requested.
  pub fn with_prompt(prompt: F) -> Self {
    StdinAgent { prompt: prompt, }
  }
}

impl<F: Fn(&crate::state::State) -> String> Agent for StdinAgent<F> {
  fn propose_move(&mut self, state: &crate::state::State) -> Result {
    print!("{}", (self.prompt)(state));
    let mut line = String::new();
    let bytes_read = io::stdin().lock().read_line(&mut line)?;
    if bytes_read == 0 {
      return Err(Error::Exhausted)
    }
    Ok(Action::from_str(line.trim())?)
  }
}

/// An agent that reads Thud moves from an input stream.
pub struct ReaderAgent<R: io::BufRead> {
  reader: R,
}

impl<R: io::BufRead> ReaderAgent<R> {
  pub fn new(reader: R) -> Self {
    ReaderAgent { reader, }
  }
}

impl ReaderAgent<io::BufReader<fs::File>> {
  /// Returns a `ReaderAgent` that reads lines from the file at `path`.
  pub fn from_file_at<P: AsRef<path::Path>>(path: P) -> result::Result<Self, io::Error> {
    Ok(Self::from_file(fs::File::open(path)?))
  }

  /// Returns a `ReaderAgent` that reads lines from `file`.
  pub fn from_file(file: fs::File) -> Self {
    ReaderAgent { reader: io::BufReader::new(file), }
  }
}

impl<R: io::BufRead> Agent for ReaderAgent<R> {
  fn propose_move(&mut self, _state: &crate::state::State) -> Result {
    let mut line = String::new();
    let bytes_read = self.reader.read_line(&mut line)?;
    if bytes_read == 0 {
      return Err(Error::Exhausted)
    }
    Ok(Action::from_str(line.trim())?)
  }
}
<commit_msg>Extend Agent to allow off-thread computation using std::future.<commit_after>use crate::actions::Action;
use std::future::Future;
use std::io::{self, BufRead};
use std::pin::Pin;
use std::str::FromStr;
use std::sync::mpsc::{channel, Receiver, TryRecvError};
use std::sync::{Arc, Mutex};
use std::task::{Context, Poll};
use std::thread::{self, JoinHandle};
use std::{error, fmt, result};

pub type Result = result::Result<Action, Box<dyn error::Error + Send>>;

/// Error states unique to [Agent](trait.Agent.html)s that read actions in from a text stream.
#[derive(Debug)]
pub enum ReaderAgentError {
  BadMove(String),
  Exhausted,
  Io(io::Error),
}

impl error::Error for ReaderAgentError {
  fn cause(&self) -> Option<&dyn error::Error> {
    match self {
      ReaderAgentError::BadMove(_) | ReaderAgentError::Exhausted => None,
      ReaderAgentError::Io(ref e) => Some(e),
    }
  }
}

impl fmt::Display for ReaderAgentError {
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    match self {
      ReaderAgentError::BadMove(s) => write!(f, "bad move string '{}'", s),
      ReaderAgentError::Exhausted => write!(f, "exhausted list of moves"),
      ReaderAgentError::Io(e) => write!(f, "{}", e),
    }
  }
}

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

/// Implemented for agents that can play Thud.
pub trait Agent: Send {
  fn propose_action(&mut self, state: &crate::state::State) -> Result;
}

/// Tries to interpret the next line available from `stdin` as a game action.
pub fn read_action_from_stdin() -> Result {
  let mut line = String::new();
  let bytes_read = match io::stdin().lock().read_line(&mut line) {
    Ok(n) => n,
    Err(e) => return Err(Box::new(ReaderAgentError::Io(e))),
  };
  if bytes_read == 0 {
    Err(Box::new(ReaderAgentError::Exhausted))
  } else {
    match Action::from_str(line.trim()) {
      Ok(a) => Ok(a),
      Err(_) => Err(Box::new(ReaderAgentError::BadMove(line))),
    }
  }
}

/// Tries to interpret the next line of text in `reader` as a game action.
pub fn read_action_from_reader<R: io::BufRead>(reader: &mut R) -> Result {
  let mut line = String::new();
  let bytes_read = match reader.read_line(&mut line) {
    Ok(n) => n,
    Err(e) => return Err(Box::new(ReaderAgentError::Io(e))),
  };
  if bytes_read == 0 {
    Err(Box::new(ReaderAgentError::Exhausted))
  } else {
    match Action::from_str(line.trim()) {
      Ok(a) => Ok(a),
      Err(_) => Err(Box::new(ReaderAgentError::BadMove(line))),
    }
  }
}

/// Wraps around an asynchronous thread that executes an agent's move processing.
struct AgentFuture {
  rx: Receiver<Result>,
  _thread_handle: JoinHandle<()>,
}

impl AgentFuture {
  fn new(agent: Arc<Mutex<dyn Agent>>, state: &crate::state::State) -> Self {
    let (tx, rx) = channel();
    let state = state.clone();
    let thread_handle = thread::spawn(move || {
      let result = match agent.lock() {
        Ok(mut agent) => agent.propose_action(&state),
        Err(_) => panic!("agent mutex poisoned"),
      };
      tx.send(result).expect("failed to send proposed action from agent thread")
    });
    AgentFuture { rx, _thread_handle: thread_handle,  }
  }
}

impl Future for AgentFuture {
  type Output = Result;

  fn poll(self: Pin<&mut Self>, _cx: &mut Context) -> Poll<Result> {
    match self.rx.try_recv() {
      Ok(r) => Poll::Ready(r),
      Err(TryRecvError::Empty) => Poll::Pending,
      Err(e) => Poll::Ready(Err(Box::new(e))),
    }
  }
}

/// Returns a future that will query an [Agent](trait.Agent.html) off-thread and yield the result of
/// calling its `propose_action` method.
pub fn query_agent(
  agent: Arc<Mutex<dyn Agent>>,
  state: &crate::state::State,
) -> impl Future<Output = Result> {
  AgentFuture::new(agent, state)
}
<|endoftext|>


<commit_before>use crate::actions::{Action, ActionParseError};
use std::borrow::Borrow;
use std::{error, fmt, fs, path, result};
use std::io::{self, BufRead};
use std::str::FromStr;

/// Errors that may occur when querying an agent for its next move.
#[derive(Debug)]
pub enum Error {
  BadAction(ActionParseError),
  Exhausted,
  Wrapped(Box<(dyn error::Error + 'static)>),
}

impl From<ActionParseError> for Error {
  fn from(err: ActionParseError) -> Self {
    Error::BadAction(err)
  }
}

impl From<io::Error> for Error {
  fn from(err: io::Error) -> Self {
    Error::Wrapped(Box::new(err))
  }
}

impl error::Error for Error {
  fn source(&self) -> Option<&(dyn error::Error + 'static)> {
    match self {
      Error::BadAction(e) => Some(e),
      Error::Exhausted => None,
      Error::Wrapped(e) => Some(e.borrow()),
    }
  }
}

impl fmt::Display for Error {
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    write!(f, "{:?}", self)
  }
}

type Result = result::Result<Action, Error>;

/// The interface that Thud-playing agents should implement.
pub trait Agent {
  /// Requests a move for the given game state. This move should be legal to
  /// play on `state`.
  ///
  /// If an agent cannot propose a move (e.g., because it is in a bad internal
  /// state, or it has read the last move from a pre-recorded list), it should
  /// return an error.
  fn propose_move(&mut self, state: &crate::state::State) -> Result;
}

/// An agent that reads Thud moves from stdin. This agent does not lock stdin,
/// making it possible to have two different instances of it take turns reading
/// from stdin.
///
/// A prompt function may be specified, which will result in a prompt string
/// being printed before each move is read.
pub struct StdinAgent<F: Fn(&crate::state::State) -> String> {
  prompt: Option<F>,
}

impl<F: Fn(&crate::state::State) -> String> StdinAgent<F> {
  /// Returns an agent that will read moves from stdin without printing a prompt.
  pub fn new() -> Self {
    StdinAgent { prompt: None, }
  }

  /// Returns an agent that will evaluate `prompt` on the current game state and
  /// print the resulting string each time a move is requested.
  pub fn with_prompt(prompt: F) -> Self {
    StdinAgent { prompt: Some(prompt), }
  }
}

impl<F: Fn(&crate::state::State) -> String> Agent for StdinAgent<F> {
  fn propose_move(&mut self, state: &crate::state::State) -> Result {
    if let Some(ref prompt_fn) = self.prompt {
      print!("{}", prompt_fn(state));
    }
    let mut line = String::new();
    let bytes_read = io::stdin().lock().read_line(&mut line)?;
    if bytes_read == 0 {
      return Err(Error::Exhausted)
    }
    Ok(Action::from_str(line.trim())?)
  }
}

/// An agent that reads Thud moves from an input stream.
pub struct ReaderAgent<R: io::BufRead> {
  reader: R,
}

impl<R: io::BufRead> ReaderAgent<R> {
  pub fn new(reader: R) -> Self {
    ReaderAgent { reader, }
  }
}

impl ReaderAgent<io::BufReader<fs::File>> {
  /// Returns a `ReaderAgent` that reads lines from the file at `path`.
  pub fn from_file_at<P: AsRef<path::Path>>(path: P) -> result::Result<Self, io::Error> {
    Ok(Self::from_file(fs::File::open(path)?))
  }

  /// Returns a `ReaderAgent` that reads lines from `file`.
  pub fn from_file(file: fs::File) -> Self {
    ReaderAgent { reader: io::BufReader::new(file), }
  }
}

impl<R: io::BufRead> Agent for ReaderAgent<R> {
  fn propose_move(&mut self, _state: &crate::state::State) -> Result {
    let mut line = String::new();
    let bytes_read = self.reader.read_line(&mut line)?;
    if bytes_read == 0 {
      return Err(Error::Exhausted)
    }
    Ok(Action::from_str(line.trim())?)
  }
}
<commit_msg>Make StdinAgent always take a prompt, for lifetime reasons.<commit_after>use crate::actions::{Action, ActionParseError};
use std::borrow::Borrow;
use std::{error, fmt, fs, path, result};
use std::io::{self, BufRead};
use std::str::FromStr;

/// Errors that may occur when querying an agent for its next move.
#[derive(Debug)]
pub enum Error {
  BadAction(ActionParseError),
  Exhausted,
  Wrapped(Box<(dyn error::Error + 'static)>),
}

impl From<ActionParseError> for Error {
  fn from(err: ActionParseError) -> Self {
    Error::BadAction(err)
  }
}

impl From<io::Error> for Error {
  fn from(err: io::Error) -> Self {
    Error::Wrapped(Box::new(err))
  }
}

impl error::Error for Error {
  fn source(&self) -> Option<&(dyn error::Error + 'static)> {
    match self {
      Error::BadAction(e) => Some(e),
      Error::Exhausted => None,
      Error::Wrapped(e) => Some(e.borrow()),
    }
  }
}

impl fmt::Display for Error {
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    write!(f, "{:?}", self)
  }
}

type Result = result::Result<Action, Error>;

/// The interface that Thud-playing agents should implement.
pub trait Agent {
  /// Requests a move for the given game state. This move should be legal to
  /// play on `state`.
  ///
  /// If an agent cannot propose a move (e.g., because it is in a bad internal
  /// state, or it has read the last move from a pre-recorded list), it should
  /// return an error.
  fn propose_move(&mut self, state: &crate::state::State) -> Result;
}

/// An agent that reads Thud moves from stdin. This agent does not lock stdin,
/// making it possible to have two different instances of it take turns reading
/// from stdin.
///
/// A prompt function may be specified, which will result in a prompt string
/// being printed before each move is read.
pub struct StdinAgent<F: Fn(&crate::state::State) -> String> {
  prompt: F,
}

impl<F: Fn(&crate::state::State) -> String> StdinAgent<F> {
  /// Returns an agent that will evaluate `prompt` on the current game state and
  /// print the resulting string each time a move is requested.
  pub fn with_prompt(prompt: F) -> Self {
    StdinAgent { prompt: prompt, }
  }
}

impl<F: Fn(&crate::state::State) -> String> Agent for StdinAgent<F> {
  fn propose_move(&mut self, state: &crate::state::State) -> Result {
    print!("{}", (self.prompt)(state));
    let mut line = String::new();
    let bytes_read = io::stdin().lock().read_line(&mut line)?;
    if bytes_read == 0 {
      return Err(Error::Exhausted)
    }
    Ok(Action::from_str(line.trim())?)
  }
}

/// An agent that reads Thud moves from an input stream.
pub struct ReaderAgent<R: io::BufRead> {
  reader: R,
}

impl<R: io::BufRead> ReaderAgent<R> {
  pub fn new(reader: R) -> Self {
    ReaderAgent { reader, }
  }
}

impl ReaderAgent<io::BufReader<fs::File>> {
  /// Returns a `ReaderAgent` that reads lines from the file at `path`.
  pub fn from_file_at<P: AsRef<path::Path>>(path: P) -> result::Result<Self, io::Error> {
    Ok(Self::from_file(fs::File::open(path)?))
  }

  /// Returns a `ReaderAgent` that reads lines from `file`.
  pub fn from_file(file: fs::File) -> Self {
    ReaderAgent { reader: io::BufReader::new(file), }
  }
}

impl<R: io::BufRead> Agent for ReaderAgent<R> {
  fn propose_move(&mut self, _state: &crate::state::State) -> Result {
    let mut line = String::new();
    let bytes_read = self.reader.read_line(&mut line)?;
    if bytes_read == 0 {
      return Err(Error::Exhausted)
    }
    Ok(Action::from_str(line.trim())?)
  }
}
<|endoftext|>


<commit_before>use clap::{Arg, App, SubCommand};

pub fn build_ui<'a>(app: App<'a, 'a>) -> App<'a, 'a> {
    app
        .arg(Arg::with_name("increment")
             .long("inc")
             .short("i")
             .takes_value(true)
             .required(false)
             .help("Increment a counter"))

        .arg(Arg::with_name("decrement")
             .long("dec")
             .short("d")
             .takes_value(true)
             .required(false)
             .help("Decrement a counter"))

        .arg(Arg::with_name("reset")
             .long("reset")
             .takes_value(true)
             .required(false)
             .help("Reset a counter"))

        .arg(Arg::with_name("set")
             .long("set")
             .takes_value(true)
             .required(false)
             .help("Set a counter"))

        .subcommand(SubCommand::with_name("create")
                   .about("Create a counter")
                   .version("0.1")
                   .arg(Arg::with_name("name")
                        .long("name")
                        .short("n")
                        .takes_value(true)
                        .required(true)
                        .help("Create counter with this name"))
                   .arg(Arg::with_name("initval")
                        .long("init")
                        .short("i")
                        .takes_value(true)
                        .required(false)
                        .help("Initial value")))

        .subcommand(SubCommand::with_name("delete")
                   .about("Delete a counter")
                   .version("0.1")
                   .arg(Arg::with_name("name")
                        .long("name")
                        .short("n")
                        .takes_value(true)
                        .required(true)
                        .help("Create counter with this name")))

        .subcommand(SubCommand::with_name("interactive")
                   .about("Interactively count things")
                   .version("0.1")
                   .arg(Arg::with_name("spec")
                        .long("spec")
                        .short("s")
                        .takes_value(true)
                        .multiple(true)
                        .required(true)
                        .help("Specification for key-bindings. Use <KEY>=<VALUE> where KEY is the
                        key to bind (single character) and VALUE is the path to the counter to bind
                        to.")))
}

<commit_msg>Add ui for "list" subcommand<commit_after>use clap::{Arg, App, SubCommand};

pub fn build_ui<'a>(app: App<'a, 'a>) -> App<'a, 'a> {
    app
        .arg(Arg::with_name("increment")
             .long("inc")
             .short("i")
             .takes_value(true)
             .required(false)
             .help("Increment a counter"))

        .arg(Arg::with_name("decrement")
             .long("dec")
             .short("d")
             .takes_value(true)
             .required(false)
             .help("Decrement a counter"))

        .arg(Arg::with_name("reset")
             .long("reset")
             .takes_value(true)
             .required(false)
             .help("Reset a counter"))

        .arg(Arg::with_name("set")
             .long("set")
             .takes_value(true)
             .required(false)
             .help("Set a counter"))

        .subcommand(SubCommand::with_name("create")
                   .about("Create a counter")
                   .version("0.1")
                   .arg(Arg::with_name("name")
                        .long("name")
                        .short("n")
                        .takes_value(true)
                        .required(true)
                        .help("Create counter with this name"))
                   .arg(Arg::with_name("initval")
                        .long("init")
                        .short("i")
                        .takes_value(true)
                        .required(false)
                        .help("Initial value")))

        .subcommand(SubCommand::with_name("delete")
                   .about("Delete a counter")
                   .version("0.1")
                   .arg(Arg::with_name("name")
                        .long("name")
                        .short("n")
                        .takes_value(true)
                        .required(true)
                        .help("Create counter with this name")))

        .subcommand(SubCommand::with_name("list")
                   .about("List counters")
                   .version("0.1")
                   .arg(Arg::with_name("name")
                        .long("name")
                        .short("n")
                        .takes_value(true)
                        .required(false)
                        .help("List counters with this name (foo/bar and baz/bar would match 'bar')"))

                   .arg(Arg::with_name("greater-than")
                        .long("greater")
                        .short("g")
                        .takes_value(true)
                        .required(false)
                        .help("List counters which are greater than VALUE"))

                   .arg(Arg::with_name("lower-than")
                        .long("lower")
                        .short("l")
                        .takes_value(true)
                        .required(false)
                        .help("List counters which are lower than VALUE"))

                   .arg(Arg::with_name("equals")
                        .long("equal")
                        .short("e")
                        .takes_value(true)
                        .required(false)
                        .help("List counters which equal VALUE"))
        )

        .subcommand(SubCommand::with_name("interactive")
                   .about("Interactively count things")
                   .version("0.1")
                   .arg(Arg::with_name("spec")
                        .long("spec")
                        .short("s")
                        .takes_value(true)
                        .multiple(true)
                        .required(true)
                        .help("Specification for key-bindings. Use <KEY>=<VALUE> where KEY is the
                        key to bind (single character) and VALUE is the path to the counter to bind
                        to.")))
}

<|endoftext|>


<commit_before><commit_msg>cargo fmt<commit_after><|endoftext|>