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

// spell-checker:ignore (ToDO) ugoa cmode

#[macro_use]
extern crate uucore;

use clap::{crate_version, Arg, ArgMatches, Command, OsValues};
use std::path::{Path, PathBuf};
#[cfg(not(windows))]
use uucore::error::FromIo;
use uucore::error::{UResult, USimpleError};
#[cfg(not(windows))]
use uucore::mode;
use uucore::{display::Quotable, fs::dir_strip_dot_for_creation};
use uucore::{format_usage, InvalidEncodingHandling};

static DEFAULT_PERM: u32 = 0o755;

static ABOUT: &str = "Create the given DIRECTORY(ies) if they do not exist";
const USAGE: &str = "{} [OPTION]... [USER]";

mod options {
    pub const MODE: &str = "mode";
    pub const PARENTS: &str = "parents";
    pub const VERBOSE: &str = "verbose";
    pub const DIRS: &str = "dirs";
}

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

#[cfg(windows)]
fn get_mode(_matches: &ArgMatches, _mode_had_minus_prefix: bool) -> Result<u32, String> {
    Ok(DEFAULT_PERM)
}

#[cfg(not(windows))]
fn get_mode(matches: &ArgMatches, mode_had_minus_prefix: bool) -> Result<u32, String> {
    let digits: &[char] = &['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'];
    // Translate a ~str in octal form to u16, default to 755
    // Not tested on Windows
    let mut new_mode = DEFAULT_PERM;
    match matches.value_of(options::MODE) {
        Some(m) => {
            for mode in m.split(',') {
                if mode.contains(digits) {
                    new_mode = mode::parse_numeric(new_mode, m, true)?;
                } else {
                    let cmode = if mode_had_minus_prefix {
                        // clap parsing is finished, now put prefix back
                        format!("-{}", mode)
                    } else {
                        mode.to_string()
                    };
                    new_mode = mode::parse_symbolic(new_mode, &cmode, mode::get_umask(), true)?;
                }
            }
            Ok(new_mode)
        }
        None => Ok(DEFAULT_PERM),
    }
}

#[cfg(windows)]
fn strip_minus_from_mode(_args: &mut Vec<String>) -> bool {
    false
}

#[cfg(not(windows))]
fn strip_minus_from_mode(args: &mut Vec<String>) -> bool {
    mode::strip_minus_from_mode(args)
}

#[uucore::main]
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
    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 after_help = get_long_usage();

    // Linux-specific options, not implemented
    // opts.optflag("Z", "context", "set SELinux security context" +
    // " of each created directory to CTX"),
    let matches = uu_app().after_help(&after_help[..]).get_matches_from(args);

    let dirs = matches.values_of_os(options::DIRS).unwrap_or_default();
    let verbose = matches.is_present(options::VERBOSE);
    let recursive = matches.is_present(options::PARENTS);

    match get_mode(&matches, mode_had_minus_prefix) {
        Ok(mode) => exec(dirs, recursive, mode, verbose),
        Err(f) => Err(USimpleError::new(1, f)),
    }
}

pub fn uu_app<'a>() -> Command<'a> {
    Command::new(uucore::util_name())
        .version(crate_version!())
        .about(ABOUT)
        .override_usage(format_usage(USAGE))
        .infer_long_args(true)
        .arg(
            Arg::new(options::MODE)
                .short('m')
                .long(options::MODE)
                .help("set file mode (not implemented on windows)")
                .default_value("755"),
        )
        .arg(
            Arg::new(options::PARENTS)
                .short('p')
                .long(options::PARENTS)
                .help("make parent directories as needed"),
        )
        .arg(
            Arg::new(options::VERBOSE)
                .short('v')
                .long(options::VERBOSE)
                .help("print a message for each printed directory"),
        )
        .arg(
            Arg::new(options::DIRS)
                .multiple_occurrences(true)
                .takes_value(true)
                .min_values(1)
                .allow_invalid_utf8(true),
        )
}

/**
 * Create the list of new directories
 */
fn exec(dirs: OsValues, recursive: bool, mode: u32, verbose: bool) -> UResult<()> {
    for dir in dirs {
        // Special case to match GNU's behavior:
        // mkdir -p foo/. should work and just create foo/
        // std::fs::create_dir("foo/."); fails in pure Rust
        let path = if recursive {
            dir_strip_dot_for_creation(&PathBuf::from(dir))
        } else {
            // Normal case
            PathBuf::from(dir)
        };
        show_if_err!(mkdir(path.as_path(), recursive, mode, verbose));
    }
    Ok(())
}

fn mkdir(path: &Path, recursive: bool, mode: u32, verbose: bool) -> UResult<()> {
    create_dir(path, recursive, verbose)?;
    chmod(path, mode)
}

#[cfg(any(unix, target_os = "redox"))]
fn chmod(path: &Path, mode: u32) -> UResult<()> {
    use std::fs::{set_permissions, Permissions};
    use std::os::unix::fs::PermissionsExt;

    let mode = Permissions::from_mode(mode);

    set_permissions(path, mode)
        .map_err_context(|| format!("cannot set permissions {}", path.quote()))
}

#[cfg(windows)]
fn chmod(_path: &Path, _mode: u32) -> UResult<()> {
    // chmod on Windows only sets the readonly flag, which isn't even honored on directories
    Ok(())
}

fn create_dir(path: &Path, recursive: bool, verbose: bool) -> UResult<()> {
    if path.exists() && !recursive {
        return Err(USimpleError::new(
            1,
            format!("{}: File exists", path.display()),
        ));
    }
    if path == Path::new("") {
        return Ok(());
    }

    if recursive {
        match path.parent() {
            Some(p) => create_dir(p, recursive, verbose)?,
            None => {
                USimpleError::new(1, "failed to create whole tree");
            }
        }
    }
    match std::fs::create_dir(path) {
        Ok(()) => {
            if verbose {
                println!(
                    "{}: created directory {}",
                    uucore::util_name(),
                    path.quote()
                );
            }
            Ok(())
        }
        Err(_) if path.is_dir() => Ok(()),
        Err(e) => Err(e.into()),
    }
}
<commit_msg>mkdir.rs: Fix a clippy warning on clippy::ptr-arg<commit_after>//  * This file is part of the uutils coreutils package.
//  *
//  * (c) Nicholas Juszczak <juszczakn@gmail.com>
//  *
//  * For the full copyright and license information, please view the LICENSE
//  * file that was distributed with this source code.

// spell-checker:ignore (ToDO) ugoa cmode

#[macro_use]
extern crate uucore;

use clap::{crate_version, Arg, ArgMatches, Command, OsValues};
use std::path::{Path, PathBuf};
#[cfg(not(windows))]
use uucore::error::FromIo;
use uucore::error::{UResult, USimpleError};
#[cfg(not(windows))]
use uucore::mode;
use uucore::{display::Quotable, fs::dir_strip_dot_for_creation};
use uucore::{format_usage, InvalidEncodingHandling};

static DEFAULT_PERM: u32 = 0o755;

static ABOUT: &str = "Create the given DIRECTORY(ies) if they do not exist";
const USAGE: &str = "{} [OPTION]... [USER]";

mod options {
    pub const MODE: &str = "mode";
    pub const PARENTS: &str = "parents";
    pub const VERBOSE: &str = "verbose";
    pub const DIRS: &str = "dirs";
}

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

#[cfg(windows)]
fn get_mode(_matches: &ArgMatches, _mode_had_minus_prefix: bool) -> Result<u32, String> {
    Ok(DEFAULT_PERM)
}

#[cfg(not(windows))]
fn get_mode(matches: &ArgMatches, mode_had_minus_prefix: bool) -> Result<u32, String> {
    let digits: &[char] = &['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'];
    // Translate a ~str in octal form to u16, default to 755
    // Not tested on Windows
    let mut new_mode = DEFAULT_PERM;
    match matches.value_of(options::MODE) {
        Some(m) => {
            for mode in m.split(',') {
                if mode.contains(digits) {
                    new_mode = mode::parse_numeric(new_mode, m, true)?;
                } else {
                    let cmode = if mode_had_minus_prefix {
                        // clap parsing is finished, now put prefix back
                        format!("-{}", mode)
                    } else {
                        mode.to_string()
                    };
                    new_mode = mode::parse_symbolic(new_mode, &cmode, mode::get_umask(), true)?;
                }
            }
            Ok(new_mode)
        }
        None => Ok(DEFAULT_PERM),
    }
}

#[cfg(windows)]
fn strip_minus_from_mode(_args: &mut [String]) -> bool {
    false
}

#[cfg(not(windows))]
fn strip_minus_from_mode(args: &mut Vec<String>) -> bool {
    mode::strip_minus_from_mode(args)
}

#[uucore::main]
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
    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 after_help = get_long_usage();

    // Linux-specific options, not implemented
    // opts.optflag("Z", "context", "set SELinux security context" +
    // " of each created directory to CTX"),
    let matches = uu_app().after_help(&after_help[..]).get_matches_from(args);

    let dirs = matches.values_of_os(options::DIRS).unwrap_or_default();
    let verbose = matches.is_present(options::VERBOSE);
    let recursive = matches.is_present(options::PARENTS);

    match get_mode(&matches, mode_had_minus_prefix) {
        Ok(mode) => exec(dirs, recursive, mode, verbose),
        Err(f) => Err(USimpleError::new(1, f)),
    }
}

pub fn uu_app<'a>() -> Command<'a> {
    Command::new(uucore::util_name())
        .version(crate_version!())
        .about(ABOUT)
        .override_usage(format_usage(USAGE))
        .infer_long_args(true)
        .arg(
            Arg::new(options::MODE)
                .short('m')
                .long(options::MODE)
                .help("set file mode (not implemented on windows)")
                .default_value("755"),
        )
        .arg(
            Arg::new(options::PARENTS)
                .short('p')
                .long(options::PARENTS)
                .help("make parent directories as needed"),
        )
        .arg(
            Arg::new(options::VERBOSE)
                .short('v')
                .long(options::VERBOSE)
                .help("print a message for each printed directory"),
        )
        .arg(
            Arg::new(options::DIRS)
                .multiple_occurrences(true)
                .takes_value(true)
                .min_values(1)
                .allow_invalid_utf8(true),
        )
}

/**
 * Create the list of new directories
 */
fn exec(dirs: OsValues, recursive: bool, mode: u32, verbose: bool) -> UResult<()> {
    for dir in dirs {
        // Special case to match GNU's behavior:
        // mkdir -p foo/. should work and just create foo/
        // std::fs::create_dir("foo/."); fails in pure Rust
        let path = if recursive {
            dir_strip_dot_for_creation(&PathBuf::from(dir))
        } else {
            // Normal case
            PathBuf::from(dir)
        };
        show_if_err!(mkdir(path.as_path(), recursive, mode, verbose));
    }
    Ok(())
}

fn mkdir(path: &Path, recursive: bool, mode: u32, verbose: bool) -> UResult<()> {
    create_dir(path, recursive, verbose)?;
    chmod(path, mode)
}

#[cfg(any(unix, target_os = "redox"))]
fn chmod(path: &Path, mode: u32) -> UResult<()> {
    use std::fs::{set_permissions, Permissions};
    use std::os::unix::fs::PermissionsExt;

    let mode = Permissions::from_mode(mode);

    set_permissions(path, mode)
        .map_err_context(|| format!("cannot set permissions {}", path.quote()))
}

#[cfg(windows)]
fn chmod(_path: &Path, _mode: u32) -> UResult<()> {
    // chmod on Windows only sets the readonly flag, which isn't even honored on directories
    Ok(())
}

fn create_dir(path: &Path, recursive: bool, verbose: bool) -> UResult<()> {
    if path.exists() && !recursive {
        return Err(USimpleError::new(
            1,
            format!("{}: File exists", path.display()),
        ));
    }
    if path == Path::new("") {
        return Ok(());
    }

    if recursive {
        match path.parent() {
            Some(p) => create_dir(p, recursive, verbose)?,
            None => {
                USimpleError::new(1, "failed to create whole tree");
            }
        }
    }
    match std::fs::create_dir(path) {
        Ok(()) => {
            if verbose {
                println!(
                    "{}: created directory {}",
                    uucore::util_name(),
                    path.quote()
                );
            }
            Ok(())
        }
        Err(_) if path.is_dir() => Ok(()),
        Err(e) => Err(e.into()),
    }
}
<|endoftext|>


<commit_before>//  * This file is part of the uutils coreutils package.
//  *
//  * (c) KokaKiwi <kokakiwi@kokakiwi.net>
//  * (c) Jian Zeng <anonymousknight86@gmail.com>
//  *
//  * For the full copyright and license information, please view the LICENSE
//  * file that was distributed with this source code.

#[macro_use]
extern crate uucore;

use clap::{App, Arg};
use uucore::utmpx::{self, Utmpx};

static VERSION: &str = env!("CARGO_PKG_VERSION");
static ABOUT: &str = "Print the user names of users currently logged in to the current host";

static ARG_FILES: &str = "files";

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

fn get_long_usage() -> String {
    format!(
        "Output who is currently logged in according to FILE.
If FILE is not specified, use {}.  /var/log/wtmp as FILE is common.",
        utmpx::DEFAULT_FILE
    )
}

pub fn uumain(args: impl uucore::Args) -> i32 {
    let usage = get_usage();
    let after_help = get_long_usage();

    let matches = App::new(executable!())
        .version(VERSION)
        .about(ABOUT)
        .usage(&usage[..])
        .after_help(&after_help[..])
        .arg(Arg::with_name(ARG_FILES).takes_value(true).max_values(1))
        .get_matches_from(args);

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

    let filename = if !files.is_empty() {
        files[0].as_ref()
    } else {
        utmpx::DEFAULT_FILE
    };

    let mut users = Utmpx::iter_all_records()
        .read_from(filename)
        .filter(Utmpx::is_user_process)
        .map(|ut| ut.user())
        .collect::<Vec<_>>();

    if !users.is_empty() {
        users.sort();
        println!("{}", users.join(" "));
    }

    0
}
<commit_msg>refactor/users ~ polish spelling (comments, names, and exceptions)<commit_after>//  * This file is part of the uutils coreutils package.
//  *
//  * (c) KokaKiwi <kokakiwi@kokakiwi.net>
//  * (c) Jian Zeng <anonymousknight86@gmail.com>
//  *
//  * For the full copyright and license information, please view the LICENSE
//  * file that was distributed with this source code.

// spell-checker:ignore (paths) wtmp

#[macro_use]
extern crate uucore;

use clap::{App, Arg};
use uucore::utmpx::{self, Utmpx};

static VERSION: &str = env!("CARGO_PKG_VERSION");
static ABOUT: &str = "Print the user names of users currently logged in to the current host";

static ARG_FILES: &str = "files";

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

fn get_long_usage() -> String {
    format!(
        "Output who is currently logged in according to FILE.
If FILE is not specified, use {}.  /var/log/wtmp as FILE is common.",
        utmpx::DEFAULT_FILE
    )
}

pub fn uumain(args: impl uucore::Args) -> i32 {
    let usage = get_usage();
    let after_help = get_long_usage();

    let matches = App::new(executable!())
        .version(VERSION)
        .about(ABOUT)
        .usage(&usage[..])
        .after_help(&after_help[..])
        .arg(Arg::with_name(ARG_FILES).takes_value(true).max_values(1))
        .get_matches_from(args);

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

    let filename = if !files.is_empty() {
        files[0].as_ref()
    } else {
        utmpx::DEFAULT_FILE
    };

    let mut users = Utmpx::iter_all_records()
        .read_from(filename)
        .filter(Utmpx::is_user_process)
        .map(|ut| ut.user())
        .collect::<Vec<_>>();

    if !users.is_empty() {
        users.sort();
        println!("{}", users.join(" "));
    }

    0
}
<|endoftext|>


<commit_before>#![cfg_attr(test, allow(dead_code))]

use self::imp::{drop_handler, make_handler};

pub use self::imp::cleanup;
pub use self::imp::init;

pub struct Handler {
    _data: *mut libc::c_void,
}

impl Handler {
    pub unsafe fn new() -> Handler {
        make_handler()
    }

    fn null() -> Handler {
        Handler { _data: crate::ptr::null_mut() }
    }
}

impl Drop for Handler {
    fn drop(&mut self) {
        unsafe {
            drop_handler(self);
        }
    }
}

#[cfg(any(
    target_os = "linux",
    target_os = "macos",
    target_os = "dragonfly",
    target_os = "freebsd",
    target_os = "solaris",
    all(target_os = "netbsd", not(target_vendor = "rumprun")),
    target_os = "openbsd"
))]
mod imp {
    use super::Handler;
    use crate::mem;
    use crate::ptr;

    use libc::MAP_FAILED;
    use libc::{mmap, munmap};
    use libc::{sigaction, sighandler_t, SA_ONSTACK, SA_SIGINFO, SIGBUS, SIG_DFL};
    use libc::{sigaltstack, SIGSTKSZ, SS_DISABLE};
    use libc::{MAP_ANON, MAP_PRIVATE, PROT_NONE, PROT_READ, PROT_WRITE, SIGSEGV};

    use crate::sys_common::thread_info;

    #[cfg(any(target_os = "linux", target_os = "android"))]
    unsafe fn siginfo_si_addr(info: *mut libc::siginfo_t) -> usize {
        #[repr(C)]
        struct siginfo_t {
            a: [libc::c_int; 3], // si_signo, si_errno, si_code
            si_addr: *mut libc::c_void,
        }

        (*(info as *const siginfo_t)).si_addr as usize
    }

    #[cfg(not(any(target_os = "linux", target_os = "android")))]
    unsafe fn siginfo_si_addr(info: *mut libc::siginfo_t) -> usize {
        (*info).si_addr as usize
    }

    // Signal handler for the SIGSEGV and SIGBUS handlers. We've got guard pages
    // (unmapped pages) at the end of every thread's stack, so if a thread ends
    // up running into the guard page it'll trigger this handler. We want to
    // detect these cases and print out a helpful error saying that the stack
    // has overflowed. All other signals, however, should go back to what they
    // were originally supposed to do.
    //
    // This handler currently exists purely to print an informative message
    // whenever a thread overflows its stack. We then abort to exit and
    // indicate a crash, but to avoid a misleading SIGSEGV that might lead
    // users to believe that unsafe code has accessed an invalid pointer; the
    // SIGSEGV encountered when overflowing the stack is expected and
    // well-defined.
    //
    // If this is not a stack overflow, the handler un-registers itself and
    // then returns (to allow the original signal to be delivered again).
    // Returning from this kind of signal handler is technically not defined
    // to work when reading the POSIX spec strictly, but in practice it turns
    // out many large systems and all implementations allow returning from a
    // signal handler to work. For a more detailed explanation see the
    // comments on #26458.
    unsafe extern "C" fn signal_handler(
        signum: libc::c_int,
        info: *mut libc::siginfo_t,
        _data: *mut libc::c_void,
    ) {
        use crate::sys_common::util::report_overflow;

        let guard = thread_info::stack_guard().unwrap_or(0..0);
        let addr = siginfo_si_addr(info);

        // If the faulting address is within the guard page, then we print a
        // message saying so and abort.
        if guard.start <= addr && addr < guard.end {
            report_overflow();
            rtabort!("stack overflow");
        } else {
            // Unregister ourselves by reverting back to the default behavior.
            let mut action: sigaction = mem::zeroed();
            action.sa_sigaction = SIG_DFL;
            sigaction(signum, &action, ptr::null_mut());

            // See comment above for why this function returns.
        }
    }

    static mut MAIN_ALTSTACK: *mut libc::c_void = ptr::null_mut();
    static mut NEED_ALTSTACK: bool = false;

    pub unsafe fn init() {
        let mut action: sigaction = mem::zeroed();
        for &signal in &[SIGSEGV, SIGBUS] {
            sigaction(signal, ptr::null_mut(), &mut action);
            // Configure our signal handler if one is not already set.
            if action.sa_sigaction == SIG_DFL {
                action.sa_flags = SA_SIGINFO | SA_ONSTACK;
                action.sa_sigaction = signal_handler as sighandler_t;
                sigaction(signal, &action, ptr::null_mut());
                NEED_ALTSTACK = true;
            }
        }

        let handler = make_handler();
        MAIN_ALTSTACK = handler._data;
        mem::forget(handler);
    }

    pub unsafe fn cleanup() {
        Handler { _data: MAIN_ALTSTACK };
    }

    unsafe fn get_stackp() -> *mut libc::c_void {
        let page_size = crate::sys::unix::os::page_size();
        let stackp =
            mmap(ptr::null_mut(), SIGSTKSZ + page_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
        if stackp == MAP_FAILED {
            panic!("failed to allocate an alternative stack");
        }
        let guard_result = libc::mprotect(stackp, page_size, PROT_NONE);
        if guard_result != 0 {
            panic!("failed to set up alternative stack guard page");
        }
        stackp
    }

    #[cfg(any(
        target_os = "linux",
        target_os = "macos",
        target_os = "freebsd",
        target_os = "netbsd",
        target_os = "openbsd",
        target_os = "solaris"
    ))]
    unsafe fn get_stack() -> libc::stack_t {
        libc::stack_t { ss_sp: get_stackp(), ss_flags: 0, ss_size: SIGSTKSZ }
    }

    #[cfg(target_os = "dragonfly")]
    unsafe fn get_stack() -> libc::stack_t {
        libc::stack_t { ss_sp: get_stackp() as *mut i8, ss_flags: 0, ss_size: SIGSTKSZ }
    }

    pub unsafe fn make_handler() -> Handler {
        if !NEED_ALTSTACK {
            return Handler::null();
        }
        let mut stack = mem::zeroed();
        sigaltstack(ptr::null(), &mut stack);
        // Configure alternate signal stack, if one is not already set.
        if stack.ss_flags & SS_DISABLE != 0 {
            stack = get_stack();
            sigaltstack(&stack, ptr::null_mut());
            Handler { _data: stack.ss_sp as *mut libc::c_void }
        } else {
            Handler::null()
        }
    }

    pub unsafe fn drop_handler(handler: &mut Handler) {
        if !handler._data.is_null() {
            let stack = libc::stack_t {
                ss_sp: ptr::null_mut(),
                ss_flags: SS_DISABLE,
                // Workaround for bug in macOS implementation of sigaltstack
                // UNIX2003 which returns ENOMEM when disabling a stack while
                // passing ss_size smaller than MINSIGSTKSZ. According to POSIX
                // both ss_sp and ss_size should be ignored in this case.
                ss_size: SIGSTKSZ,
            };
            sigaltstack(&stack, ptr::null_mut());
            munmap(handler._data, SIGSTKSZ);
        }
    }
}

#[cfg(not(any(
    target_os = "linux",
    target_os = "macos",
    target_os = "dragonfly",
    target_os = "freebsd",
    target_os = "solaris",
    all(target_os = "netbsd", not(target_vendor = "rumprun")),
    target_os = "openbsd"
)))]
mod imp {
    pub unsafe fn init() {}

    pub unsafe fn cleanup() {}

    pub unsafe fn make_handler() -> super::Handler {
        super::Handler::null()
    }

    pub unsafe fn drop_handler(_handler: &mut super::Handler) {}
}
<commit_msg>return a pointer to the end of the valid part of the sigstack, no further<commit_after>#![cfg_attr(test, allow(dead_code))]

use self::imp::{drop_handler, make_handler};

pub use self::imp::cleanup;
pub use self::imp::init;

pub struct Handler {
    _data: *mut libc::c_void,
}

impl Handler {
    pub unsafe fn new() -> Handler {
        make_handler()
    }

    fn null() -> Handler {
        Handler { _data: crate::ptr::null_mut() }
    }
}

impl Drop for Handler {
    fn drop(&mut self) {
        unsafe {
            drop_handler(self);
        }
    }
}

#[cfg(any(
    target_os = "linux",
    target_os = "macos",
    target_os = "dragonfly",
    target_os = "freebsd",
    target_os = "solaris",
    all(target_os = "netbsd", not(target_vendor = "rumprun")),
    target_os = "openbsd"
))]
mod imp {
    use super::Handler;
    use crate::mem;
    use crate::ptr;

    use libc::MAP_FAILED;
    use libc::{mmap, munmap};
    use libc::{sigaction, sighandler_t, SA_ONSTACK, SA_SIGINFO, SIGBUS, SIG_DFL};
    use libc::{sigaltstack, SIGSTKSZ, SS_DISABLE};
    use libc::{MAP_ANON, MAP_PRIVATE, PROT_NONE, PROT_READ, PROT_WRITE, SIGSEGV};

    use crate::sys::unix::os::page_size;
    use crate::sys_common::thread_info;

    #[cfg(any(target_os = "linux", target_os = "android"))]
    unsafe fn siginfo_si_addr(info: *mut libc::siginfo_t) -> usize {
        #[repr(C)]
        struct siginfo_t {
            a: [libc::c_int; 3], // si_signo, si_errno, si_code
            si_addr: *mut libc::c_void,
        }

        (*(info as *const siginfo_t)).si_addr as usize
    }

    #[cfg(not(any(target_os = "linux", target_os = "android")))]
    unsafe fn siginfo_si_addr(info: *mut libc::siginfo_t) -> usize {
        (*info).si_addr as usize
    }

    // Signal handler for the SIGSEGV and SIGBUS handlers. We've got guard pages
    // (unmapped pages) at the end of every thread's stack, so if a thread ends
    // up running into the guard page it'll trigger this handler. We want to
    // detect these cases and print out a helpful error saying that the stack
    // has overflowed. All other signals, however, should go back to what they
    // were originally supposed to do.
    //
    // This handler currently exists purely to print an informative message
    // whenever a thread overflows its stack. We then abort to exit and
    // indicate a crash, but to avoid a misleading SIGSEGV that might lead
    // users to believe that unsafe code has accessed an invalid pointer; the
    // SIGSEGV encountered when overflowing the stack is expected and
    // well-defined.
    //
    // If this is not a stack overflow, the handler un-registers itself and
    // then returns (to allow the original signal to be delivered again).
    // Returning from this kind of signal handler is technically not defined
    // to work when reading the POSIX spec strictly, but in practice it turns
    // out many large systems and all implementations allow returning from a
    // signal handler to work. For a more detailed explanation see the
    // comments on #26458.
    unsafe extern "C" fn signal_handler(
        signum: libc::c_int,
        info: *mut libc::siginfo_t,
        _data: *mut libc::c_void,
    ) {
        use crate::sys_common::util::report_overflow;

        let guard = thread_info::stack_guard().unwrap_or(0..0);
        let addr = siginfo_si_addr(info);

        // If the faulting address is within the guard page, then we print a
        // message saying so and abort.
        if guard.start <= addr && addr < guard.end {
            report_overflow();
            rtabort!("stack overflow");
        } else {
            // Unregister ourselves by reverting back to the default behavior.
            let mut action: sigaction = mem::zeroed();
            action.sa_sigaction = SIG_DFL;
            sigaction(signum, &action, ptr::null_mut());

            // See comment above for why this function returns.
        }
    }

    static mut MAIN_ALTSTACK: *mut libc::c_void = ptr::null_mut();
    static mut NEED_ALTSTACK: bool = false;

    pub unsafe fn init() {
        let mut action: sigaction = mem::zeroed();
        for &signal in &[SIGSEGV, SIGBUS] {
            sigaction(signal, ptr::null_mut(), &mut action);
            // Configure our signal handler if one is not already set.
            if action.sa_sigaction == SIG_DFL {
                action.sa_flags = SA_SIGINFO | SA_ONSTACK;
                action.sa_sigaction = signal_handler as sighandler_t;
                sigaction(signal, &action, ptr::null_mut());
                NEED_ALTSTACK = true;
            }
        }

        let handler = make_handler();
        MAIN_ALTSTACK = handler._data;
        mem::forget(handler);
    }

    pub unsafe fn cleanup() {
        Handler { _data: MAIN_ALTSTACK };
    }

    unsafe fn get_stackp() -> *mut libc::c_void {
        let stackp =
            mmap(ptr::null_mut(), SIGSTKSZ + page_size(), PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
        if stackp == MAP_FAILED {
            panic!("failed to allocate an alternative stack");
        }
        let guard_result = libc::mprotect(stackp, page_size(), PROT_NONE);
        if guard_result != 0 {
            panic!("failed to set up alternative stack guard page");
        }
        stackp.add(page_size())
    }

    #[cfg(any(
        target_os = "linux",
        target_os = "macos",
        target_os = "freebsd",
        target_os = "netbsd",
        target_os = "openbsd",
        target_os = "solaris"
    ))]
    unsafe fn get_stack() -> libc::stack_t {
        libc::stack_t { ss_sp: get_stackp(), ss_flags: 0, ss_size: SIGSTKSZ }
    }

    #[cfg(target_os = "dragonfly")]
    unsafe fn get_stack() -> libc::stack_t {
        libc::stack_t { ss_sp: get_stackp() as *mut i8, ss_flags: 0, ss_size: SIGSTKSZ }
    }

    pub unsafe fn make_handler() -> Handler {
        if !NEED_ALTSTACK {
            return Handler::null();
        }
        let mut stack = mem::zeroed();
        sigaltstack(ptr::null(), &mut stack);
        // Configure alternate signal stack, if one is not already set.
        if stack.ss_flags & SS_DISABLE != 0 {
            stack = get_stack();
            sigaltstack(&stack, ptr::null_mut());
            Handler { _data: stack.ss_sp as *mut libc::c_void }
        } else {
            Handler::null()
        }
    }

    pub unsafe fn drop_handler(handler: &mut Handler) {
        if !handler._data.is_null() {
            let stack = libc::stack_t {
                ss_sp: ptr::null_mut(),
                ss_flags: SS_DISABLE,
                // Workaround for bug in macOS implementation of sigaltstack
                // UNIX2003 which returns ENOMEM when disabling a stack while
                // passing ss_size smaller than MINSIGSTKSZ. According to POSIX
                // both ss_sp and ss_size should be ignored in this case.
                ss_size: SIGSTKSZ,
            };
            sigaltstack(&stack, ptr::null_mut());
            // We know from `get_stackp` that the alternate stack we installed is part of a mapping
            // that started one page earlier, so walk back a page and unmap from there.
            munmap(handler._data.sub(page_size()), SIGSTKSZ + page_size());
        }
    }
}

#[cfg(not(any(
    target_os = "linux",
    target_os = "macos",
    target_os = "dragonfly",
    target_os = "freebsd",
    target_os = "solaris",
    all(target_os = "netbsd", not(target_vendor = "rumprun")),
    target_os = "openbsd"
)))]
mod imp {
    pub unsafe fn init() {}

    pub unsafe fn cleanup() {}

    pub unsafe fn make_handler() -> super::Handler {
        super::Handler::null()
    }

    pub unsafe fn drop_handler(_handler: &mut super::Handler) {}
}
<|endoftext|>


<commit_before>extern crate decimal;

use decimal::*;
use std::fs::File;
use std::path::Path;
use std::io::BufRead;
use std::io::BufReader;

fn find_end_quote(s: &str, quote: char) -> Option<usize> {
    match s.find(quote) {
        None => None,
        Some(i) => {
            match s[i+1..].chars().next() {
                None => Some(i),
                Some(c) if c == quote => find_end_quote(&s[i+2..], quote).and_then(|j| { Some(i + 2 + j) }),
                Some(_) => Some(i),
            }
        }
    }
}

fn split_token<'a>(line: &'a str) -> (&'a str, &'a str) {
    let line = line.trim_left();
    if line.starts_with("--") {
        ("", "")
    } else if line.starts_with("\"") {
        let end = find_end_quote(&line[1..], '"').expect("Unmatched double quote") + 1;
        (&line[1..end], &line[end + 1..])
    } else if line.starts_with("'") {
        let end = find_end_quote(&line[1..], '\'').expect("Unmatched single quote") + 1;
        (&line[1..end], &line[end + 1..])
    } else {
        match line.find(char::is_whitespace) {
            None => (line, ""),
            Some(end) => (&line[0..end], &line[end + 1..]),
        }
    }
}

#[derive(Debug)]
struct Scanner<'a> {
    current: &'a str,
    remaining: &'a str,
}

impl<'a> Scanner<'a> {
    pub fn new(line: &'a str) -> Scanner<'a> {
        Scanner {
            current: "",
            remaining: line,
        }
    }

    pub fn current(&self) -> &'a str {
        self.current
    }

    pub fn remaining(&self) -> &'a str {
        self.remaining
    }

    pub fn next(&mut self) -> &'a str {
        let (current, remaining) = split_token(self.remaining);
        self.current = current;
        self.remaining = remaining;
        self.current
    }
}

#[derive(Debug)]
enum Directive<'a> {
    Precision(isize),
    Rounding(Rounding),
    MaxExponent(isize),
    MinExponent(isize),
    Version(&'a str),
    Extended(bool),
    Clamp(bool),
    Test(&'a str),
}

#[derive(Debug)]
enum Op<'a> {
    Abs(&'a str),
    Add(&'a str, &'a str),
    And(&'a str, &'a str),
    Apply(&'a str),
    Canonical(&'a str),
    Class(&'a str),
    Compare(&'a str, &'a str),
    CompareSig(&'a str, &'a str),
    CompareTotal(&'a str, &'a str),
    CompareTotalMag(&'a str, &'a str),
    Copy(&'a str),
    CopyAbs(&'a str),
    CopyNegate(&'a str),
    CopySign(&'a str),
    Divide(&'a str, &'a str),
    DivideInt(&'a str, &'a str),
    Exp(&'a str),
    Fma(&'a str, &'a str, &'a str),
    Invert(&'a str),
    Ln(&'a str),
    Log10(&'a str),
    LogB(&'a str),
    Max(&'a str, &'a str),
    MaxMag(&'a str, &'a str),
    Min(&'a str, &'a str),
    MinMag(&'a str, &'a str),
    Minus(&'a str),
    Multiply(&'a str, &'a str),
    NextMinus(&'a str),
    NextPlus(&'a str),
    NextToward(&'a str, &'a str),
    Or(&'a str, &'a str),
    Plus(&'a str, &'a str),
    Quantize(&'a str, &'a str),
    Reduce(&'a str),
    Remainder(&'a str, &'a str),
    Rescale(&'a str, &'a str),
    Rotate(&'a str, &'a str),
    SameQuantum(&'a str, &'a str),
    ScaleB(&'a str),
    Shift(&'a str, &'a str),
    SquareRoot(&'a str),
    Subtract(&'a str, &'a str),
    ToEng(&'a str),
    ToIntegral(&'a str),
    ToIntegralExact(&'a str),
    ToSci(&'a str),
    Trim(&'a str),
    Xor(&'a str, &'a str),
}

#[derive(Debug)]
struct Test<'a> {
    id: &'a str,
    op: Op<'a>,
    result: &'a str,
    conditions: Status,
}

#[derive(Debug)]
enum Instr<'a> {
    Directive(Directive<'a>),
    Test(Test<'a>),
}

fn parse_directive<'a>(s: &mut Scanner<'a>) -> Directive<'a> {
    let keyword = s.current().trim_right_matches(':').to_lowercase();
    match keyword.as_ref() {
        "precision" => {
            let val = s.next().parse::<isize>().expect("No value for precision");
            Directive::Precision(val)
        }
        "rounding" => {
            Directive::Rounding(match s.next() {
                "ceiling" => Rounding::Ceiling,
                "down" => Rounding::Down,
                "floor" => Rounding::Floor,
                "half_down" => Rounding::HalfDown,
                "half_even" => Rounding::HalfEven,
                "half_up" => Rounding::HalfUp,
                "up" => Rounding::Up,
                "05up" => Rounding::ZeroOrFiveUp,
                err => panic!("Unknown rounding mode {}", err),
            })
        }
        "maxexponent" => {
            let val = s.next()
                       .trim_left_matches('+')
                       .parse::<isize>()
                       .expect("No value for maxexponent");
            Directive::MaxExponent(val)
        }
        "minexponent" => {
            let val = s.next().parse::<isize>().expect("No value for minexponent");
            Directive::MinExponent(val)
        }
        "version" => {
            Directive::Version(s.next())
        }
        "extended" => {
            let val = s.next().parse::<isize>().expect("No value for extended");
            Directive::Extended(val != 0)
        }
        "clamp" => {
            let val = s.next().parse::<isize>().expect("No value for clamp");
            Directive::Clamp(val != 0)
        }
        "dectest" => {
            Directive::Test(s.next())
        }
        _ => panic!("Cannot parse directive {} {}", s.current(), s.remaining()),
    }
}

fn parse_test<'a>(s: &mut Scanner<'a>) -> Test<'a> {
    let id = s.current();
    let op = match s.next().to_lowercase().as_ref() {
        "abs" => Op::Abs(s.next()),
        "add" => Op::Add(s.next(), s.next()),
        "and" => Op::And(s.next(), s.next()),
        "apply" => Op::Apply(s.next()),
        "canonical" => Op::Canonical(s.next()),
        "class" => Op::Class(s.next()),
        "compare" => Op::Compare(s.next(), s.next()),
        "comparesig" => Op::CompareSig(s.next(), s.next()),
        "comparetotal" => Op::CompareTotal(s.next(), s.next()),
        "comparetotalmag" => Op::CompareTotalMag(s.next(), s.next()),
        "copy" => Op::Copy(s.next()),
        "copyabs" => Op::CopyAbs(s.next()),
        "copynegate" => Op::CopyNegate(s.next()),
        "copysign" => Op::CopySign(s.next()),
        "divide" => Op::Divide(s.next(), s.next()),
        "divideint" => Op::DivideInt(s.next(), s.next()),
        "exp" => Op::Exp(s.next()),
        "fma" => Op::Fma(s.next(), s.next(), s.next()),
        "invert" => Op::Invert(s.next()),
        "ln" => Op::Ln(s.next()),
        "log10" => Op::Log10(s.next()),
        "logb" => Op::LogB(s.next()),
        "max" => Op::Max(s.next(), s.next()),
        "maxmag" => Op::MaxMag(s.next(), s.next()),
        "min" => Op::Min(s.next(), s.next()),
        "minmag" => Op::MinMag(s.next(), s.next()),
        "minus" => Op::Minus(s.next()),
        "multiply" => Op::Multiply(s.next(), s.next()),
        "nextminus" => Op::NextMinus(s.next()),
        "nextplus" => Op::NextPlus(s.next()),
        "nexttoward" => Op::NextToward(s.next(), s.next()),
        "or" => Op::Or(s.next(), s.next()),
        "plus" => Op::Plus(s.next(), s.next()),
        "quantize" => Op::Quantize(s.next(), s.next()),
        "reduce" => Op::Reduce(s.next()),
        "remainder" => Op::Remainder(s.next(), s.next()),
        "rescale" => Op::Rescale(s.next(), s.next()),
        "rotate" => Op::Rotate(s.next(), s.next()),
        "samequantum" => Op::SameQuantum(s.next(), s.next()),
        "scaleb" => Op::ScaleB(s.next()),
        "shift" => Op::Shift(s.next(), s.next()),
        "squareroot" => Op::SquareRoot(s.next()),
        "subtract" => Op::Subtract(s.next(), s.next()),
        "toeng" => Op::ToEng(s.next()),
        "tointegral" => Op::ToIntegral(s.next()),
        "tointegralexact" => Op::ToIntegralExact(s.next()),
        "tosci" => Op::ToSci(s.next()),
        "trim" => Op::Trim(s.next()),
        "xor" => Op::Xor(s.next(), s.next()),
        err => panic!("Unknown op {}", err),
    };
    if s.next() != "->" {
        panic!("Missing -> [{} {}]", s.current(), s.remaining());
    }
    let result = s.next();
    let mut status = Status::empty();
    loop {
        let cond = s.next().to_lowercase();
        if cond.is_empty() {
            break;
        }
        status = status |
                 match cond.as_ref() {
            "conversion_syntax" => CONVERSION_SYNTAX,
            "division_by_zero" => DIVISION_BY_ZERO,
            "division_impossible" => DIVISION_IMPOSSIBLE,
            "division_undefined" => DIVISION_UNDEFINED,
            "insufficient_storage" => INSUFFICIENT_STORAGE,
            "inexact" => INEXACT,
            "invalid_context" => INVALID_CONTEXT,
            "invalid_operation" => INVALID_OPERATION,
            "lost_digits" => LOST_DIGITS,
            "overflow" => OVERFLOW,
            "clamped" => CLAMPED,
            "rounded" => ROUNDED,
            "subnormal" => SUBNORMAL,
            "underflow" => UNDERFLOW,
            _ => panic!("Cannot parse condition {}", s.current()),
        }
    }
    Test {
        id: id,
        op: op,
        result: result,
        conditions: status,
    }
}

fn parse_line<'a>(line: &'a str) -> Option<Instr<'a>> {
    let mut scanner = Scanner::new(line);
    match scanner.next() {
        "" => None,
        token if token.starts_with("--") => None,
        token if token.ends_with(":") => Some(Instr::Directive(parse_directive(&mut scanner))),
        _ => Some(Instr::Test(parse_test(&mut scanner))),
    }
}

fn run_test(path: &Path) {
    let file = File::open(path);
    println!("{:?}", file);
    for line in BufReader::new(File::open(path).unwrap()).lines() {
        let line = line.unwrap();
        println!("{}", line);
        println!("\t{:?}", parse_line(&line));
    }
}

fn main() {
    let filepath = std::env::args().nth(1).expect("Filename to test");
    let path = Path::new(&filepath);
    run_test(path);
}
<commit_msg>Fix bugs in op definitions. Add missing ops.<commit_after>extern crate decimal;

use decimal::*;
use std::fs::File;
use std::path::Path;
use std::io::BufRead;
use std::io::BufReader;

fn find_end_quote(s: &str, quote: char) -> Option<usize> {
    match s.find(quote) {
        None => None,
        Some(i) => {
            match s[i+1..].chars().next() {
                None => Some(i),
                Some(c) if c == quote => find_end_quote(&s[i+2..], quote).and_then(|j| { Some(i + 2 + j) }),
                Some(_) => Some(i),
            }
        }
    }
}

fn split_token<'a>(line: &'a str) -> (&'a str, &'a str) {
    let line = line.trim_left();
    if line.starts_with("--") {
        ("", "")
    } else if line.starts_with("\"") {
        let end = find_end_quote(&line[1..], '"').expect("Unmatched double quote") + 1;
        (&line[1..end], &line[end + 1..])
    } else if line.starts_with("'") {
        let end = find_end_quote(&line[1..], '\'').expect("Unmatched single quote") + 1;
        (&line[1..end], &line[end + 1..])
    } else {
        match line.find(char::is_whitespace) {
            None => (line, ""),
            Some(end) => (&line[0..end], &line[end + 1..]),
        }
    }
}

#[derive(Debug)]
struct Scanner<'a> {
    current: &'a str,
    remaining: &'a str,
}

impl<'a> Scanner<'a> {
    pub fn new(line: &'a str) -> Scanner<'a> {
        Scanner {
            current: "",
            remaining: line,
        }
    }

    pub fn current(&self) -> &'a str {
        self.current
    }

    pub fn remaining(&self) -> &'a str {
        self.remaining
    }

    pub fn next(&mut self) -> &'a str {
        let (current, remaining) = split_token(self.remaining);
        self.current = current;
        self.remaining = remaining;
        self.current
    }
}

#[derive(Debug)]
enum Directive<'a> {
    Precision(isize),
    Rounding(Rounding),
    MaxExponent(isize),
    MinExponent(isize),
    Version(&'a str),
    Extended(bool),
    Clamp(bool),
    Test(&'a str),
}

#[derive(Debug)]
enum Op<'a> {
    Abs(&'a str),
    Add(&'a str, &'a str),
    And(&'a str, &'a str),
    Apply(&'a str),
    Canonical(&'a str),
    Class(&'a str),
    Compare(&'a str, &'a str),
    CompareSig(&'a str, &'a str),
    CompareTotal(&'a str, &'a str),
    CompareTotalMag(&'a str, &'a str),
    Copy(&'a str),
    CopyAbs(&'a str),
    CopyNegate(&'a str),
    CopySign(&'a str, &'a str),
    Divide(&'a str, &'a str),
    DivideInt(&'a str, &'a str),
    Exp(&'a str),
    Fma(&'a str, &'a str, &'a str),
    Invert(&'a str),
    Ln(&'a str),
    Log10(&'a str),
    LogB(&'a str),
    Max(&'a str, &'a str),
    MaxMag(&'a str, &'a str),
    Min(&'a str, &'a str),
    MinMag(&'a str, &'a str),
    Minus(&'a str),
    Multiply(&'a str, &'a str),
    NextMinus(&'a str),
    NextPlus(&'a str),
    NextToward(&'a str, &'a str),
    Or(&'a str, &'a str),
    Plus(&'a str),
    Power(&'a str, &'a str),
    Quantize(&'a str, &'a str),
    Reduce(&'a str),
    Remainder(&'a str, &'a str),
    RemainderNear(&'a str, &'a str),
    Rescale(&'a str, &'a str),
    Rotate(&'a str, &'a str),
    SameQuantum(&'a str, &'a str),
    ScaleB(&'a str, &'a str),
    Shift(&'a str, &'a str),
    SquareRoot(&'a str),
    Subtract(&'a str, &'a str),
    ToEng(&'a str),
    ToIntegral(&'a str),
    ToIntegralExact(&'a str),
    ToSci(&'a str),
    Trim(&'a str),
    Xor(&'a str, &'a str),
}

#[derive(Debug)]
struct Test<'a> {
    id: &'a str,
    op: Op<'a>,
    result: &'a str,
    conditions: Status,
}

#[derive(Debug)]
enum Instr<'a> {
    Directive(Directive<'a>),
    Test(Test<'a>),
}

fn parse_directive<'a>(s: &mut Scanner<'a>) -> Directive<'a> {
    let keyword = s.current().trim_right_matches(':').to_lowercase();
    match keyword.as_ref() {
        "precision" => {
            let val = s.next().parse::<isize>().expect("No value for precision");
            Directive::Precision(val)
        }
        "rounding" => {
            Directive::Rounding(match s.next() {
                "ceiling" => Rounding::Ceiling,
                "down" => Rounding::Down,
                "floor" => Rounding::Floor,
                "half_down" => Rounding::HalfDown,
                "half_even" => Rounding::HalfEven,
                "half_up" => Rounding::HalfUp,
                "up" => Rounding::Up,
                "05up" => Rounding::ZeroOrFiveUp,
                err => panic!("Unknown rounding mode {}", err),
            })
        }
        "maxexponent" => {
            let val = s.next()
                       .trim_left_matches('+')
                       .parse::<isize>()
                       .expect("No value for maxexponent");
            Directive::MaxExponent(val)
        }
        "minexponent" => {
            let val = s.next().parse::<isize>().expect("No value for minexponent");
            Directive::MinExponent(val)
        }
        "version" => {
            Directive::Version(s.next())
        }
        "extended" => {
            let val = s.next().parse::<isize>().expect("No value for extended");
            Directive::Extended(val != 0)
        }
        "clamp" => {
            let val = s.next().parse::<isize>().expect("No value for clamp");
            Directive::Clamp(val != 0)
        }
        "dectest" => {
            Directive::Test(s.next())
        }
        _ => panic!("Cannot parse directive {} {}", s.current(), s.remaining()),
    }
}

fn parse_test<'a>(s: &mut Scanner<'a>) -> Test<'a> {
    let id = s.current();
    let op = match s.next().to_lowercase().as_ref() {
        "abs" => Op::Abs(s.next()),
        "add" => Op::Add(s.next(), s.next()),
        "and" => Op::And(s.next(), s.next()),
        "apply" => Op::Apply(s.next()),
        "canonical" => Op::Canonical(s.next()),
        "class" => Op::Class(s.next()),
        "compare" => Op::Compare(s.next(), s.next()),
        "comparesig" => Op::CompareSig(s.next(), s.next()),
        "comparetotal" => Op::CompareTotal(s.next(), s.next()),
        "comparetotmag" => Op::CompareTotalMag(s.next(), s.next()),
        "copy" => Op::Copy(s.next()),
        "copyabs" => Op::CopyAbs(s.next()),
        "copynegate" => Op::CopyNegate(s.next()),
        "copysign" => Op::CopySign(s.next(), s.next()),
        "divide" => Op::Divide(s.next(), s.next()),
        "divideint" => Op::DivideInt(s.next(), s.next()),
        "exp" => Op::Exp(s.next()),
        "fma" => Op::Fma(s.next(), s.next(), s.next()),
        "invert" => Op::Invert(s.next()),
        "ln" => Op::Ln(s.next()),
        "log10" => Op::Log10(s.next()),
        "logb" => Op::LogB(s.next()),
        "max" => Op::Max(s.next(), s.next()),
        "maxmag" => Op::MaxMag(s.next(), s.next()),
        "min" => Op::Min(s.next(), s.next()),
        "minmag" => Op::MinMag(s.next(), s.next()),
        "minus" => Op::Minus(s.next()),
        "multiply" => Op::Multiply(s.next(), s.next()),
        "nextminus" => Op::NextMinus(s.next()),
        "nextplus" => Op::NextPlus(s.next()),
        "nexttoward" => Op::NextToward(s.next(), s.next()),
        "or" => Op::Or(s.next(), s.next()),
        "plus" => Op::Plus(s.next()),
        "power" => Op::Power(s.next(), s.next()),
        "quantize" => Op::Quantize(s.next(), s.next()),
        "reduce" => Op::Reduce(s.next()),
        "remainder" => Op::Remainder(s.next(), s.next()),
        "remaindernear" => Op::RemainderNear(s.next(), s.next()),
        "rescale" => Op::Rescale(s.next(), s.next()),
        "rotate" => Op::Rotate(s.next(), s.next()),
        "samequantum" => Op::SameQuantum(s.next(), s.next()),
        "scaleb" => Op::ScaleB(s.next(), s.next()),
        "shift" => Op::Shift(s.next(), s.next()),
        "squareroot" => Op::SquareRoot(s.next()),
        "subtract" => Op::Subtract(s.next(), s.next()),
        "toeng" => Op::ToEng(s.next()),
        "tointegral" => Op::ToIntegral(s.next()),
        "tointegralx" => Op::ToIntegralExact(s.next()),
        "tosci" => Op::ToSci(s.next()),
        "trim" => Op::Trim(s.next()),
        "xor" => Op::Xor(s.next(), s.next()),
        err => panic!("Unknown op {}", err),
    };
    if s.next() != "->" {
        panic!("Missing -> [{} {}]", s.current(), s.remaining());
    }
    let result = s.next();
    let mut status = Status::empty();
    loop {
        let cond = s.next().to_lowercase();
        if cond.is_empty() {
            break;
        }
        status = status |
                 match cond.as_ref() {
            "conversion_syntax" => CONVERSION_SYNTAX,
            "division_by_zero" => DIVISION_BY_ZERO,
            "division_impossible" => DIVISION_IMPOSSIBLE,
            "division_undefined" => DIVISION_UNDEFINED,
            "insufficient_storage" => INSUFFICIENT_STORAGE,
            "inexact" => INEXACT,
            "invalid_context" => INVALID_CONTEXT,
            "invalid_operation" => INVALID_OPERATION,
            "lost_digits" => LOST_DIGITS,
            "overflow" => OVERFLOW,
            "clamped" => CLAMPED,
            "rounded" => ROUNDED,
            "subnormal" => SUBNORMAL,
            "underflow" => UNDERFLOW,
            _ => panic!("Cannot parse condition {}", s.current()),
        }
    }
    Test {
        id: id,
        op: op,
        result: result,
        conditions: status,
    }
}

fn parse_line<'a>(line: &'a str) -> Option<Instr<'a>> {
    let mut scanner = Scanner::new(line);
    match scanner.next() {
        "" => None,
        token if token.starts_with("--") => None,
        token if token.ends_with(":") => Some(Instr::Directive(parse_directive(&mut scanner))),
        _ => Some(Instr::Test(parse_test(&mut scanner))),
    }
}

fn run_test(path: &Path) {
    let file = File::open(path);
    println!("{:?}", file);
    for line in BufReader::new(File::open(path).unwrap()).lines() {
        let line = line.unwrap();
        println!("{}", line);
        println!("\t{:?}", parse_line(&line));
    }
}

fn main() {
    let filepath = std::env::args().nth(1).expect("Filename to test");
    let path = Path::new(&filepath);
    run_test(path);
}
<|endoftext|>


<commit_before>extern crate arguments;
extern crate configuration;
extern crate random;
extern crate sql;
extern crate sqlite;
extern crate term;
extern crate time;

#[macro_use]
extern crate log;

#[macro_use]
extern crate streamer;

use configuration::format::TOML;
use log::LogLevel;
use streamer::{platform, schedule, system, traffic, workload};

pub use streamer::{Config, Error, Result};

pub type Data = (platform::Profile, platform::Profile);
pub type Event = system::Event;
pub type System = system::System<traffic::Fractal,
                                 workload::Random,
                                 platform::Thermal,
                                 schedule::Impartial>;

const USAGE: &'static str = "
Usage: streamer [options]

Options:
    --config <path>          Configuration file (required).
    --length <time>          Time span to synthesize in seconds [default: 10].
    --output <path>          Output file for power and temperature profiles.

    --verbose                Display progress information.
    --help                   Display this message.
";

mod logger;
mod output;

use output::Output;

fn main() {
    start().unwrap_or_else(|error| fail(error));
}

fn start() -> Result<()> {
    let arguments = ok!(arguments::parse(std::env::args()));
    if arguments.get::<bool>("help").unwrap_or(false) {
        help();
    }
    if arguments.get::<bool>("verbose").unwrap_or(false) {
        logger::setup(LogLevel::Info);
    } else {
        logger::setup(LogLevel::Warn);
    }

    let config = ok!(TOML::open(some!(arguments.get::<String>("config"),
                                      "a configuration file is required")));

    let mut system = try!(construct_system(&config));
    let mut output = try!(output::new(&system, arguments.get::<String>("output")));

    let length = arguments.get::<f64>("length").unwrap_or(10.0);
    info!(target: "Streamer", "Synthesizing {} seconds...", length);
    let start = time::now();

    while let Some((event, data)) = system.next() {
        display(&system, &event);
        try!(output.next(&event, &data));
        if event.time > length {
            break;
        }
    }

    let elapsed = time::now() - start;
    info!(target: "Streamer", "Well done in {:.2} seconds.",
          elapsed.num_milliseconds() as f64 / 1000.0);

    Ok(())
}

fn construct_system(config: &Config) -> Result<System> {
    use streamer::platform::Platform;

    let source = {
        let seed = config.get::<i64>("seed").map(|&seed| seed as u64).unwrap_or(0);
        let seed = if seed > 0 { seed } else { time::now().to_timespec().sec as u64 };
        let seed = [0x12345678 & seed, 0x87654321 & seed];
        random::default().seed(seed)
    };

    macro_rules! branch(($name:expr) => (config.branch($name).as_ref().unwrap_or(config)));

    let traffic = try!(traffic::Fractal::new(branch!("traffic"), &source));
    let workload = try!(workload::Random::new(branch!("workload"), &source));
    let platform = try!(platform::Thermal::new(branch!("platform")));
    let schedule = try!(schedule::Impartial::new(branch!("schedule"), platform.elements()));

    System::new(traffic, workload, platform, schedule)
}

fn display(system: &System, event: &Event) {
    use streamer::system::EventKind;

    let (job, kind) = match &event.kind {
        &EventKind::Arrived(ref job) => (job, "arrived"),
        &EventKind::Started(ref job) => (job, "started"),
        &EventKind::Finished(ref job) => (job, "finished"),
    };
    let pattern = &job.pattern;
    info!(target: "Streamer",
          "{:7.2} s | job #{:3} ( {:20} | {:2} units | {:6.2} s ) {:8} | {:2} queued",
          event.time, job.id, pattern.name, pattern.units,
          (pattern.steps as f64) * pattern.time_step, kind,
          system.history().arrived - system.history().started);
}

fn help() -> ! {
    println!("{}", USAGE.trim());
    std::process::exit(0);
}

#[allow(unused_must_use)]
fn fail(error: Error) -> ! {
    use std::io::{stderr, Write};
    if let Some(mut output) = term::stderr() {
        output.fg(term::color::RED);
        output.write_all(format!("Error: {}.\n", error).as_bytes());
    }
    std::process::exit(1);
}
<commit_msg>bin: make use of Pattern::duration<commit_after>extern crate arguments;
extern crate configuration;
extern crate random;
extern crate sql;
extern crate sqlite;
extern crate term;
extern crate time;

#[macro_use]
extern crate log;

#[macro_use]
extern crate streamer;

use configuration::format::TOML;
use log::LogLevel;
use streamer::{platform, schedule, system, traffic, workload};

pub use streamer::{Config, Error, Result};

pub type Data = (platform::Profile, platform::Profile);
pub type Event = system::Event;
pub type System = system::System<traffic::Fractal,
                                 workload::Random,
                                 platform::Thermal,
                                 schedule::Impartial>;

const USAGE: &'static str = "
Usage: streamer [options]

Options:
    --config <path>          Configuration file (required).
    --length <time>          Time span to synthesize in seconds [default: 10].
    --output <path>          Output file for power and temperature profiles.

    --verbose                Display progress information.
    --help                   Display this message.
";

mod logger;
mod output;

use output::Output;

fn main() {
    start().unwrap_or_else(|error| fail(error));
}

fn start() -> Result<()> {
    let arguments = ok!(arguments::parse(std::env::args()));
    if arguments.get::<bool>("help").unwrap_or(false) {
        help();
    }
    if arguments.get::<bool>("verbose").unwrap_or(false) {
        logger::setup(LogLevel::Info);
    } else {
        logger::setup(LogLevel::Warn);
    }

    let config = ok!(TOML::open(some!(arguments.get::<String>("config"),
                                      "a configuration file is required")));

    let mut system = try!(construct_system(&config));
    let mut output = try!(output::new(&system, arguments.get::<String>("output")));

    let length = arguments.get::<f64>("length").unwrap_or(10.0);
    info!(target: "Streamer", "Synthesizing {} seconds...", length);
    let start = time::now();

    while let Some((event, data)) = system.next() {
        display(&system, &event);
        try!(output.next(&event, &data));
        if event.time > length {
            break;
        }
    }

    let elapsed = time::now() - start;
    info!(target: "Streamer", "Well done in {:.2} seconds.",
          elapsed.num_milliseconds() as f64 / 1000.0);

    Ok(())
}

fn construct_system(config: &Config) -> Result<System> {
    use streamer::platform::Platform;

    let source = {
        let seed = config.get::<i64>("seed").map(|&seed| seed as u64).unwrap_or(0);
        let seed = if seed > 0 { seed } else { time::now().to_timespec().sec as u64 };
        let seed = [0x12345678 & seed, 0x87654321 & seed];
        random::default().seed(seed)
    };

    macro_rules! branch(($name:expr) => (config.branch($name).as_ref().unwrap_or(config)));

    let traffic = try!(traffic::Fractal::new(branch!("traffic"), &source));
    let workload = try!(workload::Random::new(branch!("workload"), &source));
    let platform = try!(platform::Thermal::new(branch!("platform")));
    let schedule = try!(schedule::Impartial::new(branch!("schedule"), platform.elements()));

    System::new(traffic, workload, platform, schedule)
}

fn display(system: &System, event: &Event) {
    use streamer::system::EventKind;

    let (job, kind) = match &event.kind {
        &EventKind::Arrived(ref job) => (job, "arrived"),
        &EventKind::Started(ref job) => (job, "started"),
        &EventKind::Finished(ref job) => (job, "finished"),
    };
    let pattern = &job.pattern;
    info!(target: "Streamer",
          "{:7.2} s | job #{:3} ( {:20} | {:2} units | {:6.2} s ) {:8} | {:2} queued",
          event.time, job.id, pattern.name, pattern.units, pattern.duration(), kind,
          system.history().arrived - system.history().started);
}

fn help() -> ! {
    println!("{}", USAGE.trim());
    std::process::exit(0);
}

#[allow(unused_must_use)]
fn fail(error: Error) -> ! {
    use std::io::{stderr, Write};
    if let Some(mut output) = term::stderr() {
        output.fg(term::color::RED);
        output.write_all(format!("Error: {}.\n", error).as_bytes());
    }
    std::process::exit(1);
}
<|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/.
 */

use grid::Grid;
use self::error::SourceError;
use std::io::Read;

pub mod error;

impl<T: ?Sized + Read> Source for T {}

/// The `Source` trait allows to use any implementor of the `Read` trait
/// as an input source for the grid string format with no additional effort.
pub trait Source: Read {
    /// Creates a `Grid` from a readable source.
    ///
    /// Reads from the source until EOF, parses the data as a string,
    /// checking that the size is correct, then decodes it and returns `Grid`.
    ///
    /// # Errors
    ///
    /// Returns an error if either the read failed,
    /// a character other than `0`, `1`, `.` or `\n` was found,
    /// or the array isn't properly sized.
    ///
    /// # Examples
    ///
    /// ```rust
    /// # use std::error::Error;
    /// # use std::io;
    /// # use std::io::Write;
    /// # use takuzu::Source;
    /// let grid = match io::stdin().source() {
    ///     Ok(grid) => grid,
    ///     Err(err) => {
    ///         write!(io::stderr(), "error: {}\n", err.description()).unwrap();
    ///         return
    ///     },
    /// };
    /// ```
    fn source(&mut self) -> Result<Grid, SourceError> {
        let mut buffer = String::new();
        self.read_to_string(&mut buffer)?;
        buffer.parse().map_err(Into::into)
    }
}
<commit_msg>`Source` doesn't need the `Read` trait bound<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/.
 */

use grid::Grid;
use self::error::SourceError;
use std::io::Read;

pub mod error;

/// The `Source` trait allows to use any implementor as an input source.
///
/// # `Read` source
///
/// The `Source` trait allows to use any implementor of the `Read` trait
/// with no additional effort.
/// It reads from the source until EOF, parses the data as a string,
/// checking that the size is correct, then decodes it and returns `Grid`.
///
/// ## Errors
///
/// Returns an error if either the read failed,
/// a character other than `0`, `1`, `.` or `\n` was found,
/// or the array isn't properly sized.
///
/// ## Examples
///
/// ```rust
/// # use std::error::Error;
/// # use std::io;
/// # use std::io::Write;
/// # use takuzu::Source;
/// let grid = match io::stdin().source() {
///     Ok(grid) => grid,
///     Err(err) => {
///         writeln!(io::stderr(), "error: {}", err).unwrap();
///         return
///     },
/// };
/// ```
pub trait Source {
    /// Creates a `Grid` from a source.
    fn source(&mut self) -> Result<Grid, SourceError>;
}

impl<T: ?Sized> Source for T
    where T: Read {
    fn source(&mut self) -> Result<Grid, SourceError> {
        let mut buffer = String::new();
        self.read_to_string(&mut buffer)?;
        buffer.parse().map_err(Into::into)
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2017 Jason White
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

//! Provides the ability to retry an operation until it succeeds.
//!
//! # Examples
//!
//! ```
//! use std::time::Duration;
//! use std::io;
//! use std::io::Write;
//! use std::error::Error;
//!
//! use button::retry::Retry;
//!
//! fn find_answer(answer: &str) -> io::Result<()> {
//!     print!("Please enter the correct answer: ");
//!     io::stdout().flush()?;
//!
//!     let mut buf = String::new();
//!     io::stdin().read_line(&mut buf)?;
//!
//!     return if buf.trim() == answer {
//!         Ok(())
//!     } else {
//!         Err(io::Error::new(io::ErrorKind::Other, "Sorry, that is not the answer."))
//!     }
//! }
//!
//! fn retry_progress(retry: &Retry,
//!                   err: &io::Error,
//!                   remaining: u32,
//!                   delay: Duration) -> bool {
//!     println!("Error: {} ({} attempt(s) remaining. Retrying in ~{} seconds...)",
//!         err.description(),
//!         remaining,
//!         delay.as_secs()
//!     );
//!     true
//! }
//!
//! let result = Retry::new()
//!     .with_retries(4)
//!     .with_delay(Duration::from_secs(1))
//!     .with_max_delay(Duration::from_secs(4))
//!     .call(|| find_answer("42"), retry_progress);
//!
//! match result {
//!     Ok(()) => println!("Correct!"),
//!     Err(err) => println!("{}", err),
//! };
//! ```

// TODO: Allow specifying a non-integer exponential backoff factor.
// TODO: Allow jittering to further help avoid the "thundering herd" problem by
// keeping retries from stacking up. Jittering is just adjusting the delay by a
// random offset within an interval. If the interval length is 0, there is
// effectively no jittering.

use std::thread::sleep;
use std::time::Duration;
use std::cmp::min;
use std::error::Error;

#[derive(Serialize, Deserialize, Ord, PartialOrd, Eq, PartialEq, Hash, Copy, Clone)]
pub struct Retry {
    /// The number of times to *retry* a function. Note that the function is
    /// always called at least once.
    pub retries: u32,

    /// The initial duration to wait. For each retry, this is multiplied by the
    /// exponential backoff factor. Set to a duration of 0 for no delay.
    pub delay: Duration,

    /// The backoff factor. A value of 1 means linear backoff. A value of 2
    /// means exponential backoff. A value of 0 means no delay at all.
    pub backoff: u32,

    /// The maximum possible delay. If `None`, there is no maximum delay.
    pub max_delay: Option<Duration>,
}

impl Default for Retry {
    fn default() -> Retry {
        Retry {
            retries: 0,
            delay: Duration::from_secs(1),
            backoff: 2,
            max_delay: None,
        }
    }
}

impl Retry {
    /// Initializes a default `Retry`.
    #[allow(unused)]
    pub fn new() -> Retry {
        Retry::default()
    }

    /// Sets the number of retries.
    #[allow(unused)]
    pub fn with_retries(mut self, retries: u32) -> Retry {
        self.retries = retries;
        self
    }

    /// Sets the initial delay.
    #[allow(unused)]
    pub fn with_delay(mut self, delay: Duration) -> Retry {
        self.delay = delay;
        self
    }

    /// Sets the backoff.
    #[allow(unused)]
    pub fn with_backoff(mut self, backoff: u32) -> Retry {
        self.backoff = backoff;
        self
    }

    /// Sets the maximum possible delay.
    #[allow(unused)]
    pub fn with_max_delay(mut self, max_delay: Duration) -> Retry {
        self.max_delay = Some(max_delay);
        self
    }

    /// Calls the function until it returns a `Ok` result. If an `Ok` result is
    /// never produced, returns the `Result` from the last call to the function
    /// that failed.
    pub fn call<F, T, E, P>(&self, mut f: F, mut progress: P) -> Result<T, E>
        where F: FnMut() -> Result<T, E>,
              P: FnMut(&Retry, &E, u32, Duration) -> bool
    {
        let mut attempt = self.retries + 1;
        let mut delay = self.delay;

        loop {
            match f() {
                Ok(value) => return Ok(value),
                Err(err) => {
                    attempt -= 1;

                    if attempt > 0 {
                        if !progress(&self, &err, attempt, delay) {
                            return Err(err);
                        }

                        sleep(delay);

                        // Increase the delay.
                        delay = match self.max_delay {
                            Some(max_delay) => {
                                min(delay * self.backoff, max_delay)
                            }
                            None => delay * self.backoff,
                        };
                    } else {
                        // No more remaining attempts.
                        return Err(err);
                    }
                }
            }
        }
    }
}

/// Dummy progress callback function. If you don't want to report progress on
/// for each retry, use this function.
#[allow(unused_variables)]
pub fn progress_dummy<E>(retry: &Retry,
                         err: &E,
                         remaining: u32,
                         delay: Duration)
                         -> bool {
    // Keep going.
    true
}

/// Progress callback function for simply printing the progress of each retry.
#[allow(unused)]
pub fn progress_print<E>(retry: &Retry,
                         err: &E,
                         remaining: u32,
                         delay: Duration)
                         -> bool
    where E: Error
{
    println!("Error: {} ({}/{} attempt(s) remaining. Retrying in ~{} seconds...)",
             err.description(),
             remaining,
             retry.retries,
             delay.as_secs());
    true
}
<commit_msg>Don't run retry doc test<commit_after>// Copyright (c) 2017 Jason White
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

//! Provides the ability to retry an operation until it succeeds.
//!
//! # Examples
//!
//! ```no_run
//! use std::time::Duration;
//! use std::io;
//! use std::io::Write;
//! use std::error::Error;
//!
//! use button::retry::Retry;
//!
//! fn find_answer(answer: &str) -> io::Result<()> {
//!     print!("Please enter the correct answer: ");
//!     io::stdout().flush()?;
//!
//!     let mut buf = String::new();
//!     io::stdin().read_line(&mut buf)?;
//!
//!     return if buf.trim() == answer {
//!         Ok(())
//!     } else {
//!         Err(io::Error::new(io::ErrorKind::Other, "Sorry, that is not the answer."))
//!     }
//! }
//!
//! fn retry_progress(retry: &Retry,
//!                   err: &io::Error,
//!                   remaining: u32,
//!                   delay: Duration) -> bool {
//!     println!("Error: {} ({} attempt(s) remaining. Retrying in ~{} seconds...)",
//!         err.description(),
//!         remaining,
//!         delay.as_secs()
//!     );
//!     true
//! }
//!
//! fn main() {
//!     let result = Retry::new()
//!         .with_retries(4)
//!         .with_delay(Duration::from_secs(1))
//!         .with_max_delay(Duration::from_secs(4))
//!         .call(|| find_answer("42"), retry_progress);
//!
//!     match result {
//!         Ok(()) => println!("Correct!"),
//!         Err(err) => println!("{}", err),
//!     };
//! }
//! ```

// TODO: Allow specifying a non-integer exponential backoff factor.
// TODO: Allow jittering to further help avoid the "thundering herd" problem by
// keeping retries from stacking up. Jittering is just adjusting the delay by a
// random offset within an interval. If the interval length is 0, there is
// effectively no jittering.

use std::thread::sleep;
use std::time::Duration;
use std::cmp::min;
use std::error::Error;

#[derive(Serialize, Deserialize, Ord, PartialOrd, Eq, PartialEq, Hash, Copy, Clone)]
pub struct Retry {
    /// The number of times to *retry* a function. Note that the function is
    /// always called at least once.
    pub retries: u32,

    /// The initial duration to wait. For each retry, this is multiplied by the
    /// exponential backoff factor. Set to a duration of 0 for no delay.
    pub delay: Duration,

    /// The backoff factor. A value of 1 means linear backoff. A value of 2
    /// means exponential backoff. A value of 0 means no delay at all.
    pub backoff: u32,

    /// The maximum possible delay. If `None`, there is no maximum delay.
    pub max_delay: Option<Duration>,
}

impl Default for Retry {
    fn default() -> Retry {
        Retry {
            retries: 0,
            delay: Duration::from_secs(1),
            backoff: 2,
            max_delay: None,
        }
    }
}

impl Retry {
    /// Initializes a default `Retry`.
    #[allow(unused)]
    pub fn new() -> Retry {
        Retry::default()
    }

    /// Sets the number of retries.
    #[allow(unused)]
    pub fn with_retries(mut self, retries: u32) -> Retry {
        self.retries = retries;
        self
    }

    /// Sets the initial delay.
    #[allow(unused)]
    pub fn with_delay(mut self, delay: Duration) -> Retry {
        self.delay = delay;
        self
    }

    /// Sets the backoff.
    #[allow(unused)]
    pub fn with_backoff(mut self, backoff: u32) -> Retry {
        self.backoff = backoff;
        self
    }

    /// Sets the maximum possible delay.
    #[allow(unused)]
    pub fn with_max_delay(mut self, max_delay: Duration) -> Retry {
        self.max_delay = Some(max_delay);
        self
    }

    /// Calls the function until it returns a `Ok` result. If an `Ok` result is
    /// never produced, returns the `Result` from the last call to the function
    /// that failed.
    pub fn call<F, T, E, P>(&self, mut f: F, mut progress: P) -> Result<T, E>
        where F: FnMut() -> Result<T, E>,
              P: FnMut(&Retry, &E, u32, Duration) -> bool
    {
        let mut attempt = self.retries + 1;
        let mut delay = self.delay;

        loop {
            match f() {
                Ok(value) => return Ok(value),
                Err(err) => {
                    attempt -= 1;

                    if attempt > 0 {
                        if !progress(&self, &err, attempt, delay) {
                            return Err(err);
                        }

                        sleep(delay);

                        // Increase the delay.
                        delay = match self.max_delay {
                            Some(max_delay) => {
                                min(delay * self.backoff, max_delay)
                            }
                            None => delay * self.backoff,
                        };
                    } else {
                        // No more remaining attempts.
                        return Err(err);
                    }
                }
            }
        }
    }
}

/// Dummy progress callback function. If you don't want to report progress on
/// for each retry, use this function.
#[allow(unused_variables)]
pub fn progress_dummy<E>(retry: &Retry,
                         err: &E,
                         remaining: u32,
                         delay: Duration)
                         -> bool {
    // Keep going.
    true
}

/// Progress callback function for simply printing the progress of each retry.
#[allow(unused)]
pub fn progress_print<E>(retry: &Retry,
                         err: &E,
                         remaining: u32,
                         delay: Duration)
                         -> bool
    where E: Error
{
    println!("Error: {} ({}/{} attempt(s) remaining. Retrying in ~{} seconds...)",
             err.description(),
             remaining,
             retry.retries,
             delay.as_secs());
    true
}
<|endoftext|>


<commit_before>// "Tifflin" Kernel
// - By John Hodge (thePowersGang)
//
// Core/lib/vec_map.rs
//! Sorted vector backed Key-Value map.
use _common::*;
use lib::borrow::Borrow;

/// Primitive key-value map backed by a sorted vector
pub struct VecMap<K: Ord,V>
{
	ents: Vec<(K,V)>,
}
/// Immutable iterator for VecMap
pub struct Iter<'a, K: 'a, V: 'a>
{
	pos: usize,
	ents: &'a [(K,V)],
}

/// An entry in a VecMap
pub enum Entry<'a, K: 'a + Ord, V: 'a>
{
	Occupied(OccupiedEntry<'a, K, V>),
	Vacant(VacantEntry<'a, K, V>),
}
/// An occupied entry in a VecMap
pub struct OccupiedEntry<'a, K: 'a + Ord, V: 'a>
{
	map: &'a mut VecMap<K,V>,
	slot: usize,
}
/// An unoccupied entyr in a VecMap
pub struct VacantEntry<'a, K: 'a + Ord, V: 'a>
{
	map: &'a mut VecMap<K,V>,
	slot: usize,
	key: K,
}

impl<K: Ord, V> VecMap<K,V>
{
	/// Create a new (empty) VecMap
	pub fn new() -> VecMap<K,V> {
		VecMap {
			ents: Vec::new(),
		}
	}

	/// Returns the previous item (replaced), if any
	pub fn insert(&mut self, key: K, value: V) -> Option<V> {
		match self.entry(key)
		{
		Entry::Occupied(e) => {
			Some( ::core::mem::replace(e.into_mut(), value) )
			},
		Entry::Vacant(e) => {
			e.insert(value);
			None
			},
		}
	}

	/// Return an 'entry' in the map, allowing cheap handling of insertion/lookup
	pub fn entry(&mut self, key: K) -> Entry<K, V>
	{
		// Binary search for the specified key
		match self.ents.binary_search_by(|e| e.0.cmp(&key))
		{
		Ok(idx) =>  Entry::Occupied( OccupiedEntry { map: self, slot: idx } ),
		Err(idx) => Entry::Vacant(   VacantEntry { map: self, slot: idx, key: key } ),
		}
	}

	pub fn get<Q: ?Sized>(&self, key: &Q) -> Option<&V>
	where
		Q: Ord,
		K: Borrow<Q>
	{
		match self.ents.binary_search_by(|e| e.0.borrow().cmp(key))
		{
		Ok(idx) => Some( &self.ents[idx].1 ),
		Err(_) => None,
		}
	}

	/// Return a read-only iterator
	pub fn iter(&self) -> Iter<K,V> {
		Iter {
			pos: 0,
			ents: &*self.ents,
		}
	}
}

impl<'a, K, V> ::core::iter::Iterator for Iter<'a, K, V>
{
	type Item = (&'a K, &'a V);

	fn next(&mut self) -> Option<(&'a K, &'a V)>
	{
		if self.pos <= self.ents.len()
		{
			let e = &self.ents[self.pos];
			self.pos += 1;
			Some( (&e.0, &e.1) )
		}
		else
		{
			None
		}
	}
}

impl<'a,K: Ord,V> OccupiedEntry<'a, K, V>
{
	/// Return a limited-lifetime pointer to the item
	pub fn get_mut(&mut self) -> &mut V
	{
		&mut self.map.ents[self.slot].1
	}
	/// Consume the Entry and return a pointer to the item
	pub fn into_mut(self) -> &'a mut V
	{
		&mut self.map.ents[self.slot].1
	}
}

impl<'a,K: Ord,V> VacantEntry<'a, K, V>
{
	/// Insert a value at this position and return a pointer to it
	pub fn insert(self, value: V) -> &'a mut V {
		self.map.ents.insert(self.slot, (self.key, value));
		&mut self.map.ents[self.slot].1
	}
}

<commit_msg>Kernel - Fix off-by-one in VecMap causing panic<commit_after>// "Tifflin" Kernel
// - By John Hodge (thePowersGang)
//
// Core/lib/vec_map.rs
//! Sorted vector backed Key-Value map.
use _common::*;
use lib::borrow::Borrow;

/// Primitive key-value map backed by a sorted vector
pub struct VecMap<K: Ord,V>
{
	ents: Vec<(K,V)>,
}
/// Immutable iterator for VecMap
pub struct Iter<'a, K: 'a, V: 'a>
{
	pos: usize,
	ents: &'a [(K,V)],
}

/// An entry in a VecMap
pub enum Entry<'a, K: 'a + Ord, V: 'a>
{
	Occupied(OccupiedEntry<'a, K, V>),
	Vacant(VacantEntry<'a, K, V>),
}
/// An occupied entry in a VecMap
pub struct OccupiedEntry<'a, K: 'a + Ord, V: 'a>
{
	map: &'a mut VecMap<K,V>,
	slot: usize,
}
/// An unoccupied entyr in a VecMap
pub struct VacantEntry<'a, K: 'a + Ord, V: 'a>
{
	map: &'a mut VecMap<K,V>,
	slot: usize,
	key: K,
}

impl<K: Ord, V> VecMap<K,V>
{
	/// Create a new (empty) VecMap
	pub fn new() -> VecMap<K,V> {
		VecMap {
			ents: Vec::new(),
		}
	}

	/// Returns the previous item (replaced), if any
	pub fn insert(&mut self, key: K, value: V) -> Option<V> {
		match self.entry(key)
		{
		Entry::Occupied(e) => {
			Some( ::core::mem::replace(e.into_mut(), value) )
			},
		Entry::Vacant(e) => {
			e.insert(value);
			None
			},
		}
	}

	/// Return an 'entry' in the map, allowing cheap handling of insertion/lookup
	pub fn entry(&mut self, key: K) -> Entry<K, V>
	{
		// Binary search for the specified key
		match self.ents.binary_search_by(|e| e.0.cmp(&key))
		{
		Ok(idx) =>  Entry::Occupied( OccupiedEntry { map: self, slot: idx } ),
		Err(idx) => Entry::Vacant(   VacantEntry { map: self, slot: idx, key: key } ),
		}
	}

	pub fn get<Q: ?Sized>(&self, key: &Q) -> Option<&V>
	where
		Q: Ord,
		K: Borrow<Q>
	{
		match self.ents.binary_search_by(|e| e.0.borrow().cmp(key))
		{
		Ok(idx) => Some( &self.ents[idx].1 ),
		Err(_) => None,
		}
	}

	/// Return a read-only iterator
	pub fn iter(&self) -> Iter<K,V> {
		Iter {
			pos: 0,
			ents: &*self.ents,
		}
	}
}

impl<'a, K, V> ::core::iter::Iterator for Iter<'a, K, V>
{
	type Item = (&'a K, &'a V);

	fn next(&mut self) -> Option<(&'a K, &'a V)>
	{
		if self.pos < self.ents.len()
		{
			let e = &self.ents[self.pos];
			self.pos += 1;
			Some( (&e.0, &e.1) )
		}
		else
		{
			None
		}
	}
}

impl<'a,K: Ord,V> OccupiedEntry<'a, K, V>
{
	/// Return a limited-lifetime pointer to the item
	pub fn get_mut(&mut self) -> &mut V
	{
		&mut self.map.ents[self.slot].1
	}
	/// Consume the Entry and return a pointer to the item
	pub fn into_mut(self) -> &'a mut V
	{
		&mut self.map.ents[self.slot].1
	}
}

impl<'a,K: Ord,V> VacantEntry<'a, K, V>
{
	/// Insert a value at this position and return a pointer to it
	pub fn insert(self, value: V) -> &'a mut V {
		self.map.ents.insert(self.slot, (self.key, value));
		&mut self.map.ents[self.slot].1
	}
}

<|endoftext|>


<commit_before>use std::borrow::Cow;
use std::io::Result as IoResult;
use std::io::Write;

use byteorder::{ByteOrder, ReadBytesExt, WriteBytesExt};
use derive_into_owned::IntoOwned;

use crate::errors::PcapError;
use crate::pcapng::{CustomBinaryOption, CustomUtf8Option, PcapNgBlock, PcapNgOption, UnknownOption, WriteOptTo, BlockType, ParsedBlock};
use std::time::Duration;

/// An Enhanced Packet Block (EPB) is the standard container for storing the packets coming from the network.
#[derive(Clone, Debug, IntoOwned, Eq, PartialEq)]
pub struct EnhancedPacketBlock<'a> {

    /// It specifies the interface this packet comes from.
    /// The correct interface will be the one whose Interface Description Block
    /// (within the current Section of the file) is identified by the same number of this field.
    pub interface_id: u32,

    /// The timestamp is a single 64-bit unsigned integer that represents the number of units of time
    /// that have elapsed since 1970-01-01 00:00:00 UTC.
    pub timestamp: u64,

    /// Number of octets captured from the packet (i.e. the length of the Packet Data field).
    pub captured_len: u32,

    /// Actual length of the packet when it was transmitted on the network.
    pub original_len: u32,

    /// The data coming from the network, including link-layer headers.
    pub data: Cow<'a, [u8]>,

    /// Options
    pub options: Vec<EnhancedPacketOption<'a>>
}

impl<'a> EnhancedPacketBlock<'a> {

    pub fn timestamp(&self) -> Duration {
        Duration::from_nanos(self.timestamp)
    }
}

impl<'a> PcapNgBlock<'a> for EnhancedPacketBlock<'a> {

    const BLOCK_TYPE: BlockType = BlockType::EnhancedPacket;

    fn from_slice<B: ByteOrder>(mut slice: &'a [u8]) -> Result<(&'a [u8], Self), PcapError> {

        if slice.len() < 20 {
            return Err(PcapError::InvalidField("EnhancedPacketBlock: block length length < 20"));
        }

        let interface_id = slice.read_u32::<B>()?;
        let timestamp_high = slice.read_u32::<B>()? as u64;
        let timestamp_low = slice.read_u32::<B>()? as u64;
        let timestamp = (timestamp_high << 32) + timestamp_low;
        let captured_len = slice.read_u32::<B>()?;
        let original_len = slice.read_u32::<B>()?;

        let pad_len = (4 - (captured_len as usize % 4)) % 4;
        let tot_len = captured_len as usize + pad_len;

        if slice.len() < tot_len {
            return Err(PcapError::InvalidField("EnhancedPacketBlock: captured_len + padding > block length"));
        }

        let data = &slice[..captured_len as usize];
        slice = &slice[tot_len..];

        let (slice, options) = EnhancedPacketOption::opts_from_slice::<B>(slice)?;
        let block = EnhancedPacketBlock {
            interface_id,
            timestamp,
            captured_len,
            original_len,
            data: Cow::Borrowed(data),
            options
        };

        Ok((slice, block))
    }

    fn write_to<B: ByteOrder, W: Write>(&self, writer: &mut W) -> IoResult<usize> {

        let pad_len = (4 - (&self.data.len() % 4)) % 4;

        writer.write_u32::<B>(self.interface_id)?;

        let timestamp_high = (self.timestamp >> 32) as u32;
        writer.write_u32::<B>(timestamp_high)?;
        let timestamp_low = (self.timestamp & 0xFFFFFFFF) as u32;
        writer.write_u32::<B>(timestamp_low)?;

        writer.write_u32::<B>(self.captured_len)?;
        writer.write_u32::<B>(self.original_len)?;
        writer.write_all(&self.data)?;
        writer.write_all(&[0_u8; 3][..pad_len])?;

        let opt_len = EnhancedPacketOption::write_opts_to::<B, W>(&self.options, writer)?;

        Ok(20 + &self.data.len() + pad_len + opt_len)
    }

    fn into_parsed(self) -> ParsedBlock<'a> {
        ParsedBlock::EnhancedPacket(self)
    }
}

#[derive(Clone, Debug, IntoOwned, Eq, PartialEq)]
pub enum EnhancedPacketOption<'a> {

    /// Comment associated with the current block
    Comment(Cow<'a, str>),

    /// 32-bit flags word containing link-layer information.
    Flags(u32),

    /// Contains a hash of the packet.
    Hash(Cow<'a, [u8]>),

    /// 64-bit integer value specifying the number of packets lost
    /// (by the interface and the operating system) between this packet and the preceding one for
    /// the same interface or, for the first packet for an interface, between this packet
    /// and the start of the capture process.
    DropCount(u64),

    /// Custom option containing binary octets in the Custom Data portion
    CustomBinary(CustomBinaryOption<'a>),

    /// Custom option containing a UTF-8 string in the Custom Data portion
    CustomUtf8(CustomUtf8Option<'a>),

    /// Unknown option
    Unknown(UnknownOption<'a>)
}

impl<'a> PcapNgOption<'a> for EnhancedPacketOption<'a> {

    fn from_slice<B: ByteOrder>(code: u16, length: u16, mut slice: &'a [u8]) -> Result<Self, PcapError> {

        let opt = match code {

            1 => EnhancedPacketOption::Comment(Cow::Borrowed(std::str::from_utf8(slice)?)),
            2 => {
                if slice.len() != 4 {
                    return Err(PcapError::InvalidField("EnhancedPacketOption: Flags length != 4"))
                }
                EnhancedPacketOption::Flags(slice.read_u32::<B>()?)
            },
            3 => EnhancedPacketOption::Hash(Cow::Borrowed(slice)),
            4 => {
                if slice.len() != 8 {
                    return Err(PcapError::InvalidField("EnhancedPacketOption: DropCount length != 8"))
                }
                EnhancedPacketOption::DropCount(slice.read_u64::<B>()?)
            },

            2988 | 19372 => EnhancedPacketOption::CustomUtf8(CustomUtf8Option::from_slice::<B>(code, slice)?),
            2989 | 19373 => EnhancedPacketOption::CustomBinary(CustomBinaryOption::from_slice::<B>(code, slice)?),

            _ => EnhancedPacketOption::Unknown(UnknownOption::new(code, length, slice))
        };

        Ok(opt)
    }

    fn write_to<B: ByteOrder, W: Write>(&self, writer: &mut W) -> IoResult<usize> {
        match self {
            EnhancedPacketOption::Comment(a) => a.write_opt_to::<B, W>(1, writer),
            EnhancedPacketOption::Flags(a) => a.write_opt_to::<B, W>(2, writer),
            EnhancedPacketOption::Hash(a) => a.write_opt_to::<B, W>(3, writer),
            EnhancedPacketOption::DropCount(a) => a.write_opt_to::<B, W>(4, writer),
            EnhancedPacketOption::CustomBinary(a) => a.write_opt_to::<B, W>(a.code, writer),
            EnhancedPacketOption::CustomUtf8(a) => a.write_opt_to::<B, W>(a.code, writer),
            EnhancedPacketOption::Unknown(a) => a.write_opt_to::<B, W>(a.code, writer),
        }
    }
}<commit_msg>Fix EnhancedPacketBlock lifetime<commit_after>use std::borrow::Cow;
use std::io::Result as IoResult;
use std::io::Write;

use byteorder::{ByteOrder, ReadBytesExt, WriteBytesExt};
use derive_into_owned::IntoOwned;

use crate::errors::PcapError;
use crate::pcapng::{CustomBinaryOption, CustomUtf8Option, PcapNgBlock, PcapNgOption, UnknownOption, WriteOptTo, BlockType, ParsedBlock};
use std::time::Duration;

/// An Enhanced Packet Block (EPB) is the standard container for storing the packets coming from the network.
#[derive(Clone, Debug, IntoOwned, Eq, PartialEq)]
pub struct EnhancedPacketBlock<'a> {

    /// It specifies the interface this packet comes from.
    /// The correct interface will be the one whose Interface Description Block
    /// (within the current Section of the file) is identified by the same number of this field.
    pub interface_id: u32,

    /// The timestamp is a single 64-bit unsigned integer that represents the number of units of time
    /// that have elapsed since 1970-01-01 00:00:00 UTC.
    pub timestamp: u64,

    /// Number of octets captured from the packet (i.e. the length of the Packet Data field).
    pub captured_len: u32,

    /// Actual length of the packet when it was transmitted on the network.
    pub original_len: u32,

    /// The data coming from the network, including link-layer headers.
    pub data: Cow<'a, [u8]>,

    /// Options
    pub options: Vec<EnhancedPacketOption<'a>>
}

impl<'a, 'b> EnhancedPacketBlock<'a> {

    pub fn timestamp(&self) -> Duration {
        Duration::from_nanos(self.timestamp)
    }
}

impl<'a> PcapNgBlock<'a> for EnhancedPacketBlock<'a> {

    const BLOCK_TYPE: BlockType = BlockType::EnhancedPacket;

    fn from_slice<B: ByteOrder>(mut slice: &'a [u8]) -> Result<(&'a [u8], Self), PcapError> {

        if slice.len() < 20 {
            return Err(PcapError::InvalidField("EnhancedPacketBlock: block length length < 20"));
        }

        let interface_id = slice.read_u32::<B>()?;
        let timestamp_high = slice.read_u32::<B>()? as u64;
        let timestamp_low = slice.read_u32::<B>()? as u64;
        let timestamp = (timestamp_high << 32) + timestamp_low;
        let captured_len = slice.read_u32::<B>()?;
        let original_len = slice.read_u32::<B>()?;

        let pad_len = (4 - (captured_len as usize % 4)) % 4;
        let tot_len = captured_len as usize + pad_len;

        if slice.len() < tot_len {
            return Err(PcapError::InvalidField("EnhancedPacketBlock: captured_len + padding > block length"));
        }

        let data = &slice[..captured_len as usize];
        slice = &slice[tot_len..];

        let (slice, options) = EnhancedPacketOption::opts_from_slice::<B>(slice)?;
        let block = EnhancedPacketBlock {
            interface_id,
            timestamp,
            captured_len,
            original_len,
            data: Cow::Borrowed(data),
            options
        };

        Ok((slice, block))
    }

    fn write_to<B: ByteOrder, W: Write>(&self, writer: &mut W) -> IoResult<usize> {

        let pad_len = (4 - (&self.data.len() % 4)) % 4;

        writer.write_u32::<B>(self.interface_id)?;

        let timestamp_high = (self.timestamp >> 32) as u32;
        writer.write_u32::<B>(timestamp_high)?;
        let timestamp_low = (self.timestamp & 0xFFFFFFFF) as u32;
        writer.write_u32::<B>(timestamp_low)?;

        writer.write_u32::<B>(self.captured_len)?;
        writer.write_u32::<B>(self.original_len)?;
        writer.write_all(&self.data)?;
        writer.write_all(&[0_u8; 3][..pad_len])?;

        let opt_len = EnhancedPacketOption::write_opts_to::<B, W>(&self.options, writer)?;

        Ok(20 + &self.data.len() + pad_len + opt_len)
    }

    fn into_parsed(self) -> ParsedBlock<'a> {
        ParsedBlock::EnhancedPacket(self)
    }
}

#[derive(Clone, Debug, IntoOwned, Eq, PartialEq)]
pub enum EnhancedPacketOption<'a> {

    /// Comment associated with the current block
    Comment(Cow<'a, str>),

    /// 32-bit flags word containing link-layer information.
    Flags(u32),

    /// Contains a hash of the packet.
    Hash(Cow<'a, [u8]>),

    /// 64-bit integer value specifying the number of packets lost
    /// (by the interface and the operating system) between this packet and the preceding one for
    /// the same interface or, for the first packet for an interface, between this packet
    /// and the start of the capture process.
    DropCount(u64),

    /// Custom option containing binary octets in the Custom Data portion
    CustomBinary(CustomBinaryOption<'a>),

    /// Custom option containing a UTF-8 string in the Custom Data portion
    CustomUtf8(CustomUtf8Option<'a>),

    /// Unknown option
    Unknown(UnknownOption<'a>)
}

impl<'a> PcapNgOption<'a> for EnhancedPacketOption<'a> {

    fn from_slice<B: ByteOrder>(code: u16, length: u16, mut slice: &'a [u8]) -> Result<Self, PcapError> {

        let opt = match code {

            1 => EnhancedPacketOption::Comment(Cow::Borrowed(std::str::from_utf8(slice)?)),
            2 => {
                if slice.len() != 4 {
                    return Err(PcapError::InvalidField("EnhancedPacketOption: Flags length != 4"))
                }
                EnhancedPacketOption::Flags(slice.read_u32::<B>()?)
            },
            3 => EnhancedPacketOption::Hash(Cow::Borrowed(slice)),
            4 => {
                if slice.len() != 8 {
                    return Err(PcapError::InvalidField("EnhancedPacketOption: DropCount length != 8"))
                }
                EnhancedPacketOption::DropCount(slice.read_u64::<B>()?)
            },

            2988 | 19372 => EnhancedPacketOption::CustomUtf8(CustomUtf8Option::from_slice::<B>(code, slice)?),
            2989 | 19373 => EnhancedPacketOption::CustomBinary(CustomBinaryOption::from_slice::<B>(code, slice)?),

            _ => EnhancedPacketOption::Unknown(UnknownOption::new(code, length, slice))
        };

        Ok(opt)
    }

    fn write_to<B: ByteOrder, W: Write>(&self, writer: &mut W) -> IoResult<usize> {
        match self {
            EnhancedPacketOption::Comment(a) => a.write_opt_to::<B, W>(1, writer),
            EnhancedPacketOption::Flags(a) => a.write_opt_to::<B, W>(2, writer),
            EnhancedPacketOption::Hash(a) => a.write_opt_to::<B, W>(3, writer),
            EnhancedPacketOption::DropCount(a) => a.write_opt_to::<B, W>(4, writer),
            EnhancedPacketOption::CustomBinary(a) => a.write_opt_to::<B, W>(a.code, writer),
            EnhancedPacketOption::CustomUtf8(a) => a.write_opt_to::<B, W>(a.code, writer),
            EnhancedPacketOption::Unknown(a) => a.write_opt_to::<B, W>(a.code, writer),
        }
    }
}<|endoftext|>


<commit_before>//! Somewhat more involved example derived from 2D drag & drop application.

#[macro_use(lift)]
extern crate carboxyl;

use carboxyl::{ Sink, SignalCycle };

#[test]
fn drag_drop_example() {
    #[derive(Copy, Debug, Clone)]
    enum Event { Add(i32), Drag(usize, i32), Drop }
    let sink = Sink::new();
    let rects = SignalCycle::<Vec<i32>>::new();
    let events = sink.stream();

    let spawned = rects.snapshot(&events,
        |mut rects, ev| match ev {
            Event::Add(r) => { rects.push(r); rects },
            _ => rects,
        })
        .hold(vec![300]);

    let new_rects = events.filter_map({
        let spawned = spawned.clone();
        move |ev| match ev {
            Event::Drag(idx, pos) => {
            Some(lift!(
                move |mut rects| {
                    rects[idx] += pos;
                    rects
                },
                &spawned
            ))},
            Event::Drop => Some(spawned.clone()),
            _ => None,
        }})
        .hold(spawned.clone())
        .switch();
    let rects = rects.define(new_rects.clone());

    assert_eq!(rects.sample(), vec![300]);
    sink.send(Event::Add(61));
    assert_eq!(rects.sample(), vec![300, 61]);
    sink.send(Event::Add(66));
    assert_eq!(rects.sample(), vec![300, 61, 66]);
    sink.send(Event::Drop);
    assert_eq!(rects.sample(), vec![300, 61, 66]);
    sink.send(Event::Drag(1, 10));
    assert_eq!(rects.sample(), vec![300, 71, 66]);
}
<commit_msg>Adapt drag & drop example<commit_after>//! Somewhat more involved example derived from 2D drag & drop application.

#[macro_use(lift)]
extern crate carboxyl;

use carboxyl::{ Sink, Signal };

#[test]
fn drag_drop_example() {
    #[derive(Copy, Debug, Clone)]
    enum Event { Add(i32), Drag(usize, i32), Drop }
    let sink = Sink::new();
    let rects = Signal::<Vec<i32>>::cyclic(|rects| {
        let events = sink.stream();

        let spawned = rects.snapshot(&events,
            |mut rects, ev| match ev {
                Event::Add(r) => { rects.push(r); rects },
                _ => rects,
            })
            .hold(vec![300]);

        events.filter_map({
            let spawned = spawned.clone();
            move |ev| match ev {
                Event::Drag(idx, pos) => {
                Some(lift!(
                    move |mut rects| {
                        rects[idx] += pos;
                        rects
                    },
                    &spawned
                ))},
                Event::Drop => Some(spawned.clone()),
                _ => None,
            }})
            .hold(spawned.clone())
            .switch()
    });

    assert_eq!(rects.sample(), vec![300]);
    sink.send(Event::Add(61));
    assert_eq!(rects.sample(), vec![300, 61]);
    sink.send(Event::Add(66));
    assert_eq!(rects.sample(), vec![300, 61, 66]);
    sink.send(Event::Drop);
    assert_eq!(rects.sample(), vec![300, 61, 66]);
    sink.send(Event::Drag(1, 10));
    assert_eq!(rects.sample(), vec![300, 71, 66]);
}
<|endoftext|>