<commit_before>//  * This file is part of the uutils coreutils package.
//  *
//  * (c) Ben Eills <ben@beneills.com>
//  *
//  * For the full copyright and license information, please view the LICENSE file
//  * that was distributed with this source code.

// spell-checker:ignore (ToDO) rwxr sourcepath targetpath

extern crate clap;
extern crate libc;

mod mode;

#[macro_use]
extern crate uucore;

use clap::{App, Arg, ArgMatches};
use std::fs;
use std::path::{Path, PathBuf};
use std::result::Result;

const DEFAULT_MODE: u32 = 0o755;

#[allow(dead_code)]
pub struct Behavior {
    main_function: MainFunction,
    specified_mode: Option<u32>,
    suffix: String,
    verbose: bool,
}

#[derive(Clone, Eq, PartialEq)]
pub enum MainFunction {
    /// Create directories
    Directory,
    /// Install files to locations (primary functionality)
    Standard,
}

impl Behavior {
    /// Determine the mode for chmod after copy.
    pub fn mode(&self) -> u32 {
        match self.specified_mode {
            Some(x) => x,
            None => DEFAULT_MODE,
        }
    }
}

static ABOUT: &str = "Copy SOURCE to DEST or multiple SOURCE(s) to the existing
 DIRECTORY, while setting permission modes and owner/group";
static VERSION: &str = env!("CARGO_PKG_VERSION");

static OPT_COMPARE: &str = "compare";
static OPT_BACKUP: &str = "backup";
static OPT_BACKUP_2: &str = "backup2";
static OPT_DIRECTORY: &str = "directory";
static OPT_IGNORED: &str = "ignored";
static OPT_CREATED: &str = "created";
static OPT_GROUP: &str = "group";
static OPT_MODE: &str = "mode";
static OPT_OWNER: &str = "owner";
static OPT_PRESERVE_TIMESTAMPS: &str = "preserve-timestamps";
static OPT_STRIP: &str = "strip";
static OPT_STRIP_PROGRAM: &str = "strip-program";
static OPT_SUFFIX: &str = "suffix";
static OPT_TARGET_DIRECTORY: &str = "target-directory";
static OPT_NO_TARGET_DIRECTORY: &str = "no-target-directory";
static OPT_VERBOSE: &str = "verbose";
static OPT_PRESERVE_CONTEXT: &str = "preserve-context";
static OPT_CONTEXT: &str = "context";

static ARG_FILES: &str = "files";

fn get_usage() -> String {
    format!("{0} [OPTION]... [FILE]...", executable!())
}

/// Main install utility function, called from main.rs.
///
/// Returns a program return code.
///
pub fn uumain(args: impl uucore::Args) -> i32 {
    let usage = get_usage();

    let matches = App::new(executable!())
        .version(VERSION)
        .about(ABOUT)
        .usage(&usage[..])
        .arg(
                Arg::with_name(OPT_BACKUP)
                .long(OPT_BACKUP)
                .help("(unimplemented) make a backup of each existing destination file")
                .value_name("CONTROL")
        )
        .arg(
            // TODO implement flag
            Arg::with_name(OPT_BACKUP_2)
            .short("b")
            .help("(unimplemented) like --backup but does not accept an argument")
        )
        .arg(
            Arg::with_name(OPT_IGNORED)
            .short("c")
            .help("ignored")
        )
        .arg(
            // TODO implement flag
            Arg::with_name(OPT_COMPARE)
            .short("C")
            .long(OPT_COMPARE)
            .help("(unimplemented) compare each pair of source and destination files, and in some cases, do not modify the destination at all")
        )
        .arg(
            Arg::with_name(OPT_DIRECTORY)
                .short("d")
                .long(OPT_DIRECTORY)
                .help("treat all arguments as directory names. create all components of the specified directories")
        )

        .arg(
            // TODO implement flag
            Arg::with_name(OPT_CREATED)
                .short("D")
                .help("(unimplemented) create all leading components of DEST except the last, then copy SOURCE to DEST")
        )
        .arg(
            // TODO implement flag
            Arg::with_name(OPT_GROUP)
                .short("g")
                .long(OPT_GROUP)
                .help("(unimplemented) set group ownership, instead of process's current group")
                .value_name("GROUP")
        )
        .arg(
            Arg::with_name(OPT_MODE)
                .short("m")
                .long(OPT_MODE)
                .help("set permission mode (as in chmod), instead of rwxr-xr-x")
                .value_name("MODE")
        )
        .arg(
            // TODO implement flag
            Arg::with_name(OPT_OWNER)
                .short("o")
                .long(OPT_OWNER)
                .help("(unimplemented) set ownership (super-user only)")
                .value_name("OWNER")
        )
        .arg(
            // TODO implement flag
            Arg::with_name(OPT_PRESERVE_TIMESTAMPS)
                .short("p")
                .long(OPT_PRESERVE_TIMESTAMPS)
                .help("(unimplemented) apply access/modification times of SOURCE files to corresponding destination files")
        )
        .arg(
            // TODO implement flag
            Arg::with_name(OPT_STRIP)
            .short("s")
            .long(OPT_STRIP)
            .help("(unimplemented) strip symbol tables")
        )
        .arg(
            // TODO implement flag
            Arg::with_name(OPT_STRIP_PROGRAM)
                .long(OPT_STRIP_PROGRAM)
                .help("(unimplemented) program used to strip binaries")
                .value_name("PROGRAM")
        )
        .arg(
            // TODO implement flag
            Arg::with_name(OPT_SUFFIX)
                .short("S")
                .long(OPT_SUFFIX)
                .help("(unimplemented) override the usual backup suffix")
                .value_name("SUFFIX")
        )
        .arg(
            // TODO implement flag
            Arg::with_name(OPT_TARGET_DIRECTORY)
                .short("t")
                .long(OPT_TARGET_DIRECTORY)
                .help("(unimplemented) move all SOURCE arguments into DIRECTORY")
                .value_name("DIRECTORY")
        )
        .arg(
            // TODO implement flag
            Arg::with_name(OPT_NO_TARGET_DIRECTORY)
                .short("T")
                .long(OPT_NO_TARGET_DIRECTORY)
                .help("(unimplemented) treat DEST as a normal file")

        )
        .arg(
            Arg::with_name(OPT_VERBOSE)
            .short("v")
            .long(OPT_VERBOSE)
            .help("explain what is being done")
        )
        .arg(
            // TODO implement flag
            Arg::with_name(OPT_PRESERVE_CONTEXT)
                .short("P")
                .long(OPT_PRESERVE_CONTEXT)
                .help("(unimplemented) preserve security context")
        )
        .arg(
            // TODO implement flag
            Arg::with_name(OPT_CONTEXT)
                .short("Z")
                .long(OPT_CONTEXT)
                .help("(unimplemented) set security context of files and directories")
                .value_name("CONTEXT")
        )
        .arg(Arg::with_name(ARG_FILES).multiple(true).takes_value(true))
        .get_matches_from(args);

    let paths: Vec<String> = matches
        .values_of(ARG_FILES)
        .map(|v| v.map(ToString::to_string).collect())
        .unwrap_or_default();

    if let Err(s) = check_unimplemented(&matches) {
        show_error!("Unimplemented feature: {}", s);
        return 2;
    }

    let behavior = match behavior(&matches) {
        Ok(x) => x,
        Err(ret) => {
            return ret;
        }
    };

    match behavior.main_function {
        MainFunction::Directory => directory(paths, behavior),
        MainFunction::Standard => standard(paths, behavior),
    }
}

/// Check for unimplemented command line arguments.
///
/// Either return the degenerate Ok value, or an Err with string.
///
/// # Errors
///
/// Error datum is a string of the unimplemented argument.
///
///
fn check_unimplemented<'a>(matches: &ArgMatches) -> Result<(), &'a str> {
    if matches.is_present(OPT_BACKUP) {
        Err("--backup")
    } else if matches.is_present(OPT_BACKUP_2) {
        Err("-b")
    } else if matches.is_present(OPT_COMPARE) {
        Err("--compare, -C")
    } else if matches.is_present(OPT_CREATED) {
        Err("-D")
    } else if matches.is_present(OPT_GROUP) {
        Err("--group, -g")
    } else if matches.is_present(OPT_OWNER) {
        Err("--owner, -o")
    } else if matches.is_present(OPT_PRESERVE_TIMESTAMPS) {
        Err("--preserve-timestamps, -p")
    } else if matches.is_present(OPT_STRIP) {
        Err("--strip, -s")
    } else if matches.is_present(OPT_STRIP_PROGRAM) {
        Err("--strip-program")
    } else if matches.is_present(OPT_SUFFIX) {
        Err("--suffix, -S")
    } else if matches.is_present(OPT_TARGET_DIRECTORY) {
        Err("--target-directory, -t")
    } else if matches.is_present(OPT_NO_TARGET_DIRECTORY) {
        Err("--no-target-directory, -T")
    } else if matches.is_present(OPT_PRESERVE_CONTEXT) {
        Err("--preserve-context, -P")
    } else if matches.is_present(OPT_CONTEXT) {
        Err("--context, -Z")
    } else {
        Ok(())
    }
}

/// Determine behavior, given command line arguments.
///
/// If successful, returns a filled-out Behavior struct.
///
/// # Errors
///
/// In event of failure, returns an integer intended as a program return code.
///
fn behavior(matches: &ArgMatches) -> Result<Behavior, i32> {
    let main_function = if matches.is_present("directory") {
        MainFunction::Directory
    } else {
        MainFunction::Standard
    };

    let considering_dir: bool = MainFunction::Directory == main_function;

    let specified_mode: Option<u32> = if matches.is_present(OPT_MODE) {
        match matches.value_of(OPT_MODE) {
            Some(x) => match mode::parse(&x[..], considering_dir) {
                Ok(y) => Some(y),
                Err(err) => {
                    show_error!("Invalid mode string: {}", err);
                    return Err(1);
                }
            },
            None => {
                show_error!(
                    "option '--mode' requires an argument\n \
                     Try '{} --help' for more information.",
                    executable!()
                );
                return Err(1);
            }
        }
    } else {
        None
    };

    let backup_suffix = if matches.is_present(OPT_SUFFIX) {
        match matches.value_of(OPT_SUFFIX) {
            Some(x) => x,
            None => {
                show_error!(
                    "option '--suffix' requires an argument\n\
                     Try '{} --help' for more information.",
                    executable!()
                );
                return Err(1);
            }
        }
    } else {
        "~"
    };

    Ok(Behavior {
        main_function,
        specified_mode,
        suffix: backup_suffix.to_string(),
        verbose: matches.is_present(OPT_VERBOSE),
    })
}

/// Creates directories.
///
/// GNU man pages describe this functionality as creating 'all components of
/// the specified directories'.
///
/// Returns an integer intended as a program return code.
///
fn directory(paths: Vec<String>, b: Behavior) -> i32 {
    if paths.is_empty() {
        println!("{} with -d requires at least one argument.", executable!());
        1
    } else {
        let mut all_successful = true;

        for directory in paths.iter() {
            let path = Path::new(directory);

            // if the path already exist, don't try to create it again
            if !path.exists() {
                if let Err(e) = fs::create_dir(directory) {
                    show_info!("{}: {}", path.display(), e.to_string());
                    all_successful = false;
                }
            }

            if mode::chmod(&path, b.mode()).is_err() {
                all_successful = false;
            }

            if b.verbose {
                show_info!("created directory '{}'", path.display());
            }
        }
        if all_successful {
            0
        } else {
            1
        }
    }
}

/// Test if the path is a new file path that can be
/// created immediately
fn is_new_file_path(path: &Path) -> bool {
    path.is_file() || !path.exists() && path.parent().map(Path::is_dir).unwrap_or(true)
}

/// Perform an install, given a list of paths and behavior.
///
/// Returns an integer intended as a program return code.
///
fn standard(paths: Vec<String>, b: Behavior) -> i32 {
    if paths.len() < 2 {
        println!("{} requires at least 2 arguments.", executable!());
        1
    } else {
        let sources = &paths[0..paths.len() - 1]
            .iter()
            .map(PathBuf::from)
            .collect::<Vec<_>>();
        let target = Path::new(paths.last().unwrap());

        if (target.is_file() || is_new_file_path(target)) && sources.len() == 1 {
            copy_file_to_file(&sources[0], &target.to_path_buf(), &b)
        } else {
            copy_files_into_dir(sources, &target.to_path_buf(), &b)
        }
    }
}

/// Copy some files into a directory.
///
/// Prints verbose information and error messages.
/// Returns an integer intended as a program return code.
///
/// # Parameters
///
/// _files_ must all exist as non-directories.
/// _target_dir_ must be a directory.
///
fn copy_files_into_dir(files: &[PathBuf], target_dir: &PathBuf, b: &Behavior) -> i32 {
    if !target_dir.is_dir() {
        show_error!("target ‘{}’ is not a directory", target_dir.display());
        return 1;
    }

    let mut all_successful = true;
    for sourcepath in files.iter() {
        let targetpath = match sourcepath.as_os_str().to_str() {
            Some(name) => target_dir.join(name),
            None => {
                show_error!(
                    "cannot stat ‘{}’: No such file or directory",
                    sourcepath.display()
                );

                all_successful = false;
                continue;
            }
        };

        if copy(sourcepath, &targetpath, b).is_err() {
            all_successful = false;
        }
    }
    if all_successful {
        0
    } else {
        1
    }
}

/// Copy a file to another file.
///
/// Prints verbose information and error messages.
/// Returns an integer intended as a program return code.
///
/// # Parameters
///
/// _file_ must exist as a non-directory.
/// _target_ must be a non-directory
///
fn copy_file_to_file(file: &PathBuf, target: &PathBuf, b: &Behavior) -> i32 {
    if copy(file, &target, b).is_err() {
        1
    } else {
        0
    }
}

/// Copy one file to a new location, changing metadata.
///
/// # Parameters
///
/// _from_ must exist as a non-directory.
/// _to_ must be a non-existent file, whose parent directory exists.
///
/// # Errors
///
/// If the copy system call fails, we print a verbose error and return an empty error value.
///
fn copy(from: &PathBuf, to: &PathBuf, b: &Behavior) -> Result<(), ()> {
    let io_result = fs::copy(from, to);

    if let Err(err) = io_result {
        show_error!(
            "install: cannot install ‘{}’ to ‘{}’: {}",
            from.display(),
            to.display(),
            err
        );
        return Err(());
    }

    if mode::chmod(&to, b.mode()).is_err() {
        return Err(());
    }

    if b.verbose {
        show_info!("'{}' -> '{}'", from.display(), to.display());
    }

    Ok(())
}
<commit_msg>feature(install): remove a duplicate check. Already done in is_new_file_path<commit_after>//  * This file is part of the uutils coreutils package.
//  *
//  * (c) Ben Eills <ben@beneills.com>
//  *
//  * For the full copyright and license information, please view the LICENSE file
//  * that was distributed with this source code.

// spell-checker:ignore (ToDO) rwxr sourcepath targetpath

extern crate clap;
extern crate libc;

mod mode;

#[macro_use]
extern crate uucore;

use clap::{App, Arg, ArgMatches};
use std::fs;
use std::path::{Path, PathBuf};
use std::result::Result;

const DEFAULT_MODE: u32 = 0o755;

#[allow(dead_code)]
pub struct Behavior {
    main_function: MainFunction,
    specified_mode: Option<u32>,
    suffix: String,
    verbose: bool,
}

#[derive(Clone, Eq, PartialEq)]
pub enum MainFunction {
    /// Create directories
    Directory,
    /// Install files to locations (primary functionality)
    Standard,
}

impl Behavior {
    /// Determine the mode for chmod after copy.
    pub fn mode(&self) -> u32 {
        match self.specified_mode {
            Some(x) => x,
            None => DEFAULT_MODE,
        }
    }
}

static ABOUT: &str = "Copy SOURCE to DEST or multiple SOURCE(s) to the existing
 DIRECTORY, while setting permission modes and owner/group";
static VERSION: &str = env!("CARGO_PKG_VERSION");

static OPT_COMPARE: &str = "compare";
static OPT_BACKUP: &str = "backup";
static OPT_BACKUP_2: &str = "backup2";
static OPT_DIRECTORY: &str = "directory";
static OPT_IGNORED: &str = "ignored";
static OPT_CREATED: &str = "created";
static OPT_GROUP: &str = "group";
static OPT_MODE: &str = "mode";
static OPT_OWNER: &str = "owner";
static OPT_PRESERVE_TIMESTAMPS: &str = "preserve-timestamps";
static OPT_STRIP: &str = "strip";
static OPT_STRIP_PROGRAM: &str = "strip-program";
static OPT_SUFFIX: &str = "suffix";
static OPT_TARGET_DIRECTORY: &str = "target-directory";
static OPT_NO_TARGET_DIRECTORY: &str = "no-target-directory";
static OPT_VERBOSE: &str = "verbose";
static OPT_PRESERVE_CONTEXT: &str = "preserve-context";
static OPT_CONTEXT: &str = "context";

static ARG_FILES: &str = "files";

fn get_usage() -> String {
    format!("{0} [OPTION]... [FILE]...", executable!())
}

/// Main install utility function, called from main.rs.
///
/// Returns a program return code.
///
pub fn uumain(args: impl uucore::Args) -> i32 {
    let usage = get_usage();

    let matches = App::new(executable!())
        .version(VERSION)
        .about(ABOUT)
        .usage(&usage[..])
        .arg(
                Arg::with_name(OPT_BACKUP)
                .long(OPT_BACKUP)
                .help("(unimplemented) make a backup of each existing destination file")
                .value_name("CONTROL")
        )
        .arg(
            // TODO implement flag
            Arg::with_name(OPT_BACKUP_2)
            .short("b")
            .help("(unimplemented) like --backup but does not accept an argument")
        )
        .arg(
            Arg::with_name(OPT_IGNORED)
            .short("c")
            .help("ignored")
        )
        .arg(
            // TODO implement flag
            Arg::with_name(OPT_COMPARE)
            .short("C")
            .long(OPT_COMPARE)
            .help("(unimplemented) compare each pair of source and destination files, and in some cases, do not modify the destination at all")
        )
        .arg(
            Arg::with_name(OPT_DIRECTORY)
                .short("d")
                .long(OPT_DIRECTORY)
                .help("treat all arguments as directory names. create all components of the specified directories")
        )

        .arg(
            // TODO implement flag
            Arg::with_name(OPT_CREATED)
                .short("D")
                .help("(unimplemented) create all leading components of DEST except the last, then copy SOURCE to DEST")
        )
        .arg(
            // TODO implement flag
            Arg::with_name(OPT_GROUP)
                .short("g")
                .long(OPT_GROUP)
                .help("(unimplemented) set group ownership, instead of process's current group")
                .value_name("GROUP")
        )
        .arg(
            Arg::with_name(OPT_MODE)
                .short("m")
                .long(OPT_MODE)
                .help("set permission mode (as in chmod), instead of rwxr-xr-x")
                .value_name("MODE")
        )
        .arg(
            // TODO implement flag
            Arg::with_name(OPT_OWNER)
                .short("o")
                .long(OPT_OWNER)
                .help("(unimplemented) set ownership (super-user only)")
                .value_name("OWNER")
        )
        .arg(
            // TODO implement flag
            Arg::with_name(OPT_PRESERVE_TIMESTAMPS)
                .short("p")
                .long(OPT_PRESERVE_TIMESTAMPS)
                .help("(unimplemented) apply access/modification times of SOURCE files to corresponding destination files")
        )
        .arg(
            // TODO implement flag
            Arg::with_name(OPT_STRIP)
            .short("s")
            .long(OPT_STRIP)
            .help("(unimplemented) strip symbol tables")
        )
        .arg(
            // TODO implement flag
            Arg::with_name(OPT_STRIP_PROGRAM)
                .long(OPT_STRIP_PROGRAM)
                .help("(unimplemented) program used to strip binaries")
                .value_name("PROGRAM")
        )
        .arg(
            // TODO implement flag
            Arg::with_name(OPT_SUFFIX)
                .short("S")
                .long(OPT_SUFFIX)
                .help("(unimplemented) override the usual backup suffix")
                .value_name("SUFFIX")
        )
        .arg(
            // TODO implement flag
            Arg::with_name(OPT_TARGET_DIRECTORY)
                .short("t")
                .long(OPT_TARGET_DIRECTORY)
                .help("(unimplemented) move all SOURCE arguments into DIRECTORY")
                .value_name("DIRECTORY")
        )
        .arg(
            // TODO implement flag
            Arg::with_name(OPT_NO_TARGET_DIRECTORY)
                .short("T")
                .long(OPT_NO_TARGET_DIRECTORY)
                .help("(unimplemented) treat DEST as a normal file")

        )
        .arg(
            Arg::with_name(OPT_VERBOSE)
            .short("v")
            .long(OPT_VERBOSE)
            .help("explain what is being done")
        )
        .arg(
            // TODO implement flag
            Arg::with_name(OPT_PRESERVE_CONTEXT)
                .short("P")
                .long(OPT_PRESERVE_CONTEXT)
                .help("(unimplemented) preserve security context")
        )
        .arg(
            // TODO implement flag
            Arg::with_name(OPT_CONTEXT)
                .short("Z")
                .long(OPT_CONTEXT)
                .help("(unimplemented) set security context of files and directories")
                .value_name("CONTEXT")
        )
        .arg(Arg::with_name(ARG_FILES).multiple(true).takes_value(true))
        .get_matches_from(args);

    let paths: Vec<String> = matches
        .values_of(ARG_FILES)
        .map(|v| v.map(ToString::to_string).collect())
        .unwrap_or_default();

    if let Err(s) = check_unimplemented(&matches) {
        show_error!("Unimplemented feature: {}", s);
        return 2;
    }

    let behavior = match behavior(&matches) {
        Ok(x) => x,
        Err(ret) => {
            return ret;
        }
    };

    match behavior.main_function {
        MainFunction::Directory => directory(paths, behavior),
        MainFunction::Standard => standard(paths, behavior),
    }
}

/// Check for unimplemented command line arguments.
///
/// Either return the degenerate Ok value, or an Err with string.
///
/// # Errors
///
/// Error datum is a string of the unimplemented argument.
///
///
fn check_unimplemented<'a>(matches: &ArgMatches) -> Result<(), &'a str> {
    if matches.is_present(OPT_BACKUP) {
        Err("--backup")
    } else if matches.is_present(OPT_BACKUP_2) {
        Err("-b")
    } else if matches.is_present(OPT_COMPARE) {
        Err("--compare, -C")
    } else if matches.is_present(OPT_CREATED) {
        Err("-D")
    } else if matches.is_present(OPT_GROUP) {
        Err("--group, -g")
    } else if matches.is_present(OPT_OWNER) {
        Err("--owner, -o")
    } else if matches.is_present(OPT_PRESERVE_TIMESTAMPS) {
        Err("--preserve-timestamps, -p")
    } else if matches.is_present(OPT_STRIP) {
        Err("--strip, -s")
    } else if matches.is_present(OPT_STRIP_PROGRAM) {
        Err("--strip-program")
    } else if matches.is_present(OPT_SUFFIX) {
        Err("--suffix, -S")
    } else if matches.is_present(OPT_TARGET_DIRECTORY) {
        Err("--target-directory, -t")
    } else if matches.is_present(OPT_NO_TARGET_DIRECTORY) {
        Err("--no-target-directory, -T")
    } else if matches.is_present(OPT_PRESERVE_CONTEXT) {
        Err("--preserve-context, -P")
    } else if matches.is_present(OPT_CONTEXT) {
        Err("--context, -Z")
    } else {
        Ok(())
    }
}

/// Determine behavior, given command line arguments.
///
/// If successful, returns a filled-out Behavior struct.
///
/// # Errors
///
/// In event of failure, returns an integer intended as a program return code.
///
fn behavior(matches: &ArgMatches) -> Result<Behavior, i32> {
    let main_function = if matches.is_present("directory") {
        MainFunction::Directory
    } else {
        MainFunction::Standard
    };

    let considering_dir: bool = MainFunction::Directory == main_function;

    let specified_mode: Option<u32> = if matches.is_present(OPT_MODE) {
        match matches.value_of(OPT_MODE) {
            Some(x) => match mode::parse(&x[..], considering_dir) {
                Ok(y) => Some(y),
                Err(err) => {
                    show_error!("Invalid mode string: {}", err);
                    return Err(1);
                }
            },
            None => {
                show_error!(
                    "option '--mode' requires an argument\n \
                     Try '{} --help' for more information.",
                    executable!()
                );
                return Err(1);
            }
        }
    } else {
        None
    };

    let backup_suffix = if matches.is_present(OPT_SUFFIX) {
        match matches.value_of(OPT_SUFFIX) {
            Some(x) => x,
            None => {
                show_error!(
                    "option '--suffix' requires an argument\n\
                     Try '{} --help' for more information.",
                    executable!()
                );
                return Err(1);
            }
        }
    } else {
        "~"
    };

    Ok(Behavior {
        main_function,
        specified_mode,
        suffix: backup_suffix.to_string(),
        verbose: matches.is_present(OPT_VERBOSE),
    })
}

/// Creates directories.
///
/// GNU man pages describe this functionality as creating 'all components of
/// the specified directories'.
///
/// Returns an integer intended as a program return code.
///
fn directory(paths: Vec<String>, b: Behavior) -> i32 {
    if paths.is_empty() {
        println!("{} with -d requires at least one argument.", executable!());
        1
    } else {
        let mut all_successful = true;

        for directory in paths.iter() {
            let path = Path::new(directory);

            // if the path already exist, don't try to create it again
            if !path.exists() {
                if let Err(e) = fs::create_dir(directory) {
                    show_info!("{}: {}", path.display(), e.to_string());
                    all_successful = false;
                }
            }

            if mode::chmod(&path, b.mode()).is_err() {
                all_successful = false;
            }

            if b.verbose {
                show_info!("created directory '{}'", path.display());
            }
        }
        if all_successful {
            0
        } else {
            1
        }
    }
}

/// Test if the path is a new file path that can be
/// created immediately
fn is_new_file_path(path: &Path) -> bool {
    !path.exists() && path.parent().map(Path::is_dir).unwrap_or(true)
}

/// Perform an install, given a list of paths and behavior.
///
/// Returns an integer intended as a program return code.
///
fn standard(paths: Vec<String>, b: Behavior) -> i32 {
    if paths.len() < 2 {
        println!("{} requires at least 2 arguments.", executable!());
        1
    } else {
        let sources = &paths[0..paths.len() - 1]
            .iter()
            .map(PathBuf::from)
            .collect::<Vec<_>>();
        let target = Path::new(paths.last().unwrap());

        if (target.is_file() || is_new_file_path(target)) && sources.len() == 1 {
            /* If the target already exist or directly creatable */
            copy_file_to_file(&sources[0], &target.to_path_buf(), &b)
        } else {
            copy_files_into_dir(sources, &target.to_path_buf(), &b)
        }
    }
}

/// Copy some files into a directory.
///
/// Prints verbose information and error messages.
/// Returns an integer intended as a program return code.
///
/// # Parameters
///
/// _files_ must all exist as non-directories.
/// _target_dir_ must be a directory.
///
fn copy_files_into_dir(files: &[PathBuf], target_dir: &PathBuf, b: &Behavior) -> i32 {
    if !target_dir.is_dir() {
        show_error!("target ‘{}’ is not a directory", target_dir.display());
        return 1;
    }

    let mut all_successful = true;
    for sourcepath in files.iter() {
        let targetpath = match sourcepath.as_os_str().to_str() {
            Some(name) => target_dir.join(name),
            None => {
                show_error!(
                    "cannot stat ‘{}’: No such file or directory",
                    sourcepath.display()
                );

                all_successful = false;
                continue;
            }
        };

        if copy(sourcepath, &targetpath, b).is_err() {
            all_successful = false;
        }
    }
    if all_successful {
        0
    } else {
        1
    }
}

/// Copy a file to another file.
///
/// Prints verbose information and error messages.
/// Returns an integer intended as a program return code.
///
/// # Parameters
///
/// _file_ must exist as a non-directory.
/// _target_ must be a non-directory
///
fn copy_file_to_file(file: &PathBuf, target: &PathBuf, b: &Behavior) -> i32 {
    if copy(file, &target, b).is_err() {
        1
    } else {
        0
    }
}

/// Copy one file to a new location, changing metadata.
///
/// # Parameters
///
/// _from_ must exist as a non-directory.
/// _to_ must be a non-existent file, whose parent directory exists.
///
/// # Errors
///
/// If the copy system call fails, we print a verbose error and return an empty error value.
///
fn copy(from: &PathBuf, to: &PathBuf, b: &Behavior) -> Result<(), ()> {
    let io_result = fs::copy(from, to);

    if let Err(err) = io_result {
        show_error!(
            "install: cannot install ‘{}’ to ‘{}’: {}",
            from.display(),
            to.display(),
            err
        );
        return Err(());
    }

    if mode::chmod(&to, b.mode()).is_err() {
        return Err(());
    }

    if b.verbose {
        show_info!("'{}' -> '{}'", from.display(), to.display());
    }

    Ok(())
}
<|endoftext|>


<commit_before>extern crate arrayfire as af;

use af::*;

#[allow(unused_must_use)]
fn test_backend(){
  info();

  let num_rows: u64 = 10;
  let num_cols: u64 = 10;
  let dims = Dim4::new(&[num_rows, num_cols, 1, 1]);

  println!("Create a 10-by-10 matrix of random floats on the compute device");
  let a = match randu(dims, Aftype::F32) {
    Ok(value) => value,
    Err(error) => panic!("{}", error),
  };
  print(&a);
}

#[allow(unused_must_use)]
fn main() {
  println!("There are {:?} available backends", get_backend_count().unwrap());
  let available = get_available_backends().unwrap();

  if available.contains(&AfBackend::AF_BACKEND_CPU){
    println!("Evaluating CPU Backend...");
    let err = set_backend(AfBackend::AF_BACKEND_CPU);
      match err {
        Ok(_)  => test_backend(),
        Err(e) => println!("CPU backend error: {}", e),
    };
  }

  if available.contains(&AfBackend::AF_BACKEND_CUDA){
    println!("Evaluating CUDA Backend...");
    let err = set_backend(AfBackend::AF_BACKEND_CUDA);
      match err {
        Ok(_)  => test_backend(),
        Err(e) => println!("CUDA backend error: {}", e),
    };
  }

  if available.contains(&AfBackend::AF_BACKEND_OPENCL){
    println!("Evaluating OpenCL Backend...");
    let err = set_backend(AfBackend::AF_BACKEND_OPENCL);
      match err {
        Ok(_)  => test_backend(),
        Err(e) => println!("OpenCL backend error: {}", e),
    };
  }
}
<commit_msg>add get device count to each backend for example<commit_after>extern crate arrayfire as af;

use af::*;

#[allow(unused_must_use)]
fn test_backend(){
  info();

  let num_rows: u64 = 10;
  let num_cols: u64 = 10;
  let dims = Dim4::new(&[num_rows, num_cols, 1, 1]);

  println!("Create a 10-by-10 matrix of random floats on the compute device");
  let a = match randu(dims, Aftype::F32) {
    Ok(value) => value,
    Err(error) => panic!("{}", error),
  };
  print(&a);
}

#[allow(unused_must_use)]
fn main() {
  println!("There are {:?} available backends", get_backend_count().unwrap());
  let available = get_available_backends().unwrap();

  if available.contains(&AfBackend::AF_BACKEND_CPU){
    println!("Evaluating CPU Backend...");
    println!("There are {} CPU compute devices", device_count().unwrap());
    let err = set_backend(AfBackend::AF_BACKEND_CPU);
      match err {
        Ok(_)  => test_backend(),
        Err(e) => println!("CPU backend error: {}", e),
    };
  }

  if available.contains(&AfBackend::AF_BACKEND_CUDA){
    println!("Evaluating CUDA Backend...");
    println!("There are {} CUDA compute devices", device_count().unwrap());
    let err = set_backend(AfBackend::AF_BACKEND_CUDA);
      match err {
        Ok(_)  => test_backend(),
        Err(e) => println!("CUDA backend error: {}", e),
    };
  }

  if available.contains(&AfBackend::AF_BACKEND_OPENCL){
    println!("Evaluating OpenCL Backend...");
    println!("There are {} OpenCL compute devices", device_count().unwrap());
    let err = set_backend(AfBackend::AF_BACKEND_OPENCL);
      match err {
        Ok(_)  => test_backend(),
        Err(e) => println!("OpenCL backend error: {}", e),
    };
  }
}
<|endoftext|>


<commit_before>extern crate clap;
#[macro_use] extern crate log;
extern crate env_logger;
extern crate mio;

extern crate simplesched;

use clap::{Arg, App};

use mio::buf::RingBuf;

use simplesched::Scheduler;
use simplesched::net::udp::UdpSocket;

fn main() {
    env_logger::init().unwrap();

    let matches = App::new("udp-echo")
            .version(env!("CARGO_PKG_VERSION"))
            .author("Y. T. Chung <zonyitoo@gmail.com>")
            .arg(Arg::with_name("BIND").short("b").long("bind").takes_value(true).required(true)
                    .help("Listening on this address"))
            .arg(Arg::with_name("THREADS").short("t").long("threads").takes_value(true)
                    .help("Number of threads"))
            .get_matches();

    let bind_addr = matches.value_of("BIND").unwrap().to_owned();

    Scheduler::spawn(move|| {
        let addr = bind_addr.parse().unwrap();
        let server = UdpSocket::bound(&addr).unwrap();

        info!("Listening on {:?}", server.local_addr().unwrap());

        let mut buf = RingBuf::new(1024);

        loop {
            let peer_addr = server.recv_from(&mut buf).unwrap().unwrap();
            info!("Accept connection: {:?}", peer_addr);

            server.send_to(&mut buf, &peer_addr).unwrap();
        }
    });

    Scheduler::run(matches.value_of("THREADS").unwrap_or("1").parse().unwrap());
}
<commit_msg>fixed compile error<commit_after>extern crate clap;
#[macro_use] extern crate log;
extern crate env_logger;
extern crate mio;

extern crate simplesched;

use std::net::SocketAddr;

use clap::{Arg, App};

use simplesched::Scheduler;
use simplesched::net::udp::UdpSocket;

fn main() {
    env_logger::init().unwrap();

    let matches = App::new("udp-echo")
            .version(env!("CARGO_PKG_VERSION"))
            .author("Y. T. Chung <zonyitoo@gmail.com>")
            .arg(Arg::with_name("BIND").short("b").long("bind").takes_value(true).required(true)
                    .help("Listening on this address"))
            .arg(Arg::with_name("THREADS").short("t").long("threads").takes_value(true)
                    .help("Number of threads"))
            .get_matches();

    let bind_addr = matches.value_of("BIND").unwrap().to_owned();

    Scheduler::spawn(move|| {
        let addr: SocketAddr = bind_addr.parse().unwrap();
        let server = UdpSocket::bind(&addr).unwrap();

        info!("Listening on {:?}", server.local_addr().unwrap());

        let mut buf = [0u8; 1024];

        loop {
            let (len, peer_addr) = server.recv_from(&mut buf).unwrap();
            info!("Accept connection: {:?}", peer_addr);

            server.send_to(&mut buf[..len], &peer_addr).unwrap();
        }
    });

    Scheduler::run(matches.value_of("THREADS").unwrap_or("1").parse().unwrap());
}
<|endoftext|>


<commit_before>// Copyright 2017 The Exonum Team
//
// 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.

use tempdir::TempDir;

use super::{Database, LevelDB, LevelDBOptions, MemoryDB, Snapshot, Fork};

fn leveldb_database() -> LevelDB {
    let mut options = LevelDBOptions::new();
    options.create_if_missing = true;
    LevelDB::open(TempDir::new("exonum").unwrap().path(), options).unwrap()
}

fn memorydb_database() -> MemoryDB {
    MemoryDB::new()
}

fn fork_iter<T: Database>(mut db: T) {
    let mut fork = db.fork();

    fork.put(vec![10], vec![10]);
    fork.put(vec![20], vec![20]);
    fork.put(vec![30], vec![30]);

    db.merge(fork.into_patch()).unwrap();

    let mut fork = db.fork();

    fn assert_iter(fork: &Fork, from: u8, assumed: &[(u8, u8)]) {
        let mut values = Vec::new();
        let mut iter = fork.iter(&[from]);
        while let Some((k, v)) = iter.next() {
            values.push((k[0], v[0]));
        }
        assert_eq!(values, assumed);
    }

    // Stored
    assert_iter(&fork, 0, &[(10, 10), (20, 20), (30, 30)]);
    assert_iter(&fork, 5, &[(10, 10), (20, 20), (30, 30)]);
    assert_iter(&fork, 10, &[(10, 10), (20, 20), (30, 30)]);
    assert_iter(&fork, 11, &[(20, 20), (30, 30)]);
    assert_iter(&fork, 31, &[]);

    // Inserted
    fork.put(vec![5], vec![5]);
    assert_iter(&fork, 0, &[(5, 5), (10, 10), (20, 20), (30, 30)]);
    fork.put(vec![25], vec![25]);
    assert_iter(&fork, 0, &[(5, 5), (10, 10), (20, 20), (25, 25), (30, 30)]);
    fork.put(vec![35], vec![35]);
    assert_iter(
        &fork,
        0,
        &[(5, 5), (10, 10), (20, 20), (25, 25), (30, 30), (35, 35)],
    );

    // Double inserted
    fork.put(vec![25], vec![23]);
    assert_iter(
        &fork,
        0,
        &[(5, 5), (10, 10), (20, 20), (25, 23), (30, 30), (35, 35)],
    );
    fork.put(vec![26], vec![26]);
    assert_iter(
        &fork,
        0,
        &[(5, 5), (10, 10), (20, 20), (25, 23), (26, 26), (30, 30), (35, 35)],
    );

    // Replaced
    let mut fork = db.fork();
    fork.put(vec![10], vec![11]);
    assert_iter(&fork, 0, &[(10, 11), (20, 20), (30, 30)]);
    fork.put(vec![30], vec![31]);
    assert_iter(&fork, 0, &[(10, 11), (20, 20), (30, 31)]);

    // Deleted
    let mut fork = db.fork();
    fork.remove(vec![20]);
    assert_iter(&fork, 0, &[(10, 10), (30, 30)]);
    fork.remove(vec![10]);
    assert_iter(&fork, 0, &[(30, 30)]);
    fork.put(vec![10], vec![11]);
    assert_iter(&fork, 0, &[(10, 11), (30, 30)]);
    fork.remove(vec![10]);
    assert_iter(&fork, 0, &[(30, 30)]);

    // MissDeleted
    let mut fork = db.fork();
    fork.remove(vec![5]);
    assert_iter(&fork, 0, &[(10, 10), (20, 20), (30, 30)]);
    fork.remove(vec![15]);
    assert_iter(&fork, 0, &[(10, 10), (20, 20), (30, 30)]);
    fork.remove(vec![35]);
    assert_iter(&fork, 0, &[(10, 10), (20, 20), (30, 30)]);
}

fn changelog<T: Database>(db: T) {
    let mut fork = db.fork();

    fork.put(vec![1], vec![1]);
    fork.put(vec![2], vec![2]);
    fork.put(vec![3], vec![3]);

    assert_eq!(fork.get(&[1]), Some(vec![1]));
    assert_eq!(fork.get(&[2]), Some(vec![2]));
    assert_eq!(fork.get(&[3]), Some(vec![3]));

    fork.checkpoint();

    assert_eq!(fork.get(&[1]), Some(vec![1]));
    assert_eq!(fork.get(&[2]), Some(vec![2]));
    assert_eq!(fork.get(&[3]), Some(vec![3]));

    fork.put(vec![1], vec![10]);
    fork.put(vec![4], vec![40]);
    fork.remove(vec![2]);

    assert_eq!(fork.get(&[1]), Some(vec![10]));
    assert_eq!(fork.get(&[2]), None);
    assert_eq!(fork.get(&[3]), Some(vec![3]));
    assert_eq!(fork.get(&[4]), Some(vec![40]));

    fork.rollback();

    assert_eq!(fork.get(&[1]), Some(vec![1]));
    assert_eq!(fork.get(&[2]), Some(vec![2]));
    assert_eq!(fork.get(&[3]), Some(vec![3]));
    assert_eq!(fork.get(&[4]), None);

    fork.checkpoint();

    fork.put(vec![4], vec![40]);
    fork.put(vec![4], vec![41]);
    fork.remove(vec![2]);
    fork.put(vec![2], vec![20]);

    assert_eq!(fork.get(&[1]), Some(vec![1]));
    assert_eq!(fork.get(&[2]), Some(vec![20]));
    assert_eq!(fork.get(&[3]), Some(vec![3]));
    assert_eq!(fork.get(&[4]), Some(vec![41]));

    fork.rollback();

    assert_eq!(fork.get(&[1]), Some(vec![1]));
    assert_eq!(fork.get(&[2]), Some(vec![2]));
    assert_eq!(fork.get(&[3]), Some(vec![3]));
    assert_eq!(fork.get(&[4]), None);

    fork.put(vec![2], vec![20]);

    fork.checkpoint();

    fork.put(vec![3], vec![30]);

    fork.rollback();

    assert_eq!(fork.get(&[1]), Some(vec![1]));
    assert_eq!(fork.get(&[2]), Some(vec![20]));
    assert_eq!(fork.get(&[3]), Some(vec![3]));
    assert_eq!(fork.get(&[4]), None);
}

#[test]
fn test_leveldb_fork_iter() {
    fork_iter(leveldb_database())
}

#[test]
fn test_memory_fork_iter() {
    fork_iter(memorydb_database())
}

#[test]
fn test_leveldb_changelog() {
    changelog(leveldb_database())
}

#[test]
fn test_memory_changelog() {
    changelog(memorydb_database())
}
<commit_msg>Added test for checking share state of MemoryDB<commit_after>// Copyright 2017 The Exonum Team
//
// 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.

use tempdir::TempDir;

use super::{Database, LevelDB, LevelDBOptions, MemoryDB, Snapshot, Fork};

fn leveldb_database() -> LevelDB {
    let mut options = LevelDBOptions::new();
    options.create_if_missing = true;
    LevelDB::open(TempDir::new("exonum").unwrap().path(), options).unwrap()
}

fn memorydb_database() -> MemoryDB {
    MemoryDB::new()
}

fn fork_iter<T: Database>(mut db: T) {
    let mut fork = db.fork();

    fork.put(vec![10], vec![10]);
    fork.put(vec![20], vec![20]);
    fork.put(vec![30], vec![30]);

    db.merge(fork.into_patch()).unwrap();

    let mut fork = db.fork();

    fn assert_iter(fork: &Fork, from: u8, assumed: &[(u8, u8)]) {
        let mut values = Vec::new();
        let mut iter = fork.iter(&[from]);
        while let Some((k, v)) = iter.next() {
            values.push((k[0], v[0]));
        }
        assert_eq!(values, assumed);
    }

    // Stored
    assert_iter(&fork, 0, &[(10, 10), (20, 20), (30, 30)]);
    assert_iter(&fork, 5, &[(10, 10), (20, 20), (30, 30)]);
    assert_iter(&fork, 10, &[(10, 10), (20, 20), (30, 30)]);
    assert_iter(&fork, 11, &[(20, 20), (30, 30)]);
    assert_iter(&fork, 31, &[]);

    // Inserted
    fork.put(vec![5], vec![5]);
    assert_iter(&fork, 0, &[(5, 5), (10, 10), (20, 20), (30, 30)]);
    fork.put(vec![25], vec![25]);
    assert_iter(&fork, 0, &[(5, 5), (10, 10), (20, 20), (25, 25), (30, 30)]);
    fork.put(vec![35], vec![35]);
    assert_iter(
        &fork,
        0,
        &[(5, 5), (10, 10), (20, 20), (25, 25), (30, 30), (35, 35)],
    );

    // Double inserted
    fork.put(vec![25], vec![23]);
    assert_iter(
        &fork,
        0,
        &[(5, 5), (10, 10), (20, 20), (25, 23), (30, 30), (35, 35)],
    );
    fork.put(vec![26], vec![26]);
    assert_iter(
        &fork,
        0,
        &[(5, 5), (10, 10), (20, 20), (25, 23), (26, 26), (30, 30), (35, 35)],
    );

    // Replaced
    let mut fork = db.fork();
    fork.put(vec![10], vec![11]);
    assert_iter(&fork, 0, &[(10, 11), (20, 20), (30, 30)]);
    fork.put(vec![30], vec![31]);
    assert_iter(&fork, 0, &[(10, 11), (20, 20), (30, 31)]);

    // Deleted
    let mut fork = db.fork();
    fork.remove(vec![20]);
    assert_iter(&fork, 0, &[(10, 10), (30, 30)]);
    fork.remove(vec![10]);
    assert_iter(&fork, 0, &[(30, 30)]);
    fork.put(vec![10], vec![11]);
    assert_iter(&fork, 0, &[(10, 11), (30, 30)]);
    fork.remove(vec![10]);
    assert_iter(&fork, 0, &[(30, 30)]);

    // MissDeleted
    let mut fork = db.fork();
    fork.remove(vec![5]);
    assert_iter(&fork, 0, &[(10, 10), (20, 20), (30, 30)]);
    fork.remove(vec![15]);
    assert_iter(&fork, 0, &[(10, 10), (20, 20), (30, 30)]);
    fork.remove(vec![35]);
    assert_iter(&fork, 0, &[(10, 10), (20, 20), (30, 30)]);
}

fn changelog<T: Database>(db: T) {
    let mut fork = db.fork();

    fork.put(vec![1], vec![1]);
    fork.put(vec![2], vec![2]);
    fork.put(vec![3], vec![3]);

    assert_eq!(fork.get(&[1]), Some(vec![1]));
    assert_eq!(fork.get(&[2]), Some(vec![2]));
    assert_eq!(fork.get(&[3]), Some(vec![3]));

    fork.checkpoint();

    assert_eq!(fork.get(&[1]), Some(vec![1]));
    assert_eq!(fork.get(&[2]), Some(vec![2]));
    assert_eq!(fork.get(&[3]), Some(vec![3]));

    fork.put(vec![1], vec![10]);
    fork.put(vec![4], vec![40]);
    fork.remove(vec![2]);

    assert_eq!(fork.get(&[1]), Some(vec![10]));
    assert_eq!(fork.get(&[2]), None);
    assert_eq!(fork.get(&[3]), Some(vec![3]));
    assert_eq!(fork.get(&[4]), Some(vec![40]));

    fork.rollback();

    assert_eq!(fork.get(&[1]), Some(vec![1]));
    assert_eq!(fork.get(&[2]), Some(vec![2]));
    assert_eq!(fork.get(&[3]), Some(vec![3]));
    assert_eq!(fork.get(&[4]), None);

    fork.checkpoint();

    fork.put(vec![4], vec![40]);
    fork.put(vec![4], vec![41]);
    fork.remove(vec![2]);
    fork.put(vec![2], vec![20]);

    assert_eq!(fork.get(&[1]), Some(vec![1]));
    assert_eq!(fork.get(&[2]), Some(vec![20]));
    assert_eq!(fork.get(&[3]), Some(vec![3]));
    assert_eq!(fork.get(&[4]), Some(vec![41]));

    fork.rollback();

    assert_eq!(fork.get(&[1]), Some(vec![1]));
    assert_eq!(fork.get(&[2]), Some(vec![2]));
    assert_eq!(fork.get(&[3]), Some(vec![3]));
    assert_eq!(fork.get(&[4]), None);

    fork.put(vec![2], vec![20]);

    fork.checkpoint();

    fork.put(vec![3], vec![30]);

    fork.rollback();

    assert_eq!(fork.get(&[1]), Some(vec![1]));
    assert_eq!(fork.get(&[2]), Some(vec![20]));
    assert_eq!(fork.get(&[3]), Some(vec![3]));
    assert_eq!(fork.get(&[4]), None);
}

#[test]
fn test_leveldb_fork_iter() {
    fork_iter(leveldb_database())
}

#[test]
fn test_memory_fork_iter() {
    fork_iter(memorydb_database())
}

#[test]
fn test_leveldb_changelog() {
    changelog(leveldb_database())
}

#[test]
fn test_memory_changelog() {
    changelog(memorydb_database())
}

#[test]
fn test_shared_state_memorydb() {
    let mut db = MemoryDB::new();
    let db_clone = Database::clone(&db);

    {
        let mut fork = db.fork();
        fork.put(vec![1, 2, 3], vec![2, 3, 4]);
        db.merge(fork.into_patch()).unwrap();
    }

    assert_eq!(db.fork().get(&[1, 2, 3]), Some(vec![2, 3, 4]));
    assert_eq!(db_clone.fork().get(&[1, 2, 3]), Some(vec![2, 3, 4]));
}<|endoftext|>


<commit_before>#![feature(macro_rules)]
#![feature(phase)]

#![unstable]

#[phase(plugin)]
extern crate compile_msg;

extern crate libc;
extern crate native;

use std::sync::Mutex;

#[doc(hidden)]
pub mod ffi;

/// This static variable  will store the android_app* on creation, and set it back to 0 at
///  destruction.
/// Apart from this, the static is never written, so there is no risk of race condition.
static mut ANDROID_APP: *mut ffi::android_app = 0 as *mut ffi::android_app;

/// This is the structure that serves as user data in the android_app*
#[doc(hidden)]
struct Context {
    senders: Mutex<Vec<Sender<Event>>>,
}

/// An event triggered by the Android environment.
pub enum Event {

}

#[cfg(not(target_os = "android"))]
compile_note!("You are not compiling for Android")

#[macro_export]
macro_rules! android_start(
    ($main: ident) => (
        pub mod __android_start {
            extern crate android_glue;

            // this function is here because we are sure that it will be included by the linker
            // so we call app_dummy in it, in order to be sure that the native glue will be included
            #[start]
            pub fn start(_: int, _: *const *const u8) -> int {
                unsafe { android_glue::ffi::app_dummy() };
                1
            }

            #[no_mangle]
            #[inline(never)]
            #[allow(non_snake_case)]
            pub extern "C" fn android_main(app: *mut ()) {
                android_glue::android_main2(app, proc() super::$main());
            }
        }
    )
)

/// This is the function that must be called by `android_main`
#[doc(hidden)]
pub fn android_main2(app: *mut (), main_function: proc()) {
    use native::NativeTaskBuilder;
    use std::task::TaskBuilder;
    use std::{mem, ptr};

    write_log("Entering android_main");

    unsafe { ANDROID_APP = std::mem::transmute(app) };
    let app: &mut ffi::android_app = unsafe { std::mem::transmute(app) };

    // starting the runtime
    native::start(1, &b"".as_ptr(), proc() {
        // creating the context that will be passed to the callback
        let context = Context { senders: Mutex::new(Vec::new()) };
        app.userData = unsafe { std::mem::transmute(&context) };
        app.onAppCmd = commands_callback;

        // polling for events in parallel
        TaskBuilder::new().native().spawn(proc() {
            unsafe {
                loop {
                    let mut events = mem::uninitialized();
                    let mut source = mem::uninitialized();

                    // passing -1 means that we are blocking
                    let ident = ffi::ALooper_pollAll(-1, ptr::mut_null(), &mut events,
                        &mut source);

                    // processing the event
                    if !source.is_null() {
                        let source: *mut ffi::android_poll_source = mem::transmute(source);
                        ((*source).process)(ANDROID_APP, source);
                    }
                }
            }
        });

        // let's go
        main_function();
    });

    // terminating the application
    unsafe { ANDROID_APP = 0 as *mut ffi::android_app };
}

/// The callback for commands.
#[doc(hidden)]
pub extern fn commands_callback(context: *mut ffi::android_app, command: libc::int32_t) {
    let context = get_context();

    match command {
        ffi::APP_CMD_INIT_WINDOW => {

        },
        _ => ()
    }
}

/// Returns the current Context
#[doc(hidden)]
pub fn get_context() -> &'static Context {
    let context = unsafe { (*ANDROID_APP).userData };
    unsafe { std::mem::transmute(context) }
}

/// Adds a sender where events will be sent to.
pub fn add_sender(sender: Sender<Event>) {
    get_context().senders.lock().push(sender);
}

/// Returns a handle to the native window.
pub unsafe fn get_native_window() -> ffi::NativeWindowType {
    if ANDROID_APP.is_null() {
        fail!("The application was not initialized from android_main");
    }

    loop {
        let value = (*ANDROID_APP).window;
        if !value.is_null() {
            return value;
        }

        // spin-locking
        std::io::timer::sleep(std::time::Duration::milliseconds(10));
    }
}

///
pub fn write_log(message: &str) {
    message.with_c_str(|message| {
        b"RustAndroidGlue".with_c_str(|tag| {
            unsafe { ffi::__android_log_write(3, tag, message) };
        });
    });
}
<commit_msg>Fix missing ALooper in polling thread<commit_after>#![feature(macro_rules)]
#![feature(phase)]

#![unstable]

#[phase(plugin)]
extern crate compile_msg;

extern crate libc;
extern crate native;

use std::sync::Mutex;

#[doc(hidden)]
pub mod ffi;

/// This static variable  will store the android_app* on creation, and set it back to 0 at
///  destruction.
/// Apart from this, the static is never written, so there is no risk of race condition.
static mut ANDROID_APP: *mut ffi::android_app = 0 as *mut ffi::android_app;

/// This is the structure that serves as user data in the android_app*
#[doc(hidden)]
struct Context {
    senders: Mutex<Vec<Sender<Event>>>,
}

/// An event triggered by the Android environment.
pub enum Event {

}

#[cfg(not(target_os = "android"))]
compile_note!("You are not compiling for Android")

#[macro_export]
macro_rules! android_start(
    ($main: ident) => (
        pub mod __android_start {
            extern crate android_glue;

            // this function is here because we are sure that it will be included by the linker
            // so we call app_dummy in it, in order to be sure that the native glue will be included
            #[start]
            pub fn start(_: int, _: *const *const u8) -> int {
                unsafe { android_glue::ffi::app_dummy() };
                1
            }

            #[no_mangle]
            #[inline(never)]
            #[allow(non_snake_case)]
            pub extern "C" fn android_main(app: *mut ()) {
                android_glue::android_main2(app, proc() super::$main());
            }
        }
    )
)

/// This is the function that must be called by `android_main`
#[doc(hidden)]
pub fn android_main2(app: *mut (), main_function: proc(): Send) {
    use native::NativeTaskBuilder;
    use std::task::TaskBuilder;
    use std::{mem, ptr};

    write_log("Entering android_main");

    unsafe { ANDROID_APP = std::mem::transmute(app) };
    let app: &mut ffi::android_app = unsafe { std::mem::transmute(app) };

    // starting the runtime
    native::start(1, &b"".as_ptr(), proc() {
        // creating the context that will be passed to the callback
        let context = Context { senders: Mutex::new(Vec::new()) };
        app.userData = unsafe { std::mem::transmute(&context) };
        app.onAppCmd = commands_callback;

        // executing the main function in parallel
        TaskBuilder::new().native().spawn(main_function);

        // polling for events forever
        // note that this must be done in the same thread as android_main because ALooper are
        //  thread-local
        unsafe {
            loop {
                let mut events = mem::uninitialized();
                let mut source = mem::uninitialized();

                // passing -1 means that we are blocking
                let ident = ffi::ALooper_pollAll(-1, ptr::mut_null(), &mut events,
                    &mut source);

                // processing the event
                if !source.is_null() {
                    let source: *mut ffi::android_poll_source = mem::transmute(source);
                    ((*source).process)(ANDROID_APP, source);
                }
            }
        }
    });

    // terminating the application
    unsafe { ANDROID_APP = 0 as *mut ffi::android_app };
}

/// The callback for commands.
#[doc(hidden)]
pub extern fn commands_callback(context: *mut ffi::android_app, command: libc::int32_t) {
    let context = get_context();

    match command {
        ffi::APP_CMD_INIT_WINDOW => {

        },
        _ => ()
    }
}

/// Returns the current Context
#[doc(hidden)]
pub fn get_context() -> &'static Context {
    let context = unsafe { (*ANDROID_APP).userData };
    unsafe { std::mem::transmute(context) }
}

/// Adds a sender where events will be sent to.
pub fn add_sender(sender: Sender<Event>) {
    get_context().senders.lock().push(sender);
}

/// Returns a handle to the native window.
pub unsafe fn get_native_window() -> ffi::NativeWindowType {
    if ANDROID_APP.is_null() {
        fail!("The application was not initialized from android_main");
    }

    loop {
        let value = (*ANDROID_APP).window;
        if !value.is_null() {
            return value;
        }

        // spin-locking
        std::io::timer::sleep(std::time::Duration::milliseconds(10));
    }
}

///
pub fn write_log(message: &str) {
    message.with_c_str(|message| {
        b"RustAndroidGlue".with_c_str(|tag| {
            unsafe { ffi::__android_log_write(3, tag, message) };
        });
    });
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

// http://dev.w3.org/csswg/css-syntax/#parsing
//
// The input to the tree construction stage is a sequence of tokens
// from the tokenization stage.
// The output is a tree of items with a stylesheet at the root
// and all other nodes being at-rules, style rules, or declarations.

use std::iterator::Iterator;
use std::vec;
use std::ascii::eq_ignore_ascii_case;

use ast::*;
use tokenizer::*;

// TODO: Use a trait?
enum ComponentValueIterator {
    ParserIter(~Parser),
    VectorIter(vec::ConsumeIterator<(ComponentValue, SourceLocation)>),
}

impl ComponentValueIterator {
    #[inline]
    pub fn from_str(input: ~str) -> ComponentValueIterator {
        ComponentValueIterator::from_parser(~Parser::from_str(input))
    }

    #[inline]
    pub fn from_parser(parser: ~Parser) -> ComponentValueIterator {
        ParserIter(parser)
    }

    #[inline]
    pub fn from_vector(values: ~[(ComponentValue, SourceLocation)]) -> ComponentValueIterator {
        VectorIter(values.consume_iter())
    }

    #[inline]
    pub fn next_non_whitespace(&mut self) -> Option<(ComponentValue, SourceLocation)> {
        for (component_value, location) in *self {
            if component_value != WhiteSpace { return Some((component_value, location)) }
        }
        None
    }
}

impl Iterator<(ComponentValue, SourceLocation)> for ComponentValueIterator {
    fn next(&mut self) -> Option<(ComponentValue, SourceLocation)> {
        match self {
            &ParserIter(ref mut parser) => next_component_value(*parser),
            &VectorIter(ref mut iter) => iter.next()
        }
    }
}

// Work around "error: cannot borrow `*iter` as mutable more than once at a time"
// when using a normal for loop.
macro_rules! for_iter(
    ($iter: ident, $pattern: pat, $loop_body: expr) => (
        loop {
            match $iter.next() { None => break, Some($pattern) => $loop_body }
        }
    );
)

/// Call repeatedly for the top-level of a CSS stylesheet
pub fn parse_stylesheet_rule(iter: &mut ComponentValueIterator) -> Option<Result<Rule, ErrorReason>> {
    for_iter!(iter, (component_value, location), {
        match component_value {
            WhiteSpace | CDO | CDC => (),
            AtKeyword(name) => return Some(Ok(AtRule(parse_at_rule(iter, name, location)))),
            _ => return Some(match parse_qualified_rule(iter, (component_value, location)) {
                Ok(rule) => Ok(QualifiedRule(rule)),
                Err(reason) => Err(reason),
            }),
        }
    })
    None
}

/// Call repeatedly for a non-top level list of rules eg. the content of an @media rule.
/// Same as parse_stylesheet() except for the handling of top-level CDO and CDC
pub fn parse_rule(iter: &mut ComponentValueIterator) -> Option<Result<Rule, ErrorReason>> {
    for_iter!(iter, (component_value, location), {
        match component_value {
            WhiteSpace => (),
            AtKeyword(name) => return Some(Ok(AtRule(parse_at_rule(iter, name, location)))),
            _ => return Some(match parse_qualified_rule(iter, (component_value, location)) {
                Ok(rule) => Ok(QualifiedRule(rule)),
                Err(reason) => Err(reason),
            }),
        }
    })
    None
}

/// Used eg. for CSSRuleList.insertRule()
pub fn parse_one_rule(iter: &mut ComponentValueIterator) -> Result<Rule, ErrorReason> {
    match parse_rule(iter) {
        None => Err(ErrEmptyInput),
        Some(result) => if result.is_err() || iter.next_non_whitespace().is_none() { result }
                        else { Err(ErrExtraInput) }
    }
}

/// Call repeatedly of a list of declarations.
/// @page in CSS 2.1, all declaration lists in level 3
pub fn parse_declaration_or_at_rule(iter: &mut ComponentValueIterator)
                                      -> Option<Result<DeclarationListItem, ErrorReason>> {
    for_iter!(iter, (component_value, location), {
        match component_value {
            WhiteSpace | Semicolon => (),
            AtKeyword(name) => return Some(Ok(Decl_AtRule(parse_at_rule(iter, name, location)))),
            _ => return Some(match parse_declaration(iter, (component_value, location)) {
                Ok(declaration) => Ok(Declaration(declaration)),
                Err(reason) => {
                    // Find the end of the declaration
                    for (v, _) in *iter { if v == Semicolon { break } }
                    Err(reason)
                }
            }),
        }
    })
    None
}

/// Used eg. in @supports
pub fn parse_one_declaration(iter: &mut ComponentValueIterator) -> Result<Declaration, ErrorReason> {
    match iter.next_non_whitespace() {
        None => Err(ErrEmptyInput),
        Some(item) => {
            let result = parse_declaration(iter, item);
            if result.is_err() || iter.next_non_whitespace().is_none() { result }
            else { Err(ErrExtraInput) }
        }
    }
}

/// Used eg. in attr(foo, color)
pub fn parse_one_component_value(iter: &mut ComponentValueIterator)
                                 -> Result<(ComponentValue, SourceLocation), ErrorReason> {
    match iter.next_non_whitespace() {
        None => Err(ErrEmptyInput),
        Some(item) => {
            if iter.next_non_whitespace().is_none() { Ok(item) }
            else { Err(ErrExtraInput) }
        }
    }
}

//  ***********  End of public API  ***********

fn parse_at_rule(iter: &mut ComponentValueIterator, name: ~str, location: SourceLocation)
                 -> AtRule {
    let mut prelude = ~[];
    let mut block = None;
    for_iter!(iter, (component_value, location), {
        match component_value {
            CurlyBracketBlock(content) => { block = Some(content); break },
            Semicolon => break,
            component_value => prelude.push((component_value, location)),
        }
    })
    AtRule {location: location, name: name, prelude: prelude, block: block}
}

fn parse_qualified_rule(iter: &mut ComponentValueIterator, first: (ComponentValue, SourceLocation))
                          -> Result<QualifiedRule, ErrorReason> {
    match first {
        (CurlyBracketBlock(content), location)
        => return Ok(QualifiedRule { location: location, prelude: ~[], block: content }),
        _ => (),
    }
    let mut prelude = ~[first];
    for_iter!(iter, (component_value, location), {
        match component_value {
            CurlyBracketBlock(content)
            => return Ok(QualifiedRule {location: location, prelude: prelude, block: content}),
            component_value => prelude.push((component_value, location)),
        }
    })
    Err(ErrMissingQualifiedRuleBlock)
}

fn parse_declaration(iter: &mut ComponentValueIterator, first: (ComponentValue, SourceLocation))
                       -> Result<Declaration, ErrorReason> {
    let (name, location) = match first {
        (Ident(name), location) => (name, location),
        _ => return Err(ErrInvalidDeclarationSyntax)
    };
    match iter.next_non_whitespace() {
        Some((Colon, _)) => (),
        _ => return Err(ErrInvalidDeclarationSyntax),
    }
    let mut value = ~[];
    let mut important = false;
    for_iter!(iter, (component_value, location), {
        match component_value {
            Semicolon => break,
            Delim('!') => if parse_declaration_important(iter) {
                important = true;
                break
            } else {
                return Err(ErrInvalidBangImportantSyntax)
            },
            component_value => value.push((component_value, location)),
        }
    })
    Ok(Declaration{location: location, name: name, value: value, important: important})
}

#[inline]
fn parse_declaration_important(iter: &mut ComponentValueIterator) -> bool {
    let ident_value = match iter.next_non_whitespace() {
        Some((Ident(value), _)) => value,
        _ => return false,
    };
    if !eq_ignore_ascii_case(ident_value, "important") { return false }
    match iter.next_non_whitespace() {
        Some((Semicolon, _)) => true,
        None => true,
        _ => false
    }
}
<commit_msg>Remove unused code: ComponentValueIterator.from_parser()<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

// http://dev.w3.org/csswg/css-syntax/#parsing
//
// The input to the tree construction stage is a sequence of tokens
// from the tokenization stage.
// The output is a tree of items with a stylesheet at the root
// and all other nodes being at-rules, style rules, or declarations.

use std::iterator::Iterator;
use std::vec;
use std::ascii::eq_ignore_ascii_case;

use ast::*;
use tokenizer::*;

// TODO: Use a trait?
enum ComponentValueIterator {
    ParserIter(Parser),
    VectorIter(vec::ConsumeIterator<(ComponentValue, SourceLocation)>),
}

impl ComponentValueIterator {
    #[inline]
    pub fn from_str(input: ~str) -> ComponentValueIterator {
        ParserIter(Parser::from_str(input))
    }

    #[inline]
    pub fn from_vector(values: ~[(ComponentValue, SourceLocation)]) -> ComponentValueIterator {
        VectorIter(values.consume_iter())
    }

    #[inline]
    pub fn next_non_whitespace(&mut self) -> Option<(ComponentValue, SourceLocation)> {
        for (component_value, location) in *self {
            if component_value != WhiteSpace { return Some((component_value, location)) }
        }
        None
    }
}

impl Iterator<(ComponentValue, SourceLocation)> for ComponentValueIterator {
    fn next(&mut self) -> Option<(ComponentValue, SourceLocation)> {
        match self {
            &ParserIter(ref mut parser) => next_component_value(parser),
            &VectorIter(ref mut iter) => iter.next()
        }
    }
}

// Work around "error: cannot borrow `*iter` as mutable more than once at a time"
// when using a normal for loop.
macro_rules! for_iter(
    ($iter: ident, $pattern: pat, $loop_body: expr) => (
        loop {
            match $iter.next() { None => break, Some($pattern) => $loop_body }
        }
    );
)

/// Call repeatedly for the top-level of a CSS stylesheet
pub fn parse_stylesheet_rule(iter: &mut ComponentValueIterator) -> Option<Result<Rule, ErrorReason>> {
    for_iter!(iter, (component_value, location), {
        match component_value {
            WhiteSpace | CDO | CDC => (),
            AtKeyword(name) => return Some(Ok(AtRule(parse_at_rule(iter, name, location)))),
            _ => return Some(match parse_qualified_rule(iter, (component_value, location)) {
                Ok(rule) => Ok(QualifiedRule(rule)),
                Err(reason) => Err(reason),
            }),
        }
    })
    None
}

/// Call repeatedly for a non-top level list of rules eg. the content of an @media rule.
/// Same as parse_stylesheet() except for the handling of top-level CDO and CDC
pub fn parse_rule(iter: &mut ComponentValueIterator) -> Option<Result<Rule, ErrorReason>> {
    for_iter!(iter, (component_value, location), {
        match component_value {
            WhiteSpace => (),
            AtKeyword(name) => return Some(Ok(AtRule(parse_at_rule(iter, name, location)))),
            _ => return Some(match parse_qualified_rule(iter, (component_value, location)) {
                Ok(rule) => Ok(QualifiedRule(rule)),
                Err(reason) => Err(reason),
            }),
        }
    })
    None
}

/// Used eg. for CSSRuleList.insertRule()
pub fn parse_one_rule(iter: &mut ComponentValueIterator) -> Result<Rule, ErrorReason> {
    match parse_rule(iter) {
        None => Err(ErrEmptyInput),
        Some(result) => if result.is_err() || iter.next_non_whitespace().is_none() { result }
                        else { Err(ErrExtraInput) }
    }
}

/// Call repeatedly of a list of declarations.
/// @page in CSS 2.1, all declaration lists in level 3
pub fn parse_declaration_or_at_rule(iter: &mut ComponentValueIterator)
                                      -> Option<Result<DeclarationListItem, ErrorReason>> {
    for_iter!(iter, (component_value, location), {
        match component_value {
            WhiteSpace | Semicolon => (),
            AtKeyword(name) => return Some(Ok(Decl_AtRule(parse_at_rule(iter, name, location)))),
            _ => return Some(match parse_declaration(iter, (component_value, location)) {
                Ok(declaration) => Ok(Declaration(declaration)),
                Err(reason) => {
                    // Find the end of the declaration
                    for (v, _) in *iter { if v == Semicolon { break } }
                    Err(reason)
                }
            }),
        }
    })
    None
}

/// Used eg. in @supports
pub fn parse_one_declaration(iter: &mut ComponentValueIterator) -> Result<Declaration, ErrorReason> {
    match iter.next_non_whitespace() {
        None => Err(ErrEmptyInput),
        Some(item) => {
            let result = parse_declaration(iter, item);
            if result.is_err() || iter.next_non_whitespace().is_none() { result }
            else { Err(ErrExtraInput) }
        }
    }
}

/// Used eg. in attr(foo, color)
pub fn parse_one_component_value(iter: &mut ComponentValueIterator)
                                 -> Result<(ComponentValue, SourceLocation), ErrorReason> {
    match iter.next_non_whitespace() {
        None => Err(ErrEmptyInput),
        Some(item) => {
            if iter.next_non_whitespace().is_none() { Ok(item) }
            else { Err(ErrExtraInput) }
        }
    }
}

//  ***********  End of public API  ***********

fn parse_at_rule(iter: &mut ComponentValueIterator, name: ~str, location: SourceLocation)
                 -> AtRule {
    let mut prelude = ~[];
    let mut block = None;
    for_iter!(iter, (component_value, location), {
        match component_value {
            CurlyBracketBlock(content) => { block = Some(content); break },
            Semicolon => break,
            component_value => prelude.push((component_value, location)),
        }
    })
    AtRule {location: location, name: name, prelude: prelude, block: block}
}

fn parse_qualified_rule(iter: &mut ComponentValueIterator, first: (ComponentValue, SourceLocation))
                          -> Result<QualifiedRule, ErrorReason> {
    match first {
        (CurlyBracketBlock(content), location)
        => return Ok(QualifiedRule { location: location, prelude: ~[], block: content }),
        _ => (),
    }
    let mut prelude = ~[first];
    for_iter!(iter, (component_value, location), {
        match component_value {
            CurlyBracketBlock(content)
            => return Ok(QualifiedRule {location: location, prelude: prelude, block: content}),
            component_value => prelude.push((component_value, location)),
        }
    })
    Err(ErrMissingQualifiedRuleBlock)
}

fn parse_declaration(iter: &mut ComponentValueIterator, first: (ComponentValue, SourceLocation))
                       -> Result<Declaration, ErrorReason> {
    let (name, location) = match first {
        (Ident(name), location) => (name, location),
        _ => return Err(ErrInvalidDeclarationSyntax)
    };
    match iter.next_non_whitespace() {
        Some((Colon, _)) => (),
        _ => return Err(ErrInvalidDeclarationSyntax),
    }
    let mut value = ~[];
    let mut important = false;
    for_iter!(iter, (component_value, location), {
        match component_value {
            Semicolon => break,
            Delim('!') => if parse_declaration_important(iter) {
                important = true;
                break
            } else {
                return Err(ErrInvalidBangImportantSyntax)
            },
            component_value => value.push((component_value, location)),
        }
    })
    Ok(Declaration{location: location, name: name, value: value, important: important})
}

#[inline]
fn parse_declaration_important(iter: &mut ComponentValueIterator) -> bool {
    let ident_value = match iter.next_non_whitespace() {
        Some((Ident(value), _)) => value,
        _ => return false,
    };
    if !eq_ignore_ascii_case(ident_value, "important") { return false }
    match iter.next_non_whitespace() {
        Some((Semicolon, _)) => true,
        None => true,
        _ => false
    }
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate wlroots;

use std::process::Command;
use std::thread;
use std::time::Duration;

use wlroots::{project_box, Area, Compositor, CompositorBuilder, CursorBuilder, CursorHandler,
              CursorId, InputManagerHandler, Keyboard, KeyboardHandler, Origin, Output,
              OutputBuilder, OutputBuilderResult, OutputHandler, OutputLayout,
              OutputManagerHandler, Pointer, PointerHandler, Renderer, Seat, SeatHandler, SeatId,
              Size, Surface, XCursorTheme, XdgV6ShellHandler, XdgV6ShellManagerHandler,
              XdgV6ShellSurface, XdgV6ShellSurfaceHandle};
use wlroots::key_events::KeyEvent;
use wlroots::pointer_events::{ButtonEvent, MotionEvent};
use wlroots::utils::{init_logging, L_DEBUG};
use wlroots::wlroots_sys::wlr_button_state::WLR_BUTTON_PRESSED;
use wlroots::xkbcommon::xkb::keysyms::KEY_Escape;

struct State {
    xcursor_theme: XCursorTheme,
    layout: OutputLayout,
    cursor_id: CursorId,
    shells: Vec<XdgV6ShellSurfaceHandle>,
    seat_id: Option<SeatId>
}

impl State {
    fn new(xcursor_theme: XCursorTheme, layout: OutputLayout, cursor_id: CursorId) -> Self {
        State { xcursor_theme,
                layout,
                cursor_id,
                seat_id: None,
                shells: vec![] }
    }
}

compositor_data!(State);

struct SeatHandlerEx;

struct CursorEx;

impl CursorHandler for CursorEx {}

impl SeatHandler for SeatHandlerEx {
    // TODO
}

struct XdgV6ShellHandlerEx;
struct XdgV6ShellManager;

impl XdgV6ShellHandler for XdgV6ShellHandlerEx {}
impl XdgV6ShellManagerHandler for XdgV6ShellManager {
    fn new_surface(&mut self,
                   compositor: &mut Compositor,
                   shell: &mut XdgV6ShellSurface,
                   _: &mut Surface)
                   -> Option<Box<XdgV6ShellHandler>> {
        let state: &mut State = compositor.into();
        state.shells.push(shell.weak_reference());
        for (mut output, _) in state.layout.outputs() {
            output.run(|output| output.schedule_frame()).unwrap();
        }
        Some(Box::new(XdgV6ShellHandlerEx))
    }

    fn surface_destroyed(&mut self,
                         compositor: &mut Compositor,
                         shell: &mut XdgV6ShellSurface,
                         _: &mut Surface) {
        let state: &mut State = compositor.into();
        let weak = shell.weak_reference();
        if let Some(index) = state.shells.iter().position(|s| *s == weak) {
            state.shells.remove(index);
        }
    }
}

struct OutputManager;

struct ExOutput;

struct InputManager;

struct ExPointer;

struct ExKeyboardHandler;

impl OutputManagerHandler for OutputManager {
    fn output_added<'output>(&mut self,
                             compositor: &mut Compositor,
                             builder: OutputBuilder<'output>)
                             -> Option<OutputBuilderResult<'output>> {
        let result = builder.build_best_mode(ExOutput);
        let state: &mut State = compositor.into();
        let xcursor = state.xcursor_theme
                           .get_cursor("left_ptr".into())
                           .expect("Could not load left_ptr cursor");
        let image = &xcursor.images()[0];
        // TODO use output config if present instead of auto
        state.layout.add_auto(result.output);
        let mut cursor = state.layout.cursor(state.cursor_id).unwrap();
        cursor.set_cursor_image(image);
        let (x, y) = cursor.coords();
        // https://en.wikipedia.org/wiki/Mouse_warping
        cursor.warp(None, x, y);
        Some(result)
    }
}

impl KeyboardHandler for ExKeyboardHandler {
    fn on_key(&mut self, compositor: &mut Compositor, _: &mut Keyboard, key_event: &mut KeyEvent) {
        for key in key_event.pressed_keys() {
            if key == KEY_Escape {
                compositor.terminate()
            } else {
                thread::spawn(move || {
                                  Command::new("weston-terminal").output().unwrap();
                              });
            }
        }
    }
}

impl PointerHandler for ExPointer {
    fn on_motion(&mut self, compositor: &mut Compositor, _: &mut Pointer, event: &MotionEvent) {
        let state: &mut State = compositor.into();
        let (delta_x, delta_y) = event.delta();
        state.layout
             .cursor(state.cursor_id)
             .unwrap()
             .move_to(event.device(), delta_x, delta_y);
    }

    fn on_button(&mut self, _: &mut Compositor, _: &mut Pointer, event: &ButtonEvent) {
        if event.state() == WLR_BUTTON_PRESSED {
            wlr_log!(L_DEBUG, "Clicking pointer {}", event.button())
        }
    }
}

impl OutputHandler for ExOutput {
    fn on_frame(&mut self, compositor: &mut Compositor, output: &mut Output) {
        let state: &mut State = compositor.data.downcast_mut().unwrap();
        if state.shells.len() < 1 {
            return
        }
        let renderer = compositor.renderer
                                 .as_mut()
                                 .expect("Compositor was not loaded with a renderer");
        render_shells(state, &mut renderer.render(output));
    }
}

impl InputManagerHandler for InputManager {
    fn pointer_added(&mut self,
                     _: &mut Compositor,
                     _: &mut Pointer)
                     -> Option<Box<PointerHandler>> {
        Some(Box::new(ExPointer))
    }

    fn keyboard_added(&mut self,
                      compositor: &mut Compositor,
                      keyboard: &mut Keyboard)
                      -> Option<Box<KeyboardHandler>> {
        let seat_id = {
            let state: &mut State = compositor.into();
            state.seat_id.unwrap()
        };
        let seat = compositor.seats.get(seat_id).expect("Invalid seat id");
        seat.set_keyboard(keyboard.input_device());
        Some(Box::new(ExKeyboardHandler))
    }
}

fn main() {
    init_logging(L_DEBUG, None);
    let cursor = CursorBuilder::new(Box::new(CursorEx)).expect("Could not create cursor");
    let xcursor_theme = XCursorTheme::load_theme(None, 16).expect("Could not load theme");
    let mut layout = OutputLayout::new().expect("Could not construct an output layout");

    let cursor_id = layout.attach_cursor(cursor);
    let mut compositor =
        CompositorBuilder::new().gles2(true)
                                .input_manager(Box::new(InputManager))
                                .output_manager(Box::new(OutputManager))
                                .xdg_shell_v6_manager(Box::new(XdgV6ShellManager))
                                .build_auto(State::new(xcursor_theme, layout, cursor_id));

    {
        let seat_id = Seat::create(&mut compositor, "Main Seat".into(), Box::new(SeatHandlerEx))
            .expect("Could not allocate the global seat").id();
        let state: &mut State = (&mut compositor).into();
        state.seat_id = Some(seat_id);
    }
    compositor.run();
}

/// Render the shells in the current compositor state on the given output.
fn render_shells(state: &mut State, renderer: &mut Renderer) {
    let shells = state.shells.clone();
    for mut shell in shells {
        shell.run(|shell| {
                      shell.surface()
                           .run(|surface| {
                                    let (width, height) = surface.current_state().size();
                                    let (render_width, render_height) =
                                        (width * renderer.output.scale() as i32,
                                        height * renderer.output.scale() as i32);
                                    let (lx, ly) = (0.0, 0.0);
                                    let render_box = Area::new(Origin::new(lx as i32, ly as i32),
                                                               Size::new(render_width,
                                                                         render_height));
                                    if state.layout.intersects(renderer.output, render_box) {
                                        let transform = renderer.output.get_transform().invert();
                                        let matrix = project_box(render_box,
                                                                 transform,
                                                                 0.0,
                                                                 renderer.output
                                                                         .transform_matrix());
                                        renderer.render_texture_with_matrix(&surface.texture(),
                                                                            matrix);
                                        surface.send_frame_done(Duration::from_secs(1));
                                    }
                                })
                           .unwrap()
                  })
             .unwrap();
    }
}
<commit_msg>Send seat input in the xdg shell v6 test<commit_after>#[macro_use]
extern crate wlroots;

use std::process::Command;
use std::thread;
use std::time::Duration;

use wlroots::{project_box, Area, Capability, Compositor, CompositorBuilder, CursorBuilder,
              CursorHandler, CursorId, InputManagerHandler, Keyboard, KeyboardGrab,
              KeyboardHandle, KeyboardHandler, Origin, Output, OutputBuilder, OutputBuilderResult,
              OutputHandler, OutputLayout, OutputManagerHandler, Pointer, PointerHandler,
              Renderer, Seat, SeatHandler, SeatId, Size, Surface, XCursorTheme, XdgV6ShellHandler,
              XdgV6ShellManagerHandler, XdgV6ShellState, XdgV6ShellSurface,
              XdgV6ShellSurfaceHandle};
use wlroots::key_events::KeyEvent;
use wlroots::pointer_events::{ButtonEvent, MotionEvent};
use wlroots::utils::{init_logging, L_DEBUG};
use wlroots::wlroots_sys::wlr_button_state::WLR_BUTTON_PRESSED;
use wlroots::wlroots_sys::wlr_key_state::WLR_KEY_PRESSED;
use wlroots::xkbcommon::xkb::keysyms::{KEY_Escape, KEY_F1};

struct State {
    xcursor_theme: XCursorTheme,
    keyboard: Option<KeyboardHandle>,
    layout: OutputLayout,
    cursor_id: CursorId,
    shells: Vec<XdgV6ShellSurfaceHandle>,
    seat_id: Option<SeatId>
}

impl State {
    fn new(xcursor_theme: XCursorTheme, layout: OutputLayout, cursor_id: CursorId) -> Self {
        State { xcursor_theme,
                layout,
                cursor_id,
                keyboard: None,
                seat_id: None,
                shells: vec![] }
    }
}

compositor_data!(State);

struct SeatHandlerEx;

struct CursorEx;

impl CursorHandler for CursorEx {}

impl SeatHandler for SeatHandlerEx {}

struct XdgV6ShellHandlerEx;
struct XdgV6ShellManager;

impl XdgV6ShellHandler for XdgV6ShellHandlerEx {
    fn on_commit(&mut self,
                 compositor: &mut Compositor,
                 surface: &mut Surface,
                 shell: &mut XdgV6ShellSurface) {
    }
}
impl XdgV6ShellManagerHandler for XdgV6ShellManager {
    fn new_surface(&mut self,
                   compositor: &mut Compositor,
                   shell: &mut XdgV6ShellSurface,
                   surface: &mut Surface)
                   -> Option<Box<XdgV6ShellHandler>> {
        shell.ping();
        match shell.state() {
            Some(&mut XdgV6ShellState::TopLevel(ref mut toplevel)) => {
                toplevel.set_activated(true);
            }
            _ => {}
        }
        let seat_id = {
            let state: &mut State = compositor.into();
            state.shells.push(shell.weak_reference());
            for (mut output, _) in state.layout.outputs() {
                output.run(|output| output.schedule_frame()).unwrap();
            }
            state.seat_id.unwrap()
        };
        let seat = compositor.seats.get(seat_id).expect("invalid seat id");
        let mut keyboard = seat.get_keyboard().expect("Seat did not have a keyboard set");
        keyboard.run(|keyboard| {
                         seat.keyboard_notify_enter(surface,
                                                    &mut keyboard.keycodes(),
                                                    &mut keyboard.get_modifier_masks())
                     })
                .unwrap();
        Some(Box::new(XdgV6ShellHandlerEx))
    }

    fn surface_destroyed(&mut self,
                         compositor: &mut Compositor,
                         shell: &mut XdgV6ShellSurface,
                         _: &mut Surface) {
        let state: &mut State = compositor.into();
        let weak = shell.weak_reference();
        if let Some(index) = state.shells.iter().position(|s| *s == weak) {
            state.shells.remove(index);
        }
    }
}

struct OutputManager;

struct ExOutput;

struct InputManager;

struct ExPointer;

struct ExKeyboardHandler;

impl OutputManagerHandler for OutputManager {
    fn output_added<'output>(&mut self,
                             compositor: &mut Compositor,
                             builder: OutputBuilder<'output>)
                             -> Option<OutputBuilderResult<'output>> {
        let result = builder.build_best_mode(ExOutput);
        let state: &mut State = compositor.into();
        let xcursor = state.xcursor_theme
                           .get_cursor("left_ptr".into())
                           .expect("Could not load left_ptr cursor");
        let image = &xcursor.images()[0];
        // TODO use output config if present instead of auto
        state.layout.add_auto(result.output);
        let mut cursor = state.layout.cursor(state.cursor_id).unwrap();
        cursor.set_cursor_image(image);
        let (x, y) = cursor.coords();
        // https://en.wikipedia.org/wiki/Mouse_warping
        cursor.warp(None, x, y);
        Some(result)
    }
}

impl KeyboardHandler for ExKeyboardHandler {
    fn on_key(&mut self, compositor: &mut Compositor, _: &mut Keyboard, key_event: &mut KeyEvent) {
        for key in key_event.pressed_keys() {
            if key == KEY_Escape {
                compositor.terminate()
            } else if key_event.key_state() == WLR_KEY_PRESSED {
                if key == KEY_F1 {
                    thread::spawn(move || {
                                      Command::new("weston-terminal").output().unwrap();
                                  });
                    return
                }
            }
        }
        let state: &mut State = compositor.data.downcast_mut().unwrap();
        let seat_id = state.seat_id.unwrap();
        let seat = compositor.seats.get(seat_id).expect("invalid seat id");
        seat.keyboard_notify_key(key_event.time_msec(),
                                 key_event.keycode(),
                                 key_event.key_state() as u32);
    }
}

impl PointerHandler for ExPointer {
    fn on_motion(&mut self, compositor: &mut Compositor, _: &mut Pointer, event: &MotionEvent) {
        let state: &mut State = compositor.into();
        let (delta_x, delta_y) = event.delta();
        state.layout
             .cursor(state.cursor_id)
             .unwrap()
             .move_to(event.device(), delta_x, delta_y);
    }
}

impl OutputHandler for ExOutput {
    fn on_frame(&mut self, compositor: &mut Compositor, output: &mut Output) {
        let state: &mut State = compositor.data.downcast_mut().unwrap();
        if state.shells.len() < 1 {
            return
        }
        let renderer = compositor.renderer
                                 .as_mut()
                                 .expect("Compositor was not loaded with a renderer");
        render_shells(state, &mut renderer.render(output));
    }
}

impl InputManagerHandler for InputManager {
    fn pointer_added(&mut self,
                     _: &mut Compositor,
                     _: &mut Pointer)
                     -> Option<Box<PointerHandler>> {
        Some(Box::new(ExPointer))
    }

    fn keyboard_added(&mut self,
                      compositor: &mut Compositor,
                      keyboard: &mut Keyboard)
                      -> Option<Box<KeyboardHandler>> {
        let seat_id = {
            let state: &mut State = compositor.into();
            state.keyboard = Some(keyboard.weak_reference());
            state.seat_id.unwrap()
        };
        let seat = compositor.seats.get(seat_id).expect("Invalid seat id");
        seat.set_keyboard(keyboard.input_device());
        Some(Box::new(ExKeyboardHandler))
    }
}

fn main() {
    init_logging(L_DEBUG, None);
    let cursor = CursorBuilder::new(Box::new(CursorEx)).expect("Could not create cursor");
    let xcursor_theme = XCursorTheme::load_theme(None, 16).expect("Could not load theme");
    let mut layout = OutputLayout::new().expect("Could not construct an output layout");

    let cursor_id = layout.attach_cursor(cursor);
    let mut compositor =
        CompositorBuilder::new().gles2(true)
                                .input_manager(Box::new(InputManager))
                                .output_manager(Box::new(OutputManager))
                                .xdg_shell_v6_manager(Box::new(XdgV6ShellManager))
                                .build_auto(State::new(xcursor_theme, layout, cursor_id));

    {
        let seat_id = {
            let seat = Seat::create(&mut compositor, "Main Seat".into(), Box::new(SeatHandlerEx))
                .expect("Could not allocate the global seat");
            seat.set_capabilities(Capability::all());
            seat.id()
        };
        let state: &mut State = (&mut compositor).into();
        state.seat_id = Some(seat_id);
    }
    compositor.run();
}

/// Render the shells in the current compositor state on the given output.
fn render_shells(state: &mut State, renderer: &mut Renderer) {
    let shells = state.shells.clone();
    for mut shell in shells {
        shell.run(|shell| {
                      shell.surface()
                           .run(|surface| {
                                    let (width, height) = surface.current_state().size();
                                    let (render_width, render_height) =
                                        (width * renderer.output.scale() as i32,
                                        height * renderer.output.scale() as i32);
                                    let (lx, ly) = (0.0, 0.0);
                                    let render_box = Area::new(Origin::new(lx as i32, ly as i32),
                                                               Size::new(render_width,
                                                                         render_height));
                                    if state.layout.intersects(renderer.output, render_box) {
                                        let transform = renderer.output.get_transform().invert();
                                        let matrix = project_box(render_box,
                                                                 transform,
                                                                 0.0,
                                                                 renderer.output
                                                                         .transform_matrix());
                                        renderer.render_texture_with_matrix(&surface.texture(),
                                                                            matrix);
                                        surface.send_frame_done(Duration::from_secs(1));
                                    }
                                })
                           .unwrap()
                  })
             .unwrap();
    }
}
<|endoftext|>


<commit_before><commit_msg>Remove unnecessary fn<commit_after><|endoftext|>