<commit_before>// Copyright 2016 rust-fuzz developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://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.

// Copyright 2018 TiKV Project Authors. Licensed under Apache-2.0.

//! Command line utility to run fuzz tests.
//!
//! Adopted from https://github.com/rust-fuzz/targets

#[macro_use]
extern crate structopt;
#[macro_use]
extern crate clap;
#[macro_use]
extern crate failure;
#[macro_use]
extern crate lazy_static;
extern crate cargo_metadata;
extern crate regex;

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

use failure::{Error, ResultExt};

lazy_static! {
    static ref WORKSPACE_ROOT: PathBuf = {
        let meta = cargo_metadata::metadata(None).unwrap();
        PathBuf::from(meta.workspace_root)
    };
    static ref FUZZ_ROOT: PathBuf = WORKSPACE_ROOT.join("fuzz");
    static ref FUZZ_TARGETS: Vec<String> = {
        let source = FUZZ_ROOT.join("targets/mod.rs");
        let targets_rs = fs::read_to_string(&source).unwrap();
        let match_fuzz_fs = regex::Regex::new(r"pub fn fuzz_(\w+)\(").unwrap();
        let target_names = match_fuzz_fs
            .captures_iter(&targets_rs)
            .map(|x| format!("fuzz_{}", &x[1]));
        target_names.collect()
    };
    static ref SEED_ROOT: PathBuf = FUZZ_ROOT.join("common/seeds");
}

#[derive(StructOpt, Debug)]
enum Cli {
    /// List all available targets
    #[structopt(name = "list-targets")]
    ListTargets,
    /// Run matched fuzz test with specific fuzzer.
    #[structopt(name = "run")]
    Run {
        /// The fuzzer to use.
        fuzzer: Fuzzer,
        /// The target fuzz to run.
        target: String,
    },
}

arg_enum! {
    #[derive(Debug, PartialEq, Eq, Clone, Copy)]
    enum Fuzzer {
        Afl,
        Honggfuzz,
        Libfuzzer,
    }
}

impl Fuzzer {
    /// Get Cargo package name of corresponding fuzzers.
    fn package_name(self) -> &'static str {
        match self {
            Fuzzer::Afl => "fuzzer-afl",
            Fuzzer::Honggfuzz => "fuzzer-honggfuzz",
            Fuzzer::Libfuzzer => "fuzzer-libfuzzer",
        }
    }

    /// Get Cargo directory of corresponding fuzzers.
    fn directory(self) -> PathBuf {
        FUZZ_ROOT.join(self.package_name())
    }
}

fn main() {
    use structopt::StructOpt;

    match Cli::from_args() {
        Cli::ListTargets => {
            for target in &*FUZZ_TARGETS {
                println!("{}", target);
            }
        }
        Cli::Run { fuzzer, target } => {
            run(fuzzer, &target).unwrap();
        }
    }
}

/// Write the fuzz target source file from corresponding template file.
///
/// `target` must be a valid target.
fn write_fuzz_target_source_file(fuzzer: Fuzzer, target: &str) -> Result<(), Error> {
    use std::io::Write;

    let template_file_path = fuzzer.directory().join("template.rs");
    let template = fs::read_to_string(&template_file_path).context(format!(
        "Error reading template file {}",
        template_file_path.display()
    ))?;

    let target_file_path = fuzzer.directory().join(&format!("src/bin/{}.rs", target));
    let mut file = fs::OpenOptions::new()
        .write(true)
        .create(true)
        .truncate(true)
        .open(&target_file_path)
        .context(format!(
            "Error writing fuzz target source file {}",
            target_file_path.display()
        ))?;

    let source = template.replace("__FUZZ_CLI_TARGET__", &target).replace(
        "__FUZZ_GENERATE_COMMENT__",
        "NOTE: AUTO GENERATED FROM `template.rs`",
    );

    file.write_all(source.as_bytes())?;
    Ok(())
}

/// Run one target fuzz test with specific fuzzer
fn run(fuzzer: Fuzzer, target: &str) -> Result<(), Error> {
    if FUZZ_TARGETS.iter().find(|x| *x == target).is_none() {
        panic!(
            "Unknown fuzz target `{}`. Run `list-targets` command to see available fuzz targets.",
            target
        );
    }
    write_fuzz_target_source_file(fuzzer, target)?;
    match fuzzer {
        Fuzzer::Afl => run_afl(target),
        Fuzzer::Honggfuzz => run_honggfuzz(target),
        Fuzzer::Libfuzzer => run_libfuzzer(target),
    }
}

/// Get input seeds for fuzz target
fn get_seed_dir(target: &str) -> PathBuf {
    let seeds_dir = SEED_ROOT.join(target);
    if seeds_dir.exists() {
        seeds_dir
    } else {
        SEED_ROOT.join("default")
    }
}

/// Create corpus dir for fuzz target
fn create_corpus_dir(base: impl AsRef<Path>, target: &str) -> Result<PathBuf, Error> {
    let base = base.as_ref();
    let corpus_dir = base.join(&format!("corpus-{}", target));
    fs::create_dir_all(&corpus_dir).context(format!(
        "unable to create corpus dir for {}{}",
        base.display(),
        target
    ))?;
    Ok(corpus_dir)
}

/// Run one target fuzz test using AFL
fn run_afl(target: &str) -> Result<(), Error> {
    let fuzzer = Fuzzer::Afl;

    let seed_dir = get_seed_dir(target);
    let corpus_dir = create_corpus_dir(fuzzer.directory(), target)?;

    // 1. cargo afl build (in fuzzer-afl directory)
    let fuzzer_build = Command::new("cargo")
        .args(&["afl", "build", "--bin", target])
        .current_dir(fuzzer.directory())
        .spawn()
        .context(format!("Failed to build {}", fuzzer))?
        .wait()
        .context(format!("Failed to complete building {}", fuzzer))?;

    if !fuzzer_build.success() {
        Err(format_err!(
            "error building afl instrumented binary, exit code {:?}",
            fuzzer_build.code()
        ))?;
    }

    // 2. cargo afl fuzz -i {seed_dir} -o {corpus_dir} target/debug/{instrumented_binary}
    let instrumented_bin = WORKSPACE_ROOT.join("target/debug").join(target);
    let fuzzer_bin = Command::new("cargo")
        .args(&["afl", "fuzz"])
        .arg("-i")
        .arg(&seed_dir)
        .arg("-o")
        .arg(&corpus_dir)
        .arg(&instrumented_bin)
        .current_dir(fuzzer.directory())
        .spawn()
        .context(format!("Failed to run {}", fuzzer))?
        .wait()
        .context(format!("Failed to wait {}", fuzzer))?;

    if !fuzzer_bin.success() {
        Err(format_err!(
            "{} exited with code {:?}",
            fuzzer,
            fuzzer_bin.code()
        ))?;
    }

    Ok(())
}

/// Run one target fuzz test using Honggfuzz
fn run_honggfuzz(target: &str) -> Result<(), Error> {
    let fuzzer = Fuzzer::Honggfuzz;

    let mut rust_flags = env::var("RUSTFLAGS").unwrap_or_default();
    rust_flags.push_str("-Z sanitizer=address");

    let hfuzz_args = format!(
        "-f {} \
         --exit_upon_crash \
         {}",
        get_seed_dir(target).to_string_lossy(),
        env::var("HFUZZ_RUN_ARGS").unwrap_or_default()
    );

    let fuzzer_bin = Command::new("cargo")
        .args(&["hfuzz", "run", target])
        .env("RUSTFLAGS", &rust_flags)
        .env("HFUZZ_RUN_ARGS", &hfuzz_args)
        .current_dir(fuzzer.directory())
        .spawn()
        .context(format!("Failed to run {}", fuzzer))?
        .wait()
        .context(format!("Failed to wait {}", fuzzer))?;

    if !fuzzer_bin.success() {
        Err(format_err!(
            "{} exited with code {:?}",
            fuzzer,
            fuzzer_bin.code()
        ))?;
    }

    Ok(())
}

/// Run one target fuzz test using Libfuzzer
fn run_libfuzzer(target: &str) -> Result<(), Error> {
    let fuzzer = Fuzzer::Libfuzzer;
    let seed_dir = get_seed_dir(target);
    let corpus_dir = create_corpus_dir(fuzzer.directory(), target)?;

    #[cfg(target_os = "macos")]
    let target_platform = "x86_64-apple-darwin";
    #[cfg(target_os = "linux")]
    let target_platform = "x86_64-unknown-linux-gnu";
    #[cfg(not(any(target_os = "linux", target_os = "macos")))]
    panic!("libfuzzer-sys only supports Linux and macOS");

    // FIXME: The -C codegen-units=1 and -C incremental=..
    // below seem to workaround some difficult issues in Rust nightly
    // https://github.com/rust-lang/rust/issues/53945.
    // If this is ever fixed remember to remove the fuzz-incremental
    // entry from .gitignore.
    let mut rust_flags = env::var("RUSTFLAGS").unwrap_or_default();
    rust_flags.push_str(
        "--cfg fuzzing \
         -C codegen-units=1 \
         -C incremental=fuzz-incremental \
         -C passes=sancov \
         -C llvm-args=-sanitizer-coverage-level=4 \
         -C llvm-args=-sanitizer-coverage-trace-pc-guard \
         -C llvm-args=-sanitizer-coverage-trace-compares \
         -C llvm-args=-sanitizer-coverage-trace-divs \
         -C llvm-args=-sanitizer-coverage-trace-geps \
         -C llvm-args=-sanitizer-coverage-prune-blocks=0 \
         -C debug-assertions=on \
         -C debuginfo=0 \
         -C opt-level=3 \
         -Z sanitizer=address",
    );

    let mut asan_options = env::var("ASAN_OPTIONS").unwrap_or_default();
    asan_options.push_str(" detect_odr_violation=0");

    let fuzzer_bin = Command::new("cargo")
        .args(&["run", "--target", &target_platform, "--bin", target, "--"])
        .arg(&corpus_dir)
        .arg(&seed_dir)
        .env("RUSTFLAGS", &rust_flags)
        .env("ASAN_OPTIONS", &asan_options)
        .current_dir(fuzzer.directory())
        .spawn()
        .context(format!("Failed to run {}", fuzzer))?
        .wait()
        .context(format!("Failed to wait {}", fuzzer))?;

    if !fuzzer_bin.success() {
        Err(format_err!(
            "{} exited with code {:?}",
            fuzzer,
            fuzzer_bin.code()
        ))?;
    }

    Ok(())
}
<commit_msg>Enhance error report for fuzzing (#4593)<commit_after>// Copyright 2016 rust-fuzz developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://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.

// Copyright 2018 TiKV Project Authors. Licensed under Apache-2.0.

//! Command line utility to run fuzz tests.
//!
//! Adopted from https://github.com/rust-fuzz/targets

#[macro_use]
extern crate structopt;
#[macro_use]
extern crate clap;
#[macro_use]
extern crate failure;
#[macro_use]
extern crate lazy_static;
extern crate cargo_metadata;
extern crate regex;

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

use failure::{Error, ResultExt};

lazy_static! {
    static ref WORKSPACE_ROOT: PathBuf = {
        let meta = cargo_metadata::metadata(None).unwrap();
        PathBuf::from(meta.workspace_root)
    };
    static ref FUZZ_ROOT: PathBuf = WORKSPACE_ROOT.join("fuzz");
    static ref FUZZ_TARGETS: Vec<String> = {
        let source = FUZZ_ROOT.join("targets/mod.rs");
        let targets_rs = fs::read_to_string(&source).unwrap();
        let match_fuzz_fs = regex::Regex::new(r"pub fn fuzz_(\w+)\(").unwrap();
        let target_names = match_fuzz_fs
            .captures_iter(&targets_rs)
            .map(|x| format!("fuzz_{}", &x[1]));
        target_names.collect()
    };
    static ref SEED_ROOT: PathBuf = FUZZ_ROOT.join("common/seeds");
}

#[derive(StructOpt, Debug)]
enum Cli {
    /// List all available targets
    #[structopt(name = "list-targets")]
    ListTargets,
    /// Run matched fuzz test with specific fuzzer.
    #[structopt(name = "run")]
    Run {
        /// The fuzzer to use.
        fuzzer: Fuzzer,
        /// The target fuzz to run.
        target: String,
    },
}

arg_enum! {
    #[derive(Debug, PartialEq, Eq, Clone, Copy)]
    enum Fuzzer {
        Afl,
        Honggfuzz,
        Libfuzzer,
    }
}

impl Fuzzer {
    /// Get Cargo package name of corresponding fuzzers.
    fn package_name(self) -> &'static str {
        match self {
            Fuzzer::Afl => "fuzzer-afl",
            Fuzzer::Honggfuzz => "fuzzer-honggfuzz",
            Fuzzer::Libfuzzer => "fuzzer-libfuzzer",
        }
    }

    /// Get Cargo directory of corresponding fuzzers.
    fn directory(self) -> PathBuf {
        FUZZ_ROOT.join(self.package_name())
    }
}

fn main() -> Result<(), i32> {
    use structopt::StructOpt;

    match Cli::from_args() {
        Cli::ListTargets => {
            for target in &*FUZZ_TARGETS {
                println!("{}", target);
            }
        }
        Cli::Run { fuzzer, target } => {
            if let Err(error) = run(fuzzer, &target) {
                eprintln!("Running fuzzer failed: {}", error);
                return Err(1);
            }
        }
    }
    Ok(())
}

/// Write the fuzz target source file from corresponding template file.
///
/// `target` must be a valid target.
fn write_fuzz_target_source_file(fuzzer: Fuzzer, target: &str) -> Result<(), Error> {
    use std::io::Write;

    let template_file_path = fuzzer.directory().join("template.rs");
    let template = fs::read_to_string(&template_file_path).context(format!(
        "Error reading template file {}",
        template_file_path.display()
    ))?;

    let target_file_path = fuzzer.directory().join(&format!("src/bin/{}.rs", target));
    let mut file = fs::OpenOptions::new()
        .write(true)
        .create(true)
        .truncate(true)
        .open(&target_file_path)
        .context(format!(
            "Error writing fuzz target source file {}",
            target_file_path.display()
        ))?;

    let source = template.replace("__FUZZ_CLI_TARGET__", &target).replace(
        "__FUZZ_GENERATE_COMMENT__",
        "NOTE: AUTO GENERATED FROM `template.rs`",
    );

    file.write_all(source.as_bytes())?;
    Ok(())
}

/// Run one target fuzz test with specific fuzzer
fn run(fuzzer: Fuzzer, target: &str) -> Result<(), Error> {
    if FUZZ_TARGETS.iter().find(|x| *x == target).is_none() {
        panic!(
            "Unknown fuzz target `{}`. Run `list-targets` command to see available fuzz targets.",
            target
        );
    }
    write_fuzz_target_source_file(fuzzer, target)?;
    match fuzzer {
        Fuzzer::Afl => run_afl(target),
        Fuzzer::Honggfuzz => run_honggfuzz(target),
        Fuzzer::Libfuzzer => run_libfuzzer(target),
    }
}

/// Get input seeds for fuzz target
fn get_seed_dir(target: &str) -> PathBuf {
    let seeds_dir = SEED_ROOT.join(target);
    if seeds_dir.exists() {
        seeds_dir
    } else {
        SEED_ROOT.join("default")
    }
}

/// Create corpus dir for fuzz target
fn create_corpus_dir(base: impl AsRef<Path>, target: &str) -> Result<PathBuf, Error> {
    let base = base.as_ref();
    let corpus_dir = base.join(&format!("corpus-{}", target));
    fs::create_dir_all(&corpus_dir).context(format!(
        "unable to create corpus dir for {}{}",
        base.display(),
        target
    ))?;
    Ok(corpus_dir)
}

fn pre_check(command: &mut Command, hint: &str) -> Result<(), Error> {
    let check = command
        .stdout(Stdio::null())
        .stderr(Stdio::null())
        .status()
        .unwrap();
    if !check.success() {
        Err(format_err!(
            "Pre-checking for fuzzing failed. Consider run `{}` before fuzzing.",
            hint
        ))
    } else {
        Ok(())
    }
}

/// Run one target fuzz test using AFL
fn run_afl(target: &str) -> Result<(), Error> {
    let fuzzer = Fuzzer::Afl;

    let seed_dir = get_seed_dir(target);
    let corpus_dir = create_corpus_dir(fuzzer.directory(), target)?;

    pre_check(Command::new("cargo").args(&["afl"]), "cargo install afl")?;

    // 1. cargo afl build (in fuzzer-afl directory)
    let fuzzer_build = Command::new("cargo")
        .args(&["afl", "build", "--bin", target])
        .current_dir(fuzzer.directory())
        .spawn()
        .context(format!("Failed to build {}", fuzzer))?
        .wait()
        .context(format!("Failed to complete building {}", fuzzer))?;

    if !fuzzer_build.success() {
        Err(format_err!(
            "error building afl instrumented binary, exit code {:?}",
            fuzzer_build.code()
        ))?;
    }

    // 2. cargo afl fuzz -i {seed_dir} -o {corpus_dir} target/debug/{instrumented_binary}
    let instrumented_bin = WORKSPACE_ROOT.join("target/debug").join(target);
    let fuzzer_bin = Command::new("cargo")
        .args(&["afl", "fuzz"])
        .arg("-i")
        .arg(&seed_dir)
        .arg("-o")
        .arg(&corpus_dir)
        .arg(&instrumented_bin)
        .current_dir(fuzzer.directory())
        .spawn()
        .context(format!("Failed to run {}", fuzzer))?
        .wait()
        .context(format!("Failed to wait {}", fuzzer))?;

    if !fuzzer_bin.success() {
        Err(format_err!(
            "{} exited with code {:?}",
            fuzzer,
            fuzzer_bin.code()
        ))?;
    }

    Ok(())
}

/// Run one target fuzz test using Honggfuzz
fn run_honggfuzz(target: &str) -> Result<(), Error> {
    pre_check(
        Command::new("cargo").args(&["hfuzz", "version"]),
        "cargo install hfuzz --version 0.5.34",
    )?;

    let fuzzer = Fuzzer::Honggfuzz;

    let mut rust_flags = env::var("RUSTFLAGS").unwrap_or_default();
    rust_flags.push_str("-Z sanitizer=address");

    let hfuzz_args = format!(
        "-f {} \
         --exit_upon_crash \
         {}",
        get_seed_dir(target).to_string_lossy(),
        env::var("HFUZZ_RUN_ARGS").unwrap_or_default()
    );

    let fuzzer_bin = Command::new("cargo")
        .args(&["hfuzz", "run", target])
        .env("RUSTFLAGS", &rust_flags)
        .env("HFUZZ_RUN_ARGS", &hfuzz_args)
        .current_dir(fuzzer.directory())
        .spawn()
        .context(format!("Failed to run {}", fuzzer))?
        .wait()
        .context(format!("Failed to wait {}", fuzzer))?;

    if !fuzzer_bin.success() {
        Err(format_err!(
            "{} exited with code {:?}",
            fuzzer,
            fuzzer_bin.code()
        ))?;
    }

    Ok(())
}

/// Run one target fuzz test using Libfuzzer
fn run_libfuzzer(target: &str) -> Result<(), Error> {
    let fuzzer = Fuzzer::Libfuzzer;
    let seed_dir = get_seed_dir(target);
    let corpus_dir = create_corpus_dir(fuzzer.directory(), target)?;

    #[cfg(target_os = "macos")]
    let target_platform = "x86_64-apple-darwin";
    #[cfg(target_os = "linux")]
    let target_platform = "x86_64-unknown-linux-gnu";
    #[cfg(not(any(target_os = "linux", target_os = "macos")))]
    panic!("libfuzzer-sys only supports Linux and macOS");

    // FIXME: The -C codegen-units=1 and -C incremental=..
    // below seem to workaround some difficult issues in Rust nightly
    // https://github.com/rust-lang/rust/issues/53945.
    // If this is ever fixed remember to remove the fuzz-incremental
    // entry from .gitignore.
    let mut rust_flags = env::var("RUSTFLAGS").unwrap_or_default();
    rust_flags.push_str(
        "--cfg fuzzing \
         -C codegen-units=1 \
         -C incremental=fuzz-incremental \
         -C passes=sancov \
         -C llvm-args=-sanitizer-coverage-level=4 \
         -C llvm-args=-sanitizer-coverage-trace-pc-guard \
         -C llvm-args=-sanitizer-coverage-trace-compares \
         -C llvm-args=-sanitizer-coverage-trace-divs \
         -C llvm-args=-sanitizer-coverage-trace-geps \
         -C llvm-args=-sanitizer-coverage-prune-blocks=0 \
         -C debug-assertions=on \
         -C debuginfo=0 \
         -C opt-level=3 \
         -Z sanitizer=address",
    );

    let mut asan_options = env::var("ASAN_OPTIONS").unwrap_or_default();
    asan_options.push_str(" detect_odr_violation=0");

    let fuzzer_bin = Command::new("cargo")
        .args(&["run", "--target", &target_platform, "--bin", target, "--"])
        .arg(&corpus_dir)
        .arg(&seed_dir)
        .env("RUSTFLAGS", &rust_flags)
        .env("ASAN_OPTIONS", &asan_options)
        .current_dir(fuzzer.directory())
        .spawn()
        .context(format!("Failed to run {}", fuzzer))?
        .wait()
        .context(format!("Failed to wait {}", fuzzer))?;

    if !fuzzer_bin.success() {
        Err(format_err!(
            "{} exited with code {:?}",
            fuzzer,
            fuzzer_bin.code()
        ))?;
    }

    Ok(())
}
<|endoftext|>


<commit_before>use wlroots_sys::wlr_session;

pub struct Session {
    session: *mut wlr_session
}

impl Session {
    pub(crate) unsafe fn from_ptr(session: *mut wlr_session) -> Self {
        Session { session }
    }

    pub unsafe fn as_ptr(&self) -> *mut wlr_session {
        self.session
    }
}
<commit_msg>Wrap session<commit_after>use std::marker::PhantomData;
use std::path::Path;

use libc::{c_int, c_uint, c_char};
use wlroots_sys::{wl_display, wlr_session, wlr_session_create, wlr_session_destroy,
                  wlr_session_open_file, wlr_session_close_file, wlr_session_signal_add,
                  wlr_session_change_vt, wl_listener, wl_signal, udev, udev_monitor, wlr_device,
                  dev_t};

use utils::safe_as_cstring;

pub struct Device<'session> {
    device: *mut wlr_device,
    phantom: PhantomData<&'session ()>
}

pub struct Session<'session> {
    session: *mut wlr_session,
    phantom: PhantomData<&'session ()>
}

impl <'session> Device<'session> {
    unsafe fn from_ptr<'unbound>(device: *mut wlr_device) -> Device<'unbound> {
        Device { device, phantom: PhantomData }
    }

    pub fn fd(&self) -> c_int {
        unsafe { (*self.device).fd }
    }

    pub fn dev(&self) -> dev_t {
        unsafe { (*self.device).dev }
    }
}

impl <'session> Session<'session> {
    pub(crate) unsafe fn from_ptr(session: *mut wlr_session) -> Self {
        Session { session, phantom: PhantomData }
    }

	  /// Signal for when the session becomes active/inactive.
    /// It's called when we swap virtual terminal.
    pub fn session_signal(&self) -> wl_signal {
        unsafe { (*self.session).session_signal }
    }

    pub fn active(&self) -> bool {
        unsafe { (*self.session).active }
    }

    pub fn vtnr(&self) -> c_uint {
        unsafe { (*self.session).vtnr }
    }

    pub fn seat(&self) -> [c_char; 8] {
        unsafe { (*self.session).seat }
    }

    pub fn udev(&self) -> *mut udev {
        unsafe { (*self.session).udev }
    }

    pub fn udev_monitor(&self) -> *mut udev_monitor {
        unsafe { (*self.session).mon }
    }

    pub fn devices(&self) -> Vec<Device<'session>> {
        unsafe {
            let mut devices = Vec::new();
            wl_list_for_each!((*self.session).devices,
                              link,
                              (device: wlr_device) => {
                                  devices.push(Device::from_ptr(device))
                              });
            devices
        }
    }

    /// Changes the virtual terminal.
    pub fn change_vt(&mut self, vt: c_uint) -> bool {
        unsafe {
            wlr_session_change_vt(self.session, vt)
        }
    }

    pub unsafe fn as_ptr(&self) -> *mut wlr_session {
        self.session
    }

    /// Opens a session, taking control of the current virtual terminal.
    /// This should not be called if another program is already in control
    /// of the terminal (Xorg, another Wayland compositor, etc.).
    ///
    /// If logind support is not enabled, you must have CAP_SYS_ADMIN or be root.
    /// It is safe to drop privileges after this is called.
    ///
    /// Returns `None` on error.
    pub unsafe fn new(display: *mut wl_display) -> Option<Self> {
        let session = wlr_session_create(display);
        if session.is_null() {
            None
        } else {
            Some(Session {
                session,
                phantom: PhantomData
            })
        }
    }

    /// Closes a previously opened session and restores the virtual terminal.
    /// You should call Session::close_file on each files you opened
    /// with Session::open_file before you call this.
    pub unsafe fn destroy(self) {
        wlr_session_destroy(self.session)
    }

    /// Opens the file at path.
    /// This can only be used to open DRM or evdev (input) devices.
    ///
    /// When the session becomes inactive:
    /// - DRM files lose their DRM master status
    /// - evdev files become invalid and should be closed
    ///
    /// Returns -errno on error.
    pub unsafe fn open_file<P: AsRef<Path>>(&mut self, path: P) -> c_int {
        let path_c = safe_as_cstring(path.as_ref().to_str().expect("Path was not UTF-8"));
        wlr_session_open_file(self.session, path_c.as_ptr())
    }

    pub unsafe fn close_file<P: AsRef<Path>>(&mut self, fd: c_int) {
        wlr_session_close_file(self.session, fd);
    }

    pub unsafe fn signal_add(&mut self, fd: c_int, listener: *mut wl_listener) {
        wlr_session_signal_add(self.session, fd, listener)
    }
}
<|endoftext|>


<commit_before>extern crate symbolic_expressions;

use secsp::ast::*;
use self::symbolic_expressions::Sexp;

macro_rules! cil {
    ($x:expr) => {
        $x.into_sexp()
    }
}

macro_rules! cil_list {
    [ $( $x:expr ),* $(,)* ] => {
        {
            let mut temp_vec : Vec<Sexp> = Vec::new();
            $(
                temp_vec.push($x.into());
            )*

            let sexp : Sexp = temp_vec.into();
            sexp
        }
    };
}

pub trait ToCil: Sized + Clone {
    fn into_sexp(&self) -> Sexp;
}

pub trait CilType: TypeSpecifier {
    fn requires_initializer(&self) -> bool;
}

impl CilType for SymbolType {
    fn requires_initializer(&self) -> bool {
        match *self {
            SymbolType::Context => true,
            _ => false,
        }
    }
}

fn compile_if(condition: &Expr, block: &Vec<Statement>) -> Sexp {
    let mut statement_sexpr: Sexp = cil_list!["booleanif", condition.into_sexp()];
    let mut true_branch: Sexp = cil_list!["true"];

    for stmt in block {
        true_branch.push(stmt.into_sexp());
    }

    statement_sexpr.push(true_branch);
    statement_sexpr
}

fn compile_if_else_if(
    condition: &Expr,
    block: &Vec<Statement>,
    else_ifs: &Vec<(Expr, Vec<Statement>)>,
    else_block: Option<&Vec<Statement>>,
) -> Sexp {
    let mut if_stmt = compile_if(condition, block);
    let mut false_branch = cil_list!["false"];

    let mut else_if_iter = else_ifs.into_iter().rev();
    let mut last = match else_if_iter.next() {
        Some(else_if) => {
            let (ref expr, ref statements) = *else_if;
            compile_if_else(expr, statements, else_block)
        }
        _ => panic!("compile_if_else_if called with no else_ifs"),
    };

    for else_if in else_if_iter {
        let (ref condition, ref statements) = *else_if;

        let mut stmt = compile_if(condition, statements);
        let else_branch = cil_list!["false", last];
        stmt.push(else_branch);

        last = stmt;
    }

    false_branch.push(last);
    if_stmt.push(false_branch);

    if_stmt
}

fn compile_if_else(
    condition: &Expr,
    block: &Vec<Statement>,
    else_block: Option<&Vec<Statement>>,
) -> Sexp {
    let mut if_stmt = compile_if(condition, block);

    if let Some(statements) = else_block {
        let mut false_branch = cil_list!["false"];

        for stmt in statements {
            false_branch.push(stmt.into_sexp());
        }

        if_stmt.push(false_branch);
    }

    if_stmt
}

impl ToCil for Statement {
    fn into_sexp(&self) -> Sexp {
        match *self {
            Statement::Declaration(ref decl) => decl.into_sexp(),
            Statement::MacroCall(ref id, ref params) => {
                let params_sexpr: Vec<Sexp> =
                    params.iter().map(|ref p: &Expr| p.into_sexp()).collect();

                cil_list!["call", id, params_sexpr]
            }
            Statement::IfElse {
                ref condition,
                ref then_block,
                ref else_ifs,
                ref else_block,
            } => {
                if else_ifs.is_empty() {
                    compile_if_else(condition, then_block, else_block.as_ref())
                } else {
                    compile_if_else_if(condition, then_block, else_ifs, else_block.as_ref())
                }
            }
            Statement::AccessVectorRule {
                ref rule_type,
                ref source,
                ref target,
                ref access_vector,
            } => {
                let mut rule_sexp =
                    cil_list![rule_type.to_cil(), source.into_sexp(), target.into_sexp()];

                match *access_vector {
                    AccessVector::Permission(ref expr) => {
                        rule_sexp.push(expr.into_sexp());
                    }
                    AccessVector::ClassAndPermissions(ref class, ref expr) => {
                        rule_sexp.push(cil_list![class.into_sexp(), expr.into_sexp()]);
                    }
                }

                rule_sexp
            }
            _ => Sexp::Empty,
        }
    }
}

impl ToCil for BlockType {
    fn into_sexp(&self) -> Sexp {
        self.to_cil().into()
    }
}

impl ToCil for SymbolType {
    fn into_sexp(&self) -> Sexp {
        self.to_cil().into()
    }
}

impl ToCil for MacroParameter {
    fn into_sexp(&self) -> Sexp {
        cil_list![self.qualifier.into_sexp(), self.name.clone()]
    }
}

impl ToCil for Declaration {
    fn into_sexp(&self) -> Sexp {
        match *self {
            Declaration::Block {
                ref is_abstract,
                ref qualifier,
                ref name,
                ref statements,
            } => {
                let mut statement: Sexp = cil_list![qualifier.into_sexp(), name];
                if *is_abstract {
                    let blockabstract_sexpr: Sexp = cil_list!["blockabstract", name];
                    statement.push(blockabstract_sexpr);
                }

                for stmt in statements {
                    statement.push(stmt.into_sexp());
                }

                statement
            }
            Declaration::Symbol {
                ref qualifier,
                ref name,
                ref initializer,
            } => {
                let mut declaration: Sexp = cil_list![qualifier.into_sexp(), name];

                if qualifier.requires_initializer() {
                    if let Some(ref expr) = *initializer {
                        declaration.push(expr.into_sexp());
                    } else {
                        //@todo - raise error
                    }
                }

                declaration
            }
            Declaration::Macro {
                ref name,
                ref parameters,
                ref statements,
            } => {
                let params: Vec<Sexp> = parameters.iter().map(|it| it.into_sexp()).collect();
                let mut decl: Sexp = cil_list!["macro", name, params];

                for stmt in statements {
                    decl.push(stmt.into_sexp());
                }

                decl
            }

            _ => Sexp::Empty,
        }
    }
}

impl ToCil for Expr {
    fn into_sexp(&self) -> Sexp {
        match *self {
            Expr::Binary(ref lhs, ref op, ref rhs) => {
                cil_list![cil!(op), cil!(lhs.as_ref()), cil!(rhs.as_ref())]
            }
            Expr::Unary(ref op, ref expr) => cil_list![cil!(op), cil!(expr.as_ref())],
            Expr::Variable(ref id) => id.into(),
            Expr::VariableList(ref list) => {
                let mut list_sexpr = cil_list![];

                for identifier in list {
                    list_sexpr.push(identifier);
                }

                list_sexpr
            }
            Expr::LevelRange(ref low, ref high) => cil_list![cil!(low), cil!(high)],
            Expr::Level {
                ref sensitivity,
                ref categories,
            } => {
                let categories_sexpr: Sexp = cil_list![categories.into_sexp()];

                cil_list![sensitivity, categories_sexpr]
            }
            Expr::Context {
                ref user_id,
                ref role_id,
                ref type_id,
                ref level_range,
            } => {
                let mut context_sexp: Sexp = cil_list![user_id, role_id, type_id];

                if let Some(ref expr) = *level_range {
                    context_sexp.push(expr.as_ref().into_sexp());
                }

                context_sexp
            }
            _ => Sexp::Empty, //@TODO
        }
    }
}

impl ToCil for BinaryOp {
    fn into_sexp(&self) -> Sexp {
        let result = match *self {
            BinaryOp::BitwiseAnd | BinaryOp::ConditionalAnd => "and",
            BinaryOp::BitwiseOr | BinaryOp::ConditionalOr => "or",
            BinaryOp::BitwiseXor | BinaryOp::ConditionalXor => "xor",
        };

        result.into()
    }
}

impl ToCil for UnaryOp {
    fn into_sexp(&self) -> Sexp {
        let result = match *self {
            UnaryOp::ConditionalNot | UnaryOp::BitwiseNot => "not",
        };

        result.into()
    }
}

#[cfg(test)]
mod testing {

    use super::*;

    #[test]
    pub fn compile_block_decl() {
        let decl = Declaration::Block {
            is_abstract: false,
            qualifier: BlockType::Block,
            name: "my_block".to_string(),
            statements: vec![],
        };

        let expected: Sexp = cil_list!["block", "my_block"];
        let actual = decl.into_sexp();

        assert_eq!(expected, actual);
    }

    #[test]
    pub fn compile_abstract_block_decl() {
        let decl = Declaration::Block {
            is_abstract: true,
            qualifier: BlockType::Block,
            name: "my_block".to_string(),
            statements: vec![],
        };

        let blockabstract: Sexp = cil_list!["blockabstract", "my_block"];
        let expected: Sexp = cil_list!["block", "my_block", blockabstract];
        let actual = decl.into_sexp();

        assert_eq!(expected, actual);
    }

    #[test]
    pub fn compile_conditional_exprs() {
        let inputs = vec![
            Expr::Binary(
                Box::from(Expr::var("a")),
                BinaryOp::ConditionalAnd,
                Box::from(Expr::Unary(
                    UnaryOp::ConditionalNot,
                    Box::from(Expr::var("b")),
                ))
            ),
            Expr::Binary(
                Box::from(Expr::var("a")),
                BinaryOp::ConditionalOr,
                Box::from(Expr::Binary(
                    Box::from(Expr::var("b")),
                    BinaryOp::ConditionalXor,
                    Box::from(Expr::var("c")),
                ))
            ),
        ];

        let expectations = vec![
            cil_list!["and", "a", cil_list!["not", "b"]],
            cil_list!["or", "a", cil_list!["xor", "b", "c"]],
        ];

        for id in 0..inputs.len() {
            let input = &inputs[0];
            let expected = &expectations[0];
            let actual = input.into_sexp();

            assert_eq!(expected, &actual);
        }
    }

    #[test]
    pub fn compile_if_else() {
        let input = Statement::IfElse {
            condition: Expr::var("my_bool"),
            then_block: vec![],
            else_ifs: vec![],
            else_block: Some(vec![]),
        };

        let expected =
            cil_list![
            "booleanif",
            "my_bool",
            cil_list!["true"],
            cil_list!["false"],
        ];

        let actual = input.into_sexp();
        assert_eq!(expected, actual);
    }

    #[test]
    pub fn compile_macro_call() {
        let input = Statement::MacroCall("my_macro".to_string(), vec![Expr::var("a")]);

        let expected = cil_list!["call", "my_macro", cil_list!["a"]];
        let actual = input.into_sexp();

        assert_eq!(expected, actual);
    }

    #[test]
    pub fn compile_context_decl() {
        let input = Declaration::Symbol {
            qualifier: SymbolType::Context,
            name: "my_context".to_string(),
            initializer: Some(Expr::Context {
                user_id: "user".to_string(),
                type_id: "type".to_string(),
                role_id: "role".to_string(),
                level_range: None,
            }),
        };

        let expected = cil_list!["context", "my_context", cil_list!["user", "role", "type"]];
        let actual = input.into_sexp();

        assert_eq!(expected, actual);
    }

    #[test]
    pub fn compile_access_vector_rule() {
        let input = Statement::AccessVectorRule {
            rule_type: AllowRuleType::Allow,
            source: Expr::var("src"),
            target: Expr::var("target"),
            access_vector: AccessVector::Permission(Expr::var("permission_set")),
        };

        let expected = cil_list!["allow", "src", "target", "permission_set"];
        let actual = input.into_sexp();

        assert_eq!(expected, actual);
    }

    #[test]
    pub fn compile_access_vector_rule_anonymous_perms() {
        let input = Statement::AccessVectorRule {
            rule_type: AllowRuleType::DontAudit,
            source: Expr::var("src"),
            target: Expr::var("target"),
            access_vector: AccessVector::ClassAndPermissions(
                Expr::var("security_class"),
                Expr::Binary(
                    Box::from(Expr::VariableList(
                        vec!["perm1".to_string(), "perm2".to_string()],
                    )),
                    BinaryOp::BitwiseOr,
                    Box::from(Expr::VariableList(
                        vec!["perm3".to_string(), "perm4".to_string()],
                    )),
                ),
            ),
        };

        let expected =
            cil_list![
            "dontaudit",
            "src",
            "target",
            cil_list!["security_class", cil_list!["or", cil_list!["perm1", "perm2"], cil_list!["perm3", "perm4"]]],
        ];

        let actual = input.into_sexp();
        assert_eq!(expected, actual);
    }
}<commit_msg>Clean up cil_types tests<commit_after>extern crate symbolic_expressions;

use secsp::ast::*;
use self::symbolic_expressions::Sexp;

macro_rules! cil {
    ($x:expr) => {
        $x.into_sexp()
    }
}

macro_rules! cil_list {
    [ $( $x:expr ),* $(,)* ] => {
        {
            let mut temp_vec : Vec<Sexp> = Vec::new();
            $(
                temp_vec.push($x.into());
            )*

            let sexp : Sexp = temp_vec.into();
            sexp
        }
    };
}

pub trait ToCil: Sized + Clone {
    fn into_sexp(&self) -> Sexp;
}

pub trait CilType: TypeSpecifier {
    fn requires_initializer(&self) -> bool;
}

impl CilType for SymbolType {
    fn requires_initializer(&self) -> bool {
        match *self {
            SymbolType::Context => true,
            _ => false,
        }
    }
}

fn compile_if(condition: &Expr, block: &Vec<Statement>) -> Sexp {
    let mut statement_sexpr: Sexp = cil_list!["booleanif", condition.into_sexp()];
    let mut true_branch: Sexp = cil_list!["true"];

    for stmt in block {
        true_branch.push(stmt.into_sexp());
    }

    statement_sexpr.push(true_branch);
    statement_sexpr
}

fn compile_if_else_if(
    condition: &Expr,
    block: &Vec<Statement>,
    else_ifs: &Vec<(Expr, Vec<Statement>)>,
    else_block: Option<&Vec<Statement>>,
) -> Sexp {
    let mut if_stmt = compile_if(condition, block);
    let mut false_branch = cil_list!["false"];

    let mut else_if_iter = else_ifs.into_iter().rev();
    let mut last = match else_if_iter.next() {
        Some(else_if) => {
            let (ref expr, ref statements) = *else_if;
            compile_if_else(expr, statements, else_block)
        }
        _ => panic!("compile_if_else_if called with no else_ifs"),
    };

    for else_if in else_if_iter {
        let (ref condition, ref statements) = *else_if;

        let mut stmt = compile_if(condition, statements);
        let else_branch = cil_list!["false", last];
        stmt.push(else_branch);

        last = stmt;
    }

    false_branch.push(last);
    if_stmt.push(false_branch);

    if_stmt
}

fn compile_if_else(
    condition: &Expr,
    block: &Vec<Statement>,
    else_block: Option<&Vec<Statement>>,
) -> Sexp {
    let mut if_stmt = compile_if(condition, block);

    if let Some(statements) = else_block {
        let mut false_branch = cil_list!["false"];

        for stmt in statements {
            false_branch.push(stmt.into_sexp());
        }

        if_stmt.push(false_branch);
    }

    if_stmt
}

impl ToCil for Statement {
    fn into_sexp(&self) -> Sexp {
        match *self {
            Statement::Declaration(ref decl) => decl.into_sexp(),
            Statement::MacroCall(ref id, ref params) => {
                let params_sexpr: Vec<Sexp> =
                    params.iter().map(|ref p: &Expr| p.into_sexp()).collect();

                cil_list!["call", id, params_sexpr]
            }
            Statement::IfElse {
                ref condition,
                ref then_block,
                ref else_ifs,
                ref else_block,
            } => {
                if else_ifs.is_empty() {
                    compile_if_else(condition, then_block, else_block.as_ref())
                } else {
                    compile_if_else_if(condition, then_block, else_ifs, else_block.as_ref())
                }
            }
            Statement::AccessVectorRule {
                ref rule_type,
                ref source,
                ref target,
                ref access_vector,
            } => {
                let mut rule_sexp =
                    cil_list![rule_type.to_cil(), source.into_sexp(), target.into_sexp()];

                match *access_vector {
                    AccessVector::Permission(ref expr) => {
                        rule_sexp.push(expr.into_sexp());
                    }
                    AccessVector::ClassAndPermissions(ref class, ref expr) => {
                        rule_sexp.push(cil_list![class.into_sexp(), expr.into_sexp()]);
                    }
                }

                rule_sexp
            }
            _ => Sexp::Empty,
        }
    }
}

impl ToCil for BlockType {
    fn into_sexp(&self) -> Sexp {
        self.to_cil().into()
    }
}

impl ToCil for SymbolType {
    fn into_sexp(&self) -> Sexp {
        self.to_cil().into()
    }
}

impl ToCil for MacroParameter {
    fn into_sexp(&self) -> Sexp {
        cil_list![self.qualifier.into_sexp(), self.name.clone()]
    }
}

impl ToCil for Declaration {
    fn into_sexp(&self) -> Sexp {
        match *self {
            Declaration::Block {
                ref is_abstract,
                ref qualifier,
                ref name,
                ref statements,
            } => {
                let mut statement: Sexp = cil_list![qualifier.into_sexp(), name];
                if *is_abstract {
                    let blockabstract_sexpr: Sexp = cil_list!["blockabstract", name];
                    statement.push(blockabstract_sexpr);
                }

                for stmt in statements {
                    statement.push(stmt.into_sexp());
                }

                statement
            }
            Declaration::Symbol {
                ref qualifier,
                ref name,
                ref initializer,
            } => {
                let mut declaration: Sexp = cil_list![qualifier.into_sexp(), name];

                if qualifier.requires_initializer() {
                    if let Some(ref expr) = *initializer {
                        declaration.push(expr.into_sexp());
                    } else {
                        //@todo - raise error
                    }
                }

                declaration
            }
            Declaration::Macro {
                ref name,
                ref parameters,
                ref statements,
            } => {
                let params: Vec<Sexp> = parameters.iter().map(|it| it.into_sexp()).collect();
                let mut decl: Sexp = cil_list!["macro", name, params];

                for stmt in statements {
                    decl.push(stmt.into_sexp());
                }

                decl
            }

            _ => Sexp::Empty,
        }
    }
}

impl ToCil for Expr {
    fn into_sexp(&self) -> Sexp {
        match *self {
            Expr::Binary(ref lhs, ref op, ref rhs) => {
                cil_list![cil!(op), cil!(lhs.as_ref()), cil!(rhs.as_ref())]
            }
            Expr::Unary(ref op, ref expr) => cil_list![cil!(op), cil!(expr.as_ref())],
            Expr::Variable(ref id) => id.into(),
            Expr::VariableList(ref list) => {
                let mut list_sexpr = cil_list![];

                for identifier in list {
                    list_sexpr.push(identifier);
                }

                list_sexpr
            }
            Expr::LevelRange(ref low, ref high) => cil_list![cil!(low), cil!(high)],
            Expr::Level {
                ref sensitivity,
                ref categories,
            } => {
                let categories_sexpr: Sexp = cil_list![categories.into_sexp()];

                cil_list![sensitivity, categories_sexpr]
            }
            Expr::Context {
                ref user_id,
                ref role_id,
                ref type_id,
                ref level_range,
            } => {
                let mut context_sexp: Sexp = cil_list![user_id, role_id, type_id];

                if let Some(ref expr) = *level_range {
                    context_sexp.push(expr.as_ref().into_sexp());
                }

                context_sexp
            }
            _ => Sexp::Empty, //@TODO
        }
    }
}

impl ToCil for BinaryOp {
    fn into_sexp(&self) -> Sexp {
        let result = match *self {
            BinaryOp::BitwiseAnd | BinaryOp::ConditionalAnd => "and",
            BinaryOp::BitwiseOr | BinaryOp::ConditionalOr => "or",
            BinaryOp::BitwiseXor | BinaryOp::ConditionalXor => "xor",
        };

        result.into()
    }
}

impl ToCil for UnaryOp {
    fn into_sexp(&self) -> Sexp {
        let result = match *self {
            UnaryOp::ConditionalNot | UnaryOp::BitwiseNot => "not",
        };

        result.into()
    }
}

#[cfg(test)]
mod testing {

    use super::*;
    use secsp;

    pub fn parse_and_compile_stmt(input: &str) -> Sexp {
        let stmt = match secsp::parse_from_slice(input.as_bytes()) {
            secsp::ParseResult::Ok(stmts) => stmts[0].clone(),
            _ => panic!("Unable to parse"),
        };

        stmt.into_sexp()
    }

    #[test]
    pub fn compile_block_decl() {
        let expected: Sexp = cil_list!["block", "my_block"];
        let actual = parse_and_compile_stmt("block my_block {}");

        assert_eq!(expected, actual);
    }

    #[test]
    pub fn compile_abstract_block_decl() {
        let expected: Sexp = cil_list!["block", "my_block", cil_list!["blockabstract", "my_block"]];
        let actual = parse_and_compile_stmt("abstract block my_block {}");

        assert_eq!(expected, actual);
    }

    #[test]
    pub fn compile_if_else() {
        let expected =
            cil_list![
            "booleanif",
            "my_bool",
            cil_list!["true"],
            cil_list!["false"],
        ];

        let actual = parse_and_compile_stmt(
            "
           if (my_bool) {

           } else {

           }",
        );

        assert_eq!(expected, actual);
    }

    #[test]
    pub fn compile_macro_call() {
        let expected = cil_list!["call", "my_macro", cil_list!["a"]];
        let actual = parse_and_compile_stmt("my_macro(a);");

        assert_eq!(expected, actual);
    }

    #[test]
    pub fn compile_context_decl() {
        let expected = cil_list!["context", "my_context", cil_list!["user", "role", "type"]];
        let actual = parse_and_compile_stmt("context my_context = user:role:type;");

        assert_eq!(expected, actual);
    }

    #[test]
    pub fn compile_access_vector_rule() {
        let expected = cil_list!["allow", "src", "target", "permission_set"];
        let actual = parse_and_compile_stmt("allow src target : permission_set;");

        assert_eq!(expected, actual);
    }

    #[test]
    pub fn compile_access_vector_rule_anonymous_perms() {
       let expected =
            cil_list![
            "dontaudit",
            "src",
            "target",
            cil_list!["security_class", cil_list!["or", cil_list!["perm1", "perm2"], cil_list!["perm3", "perm4"]]],
        ];

        let actual = parse_and_compile_stmt(
            "dontaudit src target : security_class ((perm1 perm2) | (perm3 perm4));",
        );

        assert_eq!(expected, actual);
    }
}<|endoftext|>


<commit_before>use postgres::{
    Rows,
    GenericConnection,
    Statement
};

use postgres::Result as PostgresResult;
use postgres::types::ToSql;
use deuterium::{SqlContext, QueryToSql};

pub type PostgresPool = ::r2d2::Pool<::r2d2_postgres::PostgresConnectionManager>;
pub type PostgresPooledConnection<'a> = ::r2d2::PooledConnection<
    'a,
    ::r2d2_postgres::PostgresConnectionManager,
>;

pub fn setup(cn_str: &str, pool_size: u32) -> PostgresPool {
    let manager = ::r2d2_postgres::PostgresConnectionManager::new(cn_str, ::postgres::SslMode::None).unwrap();
    let config = ::r2d2::Config::builder()
        .pool_size(pool_size)
        .build();

    let handler = Box::new(::r2d2::NoopErrorHandler);
    ::r2d2::Pool::new(config, manager, handler).unwrap()
}

#[allow(missing_copy_implementations)]
pub struct PostgresAdapter;

impl PostgresAdapter {
    pub fn prepare_query<'conn>(query: &QueryToSql, cn: &'conn GenericConnection) -> (SqlContext, PostgresResult<Statement<'conn>>){
        let mut ctx = SqlContext::new(Box::new(::deuterium::sql::adapter::PostgreSqlAdapter));
        let sql = query.to_final_sql(&mut ctx);

        (ctx, cn.prepare(&sql))
    }

    pub fn prepare_params<'a>(
            ext_params: &[&'a ToSql],
            ctx_params: &'a[Box<ToSql + 'static>]
        ) -> Vec<&'a (ToSql + 'a)> {

        let mut final_params = vec![];

        for param in ext_params.iter() {
            final_params.push(*param);
        }

        for param in ctx_params.iter() {
            final_params.push(&**param);
        }

        final_params
    }

    pub fn query<'conn, 'a>(stm: &'conn Statement<'conn>, params: &[&'a ToSql], ctx_params: &'a[Box<ToSql + 'static>]) -> PostgresResult<Rows<'conn>> {
        stm.query(&PostgresAdapter::prepare_params(params, ctx_params))
    }

    pub fn execute<'conn, 'a>(stm: &'conn Statement<'conn>, params: &[&'a ToSql], ctx_params: &'a[Box<ToSql + 'static>]) -> PostgresResult<u64> {
        stm.execute(&PostgresAdapter::prepare_params(params, ctx_params))
    }
}

pub trait FromRow {
    fn from_row<T, L>(query: &::deuterium::SelectQuery<T, L, Self>, row: &::postgres::Row) -> Self;
}

pub fn from_row<T, L, M: FromRow>(query: &::deuterium::SelectQuery<T, L, M>, row: &::postgres::Row) -> M {
    FromRow::from_row(query, row)
}

#[macro_export]
macro_rules! to_sql_string_pg {
    ($query:expr) => ({
        let mut ctx = ::deuterium::SqlContext::new(Box::new(::deuterium::sql::adapter::PostgreSqlAdapter));
        $query.to_final_sql(&mut ctx)
    })
}

#[macro_export]
macro_rules! query_pg {
    ($query:expr, $cn:expr, $params:expr, $rows:ident, $blk:block) => ({
        let (ctx, maybe_stm) = ::deuterium_orm::adapter::postgres::PostgresAdapter::prepare_query($query, $cn);
        let stm = match maybe_stm {
            Ok(stm) => stm,
            Err(e) => panic!("SQL query `{}` panicked at {}:{} with error `{}`",
                to_sql_string_pg!($query), file!(), line!(), e
            )
        };

        let $rows = ::deuterium_orm::adapter::postgres::PostgresAdapter::query(&stm, $params, ctx.data());

        let $rows = match $rows {
            Ok($rows) => $rows,
            Err(e) => panic!("SQL query `{}` panicked at {}:{} with error `{}`",
                to_sql_string_pg!($query), file!(), line!(), e
            ),
        };

        $blk
    });
}

#[macro_export]
macro_rules! query_models_iter {
    ($query:expr, $cn:expr, $params:expr) => (
        query_pg!($query, $cn, $params, rows, {
            rows.iter().map(|row| {
                ::deuterium_orm::adapter::postgres::from_row($query, &row)
            })
        })
    )
}

#[macro_export]
macro_rules! query_models {
    ($query:expr, $cn:expr, $params:expr) => (
        query_pg!($query, $cn, $params, rows, {
            let vec: Vec<_> = rows.iter().map(|row| {
                ::deuterium_orm::adapter::postgres::from_row($query, &row)
            }).collect();
            vec
        })
    )
}

#[macro_export]
macro_rules! query_model {
    ($query:expr, $cn:expr, $params:expr) => (
        query_pg!($query, $cn, $params, rows, {
            rows.iter().take(1).next().map(|row| {
                ::deuterium_orm::adapter::postgres::from_row($query, &row)
            })
        })
    )
}

#[macro_export]
macro_rules! exec_pg_safe {
    ($query:expr, $cn:expr, $params:expr) => ({
        let (ctx, maybe_stm) = ::deuterium_orm::adapter::postgres::PostgresAdapter::prepare_query($query, $cn);
        let stm = maybe_stm.unwrap();
        ::deuterium_orm::adapter::postgres::PostgresAdapter::execute(&stm, $params, ctx.data())
    })
}

#[macro_export]
macro_rules! exec_pg {
    ($query:expr, $cn:expr, $params:expr) => ({
        match exec_pg_safe!($query, $cn, $params) {
            Ok(res) => res,
            Err(e) => panic!("SQL query `{}` panicked at {}:{} with error `{}`",
                to_sql_string_pg!($query), file!(), line!(), e
            )
        }
    })
}

#[macro_export]
macro_rules! try_pg {
    ($e:expr) => (
        match $e {
            Ok(ok) => ok,
            Err(err) => return Err(::postgres::Error::IoError(err))
        }
    )
}

#[macro_export]
macro_rules! deuterium_enum {
    ($en:ty) => (
        impl ::postgres::types::FromSql for $en {
            fn from_sql<R: ::std::io::Read>(ty: &::postgres::types::Type, raw: &mut R) -> ::postgres::Result<$en> {
                use ::byteorder::{ReadBytesExt};
                let val = raw.read_u8();
                match val {
                    Ok(val) => Ok(::num::FromPrimitive::from_u8(val).unwrap()),
                    Err(_) => Err(::postgres::Error::WrongType(ty.clone()))
                }
            }

            fn accepts(_ty: &::postgres::types::Type) -> bool {
                true
            }
        }

        impl ::deuterium::ToSql for $en {
            fn to_sql(&self, ctx: &mut ::deuterium::SqlContext) -> String {
                let i = self.clone() as i16;
                i.to_predicate_value(ctx)
            }
        }

        impl ::deuterium::UntypedExpression for $en {
            fn expression_as_sql(&self) -> &ToSql {
                self
            }

            fn upcast_expression(&self) -> SharedExpression {
                let i = self.clone() as i16;
                ::std::rc::Rc::new(Box::new(i) as ::deuterium::BoxedExpression)
            }
        }

        impl ::deuterium::ToExpression<$en> for $en {}
        impl ::deuterium::ToExpression<i16> for $en {}
        impl ::deuterium::ToExpression<RawExpression> for $en {}

        impl ::deuterium::ToPredicateValue for $en {
            fn to_predicate_value(&self, ctx: &mut SqlContext) -> String {
                let i = self.clone() as i16;
                ctx.hold(Box::new(i))
            }
        }
    )
}
<commit_msg>fix(adapter): change `use postgres::Rows;` to `use postgres::rows::Rows;`<commit_after>use postgres::{
    GenericConnection,
    Statement
};

use postgres::rows::Rows;
use postgres::Result as PostgresResult;
use postgres::types::ToSql;
use deuterium::{SqlContext, QueryToSql};

pub type PostgresPool = ::r2d2::Pool<::r2d2_postgres::PostgresConnectionManager>;
pub type PostgresPooledConnection<'a> = ::r2d2::PooledConnection<
    'a,
    ::r2d2_postgres::PostgresConnectionManager,
>;

pub fn setup(cn_str: &str, pool_size: u32) -> PostgresPool {
    let manager = ::r2d2_postgres::PostgresConnectionManager::new(cn_str, ::postgres::SslMode::None).unwrap();
    let config = ::r2d2::Config::builder()
        .pool_size(pool_size)
        .build();

    let handler = Box::new(::r2d2::NoopErrorHandler);
    ::r2d2::Pool::new(config, manager, handler).unwrap()
}

#[allow(missing_copy_implementations)]
pub struct PostgresAdapter;

impl PostgresAdapter {
    pub fn prepare_query<'conn>(query: &QueryToSql, cn: &'conn GenericConnection) -> (SqlContext, PostgresResult<Statement<'conn>>){
        let mut ctx = SqlContext::new(Box::new(::deuterium::sql::adapter::PostgreSqlAdapter));
        let sql = query.to_final_sql(&mut ctx);

        (ctx, cn.prepare(&sql))
    }

    pub fn prepare_params<'a>(
            ext_params: &[&'a ToSql],
            ctx_params: &'a[Box<ToSql + 'static>]
        ) -> Vec<&'a (ToSql + 'a)> {

        let mut final_params = vec![];

        for param in ext_params.iter() {
            final_params.push(*param);
        }

        for param in ctx_params.iter() {
            final_params.push(&**param);
        }

        final_params
    }

    pub fn query<'conn, 'a>(stm: &'conn Statement<'conn>, params: &[&'a ToSql], ctx_params: &'a[Box<ToSql + 'static>]) -> PostgresResult<Rows<'conn>> {
        stm.query(&PostgresAdapter::prepare_params(params, ctx_params))
    }

    pub fn execute<'conn, 'a>(stm: &'conn Statement<'conn>, params: &[&'a ToSql], ctx_params: &'a[Box<ToSql + 'static>]) -> PostgresResult<u64> {
        stm.execute(&PostgresAdapter::prepare_params(params, ctx_params))
    }
}

pub trait FromRow {
    fn from_row<T, L>(query: &::deuterium::SelectQuery<T, L, Self>, row: &::postgres::rows::Row) -> Self;
}

pub fn from_row<T, L, M: FromRow>(query: &::deuterium::SelectQuery<T, L, M>, row: &::postgres::rows::Row) -> M {
    FromRow::from_row(query, row)
}

#[macro_export]
macro_rules! to_sql_string_pg {
    ($query:expr) => ({
        let mut ctx = ::deuterium::SqlContext::new(Box::new(::deuterium::sql::adapter::PostgreSqlAdapter));
        $query.to_final_sql(&mut ctx)
    })
}

#[macro_export]
macro_rules! query_pg {
    ($query:expr, $cn:expr, $params:expr, $rows:ident, $blk:block) => ({
        let (ctx, maybe_stm) = ::deuterium_orm::adapter::postgres::PostgresAdapter::prepare_query($query, $cn);
        let stm = match maybe_stm {
            Ok(stm) => stm,
            Err(e) => panic!("SQL query `{}` panicked at {}:{} with error `{}`",
                to_sql_string_pg!($query), file!(), line!(), e
            )
        };

        let $rows = ::deuterium_orm::adapter::postgres::PostgresAdapter::query(&stm, $params, ctx.data());

        let $rows = match $rows {
            Ok($rows) => $rows,
            Err(e) => panic!("SQL query `{}` panicked at {}:{} with error `{}`",
                to_sql_string_pg!($query), file!(), line!(), e
            ),
        };

        $blk
    });
}

#[macro_export]
macro_rules! query_models_iter {
    ($query:expr, $cn:expr, $params:expr) => (
        query_pg!($query, $cn, $params, rows, {
            rows.iter().map(|row| {
                ::deuterium_orm::adapter::postgres::from_row($query, &row)
            })
        })
    )
}

#[macro_export]
macro_rules! query_models {
    ($query:expr, $cn:expr, $params:expr) => (
        query_pg!($query, $cn, $params, rows, {
            let vec: Vec<_> = rows.iter().map(|row| {
                ::deuterium_orm::adapter::postgres::from_row($query, &row)
            }).collect();
            vec
        })
    )
}

#[macro_export]
macro_rules! query_model {
    ($query:expr, $cn:expr, $params:expr) => (
        query_pg!($query, $cn, $params, rows, {
            rows.iter().take(1).next().map(|row| {
                ::deuterium_orm::adapter::postgres::from_row($query, &row)
            })
        })
    )
}

#[macro_export]
macro_rules! exec_pg_safe {
    ($query:expr, $cn:expr, $params:expr) => ({
        let (ctx, maybe_stm) = ::deuterium_orm::adapter::postgres::PostgresAdapter::prepare_query($query, $cn);
        let stm = maybe_stm.unwrap();
        ::deuterium_orm::adapter::postgres::PostgresAdapter::execute(&stm, $params, ctx.data())
    })
}

#[macro_export]
macro_rules! exec_pg {
    ($query:expr, $cn:expr, $params:expr) => ({
        match exec_pg_safe!($query, $cn, $params) {
            Ok(res) => res,
            Err(e) => panic!("SQL query `{}` panicked at {}:{} with error `{}`",
                to_sql_string_pg!($query), file!(), line!(), e
            )
        }
    })
}

#[macro_export]
macro_rules! try_pg {
    ($e:expr) => (
        match $e {
            Ok(ok) => ok,
            Err(err) => return Err(::postgres::Error::IoError(err))
        }
    )
}

#[macro_export]
macro_rules! deuterium_enum {
    ($en:ty) => (
        impl ::postgres::types::FromSql for $en {
            fn from_sql<R: ::std::io::Read>(ty: &::postgres::types::Type, raw: &mut R) -> ::postgres::Result<$en> {
                use ::byteorder::{ReadBytesExt};
                let val = raw.read_u8();
                match val {
                    Ok(val) => Ok(::num::FromPrimitive::from_u8(val).unwrap()),
                    Err(_) => Err(::postgres::Error::WrongType(ty.clone()))
                }
            }

            fn accepts(_ty: &::postgres::types::Type) -> bool {
                true
            }
        }

        impl ::deuterium::ToSql for $en {
            fn to_sql(&self, ctx: &mut ::deuterium::SqlContext) -> String {
                let i = self.clone() as i16;
                i.to_predicate_value(ctx)
            }
        }

        impl ::deuterium::UntypedExpression for $en {
            fn expression_as_sql(&self) -> &ToSql {
                self
            }

            fn upcast_expression(&self) -> SharedExpression {
                let i = self.clone() as i16;
                ::std::rc::Rc::new(Box::new(i) as ::deuterium::BoxedExpression)
            }
        }

        impl ::deuterium::ToExpression<$en> for $en {}
        impl ::deuterium::ToExpression<i16> for $en {}
        impl ::deuterium::ToExpression<RawExpression> for $en {}

        impl ::deuterium::ToPredicateValue for $en {
            fn to_predicate_value(&self, ctx: &mut SqlContext) -> String {
                let i = self.clone() as i16;
                ctx.hold(Box::new(i))
            }
        }
    )
}
<|endoftext|>


<commit_before>#![allow(unused_imports, dead_code)]
use std::{io, time};
use std::net::{SocketAddr, Shutdown};
use std::collections::VecDeque;
use std::time::Duration;

use actix::{fut, Actor, ActorFuture, Arbiter, Context,
            Handler, Message, ActorResponse, Supervised};
use actix::registry::ArbiterService;
use actix::fut::WrapFuture;
use actix::actors::{Connector, ConnectorError, Connect as ResolveConnect};

use http::{Uri, HttpTryFrom, Error as HttpError};
use futures::{Async, Future, Poll};
use tokio_core::reactor::Timeout;
use tokio_core::net::{TcpStream, TcpStreamNew};
use tokio_io::{AsyncRead, AsyncWrite};

#[cfg(feature="alpn")]
use openssl::ssl::{SslMethod, SslConnector, SslVerifyMode, Error as OpensslError};
#[cfg(feature="alpn")]
use tokio_openssl::SslConnectorExt;

use HAS_OPENSSL;
use server::IoStream;

#[derive(Debug)]
/// `Connect` type represents message that can be send to `ClientConnector`
/// with connection request.
pub struct Connect(pub Uri);

impl Connect {
    /// Create `Connect` message for specified `Uri`
    pub fn new<U>(uri: U) -> Result<Connect, HttpError> where Uri: HttpTryFrom<U> {
        Ok(Connect(Uri::try_from(uri).map_err(|e| e.into())?))
    }
}

impl Message for Connect {
    type Result = Result<Connection, ClientConnectorError>;
}

/// A set of errors that can occur during connecting to a http host
#[derive(Fail, Debug)]
pub enum ClientConnectorError {
    /// Invalid url
    #[fail(display="Invalid url")]
    InvalidUrl,

    /// SSL feature is not enabled
    #[fail(display="SSL is not supported")]
    SslIsNotSupported,

    /// SSL error
    #[cfg(feature="alpn")]
    #[fail(display="{}", _0)]
    SslError(OpensslError),

    /// Connection error
    #[fail(display = "{}", _0)]
    Connector(ConnectorError),

    /// Connecting took too long
    #[fail(display = "Timeout out while establishing connection")]
    Timeout,

    /// Connector has been disconnected
    #[fail(display = "Internal error: connector has been disconnected")]
    Disconnected,

    /// Connection io error
    #[fail(display = "{}", _0)]
    IoError(io::Error),
}

impl From<ConnectorError> for ClientConnectorError {
    fn from(err: ConnectorError) -> ClientConnectorError {
        ClientConnectorError::Connector(err)
    }
}

pub struct ClientConnector {
    #[cfg(feature="alpn")]
    connector: SslConnector,
}

impl Actor for ClientConnector {
    type Context = Context<ClientConnector>;
}

impl Supervised for ClientConnector {}

impl ArbiterService for ClientConnector {}

impl Default for ClientConnector {
    fn default() -> ClientConnector {
        #[cfg(feature="alpn")]
        {
            let mut builder = SslConnector::builder(SslMethod::tls()).unwrap();
            builder.set_verify(SslVerifyMode::NONE);
            ClientConnector {
                connector: builder.build()
            }
        }

        #[cfg(not(feature="alpn"))]
        ClientConnector {}
    }
}

impl ClientConnector {

    #[cfg(feature="alpn")]
    /// Create `ClientConnector` actor with custom `SslConnector` instance.
    ///
    /// By default `ClientConnector` uses very simple ssl configuration.
    /// With `with_connector` method it is possible to use custom `SslConnector`
    /// object.
    ///
    /// ```rust
    /// # #![cfg(feature="alpn")]
    /// # extern crate actix;
    /// # extern crate actix_web;
    /// # extern crate futures;
    /// # use futures::Future;
    /// # use std::io::Write;
    /// extern crate openssl;
    /// use actix::prelude::*;
    /// use actix_web::client::{Connect, ClientConnector};
    ///
    /// use openssl::ssl::{SslMethod, SslConnector};
    ///
    /// fn main() {
    ///     let sys = System::new("test");
    ///
    ///     // Start `ClientConnector` with custom `SslConnector`
    ///     let ssl_conn = SslConnector::builder(SslMethod::tls()).unwrap().build();
    ///     let conn: Address<_> = ClientConnector::with_connector(ssl_conn).start();
    ///
    ///     Arbiter::handle().spawn({
    ///         conn.call(
    ///             Connect::new("https://www.rust-lang.org").unwrap()) // <- connect to host
    ///                 .map_err(|_| ())
    ///                 .and_then(|res| {
    ///                     if let Ok(mut stream) = res {
    ///                         stream.write_all(b"GET / HTTP/1.0\r\n\r\n").unwrap();
    ///                     }
    /// #                   Arbiter::system().do_send(actix::msgs::SystemExit(0));
    ///                     Ok(())
    ///                 })
    ///     });
    ///
    ///     sys.run();
    /// }
    /// ```
    pub fn with_connector(connector: SslConnector) -> ClientConnector {
        ClientConnector {
            connector: connector
        }
    }
}

impl Handler<Connect> for ClientConnector {
    type Result = ActorResponse<ClientConnector, Connection, ClientConnectorError>;

    fn handle(&mut self, msg: Connect, _: &mut Self::Context) -> Self::Result {
        let uri = &msg.0;

        // host name is required
        if uri.host().is_none() {
            return ActorResponse::reply(Err(ClientConnectorError::InvalidUrl))
        }

        // supported protocols
        let proto = match uri.scheme_part() {
            Some(scheme) => match Protocol::from(scheme.as_str()) {
                Some(proto) => proto,
                None => return ActorResponse::reply(Err(ClientConnectorError::InvalidUrl)),
            },
            None => return ActorResponse::reply(Err(ClientConnectorError::InvalidUrl)),
        };

        // check ssl availability
        if proto.is_secure() && !HAS_OPENSSL { //&& !HAS_TLS {
            return ActorResponse::reply(Err(ClientConnectorError::SslIsNotSupported))
        }

        let host = uri.host().unwrap().to_owned();
        let port = uri.port().unwrap_or_else(|| proto.port());

        ActorResponse::async(
            Connector::from_registry()
                .send(ResolveConnect::host_and_port(&host, port))
                .into_actor(self)
                .map_err(|_, _, _| ClientConnectorError::Disconnected)
                .and_then(move |res, _act, _| {
                    #[cfg(feature="alpn")]
                    match res {
                        Err(err) => fut::Either::B(fut::err(err.into())),
                        Ok(stream) => {
                            if proto.is_secure() {
                                fut::Either::A(
                                    _act.connector.connect_async(&host, stream)
                                        .map_err(|e| ClientConnectorError::SslError(e))
                                        .map(|stream| Connection{stream: Box::new(stream)})
                                        .into_actor(_act))
                            } else {
                                fut::Either::B(fut::ok(Connection{stream: Box::new(stream)}))
                            }
                        }
                    }

                    #[cfg(not(feature="alpn"))]
                    match res {
                        Err(err) => fut::err(err.into()),
                        Ok(stream) => {
                            if proto.is_secure() {
                                fut::err(ClientConnectorError::SslIsNotSupported)
                            } else {
                                fut::ok(Connection{stream: Box::new(stream)})
                            }
                        }
                    }
                }))
    }
}

#[derive(PartialEq, Hash, Debug, Clone, Copy)]
enum Protocol {
    Http,
    Https,
    Ws,
    Wss,
}

impl Protocol {
    fn from(s: &str) -> Option<Protocol> {
        match s {
            "http" => Some(Protocol::Http),
            "https" => Some(Protocol::Https),
            "ws" => Some(Protocol::Ws),
            "wss" => Some(Protocol::Wss),
            _ => None,
        }
    }

    fn is_secure(&self) -> bool {
        match *self {
            Protocol::Https | Protocol::Wss => true,
            _ => false,
        }
    }

    fn port(&self) -> u16 {
        match *self {
            Protocol::Http | Protocol::Ws => 80,
            Protocol::Https | Protocol::Wss => 443
        }
    }
}

pub struct Connection {
    stream: Box<IoStream>,
}

impl Connection {
    pub fn stream(&mut self) -> &mut IoStream {
        &mut *self.stream
    }
}

impl IoStream for Connection {
    fn shutdown(&mut self, how: Shutdown) -> io::Result<()> {
        IoStream::shutdown(&mut *self.stream, how)
    }

    #[inline]
    fn set_nodelay(&mut self, nodelay: bool) -> io::Result<()> {
        IoStream::set_nodelay(&mut *self.stream, nodelay)
    }

    #[inline]
    fn set_linger(&mut self, dur: Option<time::Duration>) -> io::Result<()> {
        IoStream::set_linger(&mut *self.stream, dur)
    }
}

impl io::Read for Connection {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.stream.read(buf)
    }
}

impl AsyncRead for Connection {}

impl io::Write for Connection {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.stream.write(buf)
    }

    fn flush(&mut self) -> io::Result<()> {
        self.stream.flush()
    }
}

impl AsyncWrite for Connection {
    fn shutdown(&mut self) -> Poll<(), io::Error> {
        self.stream.shutdown()
    }
}
<commit_msg>fix doc test<commit_after>#![allow(unused_imports, dead_code)]
use std::{io, time};
use std::net::{SocketAddr, Shutdown};
use std::collections::VecDeque;
use std::time::Duration;

use actix::{fut, Actor, ActorFuture, Arbiter, Context,
            Handler, Message, ActorResponse, Supervised};
use actix::registry::ArbiterService;
use actix::fut::WrapFuture;
use actix::actors::{Connector, ConnectorError, Connect as ResolveConnect};

use http::{Uri, HttpTryFrom, Error as HttpError};
use futures::{Async, Future, Poll};
use tokio_core::reactor::Timeout;
use tokio_core::net::{TcpStream, TcpStreamNew};
use tokio_io::{AsyncRead, AsyncWrite};

#[cfg(feature="alpn")]
use openssl::ssl::{SslMethod, SslConnector, SslVerifyMode, Error as OpensslError};
#[cfg(feature="alpn")]
use tokio_openssl::SslConnectorExt;

use HAS_OPENSSL;
use server::IoStream;

#[derive(Debug)]
/// `Connect` type represents message that can be send to `ClientConnector`
/// with connection request.
pub struct Connect(pub Uri);

impl Connect {
    /// Create `Connect` message for specified `Uri`
    pub fn new<U>(uri: U) -> Result<Connect, HttpError> where Uri: HttpTryFrom<U> {
        Ok(Connect(Uri::try_from(uri).map_err(|e| e.into())?))
    }
}

impl Message for Connect {
    type Result = Result<Connection, ClientConnectorError>;
}

/// A set of errors that can occur during connecting to a http host
#[derive(Fail, Debug)]
pub enum ClientConnectorError {
    /// Invalid url
    #[fail(display="Invalid url")]
    InvalidUrl,

    /// SSL feature is not enabled
    #[fail(display="SSL is not supported")]
    SslIsNotSupported,

    /// SSL error
    #[cfg(feature="alpn")]
    #[fail(display="{}", _0)]
    SslError(OpensslError),

    /// Connection error
    #[fail(display = "{}", _0)]
    Connector(ConnectorError),

    /// Connecting took too long
    #[fail(display = "Timeout out while establishing connection")]
    Timeout,

    /// Connector has been disconnected
    #[fail(display = "Internal error: connector has been disconnected")]
    Disconnected,

    /// Connection io error
    #[fail(display = "{}", _0)]
    IoError(io::Error),
}

impl From<ConnectorError> for ClientConnectorError {
    fn from(err: ConnectorError) -> ClientConnectorError {
        ClientConnectorError::Connector(err)
    }
}

pub struct ClientConnector {
    #[cfg(feature="alpn")]
    connector: SslConnector,
}

impl Actor for ClientConnector {
    type Context = Context<ClientConnector>;
}

impl Supervised for ClientConnector {}

impl ArbiterService for ClientConnector {}

impl Default for ClientConnector {
    fn default() -> ClientConnector {
        #[cfg(feature="alpn")]
        {
            let mut builder = SslConnector::builder(SslMethod::tls()).unwrap();
            builder.set_verify(SslVerifyMode::NONE);
            ClientConnector {
                connector: builder.build()
            }
        }

        #[cfg(not(feature="alpn"))]
        ClientConnector {}
    }
}

impl ClientConnector {

    #[cfg(feature="alpn")]
    /// Create `ClientConnector` actor with custom `SslConnector` instance.
    ///
    /// By default `ClientConnector` uses very simple ssl configuration.
    /// With `with_connector` method it is possible to use custom `SslConnector`
    /// object.
    ///
    /// ```rust
    /// # #![cfg(feature="alpn")]
    /// # extern crate actix;
    /// # extern crate actix_web;
    /// # extern crate futures;
    /// # use futures::Future;
    /// # use std::io::Write;
    /// extern crate openssl;
    /// use actix::prelude::*;
    /// use actix_web::client::{Connect, ClientConnector};
    ///
    /// use openssl::ssl::{SslMethod, SslConnector};
    ///
    /// fn main() {
    ///     let sys = System::new("test");
    ///
    ///     // Start `ClientConnector` with custom `SslConnector`
    ///     let ssl_conn = SslConnector::builder(SslMethod::tls()).unwrap().build();
    ///     let conn: Address<_> = ClientConnector::with_connector(ssl_conn).start();
    ///
    ///     Arbiter::handle().spawn({
    ///         conn.send(
    ///             Connect::new("https://www.rust-lang.org").unwrap()) // <- connect to host
    ///                 .map_err(|_| ())
    ///                 .and_then(|res| {
    ///                     if let Ok(mut stream) = res {
    ///                         stream.write_all(b"GET / HTTP/1.0\r\n\r\n").unwrap();
    ///                     }
    /// #                   Arbiter::system().do_send(actix::msgs::SystemExit(0));
    ///                     Ok(())
    ///                 })
    ///     });
    ///
    ///     sys.run();
    /// }
    /// ```
    pub fn with_connector(connector: SslConnector) -> ClientConnector {
        ClientConnector {
            connector: connector
        }
    }
}

impl Handler<Connect> for ClientConnector {
    type Result = ActorResponse<ClientConnector, Connection, ClientConnectorError>;

    fn handle(&mut self, msg: Connect, _: &mut Self::Context) -> Self::Result {
        let uri = &msg.0;

        // host name is required
        if uri.host().is_none() {
            return ActorResponse::reply(Err(ClientConnectorError::InvalidUrl))
        }

        // supported protocols
        let proto = match uri.scheme_part() {
            Some(scheme) => match Protocol::from(scheme.as_str()) {
                Some(proto) => proto,
                None => return ActorResponse::reply(Err(ClientConnectorError::InvalidUrl)),
            },
            None => return ActorResponse::reply(Err(ClientConnectorError::InvalidUrl)),
        };

        // check ssl availability
        if proto.is_secure() && !HAS_OPENSSL { //&& !HAS_TLS {
            return ActorResponse::reply(Err(ClientConnectorError::SslIsNotSupported))
        }

        let host = uri.host().unwrap().to_owned();
        let port = uri.port().unwrap_or_else(|| proto.port());

        ActorResponse::async(
            Connector::from_registry()
                .send(ResolveConnect::host_and_port(&host, port))
                .into_actor(self)
                .map_err(|_, _, _| ClientConnectorError::Disconnected)
                .and_then(move |res, _act, _| {
                    #[cfg(feature="alpn")]
                    match res {
                        Err(err) => fut::Either::B(fut::err(err.into())),
                        Ok(stream) => {
                            if proto.is_secure() {
                                fut::Either::A(
                                    _act.connector.connect_async(&host, stream)
                                        .map_err(|e| ClientConnectorError::SslError(e))
                                        .map(|stream| Connection{stream: Box::new(stream)})
                                        .into_actor(_act))
                            } else {
                                fut::Either::B(fut::ok(Connection{stream: Box::new(stream)}))
                            }
                        }
                    }

                    #[cfg(not(feature="alpn"))]
                    match res {
                        Err(err) => fut::err(err.into()),
                        Ok(stream) => {
                            if proto.is_secure() {
                                fut::err(ClientConnectorError::SslIsNotSupported)
                            } else {
                                fut::ok(Connection{stream: Box::new(stream)})
                            }
                        }
                    }
                }))
    }
}

#[derive(PartialEq, Hash, Debug, Clone, Copy)]
enum Protocol {
    Http,
    Https,
    Ws,
    Wss,
}

impl Protocol {
    fn from(s: &str) -> Option<Protocol> {
        match s {
            "http" => Some(Protocol::Http),
            "https" => Some(Protocol::Https),
            "ws" => Some(Protocol::Ws),
            "wss" => Some(Protocol::Wss),
            _ => None,
        }
    }

    fn is_secure(&self) -> bool {
        match *self {
            Protocol::Https | Protocol::Wss => true,
            _ => false,
        }
    }

    fn port(&self) -> u16 {
        match *self {
            Protocol::Http | Protocol::Ws => 80,
            Protocol::Https | Protocol::Wss => 443
        }
    }
}

pub struct Connection {
    stream: Box<IoStream>,
}

impl Connection {
    pub fn stream(&mut self) -> &mut IoStream {
        &mut *self.stream
    }
}

impl IoStream for Connection {
    fn shutdown(&mut self, how: Shutdown) -> io::Result<()> {
        IoStream::shutdown(&mut *self.stream, how)
    }

    #[inline]
    fn set_nodelay(&mut self, nodelay: bool) -> io::Result<()> {
        IoStream::set_nodelay(&mut *self.stream, nodelay)
    }

    #[inline]
    fn set_linger(&mut self, dur: Option<time::Duration>) -> io::Result<()> {
        IoStream::set_linger(&mut *self.stream, dur)
    }
}

impl io::Read for Connection {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.stream.read(buf)
    }
}

impl AsyncRead for Connection {}

impl io::Write for Connection {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.stream.write(buf)
    }

    fn flush(&mut self) -> io::Result<()> {
        self.stream.flush()
    }
}

impl AsyncWrite for Connection {
    fn shutdown(&mut self) -> Poll<(), io::Error> {
        self.stream.shutdown()
    }
}
<|endoftext|>


<commit_before>// TODO
// impl ToGeojson for ....
// generic number instead of f64 for position?
// rename Position to Pos

extern crate serialize;

use std::collections::TreeMap;
use serialize::json::ToJson;
use serialize::json;

/*
 * Position
 * GeoJSON Format Specification § 2.1.1
 * http://geojson.org/geojson-spec.html#positions
 */
pub struct Position(Vec<f64>);

impl ToJson for Position {
    fn to_json(&self) -> json::Json {
        let &Position(ref nums) = self;
        nums.to_json()
    }
}

/*
 * Point
 * GeoJSON Format Specification § 2.1.2
 * http://geojson.org/geojson-spec.html#point
 */
pub struct Point {
    coordinates: Position,
}

impl ToJson for Point {
    fn to_json(&self) -> json::Json {
        let mut d = TreeMap::new();
        d.insert("type".to_string(), "Point".to_string().to_json());
        d.insert("coordinates".to_string(), self.coordinates.to_json());
        d.to_json()
    }
}

/*
 * MultiPoint
 * GeoJSON Format Specification § 2.1.3
 * http://geojson.org/geojson-spec.html#multipoint
 */
pub struct MultiPoint {
    points: Vec<Point>,
}

impl ToJson for MultiPoint {
    fn to_json(&self) -> json::Json {
        let mut d = TreeMap::new();
        d.insert("type".to_string(), "MultiPoint".to_string().to_json());
        d.insert("coordinates".to_string(), self.points.to_json());
        d.to_json()
    }
}

/*
 * LineString
 * GeoJSON Format Specification § 2.1.4
 * http://geojson.org/geojson-spec.html#linestring
 */
pub struct LineString {
    coordinates: Vec<Position>,
}

impl ToJson for LineString {
    fn to_json(&self) -> json::Json {
        let mut d = TreeMap::new();
        d.insert("type".to_string(), "LineString".to_string().to_json());
        d.insert("coordinates".to_string(), self.coordinates.to_json());
        d.to_json()
    }
}

/*
 * MultiLineString
 * GeoJSON Format Specification § 2.1.5
 * http://geojson.org/geojson-spec.html#multilinestring
 */

pub struct MultiLineString {
    line_strings: Vec<LineString>,
}

impl ToJson for MultiLineString {
    fn to_json(&self) -> json::Json {
        let mut d = TreeMap::new();
        d.insert("type".to_string(), "MultiLineString".to_string().to_json());
        d.insert("coordinates".to_string(), self.line_strings.to_json());
        d.to_json()
    }
}

fn main() {
    let point = Point {
        coordinates: Position(vec![1., 2., 3.]),
    };

    let j: json::Json = point.to_json();
    let s: String = j.to_pretty_str();

    println!("{}", s);
}
<commit_msg>Implement Polygon<commit_after>// TODO
// impl ToGeojson for ....
// generic number instead of f64 for position?
// rename Position to Pos

extern crate serialize;

use std::collections::TreeMap;
use serialize::json::ToJson;
use serialize::json;

/*
 * Position
 * GeoJSON Format Specification § 2.1.1
 * http://geojson.org/geojson-spec.html#positions
 */
pub struct Position(Vec<f64>);

impl ToJson for Position {
    fn to_json(&self) -> json::Json {
        let &Position(ref nums) = self;
        nums.to_json()
    }
}

impl Clone for Position {
    fn clone(&self) -> Position {
        let &Position(ref nums) = self;
        Position(nums.clone())
    }
}

/*
 * Point
 * GeoJSON Format Specification § 2.1.2
 * http://geojson.org/geojson-spec.html#point
 */
pub struct Point {
    coordinates: Position,
}

impl ToJson for Point {
    fn to_json(&self) -> json::Json {
        let mut d = TreeMap::new();
        d.insert("type".to_string(), "Point".to_string().to_json());
        d.insert("coordinates".to_string(), self.coordinates.to_json());
        d.to_json()
    }
}

/*
 * MultiPoint
 * GeoJSON Format Specification § 2.1.3
 * http://geojson.org/geojson-spec.html#multipoint
 */
pub struct MultiPoint {
    points: Vec<Point>,
}

impl ToJson for MultiPoint {
    fn to_json(&self) -> json::Json {
        let mut d = TreeMap::new();
        d.insert("type".to_string(), "MultiPoint".to_string().to_json());
        d.insert("coordinates".to_string(), self.points.to_json());
        d.to_json()
    }
}

/*
 * LineString
 * GeoJSON Format Specification § 2.1.4
 * http://geojson.org/geojson-spec.html#linestring
 */
pub struct LineString {
    coordinates: Vec<Position>,
}

impl ToJson for LineString {
    fn to_json(&self) -> json::Json {
        let mut d = TreeMap::new();
        d.insert("type".to_string(), "LineString".to_string().to_json());
        d.insert("coordinates".to_string(), self.coordinates.to_json());
        d.to_json()
    }
}

/*
 * MultiLineString
 * GeoJSON Format Specification § 2.1.5
 * http://geojson.org/geojson-spec.html#multilinestring
 */

pub struct MultiLineString {
    line_strings: Vec<LineString>,
}

impl ToJson for MultiLineString {
    fn to_json(&self) -> json::Json {
        let mut d = TreeMap::new();
        d.insert("type".to_string(), "MultiLineString".to_string().to_json());
        d.insert("coordinates".to_string(), self.line_strings.to_json());
        d.to_json()
    }
}

/*
 * Polygon
 * GeoJSON Format Specification § 2.1.6
 * http://geojson.org/geojson-spec.html#polygon
 */

pub struct Polygon {
    exterior: Vec<Position>,
    holes: Vec<Vec<Position>>,
}

impl ToJson for Polygon {
    fn to_json(&self) -> json::Json {
        let mut coordinates = self.holes.clone();
        coordinates.unshift(self.exterior.clone());

        let mut d = TreeMap::new();
        d.insert("type".to_string(), "Polygon".to_string().to_json());
        d.insert("coordinates".to_string(), coordinates.to_json());
        d.to_json()
    }
}

fn main() {
    let point = Point {
        coordinates: Position(vec![1., 2., 3.]),
    };

    let j: json::Json = point.to_json();
    let s: String = j.to_pretty_str();

    println!("{}", s);
}
<|endoftext|>


<commit_before>extern crate pal;

use std::env;

use pal::{repl, run_file};

fn main() {
    let mut args = env::args();
    let _ = args.next();

    match args.next() {
        Some(arg) => run_file(&arg).unwrap(),
        None => repl(),
    }
}
<commit_msg>add functionality for interpreter to read program from standard input<commit_after>extern crate pal;

use std::env;
use std::io::{self, Read};

use pal::{repl, run_file, run_program};

fn main() {
    let mut args = env::args();
    let _ = args.next();

    match args.next() {
        Some(ref arg) if arg == "-e" => {
            let mut buf = String::new();
            let mut stdin = io::stdin();
            stdin.read_to_string(&mut buf).unwrap();

            run_program(&buf).unwrap();
        },
        Some(arg) => run_file(&arg).unwrap(),
        None => repl(),
    }
}
<|endoftext|>