<commit_before>extern crate crossbeam_queue;
extern crate crossbeam_utils;

use crossbeam_queue::SegQueue;
use crossbeam_utils::thread::scope;

const CONC_COUNT: i64 = 1000000;

#[test]
fn push_pop_1() {
    let q: SegQueue<i64> = SegQueue::new();
    q.push(37);
    assert_eq!(q.pop(), Ok(37));
}

#[test]
fn push_pop_2() {
    let q: SegQueue<i64> = SegQueue::new();
    q.push(37);
    q.push(48);
    assert_eq!(q.pop(), Ok(37));
    assert_eq!(q.pop(), Ok(48));
}

#[test]
fn push_pop_empty_check() {
    let q: SegQueue<i64> = SegQueue::new();
    assert_eq!(q.is_empty(), true);
    q.push(42);
    assert_eq!(q.is_empty(), false);
    assert_eq!(q.pop(), Ok(42));
    assert_eq!(q.is_empty(), true);
}

#[test]
fn push_pop_many_seq() {
    let q: SegQueue<i64> = SegQueue::new();
    for i in 0..200 {
        q.push(i)
    }
    for i in 0..200 {
        assert_eq!(q.pop(), Ok(i));
    }
}

#[test]
fn push_pop_many_spsc() {
    let q: SegQueue<i64> = SegQueue::new();

    scope(|scope| {
        scope.spawn(|_| {
            let mut next = 0;

            while next < CONC_COUNT {
                if let Ok(elem) = q.pop() {
                    assert_eq!(elem, next);
                    next += 1;
                }
            }
        });

        for i in 0..CONC_COUNT {
            q.push(i)
        }
    }).unwrap();
}

#[test]
fn push_pop_many_spmc() {
    fn recv(_t: i32, q: &SegQueue<i64>) {
        let mut cur = -1;
        for _i in 0..CONC_COUNT {
            if let Ok(elem) = q.pop() {
                assert!(elem > cur);
                cur = elem;

                if cur == CONC_COUNT - 1 {
                    break;
                }
            }
        }
    }

    let q: SegQueue<i64> = SegQueue::new();
    scope(|scope| {
        for i in 0..3 {
            let q = &q;
            scope.spawn(move |_| recv(i, q));
        }

        scope.spawn(|_| {
            for i in 0..CONC_COUNT {
                q.push(i);
            }
        });
    }).unwrap();
}

#[test]
fn push_pop_many_mpmc() {
    enum LR {
        Left(i64),
        Right(i64),
    }

    let q: SegQueue<LR> = SegQueue::new();

    scope(|scope| {
        for _t in 0..2 {
            scope.spawn(|_| {
                for i in CONC_COUNT - 1..CONC_COUNT {
                    q.push(LR::Left(i))
                }
            });
            scope.spawn(|_| {
                for i in CONC_COUNT - 1..CONC_COUNT {
                    q.push(LR::Right(i))
                }
            });
            scope.spawn(|_| {
                let mut vl = vec![];
                let mut vr = vec![];
                for _i in 0..CONC_COUNT {
                    match q.pop() {
                        Ok(LR::Left(x)) => vl.push(x),
                        Ok(LR::Right(x)) => vr.push(x),
                        _ => {}
                    }
                }

                let mut vl2 = vl.clone();
                let mut vr2 = vr.clone();
                vl2.sort();
                vr2.sort();

                assert_eq!(vl, vl2);
                assert_eq!(vr, vr2);
            });
        }
    }).unwrap();
}
<commit_msg>Copy tests from unbounded channel<commit_after>extern crate crossbeam_queue;
extern crate crossbeam_utils;
extern crate rand;

use std::sync::atomic::{AtomicUsize, Ordering};

use crossbeam_queue::SegQueue;
use crossbeam_utils::thread::scope;
use rand::{thread_rng, Rng};

#[test]
fn smoke() {
    let q = SegQueue::new();
    q.push(7);
    assert_eq!(q.pop(), Ok(7));

    q.push(8);
    assert_eq!(q.pop(), Ok(8));
    assert!(q.pop().is_err());
}

#[test]
fn len_empty_full() {
    let q = SegQueue::new();

    assert_eq!(q.len(), 0);
    assert_eq!(q.is_empty(), true);

    q.push(());

    assert_eq!(q.len(), 1);
    assert_eq!(q.is_empty(), false);

    q.pop().unwrap();

    assert_eq!(q.len(), 0);
    assert_eq!(q.is_empty(), true);
}

#[test]
fn len() {
    let q = SegQueue::new();

    assert_eq!(q.len(), 0);

    for i in 0..50 {
        q.push(i);
        assert_eq!(q.len(), i + 1);
    }

    for i in 0..50 {
        q.pop().unwrap();
        assert_eq!(q.len(), 50 - i - 1);
    }

    assert_eq!(q.len(), 0);
}

#[test]
fn spsc() {
    const COUNT: usize = 100_000;

    let q = SegQueue::new();

    scope(|scope| {
        scope.spawn(|_| {
            for i in 0..COUNT {
                loop {
                    if let Ok(x) = q.pop() {
                        assert_eq!(x, i);
                        break;
                    }
                }
            }
            assert!(q.pop().is_err());
        });
        scope.spawn(|_| {
            for i in 0..COUNT {
                q.push(i);
            }
        });
    }).unwrap();
}

#[test]
fn mpmc() {
    const COUNT: usize = 25_000;
    const THREADS: usize = 4;

    let q = SegQueue::<usize>::new();
    let v = (0..COUNT).map(|_| AtomicUsize::new(0)).collect::<Vec<_>>();

    scope(|scope| {
        for _ in 0..THREADS {
            scope.spawn(|_| {
                for _ in 0..COUNT {
                    let n = loop {
                        if let Ok(x) = q.pop() {
                            break x;
                        }
                    };
                    v[n].fetch_add(1, Ordering::SeqCst);
                }
            });
        }
        for _ in 0..THREADS {
            scope.spawn(|_| {
                for i in 0..COUNT {
                    q.push(i);
                }
            });
        }
    }).unwrap();

    for c in v {
        assert_eq!(c.load(Ordering::SeqCst), THREADS);
    }
}

#[test]
fn drops() {
    static DROPS: AtomicUsize = AtomicUsize::new(0);

    #[derive(Debug, PartialEq)]
    struct DropCounter;

    impl Drop for DropCounter {
        fn drop(&mut self) {
            DROPS.fetch_add(1, Ordering::SeqCst);
        }
    }

    let mut rng = thread_rng();

    for _ in 0..100 {
        let steps = rng.gen_range(0, 10_000);
        let additional = rng.gen_range(0, 1000);

        DROPS.store(0, Ordering::SeqCst);
        let q = SegQueue::new();

        scope(|scope| {
            scope.spawn(|_| {
                for _ in 0..steps {
                    while q.pop().is_err() {}
                }
            });

            scope.spawn(|_| {
                for _ in 0..steps {
                    q.push(DropCounter);
                }
            });
        }).unwrap();

        for _ in 0..additional {
            q.push(DropCounter);
        }

        assert_eq!(DROPS.load(Ordering::SeqCst), steps);
        drop(q);
        assert_eq!(DROPS.load(Ordering::SeqCst), steps + additional);
    }
}
<|endoftext|>


<commit_before>//! 64-bit specific Apple (ios/darwin) definitions

pub type c_long = i64;
pub type c_ulong = u64;

s! {
    pub struct pthread_attr_t {
        __sig: c_long,
        __opaque: [::c_char; 56]
    }
}

pub const __PTHREAD_MUTEX_SIZE__: usize = 56;
pub const __PTHREAD_COND_SIZE__: usize = 40;
pub const __PTHREAD_CONDATTR_SIZE__: usize = 8;
pub const __PTHREAD_RWLOCK_SIZE__: usize = 192;

pub const TIOCTIMESTAMP: ::c_ulong = 0x40107459;
pub const TIOCDCDTIMESTAMP: ::c_ulong = 0x40107458;
<commit_msg>Add FIONREAD for apple/b64<commit_after>//! 64-bit specific Apple (ios/darwin) definitions

pub type c_long = i64;
pub type c_ulong = u64;

s! {
    pub struct pthread_attr_t {
        __sig: c_long,
        __opaque: [::c_char; 56]
    }
}

pub const __PTHREAD_MUTEX_SIZE__: usize = 56;
pub const __PTHREAD_COND_SIZE__: usize = 40;
pub const __PTHREAD_CONDATTR_SIZE__: usize = 8;
pub const __PTHREAD_RWLOCK_SIZE__: usize = 192;

pub const TIOCTIMESTAMP: ::c_ulong = 0x40107459;
pub const TIOCDCDTIMESTAMP: ::c_ulong = 0x40107458;

pub const FIONREAD: ::c_ulong = 0x4004667f;
<|endoftext|>


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

// spell-checker:ignore (ToDO) Chmoder cmode fmode fperm fref ugoa RFILE RFILE's

#[macro_use]
extern crate uucore;

use clap::{crate_version, App, Arg};
use std::fs;
use std::os::unix::fs::{MetadataExt, PermissionsExt};
use std::path::Path;
use uucore::fs::display_permissions_unix;
use uucore::libc::mode_t;
#[cfg(not(windows))]
use uucore::mode;
use uucore::InvalidEncodingHandling;
use walkdir::WalkDir;

static ABOUT: &str = "Change the mode of each FILE to MODE.
 With --reference, change the mode of each FILE to that of RFILE.";

mod options {
    pub const CHANGES: &str = "changes";
    pub const QUIET: &str = "quiet"; // visible_alias("silent")
    pub const VERBOSE: &str = "verbose";
    pub const NO_PRESERVE_ROOT: &str = "no-preserve-root";
    pub const PRESERVE_ROOT: &str = "preserve-root";
    pub const REFERENCE: &str = "RFILE";
    pub const RECURSIVE: &str = "recursive";
    pub const MODE: &str = "MODE";
    pub const FILE: &str = "FILE";
}

fn usage() -> String {
    format!(
        "{0} [OPTION]... MODE[,MODE]... FILE...
or: {0} [OPTION]... OCTAL-MODE FILE...
or: {0} [OPTION]... --reference=RFILE FILE...",
        uucore::execution_phrase()
    )
}

fn get_long_usage() -> String {
    String::from("Each MODE is of the form '[ugoa]*([-+=]([rwxXst]*|[ugo]))+|[-+=]?[0-7]+'.")
}

pub fn uumain(args: impl uucore::Args) -> i32 {
    let mut args = args
        .collect_str(InvalidEncodingHandling::ConvertLossy)
        .accept_any();

    // Before we can parse 'args' with clap (and previously getopts),
    // a possible MODE prefix '-' needs to be removed (e.g. "chmod -x FILE").
    let mode_had_minus_prefix = strip_minus_from_mode(&mut args);

    let usage = usage();
    let after_help = get_long_usage();

    let matches = uu_app()
        .usage(&usage[..])
        .after_help(&after_help[..])
        .get_matches_from(args);

    let changes = matches.is_present(options::CHANGES);
    let quiet = matches.is_present(options::QUIET);
    let verbose = matches.is_present(options::VERBOSE);
    let preserve_root = matches.is_present(options::PRESERVE_ROOT);
    let recursive = matches.is_present(options::RECURSIVE);
    let fmode = matches
        .value_of(options::REFERENCE)
        .and_then(|fref| match fs::metadata(fref) {
            Ok(meta) => Some(meta.mode()),
            Err(err) => crash!(1, "cannot stat attributes of '{}': {}", fref, err),
        });
    let modes = matches.value_of(options::MODE).unwrap(); // should always be Some because required
    let cmode = if mode_had_minus_prefix {
        // clap parsing is finished, now put prefix back
        format!("-{}", modes)
    } else {
        modes.to_string()
    };
    let mut files: Vec<String> = matches
        .values_of(options::FILE)
        .map(|v| v.map(ToString::to_string).collect())
        .unwrap_or_default();
    let cmode = if fmode.is_some() {
        // "--reference" and MODE are mutually exclusive
        // if "--reference" was used MODE needs to be interpreted as another FILE
        // it wasn't possible to implement this behavior directly with clap
        files.push(cmode);
        None
    } else {
        Some(cmode)
    };

    if files.is_empty() {
        crash!(1, "missing operand");
    }

    let chmoder = Chmoder {
        changes,
        quiet,
        verbose,
        preserve_root,
        recursive,
        fmode,
        cmode,
    };
    match chmoder.chmod(files) {
        Ok(()) => {}
        Err(e) => return e,
    }

    0
}

pub fn uu_app() -> App<'static, 'static> {
    App::new(uucore::util_name())
        .version(crate_version!())
        .about(ABOUT)
        .arg(
            Arg::with_name(options::CHANGES)
                .long(options::CHANGES)
                .short("c")
                .help("like verbose but report only when a change is made"),
        )
        .arg(
            Arg::with_name(options::QUIET)
                .long(options::QUIET)
                .visible_alias("silent")
                .short("f")
                .help("suppress most error messages"),
        )
        .arg(
            Arg::with_name(options::VERBOSE)
                .long(options::VERBOSE)
                .short("v")
                .help("output a diagnostic for every file processed"),
        )
        .arg(
            Arg::with_name(options::NO_PRESERVE_ROOT)
                .long(options::NO_PRESERVE_ROOT)
                .help("do not treat '/' specially (the default)"),
        )
        .arg(
            Arg::with_name(options::PRESERVE_ROOT)
                .long(options::PRESERVE_ROOT)
                .help("fail to operate recursively on '/'"),
        )
        .arg(
            Arg::with_name(options::RECURSIVE)
                .long(options::RECURSIVE)
                .short("R")
                .help("change files and directories recursively"),
        )
        .arg(
            Arg::with_name(options::REFERENCE)
                .long("reference")
                .takes_value(true)
                .help("use RFILE's mode instead of MODE values"),
        )
        .arg(
            Arg::with_name(options::MODE)
                .required_unless(options::REFERENCE)
                .takes_value(true),
            // It would be nice if clap could parse with delimiter, e.g. "g-x,u+x",
            // however .multiple(true) cannot be used here because FILE already needs that.
            // Only one positional argument with .multiple(true) set is allowed per command
        )
        .arg(
            Arg::with_name(options::FILE)
                .required_unless(options::MODE)
                .multiple(true),
        )
}

// Iterate 'args' and delete the first occurrence
// of a prefix '-' if it's associated with MODE
// e.g. "chmod -v -xw -R FILE" -> "chmod -v xw -R FILE"
pub fn strip_minus_from_mode(args: &mut Vec<String>) -> bool {
    for arg in args {
        if arg == "--" {
            break;
        }
        if arg.starts_with('-') {
            if let Some(second) = arg.chars().nth(1) {
                match second {
                    'r' | 'w' | 'x' | 'X' | 's' | 't' | 'u' | 'g' | 'o' | '0'..='7' => {
                        // TODO: use strip_prefix() once minimum rust version reaches 1.45.0
                        *arg = arg[1..arg.len()].to_string();
                        return true;
                    }
                    _ => {}
                }
            }
        }
    }
    false
}

struct Chmoder {
    changes: bool,
    quiet: bool,
    verbose: bool,
    preserve_root: bool,
    recursive: bool,
    fmode: Option<u32>,
    cmode: Option<String>,
}

impl Chmoder {
    fn chmod(&self, files: Vec<String>) -> Result<(), i32> {
        let mut r = Ok(());

        for filename in &files {
            let filename = &filename[..];
            let file = Path::new(filename);
            if !file.exists() {
                if is_symlink(file) {
                    println!(
                        "failed to change mode of '{}' from 0000 (---------) to 0000 (---------)",
                        filename
                    );
                    if !self.quiet {
                        show_error!("cannot operate on dangling symlink '{}'", filename);
                    }
                } else if !self.quiet {
                    show_error!("cannot access '{}': No such file or directory", filename);
                }
                return Err(1);
            }
            if self.recursive && self.preserve_root && filename == "/" {
                show_error!(
                    "it is dangerous to operate recursively on '{}'\nuse --no-preserve-root to override this failsafe",
                    filename
                );
                return Err(1);
            }
            if !self.recursive {
                r = self.chmod_file(file).and(r);
            } else {
                for entry in WalkDir::new(&filename).into_iter().filter_map(|e| e.ok()) {
                    let file = entry.path();
                    r = self.chmod_file(file).and(r);
                }
            }
        }
        r
    }

    #[cfg(windows)]
    fn chmod_file(&self, file: &Path) -> Result<(), i32> {
        // chmod is useless on Windows
        // it doesn't set any permissions at all
        // instead it just sets the readonly attribute on the file
        Err(0)
    }
    #[cfg(any(unix, target_os = "redox"))]
    fn chmod_file(&self, file: &Path) -> Result<(), i32> {
        use uucore::mode::get_umask;

        let fperm = match fs::metadata(file) {
            Ok(meta) => meta.mode() & 0o7777,
            Err(err) => {
                if is_symlink(file) {
                    if self.verbose {
                        println!(
                            "neither symbolic link '{}' nor referent has been changed",
                            file.display()
                        );
                    }
                    return Ok(());
                } else if err.kind() == std::io::ErrorKind::PermissionDenied {
                    show_error!("'{}': Permission denied", file.display());
                } else {
                    show_error!("'{}': {}", file.display(), err);
                }
                return Err(1);
            }
        };
        match self.fmode {
            Some(mode) => self.change_file(fperm, mode, file)?,
            None => {
                let cmode_unwrapped = self.cmode.clone().unwrap();
                let mut new_mode = fperm;
                let mut naively_expected_new_mode = new_mode;
                for mode in cmode_unwrapped.split(',') {
                    // cmode is guaranteed to be Some in this case
                    let arr: &[char] = &['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'];
                    let result = if mode.contains(arr) {
                        mode::parse_numeric(new_mode, mode, file.is_dir()).map(|v| (v, v))
                    } else {
                        mode::parse_symbolic(new_mode, mode, get_umask(), file.is_dir()).map(|m| {
                            // calculate the new mode as if umask was 0
                            let naive_mode = mode::parse_symbolic(
                                naively_expected_new_mode,
                                mode,
                                0,
                                file.is_dir(),
                            )
                            .unwrap(); // we know that mode must be valid, so this cannot fail
                            (m, naive_mode)
                        })
                    };
                    match result {
                        Ok((mode, naive_mode)) => {
                            new_mode = mode;
                            naively_expected_new_mode = naive_mode;
                        }
                        Err(f) => {
                            if !self.quiet {
                                show_error!("{}", f);
                            }
                            return Err(1);
                        }
                    }
                }
                self.change_file(fperm, new_mode, file)?;
                // if a permission would have been removed if umask was 0, but it wasn't because umask was not 0, print an error and fail
                if (new_mode & !naively_expected_new_mode) != 0 {
                    show_error!(
                        "{}: new permissions are {}, not {}",
                        file.display(),
                        display_permissions_unix(new_mode as mode_t, false),
                        display_permissions_unix(naively_expected_new_mode as mode_t, false)
                    );
                    return Err(1);
                }
            }
        }

        Ok(())
    }

    #[cfg(unix)]
    fn change_file(&self, fperm: u32, mode: u32, file: &Path) -> Result<(), i32> {
        if fperm == mode {
            if self.verbose && !self.changes {
                println!(
                    "mode of '{}' retained as {:04o} ({})",
                    file.display(),
                    fperm,
                    display_permissions_unix(fperm as mode_t, false),
                );
            }
            Ok(())
        } else if let Err(err) = fs::set_permissions(file, fs::Permissions::from_mode(mode)) {
            if !self.quiet {
                show_error!("{}", err);
            }
            if self.verbose {
                println!(
                    "failed to change mode of file '{}' from {:04o} ({}) to {:04o} ({})",
                    file.display(),
                    fperm,
                    display_permissions_unix(fperm as mode_t, false),
                    mode,
                    display_permissions_unix(mode as mode_t, false)
                );
            }
            Err(1)
        } else {
            if self.verbose || self.changes {
                println!(
                    "mode of '{}' changed from {:04o} ({}) to {:04o} ({})",
                    file.display(),
                    fperm,
                    display_permissions_unix(fperm as mode_t, false),
                    mode,
                    display_permissions_unix(mode as mode_t, false)
                );
            }
            Ok(())
        }
    }
}

pub fn is_symlink<P: AsRef<Path>>(path: P) -> bool {
    match fs::symlink_metadata(path) {
        Ok(m) => m.file_type().is_symlink(),
        Err(_) => false,
    }
}
<commit_msg>chmod: remove redundant cfg<commit_after>// This file is part of the uutils coreutils package.
//
// (c) Alex Lyon <arcterus@mail.com>
//
// For the full copyright and license information, please view the LICENSE
// file that was distributed with this source code.

// spell-checker:ignore (ToDO) Chmoder cmode fmode fperm fref ugoa RFILE RFILE's

#[macro_use]
extern crate uucore;

use clap::{crate_version, App, Arg};
use std::fs;
use std::os::unix::fs::{MetadataExt, PermissionsExt};
use std::path::Path;
use uucore::fs::display_permissions_unix;
use uucore::libc::mode_t;
#[cfg(not(windows))]
use uucore::mode;
use uucore::InvalidEncodingHandling;
use walkdir::WalkDir;

static ABOUT: &str = "Change the mode of each FILE to MODE.
 With --reference, change the mode of each FILE to that of RFILE.";

mod options {
    pub const CHANGES: &str = "changes";
    pub const QUIET: &str = "quiet"; // visible_alias("silent")
    pub const VERBOSE: &str = "verbose";
    pub const NO_PRESERVE_ROOT: &str = "no-preserve-root";
    pub const PRESERVE_ROOT: &str = "preserve-root";
    pub const REFERENCE: &str = "RFILE";
    pub const RECURSIVE: &str = "recursive";
    pub const MODE: &str = "MODE";
    pub const FILE: &str = "FILE";
}

fn usage() -> String {
    format!(
        "{0} [OPTION]... MODE[,MODE]... FILE...
or: {0} [OPTION]... OCTAL-MODE FILE...
or: {0} [OPTION]... --reference=RFILE FILE...",
        uucore::execution_phrase()
    )
}

fn get_long_usage() -> String {
    String::from("Each MODE is of the form '[ugoa]*([-+=]([rwxXst]*|[ugo]))+|[-+=]?[0-7]+'.")
}

pub fn uumain(args: impl uucore::Args) -> i32 {
    let mut args = args
        .collect_str(InvalidEncodingHandling::ConvertLossy)
        .accept_any();

    // Before we can parse 'args' with clap (and previously getopts),
    // a possible MODE prefix '-' needs to be removed (e.g. "chmod -x FILE").
    let mode_had_minus_prefix = strip_minus_from_mode(&mut args);

    let usage = usage();
    let after_help = get_long_usage();

    let matches = uu_app()
        .usage(&usage[..])
        .after_help(&after_help[..])
        .get_matches_from(args);

    let changes = matches.is_present(options::CHANGES);
    let quiet = matches.is_present(options::QUIET);
    let verbose = matches.is_present(options::VERBOSE);
    let preserve_root = matches.is_present(options::PRESERVE_ROOT);
    let recursive = matches.is_present(options::RECURSIVE);
    let fmode = matches
        .value_of(options::REFERENCE)
        .and_then(|fref| match fs::metadata(fref) {
            Ok(meta) => Some(meta.mode()),
            Err(err) => crash!(1, "cannot stat attributes of '{}': {}", fref, err),
        });
    let modes = matches.value_of(options::MODE).unwrap(); // should always be Some because required
    let cmode = if mode_had_minus_prefix {
        // clap parsing is finished, now put prefix back
        format!("-{}", modes)
    } else {
        modes.to_string()
    };
    let mut files: Vec<String> = matches
        .values_of(options::FILE)
        .map(|v| v.map(ToString::to_string).collect())
        .unwrap_or_default();
    let cmode = if fmode.is_some() {
        // "--reference" and MODE are mutually exclusive
        // if "--reference" was used MODE needs to be interpreted as another FILE
        // it wasn't possible to implement this behavior directly with clap
        files.push(cmode);
        None
    } else {
        Some(cmode)
    };

    if files.is_empty() {
        crash!(1, "missing operand");
    }

    let chmoder = Chmoder {
        changes,
        quiet,
        verbose,
        preserve_root,
        recursive,
        fmode,
        cmode,
    };
    match chmoder.chmod(files) {
        Ok(()) => {}
        Err(e) => return e,
    }

    0
}

pub fn uu_app() -> App<'static, 'static> {
    App::new(uucore::util_name())
        .version(crate_version!())
        .about(ABOUT)
        .arg(
            Arg::with_name(options::CHANGES)
                .long(options::CHANGES)
                .short("c")
                .help("like verbose but report only when a change is made"),
        )
        .arg(
            Arg::with_name(options::QUIET)
                .long(options::QUIET)
                .visible_alias("silent")
                .short("f")
                .help("suppress most error messages"),
        )
        .arg(
            Arg::with_name(options::VERBOSE)
                .long(options::VERBOSE)
                .short("v")
                .help("output a diagnostic for every file processed"),
        )
        .arg(
            Arg::with_name(options::NO_PRESERVE_ROOT)
                .long(options::NO_PRESERVE_ROOT)
                .help("do not treat '/' specially (the default)"),
        )
        .arg(
            Arg::with_name(options::PRESERVE_ROOT)
                .long(options::PRESERVE_ROOT)
                .help("fail to operate recursively on '/'"),
        )
        .arg(
            Arg::with_name(options::RECURSIVE)
                .long(options::RECURSIVE)
                .short("R")
                .help("change files and directories recursively"),
        )
        .arg(
            Arg::with_name(options::REFERENCE)
                .long("reference")
                .takes_value(true)
                .help("use RFILE's mode instead of MODE values"),
        )
        .arg(
            Arg::with_name(options::MODE)
                .required_unless(options::REFERENCE)
                .takes_value(true),
            // It would be nice if clap could parse with delimiter, e.g. "g-x,u+x",
            // however .multiple(true) cannot be used here because FILE already needs that.
            // Only one positional argument with .multiple(true) set is allowed per command
        )
        .arg(
            Arg::with_name(options::FILE)
                .required_unless(options::MODE)
                .multiple(true),
        )
}

// Iterate 'args' and delete the first occurrence
// of a prefix '-' if it's associated with MODE
// e.g. "chmod -v -xw -R FILE" -> "chmod -v xw -R FILE"
pub fn strip_minus_from_mode(args: &mut Vec<String>) -> bool {
    for arg in args {
        if arg == "--" {
            break;
        }
        if arg.starts_with('-') {
            if let Some(second) = arg.chars().nth(1) {
                match second {
                    'r' | 'w' | 'x' | 'X' | 's' | 't' | 'u' | 'g' | 'o' | '0'..='7' => {
                        // TODO: use strip_prefix() once minimum rust version reaches 1.45.0
                        *arg = arg[1..arg.len()].to_string();
                        return true;
                    }
                    _ => {}
                }
            }
        }
    }
    false
}

struct Chmoder {
    changes: bool,
    quiet: bool,
    verbose: bool,
    preserve_root: bool,
    recursive: bool,
    fmode: Option<u32>,
    cmode: Option<String>,
}

impl Chmoder {
    fn chmod(&self, files: Vec<String>) -> Result<(), i32> {
        let mut r = Ok(());

        for filename in &files {
            let filename = &filename[..];
            let file = Path::new(filename);
            if !file.exists() {
                if is_symlink(file) {
                    println!(
                        "failed to change mode of '{}' from 0000 (---------) to 0000 (---------)",
                        filename
                    );
                    if !self.quiet {
                        show_error!("cannot operate on dangling symlink '{}'", filename);
                    }
                } else if !self.quiet {
                    show_error!("cannot access '{}': No such file or directory", filename);
                }
                return Err(1);
            }
            if self.recursive && self.preserve_root && filename == "/" {
                show_error!(
                    "it is dangerous to operate recursively on '{}'\nuse --no-preserve-root to override this failsafe",
                    filename
                );
                return Err(1);
            }
            if !self.recursive {
                r = self.chmod_file(file).and(r);
            } else {
                for entry in WalkDir::new(&filename).into_iter().filter_map(|e| e.ok()) {
                    let file = entry.path();
                    r = self.chmod_file(file).and(r);
                }
            }
        }
        r
    }

    #[cfg(windows)]
    fn chmod_file(&self, file: &Path) -> Result<(), i32> {
        // chmod is useless on Windows
        // it doesn't set any permissions at all
        // instead it just sets the readonly attribute on the file
        Err(0)
    }
    #[cfg(unix)]
    fn chmod_file(&self, file: &Path) -> Result<(), i32> {
        use uucore::mode::get_umask;

        let fperm = match fs::metadata(file) {
            Ok(meta) => meta.mode() & 0o7777,
            Err(err) => {
                if is_symlink(file) {
                    if self.verbose {
                        println!(
                            "neither symbolic link '{}' nor referent has been changed",
                            file.display()
                        );
                    }
                    return Ok(());
                } else if err.kind() == std::io::ErrorKind::PermissionDenied {
                    show_error!("'{}': Permission denied", file.display());
                } else {
                    show_error!("'{}': {}", file.display(), err);
                }
                return Err(1);
            }
        };
        match self.fmode {
            Some(mode) => self.change_file(fperm, mode, file)?,
            None => {
                let cmode_unwrapped = self.cmode.clone().unwrap();
                let mut new_mode = fperm;
                let mut naively_expected_new_mode = new_mode;
                for mode in cmode_unwrapped.split(',') {
                    // cmode is guaranteed to be Some in this case
                    let arr: &[char] = &['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'];
                    let result = if mode.contains(arr) {
                        mode::parse_numeric(new_mode, mode, file.is_dir()).map(|v| (v, v))
                    } else {
                        mode::parse_symbolic(new_mode, mode, get_umask(), file.is_dir()).map(|m| {
                            // calculate the new mode as if umask was 0
                            let naive_mode = mode::parse_symbolic(
                                naively_expected_new_mode,
                                mode,
                                0,
                                file.is_dir(),
                            )
                            .unwrap(); // we know that mode must be valid, so this cannot fail
                            (m, naive_mode)
                        })
                    };
                    match result {
                        Ok((mode, naive_mode)) => {
                            new_mode = mode;
                            naively_expected_new_mode = naive_mode;
                        }
                        Err(f) => {
                            if !self.quiet {
                                show_error!("{}", f);
                            }
                            return Err(1);
                        }
                    }
                }
                self.change_file(fperm, new_mode, file)?;
                // if a permission would have been removed if umask was 0, but it wasn't because umask was not 0, print an error and fail
                if (new_mode & !naively_expected_new_mode) != 0 {
                    show_error!(
                        "{}: new permissions are {}, not {}",
                        file.display(),
                        display_permissions_unix(new_mode as mode_t, false),
                        display_permissions_unix(naively_expected_new_mode as mode_t, false)
                    );
                    return Err(1);
                }
            }
        }

        Ok(())
    }

    #[cfg(unix)]
    fn change_file(&self, fperm: u32, mode: u32, file: &Path) -> Result<(), i32> {
        if fperm == mode {
            if self.verbose && !self.changes {
                println!(
                    "mode of '{}' retained as {:04o} ({})",
                    file.display(),
                    fperm,
                    display_permissions_unix(fperm as mode_t, false),
                );
            }
            Ok(())
        } else if let Err(err) = fs::set_permissions(file, fs::Permissions::from_mode(mode)) {
            if !self.quiet {
                show_error!("{}", err);
            }
            if self.verbose {
                println!(
                    "failed to change mode of file '{}' from {:04o} ({}) to {:04o} ({})",
                    file.display(),
                    fperm,
                    display_permissions_unix(fperm as mode_t, false),
                    mode,
                    display_permissions_unix(mode as mode_t, false)
                );
            }
            Err(1)
        } else {
            if self.verbose || self.changes {
                println!(
                    "mode of '{}' changed from {:04o} ({}) to {:04o} ({})",
                    file.display(),
                    fperm,
                    display_permissions_unix(fperm as mode_t, false),
                    mode,
                    display_permissions_unix(mode as mode_t, false)
                );
            }
            Ok(())
        }
    }
}

pub fn is_symlink<P: AsRef<Path>>(path: P) -> bool {
    match fs::symlink_metadata(path) {
        Ok(m) => m.file_type().is_symlink(),
        Err(_) => false,
    }
}
<|endoftext|>


<commit_before>// Copyright (c) The Diem Core Contributors
// SPDX-License-Identifier: Apache-2.0

use super::{arb_internal_nibble_path, skip_common_prefix, NibblePath};
use diem_nibble::Nibble;
use proptest::prelude::*;

#[test]
fn test_nibble_path_fmt() {
    let nibble_path = NibblePath::new(vec![0x12, 0x34, 0x56]);
    assert_eq!(format!("{:?}", nibble_path), "123456");

    let nibble_path = NibblePath::new_odd(vec![0x12, 0x34, 0x50]);
    assert_eq!(format!("{:?}", nibble_path), "12345");
}

#[test]
fn test_create_nibble_path_success() {
    let nibble_path = NibblePath::new(vec![0x12, 0x34, 0x56]);
    assert_eq!(nibble_path.num_nibbles(), 6);

    let nibble_path = NibblePath::new_odd(vec![0x12, 0x34, 0x50]);
    assert_eq!(nibble_path.num_nibbles(), 5);

    let nibble_path = NibblePath::new(vec![]);
    assert_eq!(nibble_path.num_nibbles(), 0);
}

#[test]
#[should_panic(expected = "Last nibble must be 0.")]
fn test_create_nibble_path_failure() {
    let bytes = vec![0x12, 0x34, 0x56];
    let _nibble_path = NibblePath::new_odd(bytes);
}

#[test]
#[should_panic(expected = "Should have odd number of nibbles.")]
fn test_empty_nibble_path() {
    NibblePath::new_odd(vec![]);
}

#[test]
fn test_get_nibble() {
    let bytes = vec![0x12, 0x34];
    let nibble_path = NibblePath::new(bytes);
    assert_eq!(nibble_path.get_nibble(0), Nibble::from(0x01));
    assert_eq!(nibble_path.get_nibble(1), Nibble::from(0x02));
    assert_eq!(nibble_path.get_nibble(2), Nibble::from(0x03));
    assert_eq!(nibble_path.get_nibble(3), Nibble::from(0x04));
}

#[test]
fn test_nibble_iterator() {
    let bytes = vec![0x12, 0x30];
    let nibble_path = NibblePath::new_odd(bytes);
    let mut iter = nibble_path.nibbles();
    assert_eq!(iter.next().unwrap(), Nibble::from(0x01));
    assert_eq!(iter.next().unwrap(), Nibble::from(0x02));
    assert_eq!(iter.next().unwrap(), Nibble::from(0x03));
    assert_eq!(iter.next(), None);
}

#[test]
fn test_get_bit() {
    let bytes = vec![0x01, 0x02];
    let nibble_path = NibblePath::new(bytes);
    assert_eq!(nibble_path.get_bit(0), false);
    assert_eq!(nibble_path.get_bit(1), false);
    assert_eq!(nibble_path.get_bit(2), false);
    assert_eq!(nibble_path.get_bit(7), true);
    assert_eq!(nibble_path.get_bit(8), false);
    assert_eq!(nibble_path.get_bit(14), true);
}

#[test]
fn test_bit_iter() {
    let bytes = vec![0xc3, 0xa0];
    let nibble_path = NibblePath::new_odd(bytes);
    let mut iter = nibble_path.bits();
    // c: 0b1100
    assert_eq!(iter.next(), Some(true));
    assert_eq!(iter.next(), Some(true));
    assert_eq!(iter.next(), Some(false));
    assert_eq!(iter.next(), Some(false));
    // 3: 0b0011
    assert_eq!(iter.next(), Some(false));
    assert_eq!(iter.next(), Some(false));
    assert_eq!(iter.next(), Some(true));
    assert_eq!(iter.next(), Some(true));
    // a: 0b1010
    assert_eq!(iter.next_back(), Some(false));
    assert_eq!(iter.next_back(), Some(true));
    assert_eq!(iter.next_back(), Some(false));
    assert_eq!(iter.next_back(), Some(true));

    assert_eq!(iter.next(), None);
}

#[test]
fn test_visited_nibble_iter() {
    let bytes = vec![0x12, 0x34, 0x56];
    let nibble_path = NibblePath::new(bytes);
    let mut iter = nibble_path.nibbles();
    assert_eq!(iter.next().unwrap(), 0x01.into());
    assert_eq!(iter.next().unwrap(), 0x02.into());
    assert_eq!(iter.next().unwrap(), 0x03.into());
    let mut visited_nibble_iter = iter.visited_nibbles();
    assert_eq!(visited_nibble_iter.next().unwrap(), 0x01.into());
    assert_eq!(visited_nibble_iter.next().unwrap(), 0x02.into());
    assert_eq!(visited_nibble_iter.next().unwrap(), 0x03.into());
}

#[test]
fn test_skip_common_prefix() {
    {
        let nibble_path1 = NibblePath::new(vec![0x12, 0x34, 0x56]);
        let nibble_path2 = NibblePath::new(vec![0x12, 0x34, 0x56]);
        let mut iter1 = nibble_path1.nibbles();
        let mut iter2 = nibble_path2.nibbles();
        assert_eq!(skip_common_prefix(&mut iter1, &mut iter2), 6);
        assert!(iter1.is_finished());
        assert!(iter2.is_finished());
    }
    {
        let nibble_path1 = NibblePath::new(vec![0x12, 0x35]);
        let nibble_path2 = NibblePath::new(vec![0x12, 0x34, 0x56]);
        let mut iter1 = nibble_path1.nibbles();
        let mut iter2 = nibble_path2.nibbles();
        assert_eq!(skip_common_prefix(&mut iter1, &mut iter2), 3);
        assert_eq!(
            iter1.visited_nibbles().get_nibble_path(),
            iter2.visited_nibbles().get_nibble_path()
        );
        assert_eq!(
            iter1.remaining_nibbles().get_nibble_path(),
            NibblePath::new_odd(vec![0x50])
        );
        assert_eq!(
            iter2.remaining_nibbles().get_nibble_path(),
            NibblePath::new_odd(vec![0x45, 0x60])
        );
    }
    {
        let nibble_path1 = NibblePath::new(vec![0x12, 0x34, 0x56]);
        let nibble_path2 = NibblePath::new_odd(vec![0x12, 0x30]);
        let mut iter1 = nibble_path1.nibbles();
        let mut iter2 = nibble_path2.nibbles();
        assert_eq!(skip_common_prefix(&mut iter1, &mut iter2), 3);
        assert_eq!(
            iter1.visited_nibbles().get_nibble_path(),
            iter2.visited_nibbles().get_nibble_path()
        );
        assert_eq!(
            iter1.remaining_nibbles().get_nibble_path(),
            NibblePath::new_odd(vec![0x45, 0x60])
        );
        assert!(iter2.is_finished());
    }
}

prop_compose! {
    fn arb_nibble_path_and_current()(nibble_path in any::<NibblePath>())
        (current in 0..=nibble_path.num_nibbles(),
         nibble_path in Just(nibble_path)) -> (usize, NibblePath) {
        (current, nibble_path)
    }
}

proptest! {
    #[test]
    fn test_push(
        nibble_path in arb_internal_nibble_path(),
        nibble in any::<Nibble>()
    ) {
        let mut new_nibble_path = nibble_path.clone();
        new_nibble_path.push(nibble);
        let mut nibbles: Vec<Nibble> = nibble_path.nibbles().collect();
        nibbles.push(nibble);
        let nibble_path2 = nibbles.into_iter().collect();
        prop_assert_eq!(new_nibble_path, nibble_path2);
    }

    #[test]
    fn test_pop(mut nibble_path in any::<NibblePath>()) {
        let mut nibbles: Vec<Nibble> = nibble_path.nibbles().collect();
        let nibble_from_nibbles = nibbles.pop();
        let nibble_from_nibble_path = nibble_path.pop();
        let nibble_path2 = nibbles.into_iter().collect();
        prop_assert_eq!(nibble_path, nibble_path2);
        prop_assert_eq!(nibble_from_nibbles, nibble_from_nibble_path);
    }

    #[test]
    fn test_last(mut nibble_path in any::<NibblePath>()) {
        let nibble1 = nibble_path.last();
        let nibble2 = nibble_path.pop();
        prop_assert_eq!(nibble1, nibble2);
    }

    #[test]
    fn test_nibble_iter_roundtrip(nibble_path in any::<NibblePath>()) {
        let nibbles = nibble_path.nibbles();
        let nibble_path2 = nibbles.collect();
        prop_assert_eq!(nibble_path, nibble_path2);
    }

    #[test]
    fn test_visited_and_remaining_nibbles((current, nibble_path) in arb_nibble_path_and_current()) {
        let mut nibble_iter = nibble_path.nibbles();
        let mut visited_nibbles = vec![];
        for _ in 0..current {
            visited_nibbles.push(nibble_iter.next().unwrap());
        }
        let visited_nibble_path = nibble_iter.visited_nibbles().get_nibble_path();
        let remaining_nibble_path = nibble_iter.remaining_nibbles().get_nibble_path();
        let visited_iter = visited_nibble_path.nibbles();
        let remaining_iter = remaining_nibble_path.nibbles();
        prop_assert_eq!(visited_nibbles, visited_iter.collect::<Vec<Nibble>>());
        prop_assert_eq!(nibble_iter.collect::<Vec<Nibble>>(), remaining_iter.collect::<Vec<_>>());
   }

   #[test]
    fn test_nibble_iter_to_bit_iter((current, nibble_path) in arb_nibble_path_and_current()) {
        let mut nibble_iter = nibble_path.nibbles();
        (0..current)
            .for_each(|_| {
                nibble_iter.next().unwrap();
            }
        );
        let remaining_nibble_path = nibble_iter.remaining_nibbles().get_nibble_path();
        let remaining_bit_iter = remaining_nibble_path.bits();
        let bit_iter = nibble_iter.bits();
        prop_assert_eq!(remaining_bit_iter.collect::<Vec<bool>>(), bit_iter.collect::<Vec<_>>());
    }
}
<commit_msg>add nibble_path test<commit_after>// Copyright (c) The Diem Core Contributors
// SPDX-License-Identifier: Apache-2.0

use super::{arb_internal_nibble_path, skip_common_prefix, NibblePath};
use diem_nibble::Nibble;
use proptest::prelude::*;

#[test]
fn test_nibble_path_fmt() {
    let nibble_path = NibblePath::new(vec![0x12, 0x34, 0x56]);
    assert_eq!(format!("{:?}", nibble_path), "123456");

    let nibble_path = NibblePath::new(vec![0x12, 0x34, 0x50]);
    assert_eq!(format!("{:?}", nibble_path), "123450");

    let nibble_path = NibblePath::new_odd(vec![0x12, 0x34, 0x50]);
    assert_eq!(format!("{:?}", nibble_path), "12345");
}

#[test]
fn test_create_nibble_path_success() {
    let nibble_path = NibblePath::new(vec![0x12, 0x34, 0x56]);
    assert_eq!(nibble_path.num_nibbles(), 6);

    let nibble_path = NibblePath::new(vec![0x12, 0x34, 0x50]);
    assert_eq!(nibble_path.num_nibbles(), 6);

    let nibble_path = NibblePath::new_odd(vec![0x12, 0x34, 0x50]);
    assert_eq!(nibble_path.num_nibbles(), 5);

    let nibble_path = NibblePath::new(vec![]);
    assert_eq!(nibble_path.num_nibbles(), 0);
}

#[test]
#[should_panic(expected = "Last nibble must be 0.")]
fn test_create_nibble_path_failure() {
    let bytes = vec![0x12, 0x34, 0x56];
    let _nibble_path = NibblePath::new_odd(bytes);
}

#[test]
#[should_panic(expected = "Should have odd number of nibbles.")]
fn test_empty_nibble_path() {
    NibblePath::new_odd(vec![]);
}

#[test]
fn test_get_nibble() {
    let bytes = vec![0x12, 0x34];
    let nibble_path = NibblePath::new(bytes);
    assert_eq!(nibble_path.get_nibble(0), Nibble::from(0x01));
    assert_eq!(nibble_path.get_nibble(1), Nibble::from(0x02));
    assert_eq!(nibble_path.get_nibble(2), Nibble::from(0x03));
    assert_eq!(nibble_path.get_nibble(3), Nibble::from(0x04));
}

#[test]
fn test_nibble_iterator() {
    let bytes = vec![0x12, 0x30];
    let nibble_path = NibblePath::new_odd(bytes);
    let mut iter = nibble_path.nibbles();
    assert_eq!(iter.next().unwrap(), Nibble::from(0x01));
    assert_eq!(iter.next().unwrap(), Nibble::from(0x02));
    assert_eq!(iter.next().unwrap(), Nibble::from(0x03));
    assert_eq!(iter.next(), None);
}

#[test]
fn test_get_bit() {
    let bytes = vec![0x01, 0x02];
    let nibble_path = NibblePath::new(bytes);
    assert_eq!(nibble_path.get_bit(0), false);
    assert_eq!(nibble_path.get_bit(1), false);
    assert_eq!(nibble_path.get_bit(2), false);
    assert_eq!(nibble_path.get_bit(7), true);
    assert_eq!(nibble_path.get_bit(8), false);
    assert_eq!(nibble_path.get_bit(14), true);
}

#[test]
fn test_bit_iter() {
    let bytes = vec![0xc3, 0xa0];
    let nibble_path = NibblePath::new_odd(bytes);
    let mut iter = nibble_path.bits();
    // c: 0b1100
    assert_eq!(iter.next(), Some(true));
    assert_eq!(iter.next(), Some(true));
    assert_eq!(iter.next(), Some(false));
    assert_eq!(iter.next(), Some(false));
    // 3: 0b0011
    assert_eq!(iter.next(), Some(false));
    assert_eq!(iter.next(), Some(false));
    assert_eq!(iter.next(), Some(true));
    assert_eq!(iter.next(), Some(true));
    // a: 0b1010
    assert_eq!(iter.next_back(), Some(false));
    assert_eq!(iter.next_back(), Some(true));
    assert_eq!(iter.next_back(), Some(false));
    assert_eq!(iter.next_back(), Some(true));

    assert_eq!(iter.next(), None);
}

#[test]
fn test_visited_nibble_iter() {
    let bytes = vec![0x12, 0x34, 0x56];
    let nibble_path = NibblePath::new(bytes);
    let mut iter = nibble_path.nibbles();
    assert_eq!(iter.next().unwrap(), 0x01.into());
    assert_eq!(iter.next().unwrap(), 0x02.into());
    assert_eq!(iter.next().unwrap(), 0x03.into());
    let mut visited_nibble_iter = iter.visited_nibbles();
    assert_eq!(visited_nibble_iter.next().unwrap(), 0x01.into());
    assert_eq!(visited_nibble_iter.next().unwrap(), 0x02.into());
    assert_eq!(visited_nibble_iter.next().unwrap(), 0x03.into());
}

#[test]
fn test_skip_common_prefix() {
    {
        let nibble_path1 = NibblePath::new(vec![0x12, 0x34, 0x56]);
        let nibble_path2 = NibblePath::new(vec![0x12, 0x34, 0x56]);
        let mut iter1 = nibble_path1.nibbles();
        let mut iter2 = nibble_path2.nibbles();
        assert_eq!(skip_common_prefix(&mut iter1, &mut iter2), 6);
        assert!(iter1.is_finished());
        assert!(iter2.is_finished());
    }
    {
        let nibble_path1 = NibblePath::new(vec![0x12, 0x35]);
        let nibble_path2 = NibblePath::new(vec![0x12, 0x34, 0x56]);
        let mut iter1 = nibble_path1.nibbles();
        let mut iter2 = nibble_path2.nibbles();
        assert_eq!(skip_common_prefix(&mut iter1, &mut iter2), 3);
        assert_eq!(
            iter1.visited_nibbles().get_nibble_path(),
            iter2.visited_nibbles().get_nibble_path()
        );
        assert_eq!(
            iter1.remaining_nibbles().get_nibble_path(),
            NibblePath::new_odd(vec![0x50])
        );
        assert_eq!(
            iter2.remaining_nibbles().get_nibble_path(),
            NibblePath::new_odd(vec![0x45, 0x60])
        );
    }
    {
        let nibble_path1 = NibblePath::new(vec![0x12, 0x34, 0x56]);
        let nibble_path2 = NibblePath::new_odd(vec![0x12, 0x30]);
        let mut iter1 = nibble_path1.nibbles();
        let mut iter2 = nibble_path2.nibbles();
        assert_eq!(skip_common_prefix(&mut iter1, &mut iter2), 3);
        assert_eq!(
            iter1.visited_nibbles().get_nibble_path(),
            iter2.visited_nibbles().get_nibble_path()
        );
        assert_eq!(
            iter1.remaining_nibbles().get_nibble_path(),
            NibblePath::new_odd(vec![0x45, 0x60])
        );
        assert!(iter2.is_finished());
    }
}

prop_compose! {
    fn arb_nibble_path_and_current()(nibble_path in any::<NibblePath>())
        (current in 0..=nibble_path.num_nibbles(),
         nibble_path in Just(nibble_path)) -> (usize, NibblePath) {
        (current, nibble_path)
    }
}

proptest! {
    #[test]
    fn test_push(
        nibble_path in arb_internal_nibble_path(),
        nibble in any::<Nibble>()
    ) {
        let mut new_nibble_path = nibble_path.clone();
        new_nibble_path.push(nibble);
        let mut nibbles: Vec<Nibble> = nibble_path.nibbles().collect();
        nibbles.push(nibble);
        let nibble_path2 = nibbles.into_iter().collect();
        prop_assert_eq!(new_nibble_path, nibble_path2);
    }

    #[test]
    fn test_pop(mut nibble_path in any::<NibblePath>()) {
        let mut nibbles: Vec<Nibble> = nibble_path.nibbles().collect();
        let nibble_from_nibbles = nibbles.pop();
        let nibble_from_nibble_path = nibble_path.pop();
        let nibble_path2 = nibbles.into_iter().collect();
        prop_assert_eq!(nibble_path, nibble_path2);
        prop_assert_eq!(nibble_from_nibbles, nibble_from_nibble_path);
    }

    #[test]
    fn test_last(mut nibble_path in any::<NibblePath>()) {
        let nibble1 = nibble_path.last();
        let nibble2 = nibble_path.pop();
        prop_assert_eq!(nibble1, nibble2);
    }

    #[test]
    fn test_nibble_iter_roundtrip(nibble_path in any::<NibblePath>()) {
        let nibbles = nibble_path.nibbles();
        let nibble_path2 = nibbles.collect();
        prop_assert_eq!(nibble_path, nibble_path2);
    }

    #[test]
    fn test_visited_and_remaining_nibbles((current, nibble_path) in arb_nibble_path_and_current()) {
        let mut nibble_iter = nibble_path.nibbles();
        let mut visited_nibbles = vec![];
        for _ in 0..current {
            visited_nibbles.push(nibble_iter.next().unwrap());
        }
        let visited_nibble_path = nibble_iter.visited_nibbles().get_nibble_path();
        let remaining_nibble_path = nibble_iter.remaining_nibbles().get_nibble_path();
        let visited_iter = visited_nibble_path.nibbles();
        let remaining_iter = remaining_nibble_path.nibbles();
        prop_assert_eq!(visited_nibbles, visited_iter.collect::<Vec<Nibble>>());
        prop_assert_eq!(nibble_iter.collect::<Vec<Nibble>>(), remaining_iter.collect::<Vec<_>>());
   }

   #[test]
    fn test_nibble_iter_to_bit_iter((current, nibble_path) in arb_nibble_path_and_current()) {
        let mut nibble_iter = nibble_path.nibbles();
        (0..current)
            .for_each(|_| {
                nibble_iter.next().unwrap();
            }
        );
        let remaining_nibble_path = nibble_iter.remaining_nibbles().get_nibble_path();
        let remaining_bit_iter = remaining_nibble_path.bits();
        let bit_iter = nibble_iter.bits();
        prop_assert_eq!(remaining_bit_iter.collect::<Vec<bool>>(), bit_iter.collect::<Vec<_>>());
    }
}
<|endoftext|>


<commit_before>/* Copyright 2016 Jordan Miner
 *
 * Licensed under the MIT license <LICENSE or
 * http://opensource.org/licenses/MIT>. This file may not be copied,
 * modified, or distributed except according to those terms.
 */

#[macro_use]
extern crate clear_coat;
extern crate iup_sys;
extern crate smallvec;

use std::rc::Rc;
use iup_sys::*;
use smallvec::SmallVec;

use clear_coat::*;
use clear_coat::common_attrs_cbs::*;

struct CursorsCanvas {
    canvas: Canvas,
}

impl CursorsCanvas {
    pub fn new() -> Self {
        CursorsCanvas {
            canvas: Canvas::new(),
        }
    }
}

impl CursorAttribute for CursorsCanvas {}

unsafe impl Control for CursorsCanvas {
    fn handle(&self) -> *mut Ihandle {
        self.canvas.handle()
    }
}

fn create_cursors_page() -> Box<Control> {
    let cursors_canvas = Rc::new(CursorsCanvas::new());

    let radios_info = [
        ("None", Cursor::None),
        ("Arrow", Cursor::Arrow),
        ("Busy", Cursor::Busy),
        ("Cross", Cursor::Cross),
        ("Hand", Cursor::Hand),
        ("Help", Cursor::Help),
        ("Move", Cursor::Move),
        ("ResizeN", Cursor::ResizeN),
        ("ResizeS", Cursor::ResizeS),
        ("ResizeNS", Cursor::ResizeNS),
        ("ResizeW", Cursor::ResizeW),
        ("ResizeE", Cursor::ResizeE),
        ("ResizeWE", Cursor::ResizeWE),
        ("ResizeNE", Cursor::ResizeNE),
        ("ResizeSW", Cursor::ResizeSW),
        ("ResizeNW", Cursor::ResizeNW),
        ("ResizeSE", Cursor::ResizeSE),
        ("Text", Cursor::Text),
    ];

    let mut radios = SmallVec::<[Toggle; 32]>::new();
    for &(text, cur) in radios_info.iter() {
        let toggle = Toggle::new();
        toggle.set_title(text);
        let cursors_canvas2 = cursors_canvas.clone();
        toggle.action_event().add(move |checked| {
            if checked { cursors_canvas2.set_cursor(cur); }
        });
        radios.push(toggle);
    }

    let grid = grid_box!(
        &radios[0],
        &radios[1],
        &radios[2],
        &radios[3],
        &radios[4],
        &radios[5],
        &radios[6],
        &radios[7],
        &radios[8],
        &radios[9],
        &radios[10],
        &radios[11],
        &radios[12],
        &radios[13],
        &radios[14],
        &radios[15],
        &radios[16],
        &radios[17],
    );
    grid.set_num_div(NumDiv::Fixed(2));
    grid.fit_all_to_children();
    let page = vbox!(
        &cursors_canvas,
        hbox!(
            fill!(),
            Radio::with_child(&grid),
            fill!(),
        ),
    );
    Box::new(page)
}

fn main() {

    let dialog = Dialog::new();

    let tabs = Tabs::new();

    tabs.append_tabs(&[
        TabInfo::new(&*create_cursors_page()).title("Cursors"),
        TabInfo::new(&Fill::new()).title("File Dialog"),
    ]);

    dialog.append(&tabs).expect("failed to build the window");
    dialog.set_title("Showcase");

    dialog.show_xy(ScreenPosition::Center, ScreenPosition::Center)
          .expect("failed to show the window");
    main_loop();
}
<commit_msg>Start work on the file dialog page in Showcase<commit_after>/* Copyright 2016 Jordan Miner
 *
 * Licensed under the MIT license <LICENSE or
 * http://opensource.org/licenses/MIT>. This file may not be copied,
 * modified, or distributed except according to those terms.
 */

#[macro_use]
extern crate clear_coat;
extern crate iup_sys;
extern crate smallvec;

use std::rc::Rc;
use iup_sys::*;
use smallvec::SmallVec;

use clear_coat::*;
use clear_coat::common_attrs_cbs::*;

struct CursorsCanvas {
    canvas: Canvas,
}

impl CursorsCanvas {
    pub fn new() -> Self {
        CursorsCanvas {
            canvas: Canvas::new(),
        }
    }
}

impl CursorAttribute for CursorsCanvas {}

unsafe impl Control for CursorsCanvas {
    fn handle(&self) -> *mut Ihandle {
        self.canvas.handle()
    }
}

fn create_cursors_page() -> Box<Control> {
    let cursors_canvas = Rc::new(CursorsCanvas::new());

    let radios_info = [
        ("None", Cursor::None),
        ("Arrow", Cursor::Arrow),
        ("Busy", Cursor::Busy),
        ("Cross", Cursor::Cross),
        ("Hand", Cursor::Hand),
        ("Help", Cursor::Help),
        ("Move", Cursor::Move),
        ("ResizeN", Cursor::ResizeN),
        ("ResizeS", Cursor::ResizeS),
        ("ResizeNS", Cursor::ResizeNS),
        ("ResizeW", Cursor::ResizeW),
        ("ResizeE", Cursor::ResizeE),
        ("ResizeWE", Cursor::ResizeWE),
        ("ResizeNE", Cursor::ResizeNE),
        ("ResizeSW", Cursor::ResizeSW),
        ("ResizeNW", Cursor::ResizeNW),
        ("ResizeSE", Cursor::ResizeSE),
        ("Text", Cursor::Text),
    ];

    let mut radios = SmallVec::<[Toggle; 32]>::new();
    for &(text, cur) in radios_info.iter() {
        let toggle = Toggle::new();
        toggle.set_title(text);
        let cursors_canvas2 = cursors_canvas.clone();
        toggle.action_event().add(move |checked| {
            if checked { cursors_canvas2.set_cursor(cur); }
        });
        radios.push(toggle);
    }

    let grid = grid_box!(
        &radios[0],
        &radios[1],
        &radios[2],
        &radios[3],
        &radios[4],
        &radios[5],
        &radios[6],
        &radios[7],
        &radios[8],
        &radios[9],
        &radios[10],
        &radios[11],
        &radios[12],
        &radios[13],
        &radios[14],
        &radios[15],
        &radios[16],
        &radios[17],
    );
    grid.set_num_div(NumDiv::Fixed(2));
    grid.fit_all_to_children();
    let page = vbox!(
        &cursors_canvas,
        hbox!(
            fill!(),
            Radio::with_child(&grid),
            fill!(),
        ),
    );
    Box::new(page)
}

fn create_file_dialog_page() -> Box<Control> {

    let dir_check_box = Toggle::new();
    dir_check_box.set_title("Directory:");

    let show_dialog = Button::with_title("Show Dialog");
    show_dialog.action_event().add(move || {
        let dialog = FileDlg::new();
        dialog.popup(ScreenPosition::CenterParent, ScreenPosition::CenterParent)
              .expect("couldn't show file dialog");
    });

    let page = vbox!(
        dir_check_box,
        show_dialog,
    );
    Box::new(page)
}

fn main() {

    let dialog = Dialog::new();

    let tabs = Tabs::new();

    tabs.append_tabs(&[
        TabInfo::new(&*create_cursors_page()).title("Cursors"),
        TabInfo::new(&*create_file_dialog_page()).title("File Dialog"),
    ]);

    dialog.append(&tabs).expect("failed to build the window");
    dialog.set_title("Showcase");

    dialog.show_xy(ScreenPosition::Center, ScreenPosition::Center)
          .expect("failed to show the window");
    main_loop();
}
<|endoftext|>


<commit_before>use alloc::boxed::Box;
use collections::string::String;
use collections::vec::Vec;

use core::fmt::{Debug, Formatter, Error};

use super::termlist::parse_term_list;
use super::namedobj::{ RegionSpace, FieldFlags };
use super::parser::{AmlExecutionContext, ExecutionState};
use super::AmlError;

#[derive(Clone)]
pub enum FieldSelector {
    Region(String),
    Bank {
        region: String,
        bank_selector: Box<AmlValue>
    },
    Index {
        index_selector: String,
        data_selector: String
    }
}

#[derive(Clone)]
pub enum ObjectReference {
    ArgObj(u8),
    LocalObj(u8),
    NamedObj(String),
    Object(Box<AmlValue>),
    Index(Box<AmlValue>, Box<AmlValue>)
}

#[derive(Clone)]
pub struct Method {
    pub arg_count: u8,
    pub serialized: bool,
    pub sync_level: u8,
    pub term_list: Vec<u8>
}

pub struct Accessor {
    pub read: fn(usize) -> u64,
    pub write: fn(usize, u64)
}

impl Clone for Accessor {
    fn clone(&self) -> Accessor {
        Accessor {
            read: (*self).read,
            write: (*self).write
        }
    }
}

#[derive(Clone)]
pub enum AmlValue {
    None,
    Uninitialized,
    Buffer(Vec<u8>),
    BufferField {
        source_buf: Box<AmlValue>,
        index: Box<AmlValue>,
        length: Box<AmlValue>
    },
    DDBHandle(Vec<String>),
    DebugObject,
    Device(Vec<String>),
    Event(u64),
    FieldUnit {
        selector: FieldSelector,
        connection: Box<AmlValue>,
        flags: FieldFlags,
        offset: usize,
        length: usize
    },
    Integer(u64),
    IntegerConstant(u64),
    Method(Method),
    Mutex((u8, Option<u64>)),
    ObjectReference(ObjectReference),
    OperationRegion {
        region: RegionSpace,
        offset: Box<AmlValue>,
        len: Box<AmlValue>,
        accessor: Accessor,
        accessed_by: Option<u64>
    },
    Package(Vec<AmlValue>),
    String(String),
    PowerResource {
        system_level: u8,
        resource_order: u16,
        obj_list: Vec<String>
    },
    Processor {
        proc_id: u8,
        p_blk: Option<u32>,
        obj_list: Vec<String>
    },
    RawDataBuffer(Vec<u8>),
    ThermalZone(Vec<String>)
}

impl Debug for AmlValue {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { Ok(()) }
}

impl AmlValue {
    pub fn get_as_event(&self) -> Result<u64, AmlError> {
        match *self {
            AmlValue::Event(ref e) => Ok(e.clone()),
            _ => Err(AmlError::AmlValueError)
        }
    }

    pub fn get_as_ddb_handle(&self) -> Result<Vec<String>, AmlError> {
        match *self {
            AmlValue::DDBHandle(ref v) => Ok(v.clone()),
            _ => Err(AmlError::AmlValueError)
        }
    }

    pub fn get_as_string(&self) -> Result<String, AmlError> {
        match *self {
            AmlValue::String(ref s) => Ok(s.clone()),
            _ => Err(AmlError::AmlValueError)
        }
    }

    pub fn get_as_buffer(&self) -> Result<Vec<u8>, AmlError> {
        match *self {
            AmlValue::Buffer(ref b) => Ok(b.clone()),
            _ => Err(AmlError::AmlValueError)
        }
    }

    pub fn get_as_package(&self) -> Result<Vec<AmlValue>, AmlError> {
        match *self {
            AmlValue::Package(ref p) => Ok(p.clone()),
            _ => Err(AmlError::AmlValueError)
        }
    }

    pub fn get_as_integer(&self) -> Result<u64, AmlError> {
        match *self {
            AmlValue::IntegerConstant(ref i) => Ok(i.clone()),
            _ => Err(AmlError::AmlValueError)
        }
    }

    pub fn get_as_method(&self) -> Result<Method, AmlError> {
        match *self {
            AmlValue::Method(ref m) => Ok(m.clone()),
            _ => Err(AmlError::AmlValueError)
        }
    }
}

impl Method {
    pub fn execute(&self, scope: String, parameters: Vec<AmlValue>) -> AmlValue {
        let mut ctx = AmlExecutionContext::new(scope);
        ctx.init_arg_vars(parameters);

        parse_term_list(&self.term_list[..], &mut ctx);
        ctx.clean_namespace();

        match ctx.state {
            ExecutionState::RETURN(v) => v,
            _ => AmlValue::IntegerConstant(0)
        }
    }
}

pub fn get_namespace_string(current: String, modifier_v: AmlValue) -> String {
    // TODO: Type error if modifier not string
    let modifier = if let Ok(s) = modifier_v.get_as_string() {
        s
    } else {
        return current;
    };

    if current.len() == 0 {
        return modifier;
    }

    if modifier.len() == 0 {
        return current;
    }

    if modifier.starts_with("\\") {
        return modifier;
    }

    if modifier.starts_with("^") {
        // TODO
    }

    let mut namespace = current.clone();

    if !namespace.ends_with("\\") {
        namespace.push('.');
    }

    namespace + &modifier
}
<commit_msg>Implemented path parent character "^" when calculating scope paths<commit_after>use alloc::boxed::Box;
use collections::string::String;
use collections::string::ToString;
use collections::vec::Vec;

use core::fmt::{Debug, Formatter, Error};

use super::termlist::parse_term_list;
use super::namedobj::{ RegionSpace, FieldFlags };
use super::parser::{AmlExecutionContext, ExecutionState};
use super::AmlError;

#[derive(Clone)]
pub enum FieldSelector {
    Region(String),
    Bank {
        region: String,
        bank_selector: Box<AmlValue>
    },
    Index {
        index_selector: String,
        data_selector: String
    }
}

#[derive(Clone)]
pub enum ObjectReference {
    ArgObj(u8),
    LocalObj(u8),
    NamedObj(String),
    Object(Box<AmlValue>),
    Index(Box<AmlValue>, Box<AmlValue>)
}

#[derive(Clone)]
pub struct Method {
    pub arg_count: u8,
    pub serialized: bool,
    pub sync_level: u8,
    pub term_list: Vec<u8>
}

pub struct Accessor {
    pub read: fn(usize) -> u64,
    pub write: fn(usize, u64)
}

impl Clone for Accessor {
    fn clone(&self) -> Accessor {
        Accessor {
            read: (*self).read,
            write: (*self).write
        }
    }
}

#[derive(Clone)]
pub enum AmlValue {
    None,
    Uninitialized,
    Buffer(Vec<u8>),
    BufferField {
        source_buf: Box<AmlValue>,
        index: Box<AmlValue>,
        length: Box<AmlValue>
    },
    DDBHandle(Vec<String>),
    DebugObject,
    Device(Vec<String>),
    Event(u64),
    FieldUnit {
        selector: FieldSelector,
        connection: Box<AmlValue>,
        flags: FieldFlags,
        offset: usize,
        length: usize
    },
    Integer(u64),
    IntegerConstant(u64),
    Method(Method),
    Mutex((u8, Option<u64>)),
    ObjectReference(ObjectReference),
    OperationRegion {
        region: RegionSpace,
        offset: Box<AmlValue>,
        len: Box<AmlValue>,
        accessor: Accessor,
        accessed_by: Option<u64>
    },
    Package(Vec<AmlValue>),
    String(String),
    PowerResource {
        system_level: u8,
        resource_order: u16,
        obj_list: Vec<String>
    },
    Processor {
        proc_id: u8,
        p_blk: Option<u32>,
        obj_list: Vec<String>
    },
    RawDataBuffer(Vec<u8>),
    ThermalZone(Vec<String>)
}

impl Debug for AmlValue {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { Ok(()) }
}

impl AmlValue {
    pub fn get_as_event(&self) -> Result<u64, AmlError> {
        match *self {
            AmlValue::Event(ref e) => Ok(e.clone()),
            _ => Err(AmlError::AmlValueError)
        }
    }

    pub fn get_as_ddb_handle(&self) -> Result<Vec<String>, AmlError> {
        match *self {
            AmlValue::DDBHandle(ref v) => Ok(v.clone()),
            _ => Err(AmlError::AmlValueError)
        }
    }

    pub fn get_as_string(&self) -> Result<String, AmlError> {
        match *self {
            AmlValue::String(ref s) => Ok(s.clone()),
            _ => Err(AmlError::AmlValueError)
        }
    }

    pub fn get_as_buffer(&self) -> Result<Vec<u8>, AmlError> {
        match *self {
            AmlValue::Buffer(ref b) => Ok(b.clone()),
            _ => Err(AmlError::AmlValueError)
        }
    }

    pub fn get_as_package(&self) -> Result<Vec<AmlValue>, AmlError> {
        match *self {
            AmlValue::Package(ref p) => Ok(p.clone()),
            _ => Err(AmlError::AmlValueError)
        }
    }

    pub fn get_as_integer(&self) -> Result<u64, AmlError> {
        match *self {
            AmlValue::IntegerConstant(ref i) => Ok(i.clone()),
            _ => Err(AmlError::AmlValueError)
        }
    }

    pub fn get_as_method(&self) -> Result<Method, AmlError> {
        match *self {
            AmlValue::Method(ref m) => Ok(m.clone()),
            _ => Err(AmlError::AmlValueError)
        }
    }
}

impl Method {
    pub fn execute(&self, scope: String, parameters: Vec<AmlValue>) -> AmlValue {
        let mut ctx = AmlExecutionContext::new(scope);
        ctx.init_arg_vars(parameters);

        parse_term_list(&self.term_list[..], &mut ctx);
        ctx.clean_namespace();

        match ctx.state {
            ExecutionState::RETURN(v) => v,
            _ => AmlValue::IntegerConstant(0)
        }
    }
}

pub fn get_namespace_string(current: String, modifier_v: AmlValue) -> String {
    // TODO: Type error if modifier not string
    let mut modifier = if let Ok(s) = modifier_v.get_as_string() {
        s
    } else {
        return current;
    };

    if current.len() == 0 {
        return modifier;
    }

    if modifier.len() == 0 {
        return current;
    }

    if modifier.starts_with("\\") {
        return modifier;
    }

    let mut namespace = current.clone();

    if modifier.starts_with("^") {
        while modifier.starts_with("^") {
            modifier = modifier[1..].to_string();
            while namespace.pop() != Some('.') { }
        }
    }

    if !namespace.ends_with("\\") {
        namespace.push('.');
    }

    namespace + &modifier
}
<|endoftext|>


<commit_before>use std::collections::VecDeque;
use std::sync::{Arc, Mutex};

use wayland_client::{EventQueue, EventQueueHandle, Init};
use wayland_client::protocol::{wl_display,wl_surface,wl_shell_surface};

use {CreationError, MouseCursor, CursorState, Event, WindowAttributes};
use platform::MonitorId as PlatformMonitorId;

use super::WaylandContext;
use super::wayland_window;
use super::wayland_window::DecoratedSurface;

#[derive(Clone)]
pub struct WindowProxy {
    ctxt: Arc<WaylandContext>,
    eviter: Arc<Mutex<VecDeque<Event>>>,
}

impl WindowProxy {
    #[inline]
    pub fn wakeup_event_loop(&self) {
        // Send a sync event, so that any waiting "dispatch" will return
        self.ctxt.display.sync();
        self.eviter.lock().unwrap().push_back(Event::Awakened);
    }
}

pub struct Window {
    ctxt: Arc<WaylandContext>,
    evq: Mutex<EventQueue>,
    eviter: Arc<Mutex<VecDeque<Event>>>,
    surface: Arc<wl_surface::WlSurface>,
    size: Mutex<(u32, u32)>,
    handler_id: usize,
    decorated_id: usize
}

pub struct PollEventsIterator<'a> {
    window: &'a Window,
}

impl<'a> Iterator for PollEventsIterator<'a> {
    type Item = Event;

    fn next(&mut self) -> Option<Event> {
        self.window.next_event(false)
    }
}

pub struct WaitEventsIterator<'a> {
    window: &'a Window,
}

impl<'a> Iterator for WaitEventsIterator<'a> {
    type Item = Event;

    fn next(&mut self) -> Option<Event> {
        self.window.next_event(true)
    }
}

impl Window {
    pub fn new(ctxt: Arc<WaylandContext>, attributes: &WindowAttributes)  -> Result<Window, CreationError>
    {
        let (width, height) = attributes.dimensions.unwrap_or((800,600));

        let mut evq = ctxt.display.create_event_queue();

        let (surface, eviter, decorated) = ctxt.create_window::<DecoratedHandler>();

        // init DecoratedSurface
        let decorated_id = evq.add_handler_with_init(decorated);
        {
            let mut state = evq.state();
            let decorated = state.get_mut_handler::<DecoratedSurface<DecoratedHandler>>(decorated_id);
            *(decorated.handler()) = Some(DecoratedHandler::new());

            if let Some(PlatformMonitorId::Wayland(ref monitor_id)) = attributes.monitor {
                ctxt.with_output(monitor_id.clone(), |output| {
                    decorated.set_fullscreen(
                        wl_shell_surface::FullscreenMethod::Default,
                        0,
                        Some(output)
                    )
                });
            } else if attributes.decorations {
                decorated.set_decorate(true);
            }
        }

        // init general handler
        let handler = WindowHandler::new();
        let handler_id = evq.add_handler_with_init(handler);

        Ok(Window {
            ctxt: ctxt,
            evq: Mutex::new(evq),
            eviter: eviter,
            surface: surface,
            size: Mutex::new((width, height)),
            handler_id: handler_id,
            decorated_id: decorated_id
        })
    }

    fn process_resize(&self) {
        use std::cmp::max;
        let mut evq_guard = self.evq.lock().unwrap();
        let mut state = evq_guard.state();
        let newsize = {
            let decorated = state.get_mut_handler::<DecoratedSurface<DecoratedHandler>>(self.decorated_id);
            let newsize = decorated.handler().as_mut().and_then(|h| h.take_newsize());
            if let Some((w, h)) = newsize {
                decorated.resize(w as i32, h as i32);
                *self.size.lock().unwrap() = (w, h);
            }
            newsize
        };
        // callback_resize if any
        if let Some((w, h)) = newsize {
            let mut handler = state.get_mut_handler::<WindowHandler>(self.handler_id);
            if let Some(ref callback) = handler.resize_callback {
                callback(w, h);
            }
            self.eviter.lock().unwrap().push_back(Event::Resized(w,h));
        }
    }

    fn next_event(&self, block: bool) -> Option<Event> {
        let mut evt = {
            let mut guard = self.eviter.lock().unwrap();
            guard.pop_front()
        };
        if evt.is_some() { return evt }

        // There is no event in the queue, we need to fetch more

        // flush the display
        self.ctxt.flush();

        // read some events if some are waiting & queue is empty
        if let Some(guard) = self.evq.lock().unwrap().prepare_read() {
            guard.read_events();
        }

        // try a pending dispatch
        {
            self.ctxt.dispatch_pending();
            self.evq.lock().unwrap().dispatch_pending();
            // some events were dispatched, need to process a potential resising
            self.process_resize();
        }

        let mut evt = {
            let mut guard = self.eviter.lock().unwrap();
            guard.pop_front()
        };

        while block && evt.is_none() {
            // no event waiting, need to repopulate!
            {
                self.ctxt.flush();
                self.ctxt.dispatch();
                self.evq.lock().unwrap().dispatch_pending();
                // some events were dispatched, need to process a potential resising
                self.process_resize();
            }
            // try again
            let mut guard = self.eviter.lock().unwrap();
            evt = guard.pop_front();
        }
        evt
    }

    pub fn set_title(&self, title: &str) {
        let mut guard = self.evq.lock().unwrap();
        let mut state = guard.state();
        let mut decorated = state.get_mut_handler::<DecoratedSurface<DecoratedHandler>>(self.decorated_id);
        decorated.set_title(title.into())
    }

    #[inline]
    pub fn show(&self) {
        // TODO
    }

    #[inline]
    pub fn hide(&self) {
        // TODO
    }

    #[inline]
    pub fn get_position(&self) -> Option<(i32, i32)> {
        // Not possible with wayland
        None
    }

    #[inline]
    pub fn set_position(&self, _x: i32, _y: i32) {
        // Not possible with wayland
    }

    pub fn get_inner_size(&self) -> Option<(u32, u32)> {
        Some(self.size.lock().unwrap().clone())
    }

    #[inline]
    pub fn get_outer_size(&self) -> Option<(u32, u32)> {
        let (w, h) = self.size.lock().unwrap().clone();
        let (w, h) = super::wayland_window::add_borders(w as i32, h as i32);
        Some((w as u32, h as u32))
    }

    #[inline]
    // NOTE: This will only resize the borders, the contents must be updated by the user
    pub fn set_inner_size(&self, x: u32, y: u32) {
        let mut guard = self.evq.lock().unwrap();
        let mut state = guard.state();
        let mut decorated = state.get_mut_handler::<DecoratedSurface<DecoratedHandler>>(self.decorated_id);
        decorated.resize(x as i32, y as i32);
    }

    #[inline]
    pub fn create_window_proxy(&self) -> WindowProxy {
        WindowProxy {
            ctxt: self.ctxt.clone(),
            eviter: self.eviter.clone()
        }
    }

    #[inline]
    pub fn poll_events(&self) -> PollEventsIterator {
        PollEventsIterator {
            window: self
        }
    }

    #[inline]
    pub fn wait_events(&self) -> WaitEventsIterator {
        WaitEventsIterator {
            window: self
        }
    }

    #[inline]
    pub fn set_window_resize_callback(&mut self, callback: Option<fn(u32, u32)>) {
        let mut guard = self.evq.lock().unwrap();
        let mut state = guard.state();
        let mut handler = state.get_mut_handler::<WindowHandler>(self.handler_id);
        handler.resize_callback = callback;
    }

    #[inline]
    pub fn set_cursor(&self, _cursor: MouseCursor) {
        // TODO
    }

    #[inline]
    pub fn set_cursor_state(&self, state: CursorState) -> Result<(), String> {
        use CursorState::{Grab, Normal, Hide};
        // TODO : not yet possible on wayland to grab cursor
        match state {
            Grab => Err("Cursor cannot be grabbed on wayland yet.".to_string()),
            Hide => Err("Cursor cannot be hidden on wayland yet.".to_string()),
            Normal => Ok(())
        }
    }

    #[inline]
    pub fn hidpi_factor(&self) -> f32 {
        // TODO
        1.0
    }

    #[inline]
    pub fn set_cursor_position(&self, _x: i32, _y: i32) -> Result<(), ()> {
        // TODO: not yet possible on wayland
        Err(())
    }

    pub fn get_display(&self) -> &wl_display::WlDisplay {
        &self.ctxt.display
    }

    pub fn get_surface(&self) -> &wl_surface::WlSurface {
        &self.surface
    }
}

impl Drop for Window {
    fn drop(&mut self) {
        self.surface.destroy();
        self.ctxt.prune_dead_windows();
    }
}

struct DecoratedHandler {
    newsize: Option<(u32, u32)>
}

impl DecoratedHandler {
    fn new() -> DecoratedHandler { DecoratedHandler { newsize: None }}
    fn take_newsize(&mut self) -> Option<(u32, u32)> {
        self.newsize.take()
    }
}

impl wayland_window::Handler for DecoratedHandler {
    fn configure(&mut self,
                 _: &mut EventQueueHandle,
                 _: wl_shell_surface::Resize,
                 width: i32, height: i32)
    {
        use std::cmp::max;
        self.newsize = Some((max(width,1) as u32, max(height,1) as u32));
    }
}

struct WindowHandler {
    my_id: usize,
    resize_callback: Option<fn(u32,u32)>,
}

impl WindowHandler {
    fn new() -> WindowHandler {
        WindowHandler {
            my_id: 0,
            resize_callback: None
        }
    }
}

impl Init for WindowHandler {
    fn init(&mut self, evqh: &mut EventQueueHandle, index: usize) {
        self.my_id = index;
    }
}
<commit_msg>wayland: sync drawn border size on window creation<commit_after>use std::collections::VecDeque;
use std::sync::{Arc, Mutex};

use wayland_client::{EventQueue, EventQueueHandle, Init};
use wayland_client::protocol::{wl_display,wl_surface,wl_shell_surface};

use {CreationError, MouseCursor, CursorState, Event, WindowAttributes};
use platform::MonitorId as PlatformMonitorId;

use super::WaylandContext;
use super::wayland_window;
use super::wayland_window::DecoratedSurface;

#[derive(Clone)]
pub struct WindowProxy {
    ctxt: Arc<WaylandContext>,
    eviter: Arc<Mutex<VecDeque<Event>>>,
}

impl WindowProxy {
    #[inline]
    pub fn wakeup_event_loop(&self) {
        // Send a sync event, so that any waiting "dispatch" will return
        self.ctxt.display.sync();
        self.eviter.lock().unwrap().push_back(Event::Awakened);
    }
}

pub struct Window {
    ctxt: Arc<WaylandContext>,
    evq: Mutex<EventQueue>,
    eviter: Arc<Mutex<VecDeque<Event>>>,
    surface: Arc<wl_surface::WlSurface>,
    size: Mutex<(u32, u32)>,
    handler_id: usize,
    decorated_id: usize
}

pub struct PollEventsIterator<'a> {
    window: &'a Window,
}

impl<'a> Iterator for PollEventsIterator<'a> {
    type Item = Event;

    fn next(&mut self) -> Option<Event> {
        self.window.next_event(false)
    }
}

pub struct WaitEventsIterator<'a> {
    window: &'a Window,
}

impl<'a> Iterator for WaitEventsIterator<'a> {
    type Item = Event;

    fn next(&mut self) -> Option<Event> {
        self.window.next_event(true)
    }
}

impl Window {
    pub fn new(ctxt: Arc<WaylandContext>, attributes: &WindowAttributes)  -> Result<Window, CreationError>
    {
        let (width, height) = attributes.dimensions.unwrap_or((800,600));

        let mut evq = ctxt.display.create_event_queue();

        let (surface, eviter, decorated) = ctxt.create_window::<DecoratedHandler>();

        // init DecoratedSurface
        let decorated_id = evq.add_handler_with_init(decorated);
        {
            let mut state = evq.state();
            let decorated = state.get_mut_handler::<DecoratedSurface<DecoratedHandler>>(decorated_id);
            *(decorated.handler()) = Some(DecoratedHandler::new());

            if let Some(PlatformMonitorId::Wayland(ref monitor_id)) = attributes.monitor {
                ctxt.with_output(monitor_id.clone(), |output| {
                    decorated.set_fullscreen(
                        wl_shell_surface::FullscreenMethod::Default,
                        0,
                        Some(output)
                    )
                });
            } else if attributes.decorations {
                decorated.set_decorate(true);
            }
            // Finally, set the decorations size
            decorated.resize(width as i32, height as i32);
        }

        // init general handler
        let handler = WindowHandler::new();
        let handler_id = evq.add_handler_with_init(handler);

        Ok(Window {
            ctxt: ctxt,
            evq: Mutex::new(evq),
            eviter: eviter,
            surface: surface,
            size: Mutex::new((width, height)),
            handler_id: handler_id,
            decorated_id: decorated_id
        })
    }

    fn process_resize(&self) {
        use std::cmp::max;
        let mut evq_guard = self.evq.lock().unwrap();
        let mut state = evq_guard.state();
        let newsize = {
            let decorated = state.get_mut_handler::<DecoratedSurface<DecoratedHandler>>(self.decorated_id);
            let newsize = decorated.handler().as_mut().and_then(|h| h.take_newsize());
            if let Some((w, h)) = newsize {
                decorated.resize(w as i32, h as i32);
                *self.size.lock().unwrap() = (w, h);
            }
            newsize
        };
        // callback_resize if any
        if let Some((w, h)) = newsize {
            let mut handler = state.get_mut_handler::<WindowHandler>(self.handler_id);
            if let Some(ref callback) = handler.resize_callback {
                callback(w, h);
            }
            self.eviter.lock().unwrap().push_back(Event::Resized(w,h));
        }
    }

    fn next_event(&self, block: bool) -> Option<Event> {
        let mut evt = {
            let mut guard = self.eviter.lock().unwrap();
            guard.pop_front()
        };
        if evt.is_some() { return evt }

        // There is no event in the queue, we need to fetch more

        // flush the display
        self.ctxt.flush();

        // read some events if some are waiting & queue is empty
        if let Some(guard) = self.evq.lock().unwrap().prepare_read() {
            guard.read_events();
        }

        // try a pending dispatch
        {
            self.ctxt.dispatch_pending();
            self.evq.lock().unwrap().dispatch_pending();
            // some events were dispatched, need to process a potential resising
            self.process_resize();
        }

        let mut evt = {
            let mut guard = self.eviter.lock().unwrap();
            guard.pop_front()
        };

        while block && evt.is_none() {
            // no event waiting, need to repopulate!
            {
                self.ctxt.flush();
                self.ctxt.dispatch();
                self.evq.lock().unwrap().dispatch_pending();
                // some events were dispatched, need to process a potential resising
                self.process_resize();
            }
            // try again
            let mut guard = self.eviter.lock().unwrap();
            evt = guard.pop_front();
        }
        evt
    }

    pub fn set_title(&self, title: &str) {
        let mut guard = self.evq.lock().unwrap();
        let mut state = guard.state();
        let mut decorated = state.get_mut_handler::<DecoratedSurface<DecoratedHandler>>(self.decorated_id);
        decorated.set_title(title.into())
    }

    #[inline]
    pub fn show(&self) {
        // TODO
    }

    #[inline]
    pub fn hide(&self) {
        // TODO
    }

    #[inline]
    pub fn get_position(&self) -> Option<(i32, i32)> {
        // Not possible with wayland
        None
    }

    #[inline]
    pub fn set_position(&self, _x: i32, _y: i32) {
        // Not possible with wayland
    }

    pub fn get_inner_size(&self) -> Option<(u32, u32)> {
        Some(self.size.lock().unwrap().clone())
    }

    #[inline]
    pub fn get_outer_size(&self) -> Option<(u32, u32)> {
        let (w, h) = self.size.lock().unwrap().clone();
        let (w, h) = super::wayland_window::add_borders(w as i32, h as i32);
        Some((w as u32, h as u32))
    }

    #[inline]
    // NOTE: This will only resize the borders, the contents must be updated by the user
    pub fn set_inner_size(&self, x: u32, y: u32) {
        let mut guard = self.evq.lock().unwrap();
        let mut state = guard.state();
        let mut decorated = state.get_mut_handler::<DecoratedSurface<DecoratedHandler>>(self.decorated_id);
        decorated.resize(x as i32, y as i32);
    }

    #[inline]
    pub fn create_window_proxy(&self) -> WindowProxy {
        WindowProxy {
            ctxt: self.ctxt.clone(),
            eviter: self.eviter.clone()
        }
    }

    #[inline]
    pub fn poll_events(&self) -> PollEventsIterator {
        PollEventsIterator {
            window: self
        }
    }

    #[inline]
    pub fn wait_events(&self) -> WaitEventsIterator {
        WaitEventsIterator {
            window: self
        }
    }

    #[inline]
    pub fn set_window_resize_callback(&mut self, callback: Option<fn(u32, u32)>) {
        let mut guard = self.evq.lock().unwrap();
        let mut state = guard.state();
        let mut handler = state.get_mut_handler::<WindowHandler>(self.handler_id);
        handler.resize_callback = callback;
    }

    #[inline]
    pub fn set_cursor(&self, _cursor: MouseCursor) {
        // TODO
    }

    #[inline]
    pub fn set_cursor_state(&self, state: CursorState) -> Result<(), String> {
        use CursorState::{Grab, Normal, Hide};
        // TODO : not yet possible on wayland to grab cursor
        match state {
            Grab => Err("Cursor cannot be grabbed on wayland yet.".to_string()),
            Hide => Err("Cursor cannot be hidden on wayland yet.".to_string()),
            Normal => Ok(())
        }
    }

    #[inline]
    pub fn hidpi_factor(&self) -> f32 {
        // TODO
        1.0
    }

    #[inline]
    pub fn set_cursor_position(&self, _x: i32, _y: i32) -> Result<(), ()> {
        // TODO: not yet possible on wayland
        Err(())
    }

    pub fn get_display(&self) -> &wl_display::WlDisplay {
        &self.ctxt.display
    }

    pub fn get_surface(&self) -> &wl_surface::WlSurface {
        &self.surface
    }
}

impl Drop for Window {
    fn drop(&mut self) {
        self.surface.destroy();
        self.ctxt.prune_dead_windows();
    }
}

struct DecoratedHandler {
    newsize: Option<(u32, u32)>
}

impl DecoratedHandler {
    fn new() -> DecoratedHandler { DecoratedHandler { newsize: None }}
    fn take_newsize(&mut self) -> Option<(u32, u32)> {
        self.newsize.take()
    }
}

impl wayland_window::Handler for DecoratedHandler {
    fn configure(&mut self,
                 _: &mut EventQueueHandle,
                 _: wl_shell_surface::Resize,
                 width: i32, height: i32)
    {
        use std::cmp::max;
        self.newsize = Some((max(width,1) as u32, max(height,1) as u32));
    }
}

struct WindowHandler {
    my_id: usize,
    resize_callback: Option<fn(u32,u32)>,
}

impl WindowHandler {
    fn new() -> WindowHandler {
        WindowHandler {
            my_id: 0,
            resize_callback: None
        }
    }
}

impl Init for WindowHandler {
    fn init(&mut self, evqh: &mut EventQueueHandle, index: usize) {
        self.my_id = index;
    }
}
<|endoftext|>