<commit_before>use mozprofile::prefdata::FIREFOX_PREFERENCES;
use mozprofile::prefreader::PrefReaderError;
use mozprofile::profile::Profile;
use std::convert::From;
use std::env;
use std::error::Error;
use std::fmt;
use std::io::{Result as IoResult, Error as IoError, ErrorKind};
use std::path::{Path, PathBuf};
use std::process;
use std::process::{Command, Stdio};

pub trait Runner {
    fn start(&mut self) -> Result<(), RunnerError>;

    fn args(&mut self) -> &mut Vec<String>;

    fn build_command(&self, &mut Command);

    fn is_running(&self) -> bool;

    fn stop(&mut self) -> IoResult<Option<process::ExitStatus>>;
}

#[derive(Debug)]
pub enum RunnerError {
    Io(IoError),
    PrefReader(PrefReaderError),
}

impl fmt::Display for RunnerError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.description().fmt(f)
    }
}

impl Error for RunnerError {
    fn description(&self) -> &str {
        match *self {
            RunnerError::Io(ref err) => {
                match err.kind() {
                    ErrorKind::NotFound => "no such file or directory",
                    _ => err.description(),
                }
            }
            RunnerError::PrefReader(ref err) => err.description(),
        }
    }

    fn cause(&self) -> Option<&Error> {
        Some(match *self {
            RunnerError::Io(ref err) => err as &Error,
            RunnerError::PrefReader(ref err) => err as &Error,
        })
    }
}

impl From<IoError> for RunnerError {
    fn from(value: IoError) -> RunnerError {
        RunnerError::Io(value)
    }
}

impl From<PrefReaderError> for RunnerError {
    fn from(value: PrefReaderError) -> RunnerError {
        RunnerError::PrefReader(value)
    }
}

pub struct FirefoxRunner {
    pub binary: PathBuf,
    args: Vec<String>,
    process: Option<process::Child>,
    pub ret_code: Option<process::ExitStatus>,
    pub profile: Profile
}

impl FirefoxRunner {
    pub fn new(binary: &Path, profile: Option<Profile>) -> IoResult<FirefoxRunner> {
        let prof = match profile {
            Some(p) => p,
            None => try!(Profile::new(None))
        };

        Ok(FirefoxRunner {
            binary: binary.to_path_buf(),
            process: None,
            ret_code: None,
            args: Vec::new(),
            profile: prof
        })
    }
}

impl Runner for FirefoxRunner {
    fn start(&mut self) -> Result<(), RunnerError> {
        let mut cmd = Command::new(&self.binary);
        self.build_command(&mut cmd);

        let mut prefs = try!(self.profile.user_prefs());
        prefs.insert_slice(&FIREFOX_PREFERENCES[..]);

        try!(prefs.write());

        let process = try!(cmd.spawn());
        self.process = Some(process);
        Ok(())
    }

    fn args(&mut self) -> &mut Vec<String> {
        &mut self.args
    }

    fn build_command(&self, command: &mut Command) {
        command.args(&self.args[..]).arg("--marionette").arg("--profile").arg(&self.profile.path)
            .stdout(Stdio::inherit()).stderr(Stdio::inherit())
            .env("MOZ_NO_REMOTE", "1").env("NO_EM_RESTART", "1");
    }

    fn is_running(&self) -> bool {
        self.process.is_some() && self.ret_code.is_none()
    }

    fn stop(&mut self) -> IoResult<Option<process::ExitStatus>> {
        match self.process.as_mut() {
            Some(p) => {
                try!(p.kill());
                let status = try!(p.wait());
                self.ret_code = Some(status);
            },
            None => {}
        };
        Ok(self.ret_code)
    }
}

fn find_binary(name: &str) -> Option<PathBuf> {
    env::var("PATH")
        .ok()
        .and_then(|path_env| {
            for mut path in env::split_paths(&*path_env) {
                path.push(name);
                if path.exists() {
                    return Some(path)
                }
            }
            None
        })
}

#[cfg(target_os = "linux")]
pub mod platform {
    use super::find_binary;
    use std::path::PathBuf;

    pub fn firefox_default_path() -> Option<PathBuf> {
        find_binary("firefox")
    }
}

#[cfg(target_os = "macos")]
pub mod platform {
    use super::find_binary;
    use std::env;
    use std::path::PathBuf;

    pub fn firefox_default_path() -> Option<PathBuf> {
        let home = env::home_dir();
        for &(prefix_home, trial_path) in [
            (false, "/Applications/Firefox.app/Contents/MacOS/firefox-bin"),
            (true, "Applications/Firefox.app/Contents/MacOS/firefox-bin")].iter() {
            let path = match (home.as_ref(), prefix_home) {
                (Some(ref home_dir), true) => home_dir.join(trial_path),
                (None, true) => continue,
                (_, false) => PathBuf::from(trial_path)
            };
            if path.exists() {
                return Some(path)
            }
        }
        find_binary("firefox-bin")
    }
}

#[cfg(target_os = "windows")]
pub mod platform {
    use super::find_binary;
    use std::io::Error;
    use std::path::PathBuf;
    use winreg::RegKey;
    use winreg::enums::*;

    pub fn firefox_default_path() -> Option<PathBuf> {
        let opt_path = firefox_registry_path().unwrap_or(None);
        if let Some(path) = opt_path {
            if path.exists() {
                return Some(path)
            }
        };
        find_binary("firefox.exe")
    }

    fn firefox_registry_path() -> Result<Option<PathBuf>, Error> {
        let hklm = RegKey::predef(HKEY_LOCAL_MACHINE);
        for subtree_key in ["SOFTWARE", "SOFTWARE\\WOW6432Node"].iter() {
            let subtree = try!(hklm.open_subkey_with_flags(subtree_key, KEY_READ));
            let mozilla_org = match subtree.open_subkey_with_flags("mozilla.org\\Mozilla", KEY_READ) {
                Ok(val) => val,
                Err(_) => continue
            };
            let current_version: String = try!(mozilla_org.get_value("CurrentVersion"));
            let mozilla = try!(subtree.open_subkey_with_flags("Mozilla", KEY_READ));
            for key_res in mozilla.enum_keys() {
                let key = try!(key_res);
                let section_data = try!(mozilla.open_subkey_with_flags(&key, KEY_READ));
                let version: Result<String, _> = section_data.get_value("GeckoVer");
                if let Ok(ver) = version {
                    if ver == current_version {
                        let mut bin_key = key.to_owned();
                        bin_key.push_str("\\bin");
                        if let Ok(bin_subtree) = mozilla.open_subkey_with_flags(bin_key, KEY_READ) {
                            let path: Result<String, _> = bin_subtree.get_value("PathToExe");
                            if let Ok(path) = path {
                                return Ok(Some(PathBuf::from(path)))
                            }
                        }
                    }
                }
            }
        }
        Ok(None)
    }
}

#[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows")))]
pub mod platform {
    use std::path::PathBuf;

    pub fn firefox_default_path() -> Option<PathBuf> {
        None
    }
}
<commit_msg>Allow Firefox binary on macOS system path to take precedent over defaults. (#4)<commit_after>use mozprofile::prefdata::FIREFOX_PREFERENCES;
use mozprofile::prefreader::PrefReaderError;
use mozprofile::profile::Profile;
use std::convert::From;
use std::env;
use std::error::Error;
use std::fmt;
use std::io::{Result as IoResult, Error as IoError, ErrorKind};
use std::path::{Path, PathBuf};
use std::process;
use std::process::{Command, Stdio};

pub trait Runner {
    fn start(&mut self) -> Result<(), RunnerError>;

    fn args(&mut self) -> &mut Vec<String>;

    fn build_command(&self, &mut Command);

    fn is_running(&self) -> bool;

    fn stop(&mut self) -> IoResult<Option<process::ExitStatus>>;
}

#[derive(Debug)]
pub enum RunnerError {
    Io(IoError),
    PrefReader(PrefReaderError),
}

impl fmt::Display for RunnerError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.description().fmt(f)
    }
}

impl Error for RunnerError {
    fn description(&self) -> &str {
        match *self {
            RunnerError::Io(ref err) => {
                match err.kind() {
                    ErrorKind::NotFound => "no such file or directory",
                    _ => err.description(),
                }
            }
            RunnerError::PrefReader(ref err) => err.description(),
        }
    }

    fn cause(&self) -> Option<&Error> {
        Some(match *self {
            RunnerError::Io(ref err) => err as &Error,
            RunnerError::PrefReader(ref err) => err as &Error,
        })
    }
}

impl From<IoError> for RunnerError {
    fn from(value: IoError) -> RunnerError {
        RunnerError::Io(value)
    }
}

impl From<PrefReaderError> for RunnerError {
    fn from(value: PrefReaderError) -> RunnerError {
        RunnerError::PrefReader(value)
    }
}

pub struct FirefoxRunner {
    pub binary: PathBuf,
    args: Vec<String>,
    process: Option<process::Child>,
    pub ret_code: Option<process::ExitStatus>,
    pub profile: Profile
}

impl FirefoxRunner {
    pub fn new(binary: &Path, profile: Option<Profile>) -> IoResult<FirefoxRunner> {
        let prof = match profile {
            Some(p) => p,
            None => try!(Profile::new(None))
        };

        Ok(FirefoxRunner {
            binary: binary.to_path_buf(),
            process: None,
            ret_code: None,
            args: Vec::new(),
            profile: prof
        })
    }
}

impl Runner for FirefoxRunner {
    fn start(&mut self) -> Result<(), RunnerError> {
        let mut cmd = Command::new(&self.binary);
        self.build_command(&mut cmd);

        let mut prefs = try!(self.profile.user_prefs());
        prefs.insert_slice(&FIREFOX_PREFERENCES[..]);

        try!(prefs.write());

        let process = try!(cmd.spawn());
        self.process = Some(process);
        Ok(())
    }

    fn args(&mut self) -> &mut Vec<String> {
        &mut self.args
    }

    fn build_command(&self, command: &mut Command) {
        command.args(&self.args[..]).arg("--marionette").arg("--profile").arg(&self.profile.path)
            .stdout(Stdio::inherit()).stderr(Stdio::inherit())
            .env("MOZ_NO_REMOTE", "1").env("NO_EM_RESTART", "1");
    }

    fn is_running(&self) -> bool {
        self.process.is_some() && self.ret_code.is_none()
    }

    fn stop(&mut self) -> IoResult<Option<process::ExitStatus>> {
        match self.process.as_mut() {
            Some(p) => {
                try!(p.kill());
                let status = try!(p.wait());
                self.ret_code = Some(status);
            },
            None => {}
        };
        Ok(self.ret_code)
    }
}

fn find_binary(name: &str) -> Option<PathBuf> {
    env::var("PATH")
        .ok()
        .and_then(|path_env| {
            for mut path in env::split_paths(&*path_env) {
                path.push(name);
                if path.exists() {
                    return Some(path)
                }
            }
            None
        })
}

#[cfg(target_os = "linux")]
pub mod platform {
    use super::find_binary;
    use std::path::PathBuf;

    pub fn firefox_default_path() -> Option<PathBuf> {
        find_binary("firefox")
    }
}

#[cfg(target_os = "macos")]
pub mod platform {
    use super::find_binary;
    use std::env;
    use std::path::PathBuf;

    pub fn firefox_default_path() -> Option<PathBuf> {
        if let Some(path) = find_binary("firefox-bin") {
            return Some(path)
        }
        let home = env::home_dir();
        for &(prefix_home, trial_path) in [
            (false, "/Applications/Firefox.app/Contents/MacOS/firefox-bin"),
            (true, "Applications/Firefox.app/Contents/MacOS/firefox-bin")].iter() {
            let path = match (home.as_ref(), prefix_home) {
                (Some(ref home_dir), true) => home_dir.join(trial_path),
                (None, true) => continue,
                (_, false) => PathBuf::from(trial_path)
            };
            if path.exists() {
                return Some(path)
            }
        }
        None
    }
}

#[cfg(target_os = "windows")]
pub mod platform {
    use super::find_binary;
    use std::io::Error;
    use std::path::PathBuf;
    use winreg::RegKey;
    use winreg::enums::*;

    pub fn firefox_default_path() -> Option<PathBuf> {
        let opt_path = firefox_registry_path().unwrap_or(None);
        if let Some(path) = opt_path {
            if path.exists() {
                return Some(path)
            }
        };
        find_binary("firefox.exe")
    }

    fn firefox_registry_path() -> Result<Option<PathBuf>, Error> {
        let hklm = RegKey::predef(HKEY_LOCAL_MACHINE);
        for subtree_key in ["SOFTWARE", "SOFTWARE\\WOW6432Node"].iter() {
            let subtree = try!(hklm.open_subkey_with_flags(subtree_key, KEY_READ));
            let mozilla_org = match subtree.open_subkey_with_flags("mozilla.org\\Mozilla", KEY_READ) {
                Ok(val) => val,
                Err(_) => continue
            };
            let current_version: String = try!(mozilla_org.get_value("CurrentVersion"));
            let mozilla = try!(subtree.open_subkey_with_flags("Mozilla", KEY_READ));
            for key_res in mozilla.enum_keys() {
                let key = try!(key_res);
                let section_data = try!(mozilla.open_subkey_with_flags(&key, KEY_READ));
                let version: Result<String, _> = section_data.get_value("GeckoVer");
                if let Ok(ver) = version {
                    if ver == current_version {
                        let mut bin_key = key.to_owned();
                        bin_key.push_str("\\bin");
                        if let Ok(bin_subtree) = mozilla.open_subkey_with_flags(bin_key, KEY_READ) {
                            let path: Result<String, _> = bin_subtree.get_value("PathToExe");
                            if let Ok(path) = path {
                                return Ok(Some(PathBuf::from(path)))
                            }
                        }
                    }
                }
            }
        }
        Ok(None)
    }
}

#[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows")))]
pub mod platform {
    use std::path::PathBuf;

    pub fn firefox_default_path() -> Option<PathBuf> {
        None
    }
}
<|endoftext|>


<commit_before>use message;

pub struct Server {
    id: i32,
}

static CONNACK_OK : [u8; 4] = [32, 2, 0, 0];
static PING_RESP : [u8; 2] = [0xd0, 0];

impl Server {
    pub fn new() -> Self {
        Server { id: 4 }
    }

    pub fn new_message<C: Client>(&mut self, client: &mut C, bytes: &[u8]) {
        let message_type = message::message_type(bytes);
        match message_type {
            message::MqttType::Connect => {
                client.send(&CONNACK_OK);
            },
            message::MqttType::PingReq => {
                client.send(&PING_RESP);
            },
            _ => panic!("Unknown message type")
        }
    }
}

pub trait Client {
    fn send(&mut self, bytes: &[u8]);
}

struct TestClient {
    msgs: Vec<Vec<u8>>,
}

impl TestClient {
    fn new() -> Self {
        TestClient { msgs: vec!() }
    }

    fn last_msg(&self) -> &[u8] {
        self.msgs.last().unwrap()
    }
}

impl Client for TestClient {
    fn send(&mut self, bytes: &[u8]) {
        self.msgs.push(bytes.to_vec());
    }
}

#[test]
fn test_connect() {
    let connect_bytes = &[
        0x10u8, 0x2a, // fixed header
        0x00, 0x06, 'M' as u8, 'Q' as u8, 'I' as u8, 's' as u8, 'd' as u8, 'p' as u8,
        0x03, // protocol version
        0xcc, // connection flags 1100111x user, pw, !wr, w(01), w, !c, x
        0x00, 0x0a, // keepalive of 100
        0x00, 0x03, 'c' as u8, 'i' as u8, 'd' as u8, // client ID
        0x00, 0x04, 'w' as u8, 'i' as u8, 'l' as u8, 'l' as u8, // will topic
        0x00, 0x04, 'w' as u8, 'm' as u8, 's' as u8, 'g' as u8, // will msg
        0x00, 0x07, 'g' as u8, 'l' as u8, 'i' as u8, 'f' as u8, 't' as u8, 'e' as u8, 'l' as u8, // username
        0x00, 0x02, 'p' as u8, 'w' as u8, // password
        ][0..];

    let mut server = Server::new();
    let mut client = TestClient::new();

    server.new_message(&mut client, connect_bytes);
    assert_eq!(client.last_msg(), &CONNACK_OK);
}

#[test]
fn test_ping() {
    let ping_bytes =  &[0xc0u8, 0][0..];

    let mut server = Server::new();
    let mut client = TestClient::new();

    server.new_message(&mut client, ping_bytes);

    assert_eq!(client.last_msg(), &PING_RESP);
}

// #[test]
// fn test_pings() {
//     let ping_bytes =  &[0xc0u8, 0, 0xc0, 0, 0xc0, 0, 0xc0, 0][0..];

//     let mut server = Server::new();
//     let mut client = TestClient::new();

//     server.new_bytes(&mut client, ping_bytes);

//     assert_eq!(client.last_msg(), &PING_RESP);
// }
<commit_msg>Failing UT for multiple messages in one byte stream<commit_after>use message;

pub struct Server {
    id: i32,
}

static CONNACK_OK : [u8; 4] = [32, 2, 0, 0];
static PING_RESP : [u8; 2] = [0xd0, 0];

impl Server {
    pub fn new() -> Self {
        Server { id: 4 }
    }

    pub fn new_message<C: Client>(&mut self, client: &mut C, bytes: &[u8]) {
        let message_type = message::message_type(bytes);
        match message_type {
            message::MqttType::Connect => {
                client.send(&CONNACK_OK);
            },
            message::MqttType::PingReq => {
                client.send(&PING_RESP);
            },
            _ => panic!("Unknown message type")
        }
    }

    pub fn new_bytes<C: Client>(&mut self, client: &mut C, bytes: &[u8]) {
        self.new_message(client, bytes);
    }
}

pub trait Client {
    fn send(&mut self, bytes: &[u8]);
}

struct TestClient {
    msgs: Vec<Vec<u8>>,
}

impl TestClient {
    fn new() -> Self {
        TestClient { msgs: vec!() }
    }

    fn last_msg(&self) -> &[u8] {
        self.msgs.last().unwrap()
    }
}

impl Client for TestClient {
    fn send(&mut self, bytes: &[u8]) {
        self.msgs.push(bytes.to_vec());
    }
}

#[test]
fn test_connect() {
    let connect_bytes = &[
        0x10u8, 0x2a, // fixed header
        0x00, 0x06, 'M' as u8, 'Q' as u8, 'I' as u8, 's' as u8, 'd' as u8, 'p' as u8,
        0x03, // protocol version
        0xcc, // connection flags 1100111x user, pw, !wr, w(01), w, !c, x
        0x00, 0x0a, // keepalive of 100
        0x00, 0x03, 'c' as u8, 'i' as u8, 'd' as u8, // client ID
        0x00, 0x04, 'w' as u8, 'i' as u8, 'l' as u8, 'l' as u8, // will topic
        0x00, 0x04, 'w' as u8, 'm' as u8, 's' as u8, 'g' as u8, // will msg
        0x00, 0x07, 'g' as u8, 'l' as u8, 'i' as u8, 'f' as u8, 't' as u8, 'e' as u8, 'l' as u8, // username
        0x00, 0x02, 'p' as u8, 'w' as u8, // password
        ][0..];

    let mut server = Server::new();
    let mut client = TestClient::new();

    server.new_message(&mut client, connect_bytes);
    assert_eq!(client.last_msg(), &CONNACK_OK);
}

#[test]
fn test_ping() {
    let ping_bytes =  &[0xc0u8, 0][0..];

    let mut server = Server::new();
    let mut client = TestClient::new();

    server.new_message(&mut client, ping_bytes);

    assert_eq!(client.last_msg(), &PING_RESP);
}

#[test]
fn test_pings() {
    let ping_bytes = &[0xc0u8, 0, 0xc0, 0, 0xc0, 0, 0xc0, 0][0..];

    let mut server = Server::new();
    let mut client = TestClient::new();

    server.new_bytes(&mut client, ping_bytes);

    assert_eq!(client.last_msg(), &PING_RESP);
    assert_eq!(client.msgs.len(), 4);
    for msg in client.msgs {
        assert_eq!(msg, &PING_RESP);
    }

}
<|endoftext|>


<commit_before>use std::sync::Mutex;
use nix::sys::signal::Signal;

lazy_static! {
    static ref CLEANUP: Mutex<Option<Box<Fn(self::Signal) + Send>>> = Mutex::new(None);
}

pub fn new(signal_name: &str) -> Signal {
    println!("Using signal {}", signal_name);
    Signal::SIGTERM
}

#[cfg(unix)]
pub fn install_handler<F>(handler: F)
    where F: Fn(self::Signal) + 'static + Send + Sync
{
    use std::thread;
    use libc::c_int;
    use nix::sys::signal::*;

    // Mask all signals interesting to us. The mask propagates
    // to all threads started after this point.
    let mut mask = SigSet::empty();
    mask.add(SIGTERM);
    mask.add(SIGINT);
    // mask.add(SIGHUP);
    mask.add(SIGTSTP);
    mask.add(SIGCONT);
    mask.add(SIGCHLD);
    // mask.add(SIGUSR1);
    // mask.add(SIGUSR2);
    mask.thread_set_mask().expect("unable to set signal mask");

    set_handler(handler);

    // Indicate interest in SIGCHLD by setting a dummy handler
    pub extern "C" fn sigchld_handler(_: c_int) {}

    unsafe {
        let _ = sigaction(SIGCHLD,
                          &SigAction::new(SigHandler::Handler(sigchld_handler),
                                          SaFlags::empty(),
                                          SigSet::empty()));
    }

    // Spawn a thread to catch these signals
    thread::spawn(move || {
        loop {
            let signal = mask.wait().expect("Unable to sigwait");
            debug!("Received {:?}", signal);

            // Invoke closure
            invoke(signal);

            // Restore default behavior for received signal and unmask it
            if signal != SIGCHLD {
                let default_action =
                    SigAction::new(SigHandler::SigDfl, SaFlags::empty(), SigSet::empty());

                unsafe {
                    let _ = sigaction(signal, &default_action);
                }
            }

            let mut new_mask = SigSet::empty();
            new_mask.add(signal);

            // Re-raise with signal unmasked
            let _ = new_mask.thread_unblock();
            let _ = raise(signal);
            let _ = new_mask.thread_block();
        }
    });
}

#[cfg(windows)]
pub fn install_handler<F>(handler: F)
    where F: Fn(self::Signal) + 'static + Send + Sync
{
    use kernel32::SetConsoleCtrlHandler;
    use winapi::{BOOL, DWORD, FALSE, TRUE};

    pub unsafe extern "system" fn ctrl_handler(_: DWORD) -> BOOL {
        invoke(self::Signal::SIGTERM);

        FALSE
    }

    set_handler(handler);

    unsafe {
        SetConsoleCtrlHandler(Some(ctrl_handler), TRUE);
    }
}

fn invoke(sig: self::Signal) {
    if let Some(ref handler) = *CLEANUP.lock().unwrap() {
        handler(sig)
    }
}

fn set_handler<F>(handler: F)
    where F: Fn(self::Signal) + 'static + Send + Sync
{
    *CLEANUP.lock().unwrap() = Some(Box::new(handler));
}
<commit_msg>Add more signals to SigSet mask<commit_after>use std::sync::Mutex;
use nix::sys::signal::Signal;

lazy_static! {
    static ref CLEANUP: Mutex<Option<Box<Fn(self::Signal) + Send>>> = Mutex::new(None);
}

pub fn new(signal_name: &str) -> Signal {
    println!("Using signal {}", signal_name);
    Signal::SIGTERM
}

#[cfg(unix)]
pub fn install_handler<F>(handler: F)
    where F: Fn(self::Signal) + 'static + Send + Sync
{
    use std::thread;
    use libc::c_int;
    use nix::sys::signal::*;

    // Mask all signals interesting to us. The mask propagates
    // to all threads started after this point.
    let mut mask = SigSet::empty();
    mask.add(SIGKILL);
    mask.add(SIGTERM);
    mask.add(SIGINT);
    mask.add(SIGHUP);
    mask.add(SIGSTOP);
    mask.add(SIGCONT);
    mask.add(SIGCHLD);
    mask.add(SIGUSR1);
    mask.add(SIGUSR2);
    mask.thread_set_mask().expect("unable to set signal mask");

    set_handler(handler);

    // Indicate interest in SIGCHLD by setting a dummy handler
    pub extern "C" fn sigchld_handler(_: c_int) {}

    unsafe {
        let _ = sigaction(SIGCHLD,
                          &SigAction::new(SigHandler::Handler(sigchld_handler),
                                          SaFlags::empty(),
                                          SigSet::empty()));
    }

    // Spawn a thread to catch these signals
    thread::spawn(move || {
        loop {
            let signal = mask.wait().expect("Unable to sigwait");
            debug!("Received {:?}", signal);

            // Invoke closure
            invoke(signal);

            // Restore default behavior for received signal and unmask it
            if signal != SIGCHLD {
                let default_action =
                    SigAction::new(SigHandler::SigDfl, SaFlags::empty(), SigSet::empty());

                unsafe {
                    let _ = sigaction(signal, &default_action);
                }
            }

            let mut new_mask = SigSet::empty();
            new_mask.add(signal);

            // Re-raise with signal unmasked
            let _ = new_mask.thread_unblock();
            let _ = raise(signal);
            let _ = new_mask.thread_block();
        }
    });
}

#[cfg(windows)]
pub fn install_handler<F>(handler: F)
    where F: Fn(self::Signal) + 'static + Send + Sync
{
    use kernel32::SetConsoleCtrlHandler;
    use winapi::{BOOL, DWORD, FALSE, TRUE};

    pub unsafe extern "system" fn ctrl_handler(_: DWORD) -> BOOL {
        invoke(self::Signal::SIGTERM);

        FALSE
    }

    set_handler(handler);

    unsafe {
        SetConsoleCtrlHandler(Some(ctrl_handler), TRUE);
    }
}

fn invoke(sig: self::Signal) {
    if let Some(ref handler) = *CLEANUP.lock().unwrap() {
        handler(sig)
    }
}

fn set_handler<F>(handler: F)
    where F: Fn(self::Signal) + 'static + Send + Sync
{
    *CLEANUP.lock().unwrap() = Some(Box::new(handler));
}
<|endoftext|>


<commit_before>use metadata;
use frame;
use subframe;

use metadata::{Metadata, StreamInfo};
use frame::frame_parser;
use utility::{
  ErrorKind, ByteStream, ReadStream, StreamProducer, many_metadata,
};

use std::io;
use std::usize;
use std::fs::File;

/// FLAC stream that decodes and hold file information.
pub struct Stream
 {
  info: StreamInfo,
  metadata: Vec<Metadata>,
  producer: P,
}

/// Alias for a FLAC stream produced from `Read`.
pub type StreamReader<R>  = Stream<ReadStream<R>>;

/// Alias for a FLAC stream produced from a byte stream buffer.
pub type StreamBuffer<'a> = Stream<ByteStream<'a>>;

impl
 Stream
 where P: StreamProducer {
  /// Constructor for the default state of a FLAC stream.
  #[inline]
  pub fn new<R: io::Read>(reader: R) -> Result<StreamReader<R>, ErrorKind> {
    let producer = ReadStream::new(reader);

    Stream::from_stream_producer(producer)
  }

  /// Returns information for the current stream.
  #[inline]
  pub fn info(&self) -> StreamInfo {
    self.info
  }

  /// Returns a slice of `Metadata`
  ///
  /// This slice excludes `StreamInfo`, which is located in `Stream::info`.
  /// Everything else is related to metadata for the FLAC stream is in the
  /// slice.
  #[inline]
  pub fn metadata(&self) -> &[Metadata] {
    &self.metadata
  }

  /// Constructs a decoder with the given file name.
  ///
  /// # Failures
  ///
  /// * `ErrorKind::IO(io::ErrorKind::NotFound)` is returned when the given
  ///   filename isn't found.
  /// * `ErrorKind::IO(io::ErrorKind::InvalidData)` is returned when the data
  ///   within the file isn't valid FLAC data.
  /// * Several different parser specific errors that are structured as
  ///   `ErrorKind::<parser_name>Parser`.
  /// * Several different invalidation specific errors that are
  ///   structured as `ErrorKind::Invalid<invalidation_name>`.
  #[inline]
  pub fn from_file(filename: &str) -> Result<StreamReader<File>, ErrorKind> {
    File::open(filename).map_err(|e| ErrorKind::IO(e.kind()))
                        .and_then(|file| {
      let producer = ReadStream::new(file);

      Stream::from_stream_producer(producer)
    })
  }

  /// Constructs a decoder with the given buffer.
  ///
  /// This constructor assumes that an entire FLAC file is in the buffer.
  ///
  /// # Failures
  ///
  /// * `ErrorKind::IO(io::ErrorKind::InvalidData)` is returned when the data
  ///   within the file isn't valid FLAC data.
  /// * Several different parser specific errors that are structured as
  ///   `ErrorKind::<parser_name>Parser`.
  /// * Several different invalidation specific errors that are
  ///   structured as `ErrorKind::Invalid<invalidation_name>`.
  #[inline]
  pub fn from_buffer(buffer: &[u8]) -> Result<StreamBuffer, ErrorKind> {
    let producer = ByteStream::new(buffer);

    Stream::from_stream_producer(producer)
  }

  fn from_stream_producer(mut producer: P) -> Result<Self, ErrorKind> {
    let mut stream_info = StreamInfo::new();
    let mut metadata    = Vec::new();

    many_metadata(&mut producer, |block| {
      if let metadata::Data::StreamInfo(info) = block.data {
        stream_info = info;
      } else {
        metadata.push(block);
      }
    }).map(|_| {
      Stream {
        info: stream_info,
        metadata: metadata,
        producer: producer,
      }
    })
  }

  /// Returns an iterator over the decoded samples.
  #[inline]
  pub fn iter(&mut self) -> Iter
 {
    let samples_left = self.info.total_samples;
    let channels     = self.info.channels as usize;
    let block_size   = self.info.max_block_size as usize;
    let buffer_size  = block_size * channels;

    Iter {
      stream: self,
      channel: 0,
      block_size: 0,
      sample_index: 0,
      samples_left: samples_left,
      buffer: vec![0; buffer_size]
    }
  }

  fn next_frame(&mut self) -> Option<usize> {
    let stream_info = &self.info;
    let buffer      = &mut self.output;

    loop {
      match self.producer.parse(|i| frame_parser(i, stream_info, buffer)) {
        Ok(frame)                  => {
          let channels    = frame.header.channels as usize;
          let block_size  = frame.header.block_size as usize;
          let mut channel = 0;

          for subframe in &frame.subframes[0..channels] {
            let start  = channel * block_size;
            let end    = (channel + 1) * block_size;
            let output = &mut buffer[start..end];

            subframe::decode(&subframe, block_size, output);

            channel += 1;
          }

          frame::decode(frame.header.channel_assignment, buffer);

          return Some(block_size);
        }
        Err(ErrorKind::EndOfInput) => return None,
        Err(ErrorKind::Continue)   => continue,
        Err(_)                     => return None,
      }
    }
  }
}

/// An iterator over a reference of the decoded FLAC stream.
pub struct Iter<'a, P> where P: 'a + StreamProducer {
  stream: &'a mut Stream
,
  channel: usize,
  block_size: usize,
  sample_index: usize,
  samples_left: u64,
  buffer: Vec<i32>,
}

impl<'a, P> Iterator for Iter<'a, P> where P: StreamProducer {
  type Item = i32;

  fn next(&mut self) -> Option<Self::Item> {
    if self.sample_index == self.block_size {
      if let Some(block_size) = self.stream.next_frame() {
        self.sample_index = 0;
        self.block_size   = block_size;
      } else {
        return None;
      }
    }

    let channels = self.stream.info.channels as usize;
    let index    = self.sample_index + (self.channel * self.block_size);
    let sample   = self.stream.output[index];

    self.channel += 1;

    // Reset current channel
    if self.channel == channels {
      self.channel       = 0;
      self.sample_index += 1;
      self.samples_left -= 1;
    }

    Some(sample)
  }

  fn size_hint(&self) -> (usize, Option<usize>) {
    let samples_left = self.samples_left as usize;
    let max_value    = usize::max_value() as u64;

    // There is a chance that samples_left will be larger than a usize since
    // it is a u64. Make the upper bound None when it is.
    if self.samples_left > max_value {
      (samples_left, None)
    } else {
      (samples_left, Some(samples_left))
    }
  }
}

impl<'a, P> IntoIterator for &'a mut Stream

 where P: StreamProducer {
  type Item     = i32;
  type IntoIter = Iter<'a, P>;

  #[inline]
  fn into_iter(self) -> Self::IntoIter {
    self.iter()
  }
}
<commit_msg>Re-implement decoding with buffer in `Iter`<commit_after>use metadata;
use frame;
use subframe;

use metadata::{Metadata, StreamInfo};
use frame::frame_parser;
use utility::{
  ErrorKind, ByteStream, ReadStream, StreamProducer, many_metadata,
};

use std::io;
use std::usize;
use std::fs::File;

/// FLAC stream that decodes and hold file information.
pub struct Stream
 {
  info: StreamInfo,
  metadata: Vec<Metadata>,
  producer: P,
}

/// Alias for a FLAC stream produced from `Read`.
pub type StreamReader<R>  = Stream<ReadStream<R>>;

/// Alias for a FLAC stream produced from a byte stream buffer.
pub type StreamBuffer<'a> = Stream<ByteStream<'a>>;

impl
 Stream
 where P: StreamProducer {
  /// Constructor for the default state of a FLAC stream.
  #[inline]
  pub fn new<R: io::Read>(reader: R) -> Result<StreamReader<R>, ErrorKind> {
    let producer = ReadStream::new(reader);

    Stream::from_stream_producer(producer)
  }

  /// Returns information for the current stream.
  #[inline]
  pub fn info(&self) -> StreamInfo {
    self.info
  }

  /// Returns a slice of `Metadata`
  ///
  /// This slice excludes `StreamInfo`, which is located in `Stream::info`.
  /// Everything else is related to metadata for the FLAC stream is in the
  /// slice.
  #[inline]
  pub fn metadata(&self) -> &[Metadata] {
    &self.metadata
  }

  /// Constructs a decoder with the given file name.
  ///
  /// # Failures
  ///
  /// * `ErrorKind::IO(io::ErrorKind::NotFound)` is returned when the given
  ///   filename isn't found.
  /// * `ErrorKind::IO(io::ErrorKind::InvalidData)` is returned when the data
  ///   within the file isn't valid FLAC data.
  /// * Several different parser specific errors that are structured as
  ///   `ErrorKind::<parser_name>Parser`.
  /// * Several different invalidation specific errors that are
  ///   structured as `ErrorKind::Invalid<invalidation_name>`.
  #[inline]
  pub fn from_file(filename: &str) -> Result<StreamReader<File>, ErrorKind> {
    File::open(filename).map_err(|e| ErrorKind::IO(e.kind()))
                        .and_then(|file| {
      let producer = ReadStream::new(file);

      Stream::from_stream_producer(producer)
    })
  }

  /// Constructs a decoder with the given buffer.
  ///
  /// This constructor assumes that an entire FLAC file is in the buffer.
  ///
  /// # Failures
  ///
  /// * `ErrorKind::IO(io::ErrorKind::InvalidData)` is returned when the data
  ///   within the file isn't valid FLAC data.
  /// * Several different parser specific errors that are structured as
  ///   `ErrorKind::<parser_name>Parser`.
  /// * Several different invalidation specific errors that are
  ///   structured as `ErrorKind::Invalid<invalidation_name>`.
  #[inline]
  pub fn from_buffer(buffer: &[u8]) -> Result<StreamBuffer, ErrorKind> {
    let producer = ByteStream::new(buffer);

    Stream::from_stream_producer(producer)
  }

  fn from_stream_producer(mut producer: P) -> Result<Self, ErrorKind> {
    let mut stream_info = StreamInfo::new();
    let mut metadata    = Vec::new();

    many_metadata(&mut producer, |block| {
      if let metadata::Data::StreamInfo(info) = block.data {
        stream_info = info;
      } else {
        metadata.push(block);
      }
    }).map(|_| {
      Stream {
        info: stream_info,
        metadata: metadata,
        producer: producer,
      }
    })
  }

  /// Returns an iterator over the decoded samples.
  #[inline]
  pub fn iter(&mut self) -> Iter
 {
    let samples_left = self.info.total_samples;
    let channels     = self.info.channels as usize;
    let block_size   = self.info.max_block_size as usize;
    let buffer_size  = block_size * channels;

    Iter {
      stream: self,
      channel: 0,
      block_size: 0,
      sample_index: 0,
      samples_left: samples_left,
      buffer: vec![0; buffer_size]
    }
  }

  fn next_frame(&mut self, buffer: &mut [i32]) -> Option<usize> {
    let stream_info = &self.info;

    loop {
      match self.producer.parse(|i| frame_parser(i, stream_info, buffer)) {
        Ok(frame)                  => {
          let channels    = frame.header.channels as usize;
          let block_size  = frame.header.block_size as usize;
          let mut channel = 0;

          for subframe in &frame.subframes[0..channels] {
            let start  = channel * block_size;
            let end    = (channel + 1) * block_size;
            let output = &mut buffer[start..end];

            subframe::decode(&subframe, block_size, output);

            channel += 1;
          }

          frame::decode(frame.header.channel_assignment, buffer);

          return Some(block_size);
        }
        Err(ErrorKind::EndOfInput) => return None,
        Err(ErrorKind::Continue)   => continue,
        Err(_)                     => return None,
      }
    }
  }
}

/// An iterator over a reference of the decoded FLAC stream.
pub struct Iter<'a, P> where P: 'a + StreamProducer {
  stream: &'a mut Stream
,
  channel: usize,
  block_size: usize,
  sample_index: usize,
  samples_left: u64,
  buffer: Vec<i32>,
}

impl<'a, P> Iterator for Iter<'a, P> where P: StreamProducer {
  type Item = i32;

  fn next(&mut self) -> Option<Self::Item> {
    if self.sample_index == self.block_size {
      let buffer = &mut self.buffer;

      if let Some(block_size) = self.stream.next_frame(buffer) {
        self.sample_index = 0;
        self.block_size   = block_size;
      } else {
        return None;
      }
    }

    let channels = self.stream.info.channels as usize;
    let index    = self.sample_index + (self.channel * self.block_size);
    let sample   = self.buffer[index];

    self.channel += 1;

    // Reset current channel
    if self.channel == channels {
      self.channel       = 0;
      self.sample_index += 1;
      self.samples_left -= 1;
    }

    Some(sample)
  }

  fn size_hint(&self) -> (usize, Option<usize>) {
    let samples_left = self.samples_left as usize;
    let max_value    = usize::max_value() as u64;

    // There is a chance that samples_left will be larger than a usize since
    // it is a u64. Make the upper bound None when it is.
    if self.samples_left > max_value {
      (samples_left, None)
    } else {
      (samples_left, Some(samples_left))
    }
  }
}

impl<'a, P> IntoIterator for &'a mut Stream

 where P: StreamProducer {
  type Item     = i32;
  type IntoIter = Iter<'a, P>;

  #[inline]
  fn into_iter(self) -> Self::IntoIter {
    self.iter()
  }
}
<|endoftext|>


<commit_before>use {Stride, MutStride};
use std::ops::{Deref, DerefMut};

/// Things that can be viewed as a series of equally spaced `T`s in
/// memory.
pub trait Strided {
    type Elem;
    fn as_stride(&self) -> Stride<Self::Elem>;

    fn stride(&self) -> usize {
        self.as_stride().stride()
    }
}

/// Things that can be viewed as a series of mutable equally spaced
/// `T`s in memory.
pub trait MutStrided : Strided {
    fn as_stride_mut(&mut self) -> MutStride<<Self as Strided>::Elem>;
}

// this isn't as general as it could be.
impl<T, X: Deref<Target=[T]>> Strided for X {
    type Elem = T;
    fn as_stride(&self) -> Stride<T> {
        Stride::new(&**self)
    }

    #[inline(always)]
    fn stride(&self) -> usize {
        1
    }
}
impl<T, X: DerefMut + Deref<Target=[T]>> MutStrided for X {
    fn as_stride_mut(&mut self) -> MutStride<T> {
        MutStride::new(&mut **self)
    }
}

impl<T> Strided for [T] {
    type Elem = T;
    fn as_stride(&self) -> Stride<T> { Stride::new(self) }
    #[inline(always)]
    fn stride(&self) -> usize { 1 }
}
impl<T> MutStrided for [T] {
    fn as_stride_mut(&mut self) -> MutStride<T> { MutStride::new(self) }
}

impl<'a,T> Strided for Stride<'a,T> {
    type Elem = T;
    fn as_stride(&self) -> Stride<T> { *self }
    fn stride(&self) -> usize { Stride::stride(self) }
}
impl<'a,T> Strided for MutStride<'a,T> {
    type Elem = T;
    fn as_stride(&self) -> Stride<T> { **self }
    fn stride(&self) -> usize { MutStride::stride(self) }
}
impl<'a,T> MutStrided for MutStride<'a,T> {
    fn as_stride_mut(&mut self) -> MutStride<T> { self.reborrow() }
}
<commit_msg>Add From implementations.<commit_after>use {Stride, MutStride};
use std::ops::{Deref, DerefMut};

/// Things that can be viewed as a series of equally spaced `T`s in
/// memory.
pub trait Strided {
    type Elem;
    fn as_stride(&self) -> Stride<Self::Elem>;

    fn stride(&self) -> usize {
        self.as_stride().stride()
    }
}

/// Things that can be viewed as a series of mutable equally spaced
/// `T`s in memory.
pub trait MutStrided : Strided {
    fn as_stride_mut(&mut self) -> MutStride<<Self as Strided>::Elem>;
}

// this isn't as general as it could be.
impl<T, X: Deref<Target=[T]>> Strided for X {
    type Elem = T;
    fn as_stride(&self) -> Stride<T> {
        Stride::new(&**self)
    }

    #[inline(always)]
    fn stride(&self) -> usize {
        1
    }
}
impl<T, X: DerefMut + Deref<Target=[T]>> MutStrided for X {
    fn as_stride_mut(&mut self) -> MutStride<T> {
        MutStride::new(&mut **self)
    }
}

impl<T> Strided for [T] {
    type Elem = T;
    fn as_stride(&self) -> Stride<T> { Stride::new(self) }
    #[inline(always)]
    fn stride(&self) -> usize { 1 }
}
impl<T> MutStrided for [T] {
    fn as_stride_mut(&mut self) -> MutStride<T> { MutStride::new(self) }
}

impl<'a,T> Strided for Stride<'a,T> {
    type Elem = T;
    fn as_stride(&self) -> Stride<T> { *self }
    fn stride(&self) -> usize { Stride::stride(self) }
}
impl<'a,T> Strided for MutStride<'a,T> {
    type Elem = T;
    fn as_stride(&self) -> Stride<T> { **self }
    fn stride(&self) -> usize { MutStride::stride(self) }
}
impl<'a,T> MutStrided for MutStride<'a,T> {
    fn as_stride_mut(&mut self) -> MutStride<T> { self.reborrow() }
}

impl<'a,T, X: AsRef<[T]> + ?Sized> From<&'a X> for Stride<'a,T> {
    fn from(value: &X) -> Stride<T> { Stride::new(value.as_ref()) }
}
impl<'a,T, X: AsMut<[T]> + ?Sized> From<&'a mut X> for MutStride<'a,T> {
    fn from(value: &mut X) -> MutStride<T> { MutStride::new(value.as_mut()) }
}
<|endoftext|>


<commit_before>use std::ffi::CString;
use std::io::{IoResult, IoError, File, Open, ReadWrite};
use std::os::unix::prelude::AsRawFd;
use libc::c_int;
use libc::consts::os::bsd44::{AF_INET6, SOCK_DGRAM};
use libc::funcs::bsd43::socket;
use libc::funcs::bsd44::ioctl;
use libc::funcs::posix88::unistd::close;
use libc::types::os::common::bsd44::in6_addr;
use c_interop::*;

const DEVICE_PATH: &'static str = "/dev/net/tun";

// TODO Make not a constant
const MTU_SIZE: usize = 1500;

#[derive(Copy, Clone, Eq, PartialEq, Hash)]
pub enum TunTapType {
	Tun,
	Tap
}

pub struct TunTap {
	pub file: File,
	sock: c_int,
	if_name: [u8; IFNAMSIZ],
	if_index: c_int
}

impl Drop for TunTap {
	fn drop(&mut self) {
		unsafe { close(self.sock) };
	}
}

impl TunTap {
	pub fn create(typ: TunTapType) -> TunTap {
		TunTap::create_named(typ, &CString::from_slice(&[]))
	}

	pub fn create_named(typ: TunTapType, name: &CString) -> TunTap {
		let (file, if_name) = TunTap::create_if(typ, name);
		let (sock, if_index) = TunTap::create_socket(if_name);

		TunTap {
			file: file,
			sock: sock,
			if_name: if_name,
			if_index: if_index
		}
	}

	fn create_if(typ: TunTapType, name: &CString) -> (File, [u8; IFNAMSIZ]) {
		let name_slice = name.as_bytes_with_nul();
		if name_slice.len() > IFNAMSIZ {
			panic!("Interface name too long, max length is {}", IFNAMSIZ - 1);
		}

		let path = Path::new(DEVICE_PATH);
		let file = match File::open_mode(&path, Open, ReadWrite) {
			Err(why) => panic!("Couldn't open tun device '{}': {}", path.display(), why.desc),
			Ok(file) => file,
		};

		let mut req = ioctl_flags_data {
			ifr_name: {
				let mut buffer = [0u8; IFNAMSIZ];
				buffer.clone_from_slice(name_slice);
				buffer
			},
			ifr_flags: match typ {
				TunTapType::Tun => IFF_TUN,
				TunTapType::Tap => IFF_TAP
			}
		};

		let res = unsafe { ioctl(file.as_raw_fd(), TUNSETIFF, &mut req) };
		if res < 0 {
			panic!("{}", IoError::last_error());
		}

		(file, req.ifr_name)
	}

	fn create_socket(if_name: [u8; IFNAMSIZ]) -> (c_int, c_int) {
		let sock = unsafe { socket(AF_INET6, SOCK_DGRAM, 0) };
		if sock < 0 {
			panic!("{}", IoError::last_error());
		}

		let mut req = ioctl_ifindex_data {
			ifr_name: if_name,
			ifr_ifindex: -1
		};

		let res = unsafe { ioctl(sock, SIOCGIFINDEX, &mut req) };
		if res < 0 {
			let err = IoError::last_error();
			unsafe { close(sock) };
			panic!("{}", err);
		}

		(sock, req.ifr_ifindex)
	}

	pub fn get_name(&self) -> CString {
		let nul_pos = match self.if_name.as_slice().position_elem(&0) {
			Some(p) => p,
			None => panic!("Device name should be null-terminated")
		};

		CString::from_slice(self.if_name.slice_to(nul_pos))
	}

	pub fn up(&self) {
		let mut req = ioctl_flags_data {
			ifr_name: self.if_name,
			ifr_flags: 0
		};

		let res = unsafe { ioctl(self.sock, SIOCGIFFLAGS, &mut req) };
		if res < 0 {
			panic!("{}", IoError::last_error());
		}

		if req.ifr_flags & IFF_UP & IFF_RUNNING != 0 {
			// Already up
			return;
		}

		req.ifr_flags |= IFF_UP | IFF_RUNNING;

		let res = unsafe { ioctl(self.sock, SIOCSIFFLAGS, &mut req) };
		if res < 0 {
			panic!("{}", IoError::last_error());
		}
	}

	pub fn add_address(&self, ip: &[u8]) {
		self.up();

		if ip.len() == 4 {
			panic!("IPv4 not implemented");
		}
		else if ip.len() == 16 {
			let mut req = in6_ifreq {
				ifr6_addr: in6_addr {s6_addr: [
					(ip[ 1] as u16) << 8 | ip[ 0] as u16,
					(ip[ 3] as u16) << 8 | ip[ 2] as u16,
					(ip[ 5] as u16) << 8 | ip[ 4] as u16,
					(ip[ 7] as u16) << 8 | ip[ 6] as u16,
					(ip[ 9] as u16) << 8 | ip[ 8] as u16,
					(ip[11] as u16) << 8 | ip[10] as u16,
					(ip[13] as u16) << 8 | ip[12] as u16,
					(ip[15] as u16) << 8 | ip[14] as u16
				]},
				ifr6_prefixlen: 8,
				ifr6_ifindex: self.if_index
			};

			let res = unsafe { ioctl(self.sock, SIOCSIFADDR, &mut req) };
			if res < 0 {
				panic!("{}", IoError::last_error());
			}
		}
		else {
			panic!("IP length must be either 4 or 16 bytes, got {}", ip.len());
		}
	}

	pub fn read<'a>(&mut self, buffer: &'a mut [u8]) -> IoResult<&'a [u8]> {
		assert!(buffer.len() >= MTU_SIZE);

		let len = try!(self.file.read(buffer));
		Ok(buffer.slice_to(len))
	}

	pub fn write(&mut self, data: &[u8]) -> IoResult<()> {
		self.file.write(data)
	}
}
<commit_msg>Implement Show<commit_after>use std::ffi::CString;
use std::fmt;
use std::io::{IoResult, IoError, File, Open, ReadWrite};
use std::os::unix::prelude::AsRawFd;
use libc::c_int;
use libc::consts::os::bsd44::{AF_INET6, SOCK_DGRAM};
use libc::funcs::bsd43::socket;
use libc::funcs::bsd44::ioctl;
use libc::funcs::posix88::unistd::close;
use libc::types::os::common::bsd44::in6_addr;
use c_interop::*;

const DEVICE_PATH: &'static str = "/dev/net/tun";

// TODO Make not a constant
const MTU_SIZE: usize = 1500;

#[derive(Show, Copy, Clone, Eq, PartialEq, Hash)]
pub enum TunTapType {
	Tun,
	Tap
}

pub struct TunTap {
	pub file: File,
	sock: c_int,
	if_name: [u8; IFNAMSIZ],
	if_index: c_int
}

impl Drop for TunTap {
	fn drop(&mut self) {
		unsafe { close(self.sock) };
	}
}

impl fmt::Show for TunTap {
	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
		write!(f, "Tun({:?})", self.get_name())
	}
}

impl TunTap {
	pub fn create(typ: TunTapType) -> TunTap {
		TunTap::create_named(typ, &CString::from_slice(&[]))
	}

	pub fn create_named(typ: TunTapType, name: &CString) -> TunTap {
		let (file, if_name) = TunTap::create_if(typ, name);
		let (sock, if_index) = TunTap::create_socket(if_name);

		TunTap {
			file: file,
			sock: sock,
			if_name: if_name,
			if_index: if_index
		}
	}

	fn create_if(typ: TunTapType, name: &CString) -> (File, [u8; IFNAMSIZ]) {
		let name_slice = name.as_bytes_with_nul();
		if name_slice.len() > IFNAMSIZ {
			panic!("Interface name too long, max length is {}", IFNAMSIZ - 1);
		}

		let path = Path::new(DEVICE_PATH);
		let file = match File::open_mode(&path, Open, ReadWrite) {
			Err(why) => panic!("Couldn't open tun device '{}': {}", path.display(), why.desc),
			Ok(file) => file,
		};

		let mut req = ioctl_flags_data {
			ifr_name: {
				let mut buffer = [0u8; IFNAMSIZ];
				buffer.clone_from_slice(name_slice);
				buffer
			},
			ifr_flags: match typ {
				TunTapType::Tun => IFF_TUN,
				TunTapType::Tap => IFF_TAP
			}
		};

		let res = unsafe { ioctl(file.as_raw_fd(), TUNSETIFF, &mut req) };
		if res < 0 {
			panic!("{}", IoError::last_error());
		}

		(file, req.ifr_name)
	}

	fn create_socket(if_name: [u8; IFNAMSIZ]) -> (c_int, c_int) {
		let sock = unsafe { socket(AF_INET6, SOCK_DGRAM, 0) };
		if sock < 0 {
			panic!("{}", IoError::last_error());
		}

		let mut req = ioctl_ifindex_data {
			ifr_name: if_name,
			ifr_ifindex: -1
		};

		let res = unsafe { ioctl(sock, SIOCGIFINDEX, &mut req) };
		if res < 0 {
			let err = IoError::last_error();
			unsafe { close(sock) };
			panic!("{}", err);
		}

		(sock, req.ifr_ifindex)
	}

	pub fn get_name(&self) -> CString {
		let nul_pos = match self.if_name.as_slice().position_elem(&0) {
			Some(p) => p,
			None => panic!("Device name should be null-terminated")
		};

		CString::from_slice(self.if_name.slice_to(nul_pos))
	}

	pub fn up(&self) {
		let mut req = ioctl_flags_data {
			ifr_name: self.if_name,
			ifr_flags: 0
		};

		let res = unsafe { ioctl(self.sock, SIOCGIFFLAGS, &mut req) };
		if res < 0 {
			panic!("{}", IoError::last_error());
		}

		if req.ifr_flags & IFF_UP & IFF_RUNNING != 0 {
			// Already up
			return;
		}

		req.ifr_flags |= IFF_UP | IFF_RUNNING;

		let res = unsafe { ioctl(self.sock, SIOCSIFFLAGS, &mut req) };
		if res < 0 {
			panic!("{}", IoError::last_error());
		}
	}

	pub fn add_address(&self, ip: &[u8]) {
		self.up();

		if ip.len() == 4 {
			panic!("IPv4 not implemented");
		}
		else if ip.len() == 16 {
			let mut req = in6_ifreq {
				ifr6_addr: in6_addr {s6_addr: [
					(ip[ 1] as u16) << 8 | ip[ 0] as u16,
					(ip[ 3] as u16) << 8 | ip[ 2] as u16,
					(ip[ 5] as u16) << 8 | ip[ 4] as u16,
					(ip[ 7] as u16) << 8 | ip[ 6] as u16,
					(ip[ 9] as u16) << 8 | ip[ 8] as u16,
					(ip[11] as u16) << 8 | ip[10] as u16,
					(ip[13] as u16) << 8 | ip[12] as u16,
					(ip[15] as u16) << 8 | ip[14] as u16
				]},
				ifr6_prefixlen: 8,
				ifr6_ifindex: self.if_index
			};

			let res = unsafe { ioctl(self.sock, SIOCSIFADDR, &mut req) };
			if res < 0 {
				panic!("{}", IoError::last_error());
			}
		}
		else {
			panic!("IP length must be either 4 or 16 bytes, got {}", ip.len());
		}
	}

	pub fn read<'a>(&mut self, buffer: &'a mut [u8]) -> IoResult<&'a [u8]> {
		assert!(buffer.len() >= MTU_SIZE);

		let len = try!(self.file.read(buffer));
		Ok(buffer.slice_to(len))
	}

	pub fn write(&mut self, data: &[u8]) -> IoResult<()> {
		self.file.write(data)
	}
}
<|endoftext|>


<commit_before>extern crate mio;
extern crate mio_aio;
extern crate tempfile;

use mio::{Events, Poll, PollOpt, Token};
use mio::unix::UnixReady;
use tempfile::tempfile;
use std::os::unix::io::AsRawFd;
use std::io::{Read, Seek, SeekFrom, Write};
use std::ops::Deref;

const UDATA: Token = Token(0xdead_beef);

#[test]
pub fn test_aio_cancel() {
    const WBUF: &[u8] = b"abcdef";
    let f = tempfile().unwrap();

    let poll = Poll::new().unwrap();
    let mut events = Events::with_capacity(1024);
    let mut aiocb = mio_aio::AioCb::from_slice(f.as_raw_fd(),
        0,   //offset
        &WBUF,
        0,   //priority
        mio_aio::LioOpcode::LIO_NOP);
    poll.register(&aiocb, UDATA, UnixReady::aio().into(), PollOpt::empty())
        .expect("registration failed");

    aiocb.write().unwrap();
    aiocb.cancel().expect("aio_cancel failed");

    poll.poll(&mut events, None).expect("poll failed");
    let mut it = events.iter();
    let ev = it.next().unwrap();
    assert_eq!(ev.token(), UDATA);
    assert!(UnixReady::from(ev.readiness()).is_aio());

    // Since we cancelled the I/O, we musn't care whether it succeeded.
    let _ = aiocb.aio_return();
    assert!(it.next().is_none());
}

#[test]
pub fn test_aio_fsync() {
    const INITIAL: &[u8] = b"abcdef123456";
    let mut f = tempfile().unwrap();
    f.write_all(INITIAL).unwrap();
    let poll = Poll::new().unwrap();
    let mut events = Events::with_capacity(1024);

    let mut aiocb = mio_aio::AioCb::from_fd( f.as_raw_fd(), 0);
    poll.register(&aiocb, UDATA, UnixReady::aio().into(), PollOpt::empty())
        .expect("registration failed");

    aiocb.fsync(mio_aio::AioFsyncMode::O_SYNC).unwrap();
    poll.poll(&mut events, None).expect("poll failed");
    let mut it = events.iter();
    let ev = it.next().unwrap();
    assert_eq!(ev.token(), UDATA);
    assert!(UnixReady::from(ev.readiness()).is_aio());

    assert!(aiocb.error().is_ok());
    aiocb.aio_return().unwrap();
    assert!(it.next().is_none());
}

#[test]
pub fn test_aio_read() {
    const INITIAL: &[u8] = b"abcdef123456";
    let mut rbuf = vec![0; 4];
    const EXPECT: &[u8] = b"cdef";
    let mut f = tempfile().unwrap();
    f.write_all(INITIAL).unwrap();

    let poll = Poll::new().unwrap();
    let mut events = Events::with_capacity(1024);
    {
        let mut aiocb = mio_aio::AioCb::from_mut_slice(f.as_raw_fd(),
            2,   //offset
            &mut rbuf,
            0,   //priority
            mio_aio::LioOpcode::LIO_NOP);
        poll.register(&aiocb, UDATA, UnixReady::aio().into(), PollOpt::empty())
            .expect("registration failed");

        aiocb.read().unwrap();

        poll.poll(&mut events, None).expect("poll failed");
        let mut it = events.iter();
        let ev = it.next().unwrap();
        assert_eq!(ev.token(), UDATA);
        assert!(UnixReady::from(ev.readiness()).is_aio());

        assert!(aiocb.error().is_ok());
        assert_eq!(aiocb.aio_return().unwrap(), EXPECT.len() as isize);
        assert!(it.next().is_none());
    }
    assert!(rbuf.deref().deref() == EXPECT);
}

#[test]
pub fn test_aio_write() {
    let wbuf = String::from("abcdef").into_bytes().into_boxed_slice();
    let mut f = tempfile().unwrap();
    let mut rbuf = Vec::new();

    let poll = Poll::new().unwrap();
    let mut events = Events::with_capacity(1024);
    let mut aiocb = mio_aio::AioCb::from_slice(f.as_raw_fd(),
        0,   //offset
        &wbuf,
        0,   //priority
        mio_aio::LioOpcode::LIO_NOP);
    poll.register(&aiocb, UDATA, UnixReady::aio().into(), PollOpt::empty())
        .expect("registration failed");

    aiocb.write().unwrap();

    poll.poll(&mut events, None).expect("poll failed");
    let mut it = events.iter();
    let ev = it.next().unwrap();
    assert_eq!(ev.token(), UDATA);
    assert!(UnixReady::from(ev.readiness()).is_aio());

    assert!(aiocb.error().is_ok());
    assert_eq!(aiocb.aio_return().unwrap(), wbuf.len() as isize);
    f.seek(SeekFrom::Start(0)).unwrap();
    let len = f.read_to_end(&mut rbuf).unwrap();
    assert!(len == wbuf.len());
    assert!(rbuf == wbuf.deref().deref());
    assert!(it.next().is_none());
}

#[test]
pub fn test_aio_write_static() {
    const WBUF: &[u8] = b"abcdef";
    let mut f = tempfile().unwrap();
    let mut rbuf = Vec::new();

    let poll = Poll::new().unwrap();
    let mut events = Events::with_capacity(1024);
    let mut aiocb = mio_aio::AioCb::from_slice(f.as_raw_fd(),
        0,   //offset
        &WBUF,
        0,   //priority
        mio_aio::LioOpcode::LIO_NOP);
    poll.register(&aiocb, UDATA, UnixReady::aio().into(), PollOpt::empty())
        .expect("registration failed");

    aiocb.write().unwrap();

    poll.poll(&mut events, None).expect("poll failed");
    let mut it = events.iter();
    let ev = it.next().unwrap();
    assert_eq!(ev.token(), UDATA);
    assert!(UnixReady::from(ev.readiness()).is_aio());

    assert!(aiocb.error().is_ok());
    assert_eq!(aiocb.aio_return().unwrap(), WBUF.len() as isize);
    f.seek(SeekFrom::Start(0)).unwrap();
    let len = f.read_to_end(&mut rbuf).unwrap();
    assert!(len == WBUF.len());
    assert!(rbuf == WBUF);
    assert!(it.next().is_none());
}

// lio_listio returns EIO because one of its children failed
#[test]
pub fn test_lio_eio() {
    let wbuf0 = &b"abcdef"[..];
    let poll = Poll::new().unwrap();

    let mut builder = mio_aio::LioCbBuilder::with_capacity(1);
    let fd = -1;    // Illegal file descriptor
    builder = builder.emplace_slice(fd, 0, wbuf0, 0,
                        mio_aio::LioOpcode::LIO_WRITE);
    let mut liocb = builder.finish();
    poll.register(&liocb, UDATA, UnixReady::lio().into(), PollOpt::empty())
        .expect("registration failed");

    let r = liocb.submit();
    let expected = Err(mio_aio::Errno::EBADF);
    assert_eq!(r.unwrap_err().into_eio().unwrap()[0], expected);
}

#[test]
pub fn test_lio_oneread() {
    const INITIAL: &[u8] = b"abcdef123456";
    const EXPECT: &[u8] = b"cdef";
    let mut f = tempfile().unwrap();
    //let dbs = DivBufShared::from(vec![0; 4]);
    let mut buf = vec![0; 4];
    f.write_all(INITIAL).unwrap();

    let poll = Poll::new().unwrap();
    let mut events = Events::with_capacity(1024);

    let mut builder = mio_aio::LioCbBuilder::with_capacity(1);
    builder = builder.emplace_mut_slice(f.as_raw_fd(), 2, &mut buf[..], 0,
        mio_aio::LioOpcode::LIO_READ);
    let mut liocb = builder.finish();
    poll.register(&liocb, UDATA, UnixReady::lio().into(), PollOpt::empty())
        .expect("registration failed");

    liocb.submit().unwrap();

    poll.poll(&mut events, None).expect("poll failed");
    let mut it = events.iter();
    let ev = it.next().unwrap();
    assert_eq!(ev.token(), UDATA);
    assert!(UnixReady::from(ev.readiness()).is_lio());

    liocb.into_results(|mut iter| {
        let lr = iter.next().unwrap();
        assert_eq!(lr.result.unwrap(), EXPECT.len() as isize);
        assert!(iter.next().is_none());
    });
    assert!(it.next().is_none());
    assert_eq!(EXPECT, &buf[..]);
}

#[test]
pub fn test_lio_onewrite() {
    let wbuf = b"abcdef";
    let mut f = tempfile().unwrap();
    let mut rbuf = Vec::new();

    let poll = Poll::new().unwrap();
    let mut events = Events::with_capacity(1024);

    let mut builder = mio_aio::LioCbBuilder::with_capacity(1);
    builder = builder.emplace_slice(f.as_raw_fd(), 0, &wbuf[..], 0,
                        mio_aio::LioOpcode::LIO_WRITE);
    let mut liocb = builder.finish();
    poll.register(&liocb, UDATA, UnixReady::lio().into(), PollOpt::empty())
        .expect("registration failed");

    liocb.submit().unwrap();

    poll.poll(&mut events, None).expect("poll failed");
    let mut it = events.iter();
    let ev = it.next().unwrap();
    assert_eq!(ev.token(), UDATA);
    assert!(UnixReady::from(ev.readiness()).is_lio());

    liocb.into_results(|mut iter| {
        let lr = iter.next().unwrap();
        assert_eq!(lr.result.unwrap(), wbuf.len() as isize);
        assert!(iter.next().is_none());
    });
    f.seek(SeekFrom::Start(0)).unwrap();
    let len = f.read_to_end(&mut rbuf).unwrap();
    assert_eq!(len, wbuf.len());
    assert_eq!(&wbuf[..], &rbuf[..]);
    assert!(it.next().is_none());
}

#[test]
pub fn test_lio_tworeads() {
    const INITIAL: &[u8] = b"abcdef123456";
    const EXPECT0: &[u8] = b"cdef";
    const EXPECT1: &[u8] = b"23456";
    let mut f = tempfile().unwrap();
    let mut rbuf0 = vec![0; 4];
    let mut rbuf1 = vec![0; 5];
    f.write_all(INITIAL).unwrap();

    let poll = Poll::new().unwrap();
    let mut events = Events::with_capacity(1024);

    let mut builder = mio_aio::LioCbBuilder::with_capacity(2);
    builder = builder.emplace_mut_slice(f.as_raw_fd(), 2, &mut rbuf0[..], 0,
                            mio_aio::LioOpcode::LIO_READ);
    builder = builder.emplace_mut_slice(f.as_raw_fd(), 7, &mut rbuf1[..], 0,
                            mio_aio::LioOpcode::LIO_READ);
    let mut liocb = builder.finish();
    poll.register(&liocb, UDATA, UnixReady::lio().into(), PollOpt::empty())
        .expect("registration failed");

    liocb.submit().unwrap();

    poll.poll(&mut events, None).expect("poll failed");
    let mut it = events.iter();
    let ev = it.next().unwrap();
    assert_eq!(ev.token(), UDATA);
    assert!(UnixReady::from(ev.readiness()).is_lio());

    liocb.into_results(|mut iter| {
        let lr0 = iter.next().unwrap();
        assert_eq!(lr0.result.unwrap(), EXPECT0.len() as isize);
        let lr1 = iter.next().unwrap();
        assert_eq!(lr1.result.unwrap(), EXPECT1.len() as isize);
        assert!(iter.next().is_none());
    });
    assert_eq!(&rbuf0[..], EXPECT0);
    assert_eq!(&rbuf1[..], EXPECT1);

    assert!(it.next().is_none());
}

#[test]
pub fn test_lio_read_and_write() {
    const INITIAL0: &[u8] = b"abcdef123456";
    const WBUF1: &[u8] = b"ABCDEFGHIJKL";
    const EXPECT0: &[u8] = b"cdef";
    let mut f0 = tempfile().unwrap();
    let mut f1 = tempfile().unwrap();
    let mut rbuf0 = vec![0; 4];
    let mut rbuf1 = Vec::new();
    f0.write_all(INITIAL0).unwrap();

    let poll = Poll::new().unwrap();
    let mut events = Events::with_capacity(1024);

    let mut builder = mio_aio::LioCbBuilder::with_capacity(2);
    builder = builder.emplace_mut_slice(f0.as_raw_fd(), 2, &mut rbuf0[..], 0,
                            mio_aio::LioOpcode::LIO_READ);
    builder = builder.emplace_slice(f1.as_raw_fd(), 0, WBUF1, 0,
                        mio_aio::LioOpcode::LIO_WRITE);
    let mut liocb = builder.finish();
    poll.register(&liocb, UDATA, UnixReady::lio().into(), PollOpt::empty())
        .expect("registration failed");

    liocb.submit().unwrap();

    poll.poll(&mut events, None).expect("poll failed");
    let mut it = events.iter();
    let ev = it.next().unwrap();
    assert_eq!(ev.token(), UDATA);
    assert!(UnixReady::from(ev.readiness()).is_lio());

    liocb.into_results(|mut iter| {
        let lr0 = iter.next().unwrap();
        assert_eq!(lr0.result.unwrap(), EXPECT0.len() as isize);

        let lr1 = iter.next().unwrap();
        assert_eq!(lr1.result.unwrap(), WBUF1.len() as isize);

        assert!(iter.next().is_none());
    });
    assert_eq!(&rbuf0[..], EXPECT0);

    f1.seek(SeekFrom::Start(0)).unwrap();
    let len = f1.read_to_end(&mut rbuf1).unwrap();
    assert_eq!(len, WBUF1.len());
    assert_eq!(rbuf1, WBUF1);

    assert!(it.next().is_none());
}
<commit_msg>Clippy cleanup: needless_borrow<commit_after>extern crate mio;
extern crate mio_aio;
extern crate tempfile;

use mio::{Events, Poll, PollOpt, Token};
use mio::unix::UnixReady;
use tempfile::tempfile;
use std::os::unix::io::AsRawFd;
use std::io::{Read, Seek, SeekFrom, Write};
use std::ops::Deref;

const UDATA: Token = Token(0xdead_beef);

#[test]
pub fn test_aio_cancel() {
    const WBUF: &[u8] = b"abcdef";
    let f = tempfile().unwrap();

    let poll = Poll::new().unwrap();
    let mut events = Events::with_capacity(1024);
    let mut aiocb = mio_aio::AioCb::from_slice(f.as_raw_fd(),
        0,   //offset
        WBUF,
        0,   //priority
        mio_aio::LioOpcode::LIO_NOP);
    poll.register(&aiocb, UDATA, UnixReady::aio().into(), PollOpt::empty())
        .expect("registration failed");

    aiocb.write().unwrap();
    aiocb.cancel().expect("aio_cancel failed");

    poll.poll(&mut events, None).expect("poll failed");
    let mut it = events.iter();
    let ev = it.next().unwrap();
    assert_eq!(ev.token(), UDATA);
    assert!(UnixReady::from(ev.readiness()).is_aio());

    // Since we cancelled the I/O, we musn't care whether it succeeded.
    let _ = aiocb.aio_return();
    assert!(it.next().is_none());
}

#[test]
pub fn test_aio_fsync() {
    const INITIAL: &[u8] = b"abcdef123456";
    let mut f = tempfile().unwrap();
    f.write_all(INITIAL).unwrap();
    let poll = Poll::new().unwrap();
    let mut events = Events::with_capacity(1024);

    let mut aiocb = mio_aio::AioCb::from_fd( f.as_raw_fd(), 0);
    poll.register(&aiocb, UDATA, UnixReady::aio().into(), PollOpt::empty())
        .expect("registration failed");

    aiocb.fsync(mio_aio::AioFsyncMode::O_SYNC).unwrap();
    poll.poll(&mut events, None).expect("poll failed");
    let mut it = events.iter();
    let ev = it.next().unwrap();
    assert_eq!(ev.token(), UDATA);
    assert!(UnixReady::from(ev.readiness()).is_aio());

    assert!(aiocb.error().is_ok());
    aiocb.aio_return().unwrap();
    assert!(it.next().is_none());
}

#[test]
pub fn test_aio_read() {
    const INITIAL: &[u8] = b"abcdef123456";
    let mut rbuf = vec![0; 4];
    const EXPECT: &[u8] = b"cdef";
    let mut f = tempfile().unwrap();
    f.write_all(INITIAL).unwrap();

    let poll = Poll::new().unwrap();
    let mut events = Events::with_capacity(1024);
    {
        let mut aiocb = mio_aio::AioCb::from_mut_slice(f.as_raw_fd(),
            2,   //offset
            &mut rbuf,
            0,   //priority
            mio_aio::LioOpcode::LIO_NOP);
        poll.register(&aiocb, UDATA, UnixReady::aio().into(), PollOpt::empty())
            .expect("registration failed");

        aiocb.read().unwrap();

        poll.poll(&mut events, None).expect("poll failed");
        let mut it = events.iter();
        let ev = it.next().unwrap();
        assert_eq!(ev.token(), UDATA);
        assert!(UnixReady::from(ev.readiness()).is_aio());

        assert!(aiocb.error().is_ok());
        assert_eq!(aiocb.aio_return().unwrap(), EXPECT.len() as isize);
        assert!(it.next().is_none());
    }
    assert!(rbuf.deref().deref() == EXPECT);
}

#[test]
pub fn test_aio_write() {
    let wbuf = String::from("abcdef").into_bytes().into_boxed_slice();
    let mut f = tempfile().unwrap();
    let mut rbuf = Vec::new();

    let poll = Poll::new().unwrap();
    let mut events = Events::with_capacity(1024);
    let mut aiocb = mio_aio::AioCb::from_slice(f.as_raw_fd(),
        0,   //offset
        &wbuf,
        0,   //priority
        mio_aio::LioOpcode::LIO_NOP);
    poll.register(&aiocb, UDATA, UnixReady::aio().into(), PollOpt::empty())
        .expect("registration failed");

    aiocb.write().unwrap();

    poll.poll(&mut events, None).expect("poll failed");
    let mut it = events.iter();
    let ev = it.next().unwrap();
    assert_eq!(ev.token(), UDATA);
    assert!(UnixReady::from(ev.readiness()).is_aio());

    assert!(aiocb.error().is_ok());
    assert_eq!(aiocb.aio_return().unwrap(), wbuf.len() as isize);
    f.seek(SeekFrom::Start(0)).unwrap();
    let len = f.read_to_end(&mut rbuf).unwrap();
    assert!(len == wbuf.len());
    assert!(rbuf == wbuf.deref().deref());
    assert!(it.next().is_none());
}

#[test]
pub fn test_aio_write_static() {
    const WBUF: &[u8] = b"abcdef";
    let mut f = tempfile().unwrap();
    let mut rbuf = Vec::new();

    let poll = Poll::new().unwrap();
    let mut events = Events::with_capacity(1024);
    let mut aiocb = mio_aio::AioCb::from_slice(f.as_raw_fd(),
        0,   //offset
        WBUF,
        0,   //priority
        mio_aio::LioOpcode::LIO_NOP);
    poll.register(&aiocb, UDATA, UnixReady::aio().into(), PollOpt::empty())
        .expect("registration failed");

    aiocb.write().unwrap();

    poll.poll(&mut events, None).expect("poll failed");
    let mut it = events.iter();
    let ev = it.next().unwrap();
    assert_eq!(ev.token(), UDATA);
    assert!(UnixReady::from(ev.readiness()).is_aio());

    assert!(aiocb.error().is_ok());
    assert_eq!(aiocb.aio_return().unwrap(), WBUF.len() as isize);
    f.seek(SeekFrom::Start(0)).unwrap();
    let len = f.read_to_end(&mut rbuf).unwrap();
    assert!(len == WBUF.len());
    assert!(rbuf == WBUF);
    assert!(it.next().is_none());
}

// lio_listio returns EIO because one of its children failed
#[test]
pub fn test_lio_eio() {
    let wbuf0 = &b"abcdef"[..];
    let poll = Poll::new().unwrap();

    let mut builder = mio_aio::LioCbBuilder::with_capacity(1);
    let fd = -1;    // Illegal file descriptor
    builder = builder.emplace_slice(fd, 0, wbuf0, 0,
                        mio_aio::LioOpcode::LIO_WRITE);
    let mut liocb = builder.finish();
    poll.register(&liocb, UDATA, UnixReady::lio().into(), PollOpt::empty())
        .expect("registration failed");

    let r = liocb.submit();
    let expected = Err(mio_aio::Errno::EBADF);
    assert_eq!(r.unwrap_err().into_eio().unwrap()[0], expected);
}

#[test]
pub fn test_lio_oneread() {
    const INITIAL: &[u8] = b"abcdef123456";
    const EXPECT: &[u8] = b"cdef";
    let mut f = tempfile().unwrap();
    //let dbs = DivBufShared::from(vec![0; 4]);
    let mut buf = vec![0; 4];
    f.write_all(INITIAL).unwrap();

    let poll = Poll::new().unwrap();
    let mut events = Events::with_capacity(1024);

    let mut builder = mio_aio::LioCbBuilder::with_capacity(1);
    builder = builder.emplace_mut_slice(f.as_raw_fd(), 2, &mut buf[..], 0,
        mio_aio::LioOpcode::LIO_READ);
    let mut liocb = builder.finish();
    poll.register(&liocb, UDATA, UnixReady::lio().into(), PollOpt::empty())
        .expect("registration failed");

    liocb.submit().unwrap();

    poll.poll(&mut events, None).expect("poll failed");
    let mut it = events.iter();
    let ev = it.next().unwrap();
    assert_eq!(ev.token(), UDATA);
    assert!(UnixReady::from(ev.readiness()).is_lio());

    liocb.into_results(|mut iter| {
        let lr = iter.next().unwrap();
        assert_eq!(lr.result.unwrap(), EXPECT.len() as isize);
        assert!(iter.next().is_none());
    });
    assert!(it.next().is_none());
    assert_eq!(EXPECT, &buf[..]);
}

#[test]
pub fn test_lio_onewrite() {
    let wbuf = b"abcdef";
    let mut f = tempfile().unwrap();
    let mut rbuf = Vec::new();

    let poll = Poll::new().unwrap();
    let mut events = Events::with_capacity(1024);

    let mut builder = mio_aio::LioCbBuilder::with_capacity(1);
    builder = builder.emplace_slice(f.as_raw_fd(), 0, &wbuf[..], 0,
                        mio_aio::LioOpcode::LIO_WRITE);
    let mut liocb = builder.finish();
    poll.register(&liocb, UDATA, UnixReady::lio().into(), PollOpt::empty())
        .expect("registration failed");

    liocb.submit().unwrap();

    poll.poll(&mut events, None).expect("poll failed");
    let mut it = events.iter();
    let ev = it.next().unwrap();
    assert_eq!(ev.token(), UDATA);
    assert!(UnixReady::from(ev.readiness()).is_lio());

    liocb.into_results(|mut iter| {
        let lr = iter.next().unwrap();
        assert_eq!(lr.result.unwrap(), wbuf.len() as isize);
        assert!(iter.next().is_none());
    });
    f.seek(SeekFrom::Start(0)).unwrap();
    let len = f.read_to_end(&mut rbuf).unwrap();
    assert_eq!(len, wbuf.len());
    assert_eq!(&wbuf[..], &rbuf[..]);
    assert!(it.next().is_none());
}

#[test]
pub fn test_lio_tworeads() {
    const INITIAL: &[u8] = b"abcdef123456";
    const EXPECT0: &[u8] = b"cdef";
    const EXPECT1: &[u8] = b"23456";
    let mut f = tempfile().unwrap();
    let mut rbuf0 = vec![0; 4];
    let mut rbuf1 = vec![0; 5];
    f.write_all(INITIAL).unwrap();

    let poll = Poll::new().unwrap();
    let mut events = Events::with_capacity(1024);

    let mut builder = mio_aio::LioCbBuilder::with_capacity(2);
    builder = builder.emplace_mut_slice(f.as_raw_fd(), 2, &mut rbuf0[..], 0,
                            mio_aio::LioOpcode::LIO_READ);
    builder = builder.emplace_mut_slice(f.as_raw_fd(), 7, &mut rbuf1[..], 0,
                            mio_aio::LioOpcode::LIO_READ);
    let mut liocb = builder.finish();
    poll.register(&liocb, UDATA, UnixReady::lio().into(), PollOpt::empty())
        .expect("registration failed");

    liocb.submit().unwrap();

    poll.poll(&mut events, None).expect("poll failed");
    let mut it = events.iter();
    let ev = it.next().unwrap();
    assert_eq!(ev.token(), UDATA);
    assert!(UnixReady::from(ev.readiness()).is_lio());

    liocb.into_results(|mut iter| {
        let lr0 = iter.next().unwrap();
        assert_eq!(lr0.result.unwrap(), EXPECT0.len() as isize);
        let lr1 = iter.next().unwrap();
        assert_eq!(lr1.result.unwrap(), EXPECT1.len() as isize);
        assert!(iter.next().is_none());
    });
    assert_eq!(&rbuf0[..], EXPECT0);
    assert_eq!(&rbuf1[..], EXPECT1);

    assert!(it.next().is_none());
}

#[test]
pub fn test_lio_read_and_write() {
    const INITIAL0: &[u8] = b"abcdef123456";
    const WBUF1: &[u8] = b"ABCDEFGHIJKL";
    const EXPECT0: &[u8] = b"cdef";
    let mut f0 = tempfile().unwrap();
    let mut f1 = tempfile().unwrap();
    let mut rbuf0 = vec![0; 4];
    let mut rbuf1 = Vec::new();
    f0.write_all(INITIAL0).unwrap();

    let poll = Poll::new().unwrap();
    let mut events = Events::with_capacity(1024);

    let mut builder = mio_aio::LioCbBuilder::with_capacity(2);
    builder = builder.emplace_mut_slice(f0.as_raw_fd(), 2, &mut rbuf0[..], 0,
                            mio_aio::LioOpcode::LIO_READ);
    builder = builder.emplace_slice(f1.as_raw_fd(), 0, WBUF1, 0,
                        mio_aio::LioOpcode::LIO_WRITE);
    let mut liocb = builder.finish();
    poll.register(&liocb, UDATA, UnixReady::lio().into(), PollOpt::empty())
        .expect("registration failed");

    liocb.submit().unwrap();

    poll.poll(&mut events, None).expect("poll failed");
    let mut it = events.iter();
    let ev = it.next().unwrap();
    assert_eq!(ev.token(), UDATA);
    assert!(UnixReady::from(ev.readiness()).is_lio());

    liocb.into_results(|mut iter| {
        let lr0 = iter.next().unwrap();
        assert_eq!(lr0.result.unwrap(), EXPECT0.len() as isize);

        let lr1 = iter.next().unwrap();
        assert_eq!(lr1.result.unwrap(), WBUF1.len() as isize);

        assert!(iter.next().is_none());
    });
    assert_eq!(&rbuf0[..], EXPECT0);

    f1.seek(SeekFrom::Start(0)).unwrap();
    let len = f1.read_to_end(&mut rbuf1).unwrap();
    assert_eq!(len, WBUF1.len());
    assert_eq!(rbuf1, WBUF1);

    assert!(it.next().is_none());
}
<|endoftext|>


<commit_before>use std::convert::TryFrom;

use multihash::{Code, MultihashDigest, Sha3_512};

#[test]
fn to_u64() {
    assert_eq!(<u64>::from(Code::Keccak256), 0x1b);
}

#[test]
fn from_u64() {
    assert_eq!(Code::try_from(0xb220), Ok(Code::Blake2b256));
}

#[test]
fn hasher() {
    let expected = Sha3_512::digest(b"abcdefg");
    let hasher = Box::<dyn MultihashDigest>::from(Code::Sha3_512);
    assert_eq!(hasher.digest(b"abcdefg"), expected);
}
<commit_msg>test: add test for custom code table and hasher<commit_after>use std::convert::TryFrom;

use multihash::{wrap, Code, MultihashDigest, MultihashGeneric, Sha3_512};

#[test]
fn to_u64() {
    assert_eq!(<u64>::from(Code::Keccak256), 0x1b);
}

#[test]
fn from_u64() {
    assert_eq!(Code::try_from(0xb220), Ok(Code::Blake2b256));
}

#[test]
fn hasher() {
    let expected = Sha3_512::digest(b"abcdefg");
    let hasher = Box::<dyn MultihashDigest>::from(Code::Sha3_512);
    assert_eq!(hasher.digest(b"abcdefg"), expected);
}

#[test]
fn hasher_custom_codes() {
    enum MyCodeTable {
        Foo = 1,
        Bar = 2,
    }

    impl From<MyCodeTable> for u64 {
        /// Return the code as integer value.
        fn from(code: MyCodeTable) -> Self {
            code as _
        }
    }

    impl TryFrom<u64> for MyCodeTable {
        type Error = String;

        /// Return the `Code` based on the integer value. Error if no matching code exists.
        fn try_from(raw: u64) -> Result<Self, Self::Error> {
            match raw {
                1 => Ok(MyCodeTable::Foo),
                2 => Ok(MyCodeTable::Bar),
                _ => Err("Cannot convert".to_string()),
            }
        }
    }

    #[derive(Default)]
    struct SameHash;
    impl SameHash {
        pub const CODE: MyCodeTable = MyCodeTable::Foo;
        /// Hash some input and return the sha1 digest.
        pub fn digest(_data: &[u8]) -> MultihashGeneric<MyCodeTable> {
            let digest = b"alwaysthesame";
            wrap(Self::CODE, digest)
        }
    }

    impl MultihashDigest<MyCodeTable> for SameHash {
        #[inline]
        fn code(&self) -> MyCodeTable {
            Self::CODE
        }
        #[inline]
        fn digest(&self, data: &[u8]) -> MultihashGeneric<MyCodeTable> {
            Self::digest(data)
        }
        #[inline]
        fn input(&mut self, _data: &[u8]) {}
        #[inline]
        fn result(self) -> MultihashGeneric<MyCodeTable> {
            wrap(Self::CODE, b"alwaysthesame")
        }
        #[inline]
        fn result_reset(&mut self) -> MultihashGeneric<MyCodeTable> {
            wrap(Self::CODE, b"")
        }
        #[inline]
        fn reset(&mut self) {}
    }

    impl From<MyCodeTable> for Box<dyn MultihashDigest<MyCodeTable>> {
        fn from(code: MyCodeTable) -> Self {
            match code {
                MyCodeTable::Foo => Box::new(SameHash::default()),
                MyCodeTable::Bar => Box::new(SameHash::default()),
            }
        }
    }

    let expected = SameHash::digest(b"abcdefg");
    let hasher = Box::<dyn MultihashDigest<_>>::from(MyCodeTable::Foo);
    assert_eq!(hasher.digest(b"abcdefg"), expected);
}
<|endoftext|>


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

use crate::account_address::AccountAddress;

use anyhow::Result;
use move_core_types::{
    identifier::{IdentStr, Identifier},
    move_resource::MoveResource,
};
use serde::{Deserialize, Serialize};

/// Struct that represents a ReceivedMintEvent.
#[derive(Debug, Serialize, Deserialize)]
pub struct ReceivedMintEvent {
    amount: u64,
    currency_code: Identifier,
    destination_address: AccountAddress,
}

impl ReceivedMintEvent {
    /// Get the amount minted
    pub fn amount(&self) -> u64 {
        self.amount
    }

    /// Return the address who received the mint
    pub fn destination_address(&self) -> AccountAddress {
        self.destination_address
    }

    /// Return the code for the currency that was minted
    pub fn currency_code(&self) -> &IdentStr {
        &self.currency_code
    }

    pub fn try_from_bytes(bytes: &[u8]) -> Result<Self> {
        lcs::from_bytes(bytes).map_err(Into::into)
    }
}

impl MoveResource for ReceivedMintEvent {
    const MODULE_NAME: &'static str = "DesignatedDealer";
    const STRUCT_NAME: &'static str = "ReceivedMintEvent";
}
<commit_msg>reorder ReceivedMintEvent fields<commit_after>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::account_address::AccountAddress;

use anyhow::Result;
use move_core_types::{
    identifier::{IdentStr, Identifier},
    move_resource::MoveResource,
};
use serde::{Deserialize, Serialize};

/// Struct that represents a ReceivedMintEvent.
#[derive(Debug, Serialize, Deserialize)]
pub struct ReceivedMintEvent {
    currency_code: Identifier,
    destination_address: AccountAddress,
    amount: u64,
}

impl ReceivedMintEvent {
    /// Get the amount minted
    pub fn amount(&self) -> u64 {
        self.amount
    }

    /// Return the address who received the mint
    pub fn destination_address(&self) -> AccountAddress {
        self.destination_address
    }

    /// Return the code for the currency that was minted
    pub fn currency_code(&self) -> &IdentStr {
        &self.currency_code
    }

    pub fn try_from_bytes(bytes: &[u8]) -> Result<Self> {
        lcs::from_bytes(bytes).map_err(Into::into)
    }
}

impl MoveResource for ReceivedMintEvent {
    const MODULE_NAME: &'static str = "DesignatedDealer";
    const STRUCT_NAME: &'static str = "ReceivedMintEvent";
}
<|endoftext|>


<commit_before>extern crate tempdir;

use tempdir::TempDir;
use std::env::set_var;

#[macro_use]
mod common;

use common::util::*;

static UTIL_NAME: &'static str = "mktemp";

static TEST_TEMPLATE1: &'static str = "tempXXXXXX";
static TEST_TEMPLATE2: &'static str = "temp";
static TEST_TEMPLATE3: &'static str = "tempX";
static TEST_TEMPLATE4: &'static str = "tempXX";
static TEST_TEMPLATE5: &'static str = "tempXXX";
static TEST_TEMPLATE6: &'static str = "tempXXXlate";
static TEST_TEMPLATE7: &'static str = "XXXtemplate";
#[cfg(unix)]
static TEST_TEMPLATE8: &'static str = "tempXXXla/te";
#[cfg(windows)]
static TEST_TEMPLATE8: &'static str = "tempXXXla\\te";

const TMPDIR: &'static str = "TMPDIR";

#[test]
fn test_mktemp_mktemp() {
    let ts = TestSet::new(UTIL_NAME);

    let pathname = ts.fixtures.as_string();
    set_var(TMPDIR, pathname);

    let exit_success1 = ts.util_cmd_keepenv().arg(TEST_TEMPLATE1).run().success;
    let exit_success2 = ts.util_cmd_keepenv().arg(TEST_TEMPLATE2).run().success;
    let exit_success3 = ts.util_cmd_keepenv().arg(TEST_TEMPLATE3).run().success;
    let exit_success4 = ts.util_cmd_keepenv().arg(TEST_TEMPLATE4).run().success;
    let exit_success5 = ts.util_cmd_keepenv().arg(TEST_TEMPLATE5).run().success;
    let exit_success6 = ts.util_cmd_keepenv().arg(TEST_TEMPLATE6).run().success;
    let exit_success7 = ts.util_cmd_keepenv().arg(TEST_TEMPLATE7).run().success;
    let exit_success8 = ts.util_cmd_keepenv().arg(TEST_TEMPLATE8).run().success;

    assert!(exit_success1);
    assert!(!exit_success2);
    assert!(!exit_success3);
    assert!(!exit_success4);
    assert!(exit_success5);
    assert!(exit_success6);
    assert!(exit_success7);
    assert!(!exit_success8);
}

// TODO: test directory option when implemented
#[test]
fn test_mktemp_dry_run() {
    let ts = TestSet::new(UTIL_NAME);

    let pathname = ts.fixtures.as_string();
    set_var(TMPDIR, pathname);

    let exit_success1 = ts.util_cmd_keepenv().arg("-u").arg(TEST_TEMPLATE1).run().success;
    let exit_success2 = ts.util_cmd_keepenv().arg("-u").arg(TEST_TEMPLATE2).run().success;
    let exit_success3 = ts.util_cmd_keepenv().arg("-u").arg(TEST_TEMPLATE3).run().success;
    let exit_success4 = ts.util_cmd_keepenv().arg("-u").arg(TEST_TEMPLATE4).run().success;
    let exit_success5 = ts.util_cmd_keepenv().arg("-u").arg(TEST_TEMPLATE5).run().success;
    let exit_success6 = ts.util_cmd_keepenv().arg("-u").arg(TEST_TEMPLATE6).run().success;
    let exit_success7 = ts.util_cmd_keepenv().arg("-u").arg(TEST_TEMPLATE7).run().success;
    let exit_success8 = ts.util_cmd_keepenv().arg("-u").arg(TEST_TEMPLATE8).run().success;

    assert!(exit_success1);
    assert!(!exit_success2);
    assert!(!exit_success3);
    assert!(!exit_success4);
    assert!(exit_success5);
    assert!(exit_success6);
    assert!(exit_success7);
    assert!(!exit_success8);
}

// TOOD: test quiet option when correctry implemented

#[test]
fn test_mktemp_suffix() {
    let ts = TestSet::new(UTIL_NAME);

    let pathname = ts.fixtures.as_string();
     set_var(TMPDIR, pathname);

    let exit_success1 = ts.util_cmd_keepenv().arg("--suffix").arg("suf").arg(TEST_TEMPLATE1).run().success;
    let exit_success2 = ts.util_cmd_keepenv().arg("--suffix").arg("suf").arg(TEST_TEMPLATE2).run().success;
    let exit_success3 = ts.util_cmd_keepenv().arg("--suffix").arg("suf").arg(TEST_TEMPLATE3).run().success;
    let exit_success4 = ts.util_cmd_keepenv().arg("--suffix").arg("suf").arg(TEST_TEMPLATE4).run().success;
    let exit_success5 = ts.util_cmd_keepenv().arg("--suffix").arg("suf").arg(TEST_TEMPLATE5).run().success;
    let exit_success6 = ts.util_cmd_keepenv().arg("--suffix").arg("suf").arg(TEST_TEMPLATE6).run().success;
    let exit_success7 = ts.util_cmd_keepenv().arg("--suffix").arg("suf").arg(TEST_TEMPLATE7).run().success;
    let exit_success8 = ts.util_cmd_keepenv().arg("--suffix").arg("suf").arg(TEST_TEMPLATE8).run().success;

    assert!(exit_success1);
    assert!(!exit_success2);
    assert!(!exit_success3);
    assert!(!exit_success4);
    assert!(exit_success5);
    assert!(!exit_success6);
    assert!(!exit_success7);
    assert!(!exit_success8);
}

#[test]
fn test_mktemp_tmpdir() {
    let ts = TestSet::new(UTIL_NAME);

   let path = TempDir::new_in(ts.fixtures.as_string(), UTIL_NAME).unwrap();
   let pathname = path.path().as_os_str();

    let exit_success1 = ts.util_cmd().arg("-p").arg(pathname).arg(TEST_TEMPLATE1).run().success;
    let exit_success2 = ts.util_cmd().arg("-p").arg(pathname).arg(TEST_TEMPLATE2).run().success;
    let exit_success3 = ts.util_cmd().arg("-p").arg(pathname).arg(TEST_TEMPLATE3).run().success;
    let exit_success4 = ts.util_cmd().arg("-p").arg(pathname).arg(TEST_TEMPLATE4).run().success;
    let exit_success5 = ts.util_cmd().arg("-p").arg(pathname).arg(TEST_TEMPLATE5).run().success;
    let exit_success6 = ts.util_cmd().arg("-p").arg(pathname).arg(TEST_TEMPLATE6).run().success;
    let exit_success7 = ts.util_cmd().arg("-p").arg(pathname).arg(TEST_TEMPLATE7).run().success;
    let exit_success8 = ts.util_cmd().arg("-p").arg(pathname).arg(TEST_TEMPLATE8).run().success;

    assert!(exit_success1);
    assert!(!exit_success2);
    assert!(!exit_success3);
    assert!(!exit_success4);
    assert!(exit_success5);
    assert!(exit_success6);
    assert!(exit_success7);
    assert!(!exit_success8);
}
<commit_msg>[mktemp] use new API `env`<commit_after>extern crate tempdir;

use tempdir::TempDir;
use std::env::set_var;

#[macro_use]
mod common;

use common::util::*;

static UTIL_NAME: &'static str = "mktemp";

static TEST_TEMPLATE1: &'static str = "tempXXXXXX";
static TEST_TEMPLATE2: &'static str = "temp";
static TEST_TEMPLATE3: &'static str = "tempX";
static TEST_TEMPLATE4: &'static str = "tempXX";
static TEST_TEMPLATE5: &'static str = "tempXXX";
static TEST_TEMPLATE6: &'static str = "tempXXXlate";
static TEST_TEMPLATE7: &'static str = "XXXtemplate";
#[cfg(unix)]
static TEST_TEMPLATE8: &'static str = "tempXXXla/te";
#[cfg(windows)]
static TEST_TEMPLATE8: &'static str = "tempXXXla\\te";

const TMPDIR: &'static str = "TMPDIR";

#[test]
fn test_mktemp_mktemp() {
    let ts = TestSet::new(UTIL_NAME);

    let pathname = ts.fixtures.as_string();

    let exit_success1 = ts.util_cmd().env(TMPDIR, &pathname).arg(TEST_TEMPLATE1).run().success;
    let exit_success2 = ts.util_cmd().env(TMPDIR, &pathname).arg(TEST_TEMPLATE2).run().success;
    let exit_success3 = ts.util_cmd().env(TMPDIR, &pathname).arg(TEST_TEMPLATE3).run().success;
    let exit_success4 = ts.util_cmd().env(TMPDIR, &pathname).arg(TEST_TEMPLATE4).run().success;
    let exit_success5 = ts.util_cmd().env(TMPDIR, &pathname).arg(TEST_TEMPLATE5).run().success;
    let exit_success6 = ts.util_cmd().env(TMPDIR, &pathname).arg(TEST_TEMPLATE6).run().success;
    let exit_success7 = ts.util_cmd().env(TMPDIR, &pathname).arg(TEST_TEMPLATE7).run().success;
    let exit_success8 = ts.util_cmd().env(TMPDIR, &pathname).arg(TEST_TEMPLATE8).run().success;

    assert!(exit_success1);
    assert!(!exit_success2);
    assert!(!exit_success3);
    assert!(!exit_success4);
    assert!(exit_success5);
    assert!(exit_success6);
    assert!(exit_success7);
    assert!(!exit_success8);
}

// TODO: test directory option when implemented

#[test]
fn test_mktemp_dry_run() {
    let ts = TestSet::new(UTIL_NAME);

    let pathname = ts.fixtures.as_string();

    let exit_success1 = ts.util_cmd().env(TMPDIR, &pathname).arg("-u").arg(TEST_TEMPLATE1).run().success;
    let exit_success2 = ts.util_cmd().env(TMPDIR, &pathname).arg("-u").arg(TEST_TEMPLATE2).run().success;
    let exit_success3 = ts.util_cmd().env(TMPDIR, &pathname).arg("-u").arg(TEST_TEMPLATE3).run().success;
    let exit_success4 = ts.util_cmd().env(TMPDIR, &pathname).arg("-u").arg(TEST_TEMPLATE4).run().success;
    let exit_success5 = ts.util_cmd().env(TMPDIR, &pathname).arg("-u").arg(TEST_TEMPLATE5).run().success;
    let exit_success6 = ts.util_cmd().env(TMPDIR, &pathname).arg("-u").arg(TEST_TEMPLATE6).run().success;
    let exit_success7 = ts.util_cmd().env(TMPDIR, &pathname).arg("-u").arg(TEST_TEMPLATE7).run().success;
    let exit_success8 = ts.util_cmd().env(TMPDIR, &pathname).arg("-u").arg(TEST_TEMPLATE8).run().success;

    assert!(exit_success1);
    assert!(!exit_success2);
    assert!(!exit_success3);
    assert!(!exit_success4);
    assert!(exit_success5);
    assert!(exit_success6);
    assert!(exit_success7);
    assert!(!exit_success8);
}

// TOOD: test quiet option when correctry implemented

#[test]
fn test_mktemp_suffix() {
    let ts = TestSet::new(UTIL_NAME);

    let pathname = ts.fixtures.as_string();

    let exit_success1 = ts.util_cmd().env(TMPDIR, &pathname).arg("--suffix").arg("suf").arg(TEST_TEMPLATE1).run().success;
    let exit_success2 = ts.util_cmd().env(TMPDIR, &pathname).arg("--suffix").arg("suf").arg(TEST_TEMPLATE2).run().success;
    let exit_success3 = ts.util_cmd().env(TMPDIR, &pathname).arg("--suffix").arg("suf").arg(TEST_TEMPLATE3).run().success;
    let exit_success4 = ts.util_cmd().env(TMPDIR, &pathname).arg("--suffix").arg("suf").arg(TEST_TEMPLATE4).run().success;
    let exit_success5 = ts.util_cmd().env(TMPDIR, &pathname).arg("--suffix").arg("suf").arg(TEST_TEMPLATE5).run().success;
    let exit_success6 = ts.util_cmd().env(TMPDIR, &pathname).arg("--suffix").arg("suf").arg(TEST_TEMPLATE6).run().success;
    let exit_success7 = ts.util_cmd().env(TMPDIR, &pathname).arg("--suffix").arg("suf").arg(TEST_TEMPLATE7).run().success;
    let exit_success8 = ts.util_cmd().env(TMPDIR, &pathname).arg("--suffix").arg("suf").arg(TEST_TEMPLATE8).run().success;

    assert!(exit_success1);
    assert!(!exit_success2);
    assert!(!exit_success3);
    assert!(!exit_success4);
    assert!(exit_success5);
    assert!(!exit_success6);
    assert!(!exit_success7);
    assert!(!exit_success8);
}

#[test]
fn test_mktemp_tmpdir() {
    let ts = TestSet::new(UTIL_NAME);

   let path = TempDir::new_in(ts.fixtures.as_string(), UTIL_NAME).unwrap();
   let pathname = path.path().as_os_str();

    let exit_success1 = ts.util_cmd().arg("-p").arg(pathname).arg(TEST_TEMPLATE1).run().success;
    let exit_success2 = ts.util_cmd().arg("-p").arg(pathname).arg(TEST_TEMPLATE2).run().success;
    let exit_success3 = ts.util_cmd().arg("-p").arg(pathname).arg(TEST_TEMPLATE3).run().success;
    let exit_success4 = ts.util_cmd().arg("-p").arg(pathname).arg(TEST_TEMPLATE4).run().success;
    let exit_success5 = ts.util_cmd().arg("-p").arg(pathname).arg(TEST_TEMPLATE5).run().success;
    let exit_success6 = ts.util_cmd().arg("-p").arg(pathname).arg(TEST_TEMPLATE6).run().success;
    let exit_success7 = ts.util_cmd().arg("-p").arg(pathname).arg(TEST_TEMPLATE7).run().success;
    let exit_success8 = ts.util_cmd().arg("-p").arg(pathname).arg(TEST_TEMPLATE8).run().success;

    assert!(exit_success1);
    assert!(!exit_success2);
    assert!(!exit_success3);
    assert!(!exit_success4);
    assert!(exit_success5);
    assert!(exit_success6);
    assert!(exit_success7);
    assert!(!exit_success8);
}
<|endoftext|>