<commit_before>// Portions of this file are Copyright 2014 The Rust Project Developers.
// See http://rust-lang.org/COPYRIGHT.

use libc;
use errno::Errno;
use std::mem;
use {Error, Result};

pub use libc::consts::os::posix88::{
    SIGHUP,   // 1
    SIGINT,   // 2
    SIGQUIT,  // 3
    SIGILL,   // 4
    SIGABRT,  // 6
    SIGFPE,   // 8
    SIGKILL,  // 9
    SIGSEGV,  // 11
    SIGPIPE,  // 13
    SIGALRM,  // 14
    SIGTERM,  // 15
};

pub use self::signal::{
    SIGTRAP,
    SIGIOT,
    SIGBUS,
    SIGSYS,
    SIGURG,
    SIGSTOP,
    SIGTSTP,
    SIGCONT,
    SIGCHLD,
    SIGTTIN,
    SIGTTOU,
    SIGIO,
    SIGXCPU,
    SIGXFSZ,
    SIGVTALRM,
    SIGPROF,
    SIGWINCH,
    SIGUSR1,
    SIGUSR2,
};

pub use self::signal::SockFlag;
pub use self::signal::sigset_t;

// This doesn't always exist, but when it does, it's 7
pub const SIGEMT: libc::c_int = 7;

#[cfg(any(all(target_os = "linux",
              any(target_arch = "x86",
                  target_arch = "x86_64",
                  target_arch = "arm")),
          target_os = "android"))]
pub mod signal {
    use libc;

    bitflags!(
        flags SockFlag: libc::c_ulong {
            const SA_NOCLDSTOP = 0x00000001,
            const SA_NOCLDWAIT = 0x00000002,
            const SA_NODEFER   = 0x40000000,
            const SA_ONSTACK   = 0x08000000,
            const SA_RESETHAND = 0x80000000,
            const SA_RESTART   = 0x10000000,
            const SA_SIGINFO   = 0x00000004,
        }
    );

    pub const SIGTRAP:      libc::c_int = 5;
    pub const SIGIOT:       libc::c_int = 6;
    pub const SIGBUS:       libc::c_int = 7;
    pub const SIGUSR1:      libc::c_int = 10;
    pub const SIGUSR2:      libc::c_int = 12;
    pub const SIGSTKFLT:    libc::c_int = 16;
    pub const SIGCHLD:      libc::c_int = 17;
    pub const SIGCONT:      libc::c_int = 18;
    pub const SIGSTOP:      libc::c_int = 19;
    pub const SIGTSTP:      libc::c_int = 20;
    pub const SIGTTIN:      libc::c_int = 21;
    pub const SIGTTOU:      libc::c_int = 22;
    pub const SIGURG:       libc::c_int = 23;
    pub const SIGXCPU:      libc::c_int = 24;
    pub const SIGXFSZ:      libc::c_int = 25;
    pub const SIGVTALRM:    libc::c_int = 26;
    pub const SIGPROF:      libc::c_int = 27;
    pub const SIGWINCH:     libc::c_int = 28;
    pub const SIGIO:        libc::c_int = 29;
    pub const SIGPOLL:      libc::c_int = 29;
    pub const SIGPWR:       libc::c_int = 30;
    pub const SIGSYS:       libc::c_int = 31;
    pub const SIGUNUSED:    libc::c_int = 31;

    // This definition is not as accurate as it could be, {pid, uid, status} is
    // actually a giant union. Currently we're only interested in these fields,
    // however.
    #[repr(C)]
    #[derive(Clone, Copy)]
    pub struct siginfo {
        si_signo: libc::c_int,
        si_errno: libc::c_int,
        si_code: libc::c_int,
        pub pid: libc::pid_t,
        pub uid: libc::uid_t,
        pub status: libc::c_int,
    }

    #[repr(C)]
    #[allow(missing_copy_implementations)]
    pub struct sigaction {
        pub sa_handler: extern fn(libc::c_int),
        pub sa_mask: sigset_t,
        pub sa_flags: SockFlag,
        sa_restorer: *mut libc::c_void,
    }

    #[repr(C)]
    #[cfg(target_pointer_width = "32")]
    #[derive(Clone, Copy)]
    pub struct sigset_t {
        __val: [libc::c_ulong; 32],
    }

    #[repr(C)]
    #[cfg(target_pointer_width = "64")]
    #[derive(Clone, Copy)]
    pub struct sigset_t {
        __val: [libc::c_ulong; 16],
    }
}

#[cfg(all(target_os = "linux",
          any(target_arch = "mips", target_arch = "mipsel")))]
pub mod signal {
    use libc;

    bitflags!(
        flags SockFlag: libc::c_uint {
            const SA_NOCLDSTOP = 0x00000001,
            const SA_NOCLDWAIT = 0x00001000,
            const SA_NODEFER   = 0x40000000,
            const SA_ONSTACK   = 0x08000000,
            const SA_RESETHAND = 0x80000000,
            const SA_RESTART   = 0x10000000,
            const SA_SIGINFO   = 0x00000008,
        }
    );

    pub const SIGTRAP:      libc::c_int = 5;
    pub const SIGIOT:       libc::c_int = 6;
    pub const SIGBUS:       libc::c_int = 10;
    pub const SIGSYS:       libc::c_int = 12;
    pub const SIGUSR1:      libc::c_int = 16;
    pub const SIGUSR2:      libc::c_int = 17;
    pub const SIGCHLD:      libc::c_int = 18;
    pub const SIGCLD:       libc::c_int = 18;
    pub const SIGPWR:       libc::c_int = 19;
    pub const SIGWINCH:     libc::c_int = 20;
    pub const SIGURG:       libc::c_int = 21;
    pub const SIGIO:        libc::c_int = 22;
    pub const SIGPOLL:      libc::c_int = 22;
    pub const SIGSTOP:      libc::c_int = 23;
    pub const SIGTSTP:      libc::c_int = 24;
    pub const SIGCONT:      libc::c_int = 25;
    pub const SIGTTIN:      libc::c_int = 26;
    pub const SIGTTOU:      libc::c_int = 27;
    pub const SIGVTALRM:    libc::c_int = 28;
    pub const SIGPROF:      libc::c_int = 29;
    pub const SIGXCPU:      libc::c_int = 30;
    pub const SIGFSZ:       libc::c_int = 31;

    // This definition is not as accurate as it could be, {pid, uid, status} is
    // actually a giant union. Currently we're only interested in these fields,
    // however.
    #[repr(C)]
    pub struct siginfo {
        si_signo: libc::c_int,
        si_code: libc::c_int,
        si_errno: libc::c_int,
        pub pid: libc::pid_t,
        pub uid: libc::uid_t,
        pub status: libc::c_int,
    }

    #[repr(C)]
    pub struct sigaction {
        pub sa_flags: SockFlag,
        pub sa_handler: extern fn(libc::c_int),
        pub sa_mask: sigset_t,
        sa_restorer: *mut libc::c_void,
        sa_resv: [libc::c_int; 1],
    }

    #[repr(C)]
    pub struct sigset_t {
        __val: [libc::c_ulong; 32],
    }
}

#[cfg(any(target_os = "macos",
          target_os = "ios",
          target_os = "freebsd",
          target_os = "openbsd",
          target_os = "dragonfly"))]
pub mod signal {
    use libc;

    bitflags!(
        flags SockFlag: libc::c_int {
            const SA_NOCLDSTOP = 0x0008,
            const SA_NOCLDWAIT = 0x0020,
            const SA_NODEFER   = 0x0010,
            const SA_ONSTACK   = 0x0001,
            const SA_RESETHAND = 0x0004,
            const SA_RESTART   = 0x0002,
            const SA_SIGINFO   = 0x0040,
        }
    );

    pub const SIGTRAP:      libc::c_int = 5;
    pub const SIGIOT:       libc::c_int = 6;
    pub const SIGBUS:       libc::c_int = 10;
    pub const SIGSYS:       libc::c_int = 12;
    pub const SIGURG:       libc::c_int = 16;
    pub const SIGSTOP:      libc::c_int = 17;
    pub const SIGTSTP:      libc::c_int = 18;
    pub const SIGCONT:      libc::c_int = 19;
    pub const SIGCHLD:      libc::c_int = 20;
    pub const SIGTTIN:      libc::c_int = 21;
    pub const SIGTTOU:      libc::c_int = 22;
    pub const SIGIO:        libc::c_int = 23;
    pub const SIGXCPU:      libc::c_int = 24;
    pub const SIGXFSZ:      libc::c_int = 25;
    pub const SIGVTALRM:    libc::c_int = 26;
    pub const SIGPROF:      libc::c_int = 27;
    pub const SIGWINCH:     libc::c_int = 28;
    pub const SIGINFO:      libc::c_int = 29;
    pub const SIGUSR1:      libc::c_int = 30;
    pub const SIGUSR2:      libc::c_int = 31;

    #[cfg(any(target_os = "macos", target_os = "ios", target_os = "openbsd"))]
    pub type sigset_t = u32;
    #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
    #[repr(C)]
    #[derive(Clone, Copy)]
    pub struct sigset_t {
        bits: [u32; 4],
    }

    // This structure has more fields, but we're not all that interested in
    // them.
    #[repr(C)]
    #[derive(Clone, Copy)]
    pub struct siginfo {
        pub si_signo: libc::c_int,
        pub si_errno: libc::c_int,
        pub si_code: libc::c_int,
        pub pid: libc::pid_t,
        pub uid: libc::uid_t,
        pub status: libc::c_int,
    }

    #[cfg(any(target_os = "macos", target_os = "ios"))]
    #[repr(C)]
    #[allow(missing_copy_implementations)]
    pub struct sigaction {
        pub sa_handler: extern fn(libc::c_int),
        sa_tramp: *mut libc::c_void,
        pub sa_mask: sigset_t,
        pub sa_flags: SockFlag,
    }

    #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
    #[repr(C)]
    pub struct sigaction {
        pub sa_handler: extern fn(libc::c_int),
        pub sa_flags: SockFlag,
        pub sa_mask: sigset_t,
    }

    #[cfg(target_os = "openbsd")]
    #[repr(C)]
    pub struct sigaction {
        pub sa_handler: extern fn(libc::c_int),
        pub sa_mask: sigset_t,
        pub sa_flags: SockFlag,
    }
}

mod ffi {
    use libc;
    use super::signal::{sigaction, sigset_t};

    #[allow(improper_ctypes)]
    extern {
        pub fn sigaction(signum: libc::c_int,
                         act: *const sigaction,
                         oldact: *mut sigaction) -> libc::c_int;

        pub fn sigaddset(set: *mut sigset_t, signum: libc::c_int) -> libc::c_int;
        pub fn sigdelset(set: *mut sigset_t, signum: libc::c_int) -> libc::c_int;
        pub fn sigemptyset(set: *mut sigset_t) -> libc::c_int;

        pub fn kill(pid: libc::pid_t, signum: libc::c_int) -> libc::c_int;
    }
}

#[derive(Clone, Copy)]
pub struct SigSet {
    sigset: sigset_t
}

pub type SigNum = libc::c_int;

impl SigSet {
    pub fn empty() -> SigSet {
        let mut sigset = unsafe { mem::uninitialized::<sigset_t>() };
        let _ = unsafe { ffi::sigemptyset(&mut sigset as *mut sigset_t) };

        SigSet { sigset: sigset }
    }

    pub fn add(&mut self, signum: SigNum) -> Result<()> {
        let res = unsafe { ffi::sigaddset(&mut self.sigset as *mut sigset_t, signum) };

        if res < 0 {
            return Err(Error::Sys(Errno::last()));
        }

        Ok(())
    }

    pub fn remove(&mut self, signum: SigNum) -> Result<()> {
        let res = unsafe { ffi::sigdelset(&mut self.sigset as *mut sigset_t, signum) };

        if res < 0 {
            return Err(Error::Sys(Errno::last()));
        }

        Ok(())
    }
}

type sigaction_t = self::signal::sigaction;

pub struct SigAction {
    sigaction: sigaction_t
}

impl SigAction {
    pub fn new(handler: extern fn(libc::c_int), flags: SockFlag, mask: SigSet) -> SigAction {
        let mut s = unsafe { mem::uninitialized::<sigaction_t>() };
        s.sa_handler = handler;
        s.sa_flags = flags;
        s.sa_mask = mask.sigset;

        SigAction { sigaction: s }
    }
}

pub unsafe fn sigaction(signum: SigNum, sigaction: &SigAction) -> Result<SigAction> {
    let mut oldact = mem::uninitialized::<sigaction_t>();

    let res =
        ffi::sigaction(signum, &sigaction.sigaction as *const sigaction_t, &mut oldact as *mut sigaction_t);

    if res < 0 {
        return Err(Error::Sys(Errno::last()));
    }

    Ok(SigAction { sigaction: oldact })
}

pub fn kill(pid: libc::pid_t, signum: SigNum) -> Result<()> {
    let res = unsafe { ffi::kill(pid, signum) };

    if res < 0 {
        return Err(Error::Sys(Errno::last()));
    }

    Ok(())
}
<commit_msg>Remove sa_tramp from macos sigaction<commit_after>// Portions of this file are Copyright 2014 The Rust Project Developers.
// See http://rust-lang.org/COPYRIGHT.

use libc;
use errno::Errno;
use std::mem;
use {Error, Result};

pub use libc::consts::os::posix88::{
    SIGHUP,   // 1
    SIGINT,   // 2
    SIGQUIT,  // 3
    SIGILL,   // 4
    SIGABRT,  // 6
    SIGFPE,   // 8
    SIGKILL,  // 9
    SIGSEGV,  // 11
    SIGPIPE,  // 13
    SIGALRM,  // 14
    SIGTERM,  // 15
};

pub use self::signal::{
    SIGTRAP,
    SIGIOT,
    SIGBUS,
    SIGSYS,
    SIGURG,
    SIGSTOP,
    SIGTSTP,
    SIGCONT,
    SIGCHLD,
    SIGTTIN,
    SIGTTOU,
    SIGIO,
    SIGXCPU,
    SIGXFSZ,
    SIGVTALRM,
    SIGPROF,
    SIGWINCH,
    SIGUSR1,
    SIGUSR2,
};

pub use self::signal::SockFlag;
pub use self::signal::sigset_t;

// This doesn't always exist, but when it does, it's 7
pub const SIGEMT: libc::c_int = 7;

#[cfg(any(all(target_os = "linux",
              any(target_arch = "x86",
                  target_arch = "x86_64",
                  target_arch = "arm")),
          target_os = "android"))]
pub mod signal {
    use libc;

    bitflags!(
        flags SockFlag: libc::c_ulong {
            const SA_NOCLDSTOP = 0x00000001,
            const SA_NOCLDWAIT = 0x00000002,
            const SA_NODEFER   = 0x40000000,
            const SA_ONSTACK   = 0x08000000,
            const SA_RESETHAND = 0x80000000,
            const SA_RESTART   = 0x10000000,
            const SA_SIGINFO   = 0x00000004,
        }
    );

    pub const SIGTRAP:      libc::c_int = 5;
    pub const SIGIOT:       libc::c_int = 6;
    pub const SIGBUS:       libc::c_int = 7;
    pub const SIGUSR1:      libc::c_int = 10;
    pub const SIGUSR2:      libc::c_int = 12;
    pub const SIGSTKFLT:    libc::c_int = 16;
    pub const SIGCHLD:      libc::c_int = 17;
    pub const SIGCONT:      libc::c_int = 18;
    pub const SIGSTOP:      libc::c_int = 19;
    pub const SIGTSTP:      libc::c_int = 20;
    pub const SIGTTIN:      libc::c_int = 21;
    pub const SIGTTOU:      libc::c_int = 22;
    pub const SIGURG:       libc::c_int = 23;
    pub const SIGXCPU:      libc::c_int = 24;
    pub const SIGXFSZ:      libc::c_int = 25;
    pub const SIGVTALRM:    libc::c_int = 26;
    pub const SIGPROF:      libc::c_int = 27;
    pub const SIGWINCH:     libc::c_int = 28;
    pub const SIGIO:        libc::c_int = 29;
    pub const SIGPOLL:      libc::c_int = 29;
    pub const SIGPWR:       libc::c_int = 30;
    pub const SIGSYS:       libc::c_int = 31;
    pub const SIGUNUSED:    libc::c_int = 31;

    // This definition is not as accurate as it could be, {pid, uid, status} is
    // actually a giant union. Currently we're only interested in these fields,
    // however.
    #[repr(C)]
    #[derive(Clone, Copy)]
    pub struct siginfo {
        si_signo: libc::c_int,
        si_errno: libc::c_int,
        si_code: libc::c_int,
        pub pid: libc::pid_t,
        pub uid: libc::uid_t,
        pub status: libc::c_int,
    }

    #[repr(C)]
    #[allow(missing_copy_implementations)]
    pub struct sigaction {
        pub sa_handler: extern fn(libc::c_int),
        pub sa_mask: sigset_t,
        pub sa_flags: SockFlag,
        sa_restorer: *mut libc::c_void,
    }

    #[repr(C)]
    #[cfg(target_pointer_width = "32")]
    #[derive(Clone, Copy)]
    pub struct sigset_t {
        __val: [libc::c_ulong; 32],
    }

    #[repr(C)]
    #[cfg(target_pointer_width = "64")]
    #[derive(Clone, Copy)]
    pub struct sigset_t {
        __val: [libc::c_ulong; 16],
    }
}

#[cfg(all(target_os = "linux",
          any(target_arch = "mips", target_arch = "mipsel")))]
pub mod signal {
    use libc;

    bitflags!(
        flags SockFlag: libc::c_uint {
            const SA_NOCLDSTOP = 0x00000001,
            const SA_NOCLDWAIT = 0x00001000,
            const SA_NODEFER   = 0x40000000,
            const SA_ONSTACK   = 0x08000000,
            const SA_RESETHAND = 0x80000000,
            const SA_RESTART   = 0x10000000,
            const SA_SIGINFO   = 0x00000008,
        }
    );

    pub const SIGTRAP:      libc::c_int = 5;
    pub const SIGIOT:       libc::c_int = 6;
    pub const SIGBUS:       libc::c_int = 10;
    pub const SIGSYS:       libc::c_int = 12;
    pub const SIGUSR1:      libc::c_int = 16;
    pub const SIGUSR2:      libc::c_int = 17;
    pub const SIGCHLD:      libc::c_int = 18;
    pub const SIGCLD:       libc::c_int = 18;
    pub const SIGPWR:       libc::c_int = 19;
    pub const SIGWINCH:     libc::c_int = 20;
    pub const SIGURG:       libc::c_int = 21;
    pub const SIGIO:        libc::c_int = 22;
    pub const SIGPOLL:      libc::c_int = 22;
    pub const SIGSTOP:      libc::c_int = 23;
    pub const SIGTSTP:      libc::c_int = 24;
    pub const SIGCONT:      libc::c_int = 25;
    pub const SIGTTIN:      libc::c_int = 26;
    pub const SIGTTOU:      libc::c_int = 27;
    pub const SIGVTALRM:    libc::c_int = 28;
    pub const SIGPROF:      libc::c_int = 29;
    pub const SIGXCPU:      libc::c_int = 30;
    pub const SIGFSZ:       libc::c_int = 31;

    // This definition is not as accurate as it could be, {pid, uid, status} is
    // actually a giant union. Currently we're only interested in these fields,
    // however.
    #[repr(C)]
    pub struct siginfo {
        si_signo: libc::c_int,
        si_code: libc::c_int,
        si_errno: libc::c_int,
        pub pid: libc::pid_t,
        pub uid: libc::uid_t,
        pub status: libc::c_int,
    }

    #[repr(C)]
    pub struct sigaction {
        pub sa_flags: SockFlag,
        pub sa_handler: extern fn(libc::c_int),
        pub sa_mask: sigset_t,
        sa_restorer: *mut libc::c_void,
        sa_resv: [libc::c_int; 1],
    }

    #[repr(C)]
    pub struct sigset_t {
        __val: [libc::c_ulong; 32],
    }
}

#[cfg(any(target_os = "macos",
          target_os = "ios",
          target_os = "freebsd",
          target_os = "openbsd",
          target_os = "dragonfly"))]
pub mod signal {
    use libc;

    bitflags!(
        flags SockFlag: libc::c_int {
            const SA_NOCLDSTOP = 0x0008,
            const SA_NOCLDWAIT = 0x0020,
            const SA_NODEFER   = 0x0010,
            const SA_ONSTACK   = 0x0001,
            const SA_RESETHAND = 0x0004,
            const SA_RESTART   = 0x0002,
            const SA_SIGINFO   = 0x0040,
        }
    );

    pub const SIGTRAP:      libc::c_int = 5;
    pub const SIGIOT:       libc::c_int = 6;
    pub const SIGBUS:       libc::c_int = 10;
    pub const SIGSYS:       libc::c_int = 12;
    pub const SIGURG:       libc::c_int = 16;
    pub const SIGSTOP:      libc::c_int = 17;
    pub const SIGTSTP:      libc::c_int = 18;
    pub const SIGCONT:      libc::c_int = 19;
    pub const SIGCHLD:      libc::c_int = 20;
    pub const SIGTTIN:      libc::c_int = 21;
    pub const SIGTTOU:      libc::c_int = 22;
    pub const SIGIO:        libc::c_int = 23;
    pub const SIGXCPU:      libc::c_int = 24;
    pub const SIGXFSZ:      libc::c_int = 25;
    pub const SIGVTALRM:    libc::c_int = 26;
    pub const SIGPROF:      libc::c_int = 27;
    pub const SIGWINCH:     libc::c_int = 28;
    pub const SIGINFO:      libc::c_int = 29;
    pub const SIGUSR1:      libc::c_int = 30;
    pub const SIGUSR2:      libc::c_int = 31;

    #[cfg(any(target_os = "macos", target_os = "ios", target_os = "openbsd"))]
    pub type sigset_t = u32;
    #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
    #[repr(C)]
    #[derive(Clone, Copy)]
    pub struct sigset_t {
        bits: [u32; 4],
    }

    // This structure has more fields, but we're not all that interested in
    // them.
    #[repr(C)]
    #[derive(Clone, Copy)]
    pub struct siginfo {
        pub si_signo: libc::c_int,
        pub si_errno: libc::c_int,
        pub si_code: libc::c_int,
        pub pid: libc::pid_t,
        pub uid: libc::uid_t,
        pub status: libc::c_int,
    }

    #[cfg(any(target_os = "macos", target_os = "ios"))]
    #[repr(C)]
    #[allow(missing_copy_implementations)]
    pub struct sigaction {
        pub sa_handler: extern fn(libc::c_int),
        pub sa_mask: sigset_t,
        pub sa_flags: SockFlag,
    }

    #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
    #[repr(C)]
    pub struct sigaction {
        pub sa_handler: extern fn(libc::c_int),
        pub sa_flags: SockFlag,
        pub sa_mask: sigset_t,
    }

    #[cfg(target_os = "openbsd")]
    #[repr(C)]
    pub struct sigaction {
        pub sa_handler: extern fn(libc::c_int),
        pub sa_mask: sigset_t,
        pub sa_flags: SockFlag,
    }
}

mod ffi {
    use libc;
    use super::signal::{sigaction, sigset_t};

    #[allow(improper_ctypes)]
    extern {
        pub fn sigaction(signum: libc::c_int,
                         act: *const sigaction,
                         oldact: *mut sigaction) -> libc::c_int;

        pub fn sigaddset(set: *mut sigset_t, signum: libc::c_int) -> libc::c_int;
        pub fn sigdelset(set: *mut sigset_t, signum: libc::c_int) -> libc::c_int;
        pub fn sigemptyset(set: *mut sigset_t) -> libc::c_int;

        pub fn kill(pid: libc::pid_t, signum: libc::c_int) -> libc::c_int;
    }
}

#[derive(Clone, Copy)]
pub struct SigSet {
    sigset: sigset_t
}

pub type SigNum = libc::c_int;

impl SigSet {
    pub fn empty() -> SigSet {
        let mut sigset = unsafe { mem::uninitialized::<sigset_t>() };
        let _ = unsafe { ffi::sigemptyset(&mut sigset as *mut sigset_t) };

        SigSet { sigset: sigset }
    }

    pub fn add(&mut self, signum: SigNum) -> Result<()> {
        let res = unsafe { ffi::sigaddset(&mut self.sigset as *mut sigset_t, signum) };

        if res < 0 {
            return Err(Error::Sys(Errno::last()));
        }

        Ok(())
    }

    pub fn remove(&mut self, signum: SigNum) -> Result<()> {
        let res = unsafe { ffi::sigdelset(&mut self.sigset as *mut sigset_t, signum) };

        if res < 0 {
            return Err(Error::Sys(Errno::last()));
        }

        Ok(())
    }
}

type sigaction_t = self::signal::sigaction;

pub struct SigAction {
    sigaction: sigaction_t
}

impl SigAction {
    pub fn new(handler: extern fn(libc::c_int), flags: SockFlag, mask: SigSet) -> SigAction {
        let mut s = unsafe { mem::uninitialized::<sigaction_t>() };
        s.sa_handler = handler;
        s.sa_flags = flags;
        s.sa_mask = mask.sigset;

        SigAction { sigaction: s }
    }
}

pub unsafe fn sigaction(signum: SigNum, sigaction: &SigAction) -> Result<SigAction> {
    let mut oldact = mem::uninitialized::<sigaction_t>();

    let res =
        ffi::sigaction(signum, &sigaction.sigaction as *const sigaction_t, &mut oldact as *mut sigaction_t);

    if res < 0 {
        return Err(Error::Sys(Errno::last()));
    }

    Ok(SigAction { sigaction: oldact })
}

pub fn kill(pid: libc::pid_t, signum: SigNum) -> Result<()> {
    let res = unsafe { ffi::kill(pid, signum) };

    if res < 0 {
        return Err(Error::Sys(Errno::last()));
    }

    Ok(())
}
<|endoftext|>


<commit_before>use {Result, NixPath, from_ffi};
use errno::Errno;
use std::os::unix::io::AsRawFd;

pub mod vfs {
    #[cfg(target_pointer_width = "32")]
        pub mod hwdep {
        use libc::{c_uint};
        pub type FsType = c_uint;
        pub type BlockSize = c_uint;
        pub type NameLen = c_uint;
        pub type FragmentSize = c_uint;
        pub type SwordType = c_uint;
    }

    #[cfg(target_pointer_width = "64")]
    pub mod hwdep {
        use libc::{c_long};
        pub type FsType = c_long;
        pub type BlockSize = c_long;
        pub type NameLen = c_long;
        pub type FragmentSize = c_long;
        pub type SwordType = c_long;
    }

    use sys::statfs::vfs::hwdep::*;

    #[repr(C)]
    #[derive(Debug,Copy,Clone)]
    pub struct Statfs {
        pub f_type:  FsType,
        pub f_bsize: BlockSize,
        pub f_blocks: u64,
        pub f_bfree: u64,
        pub f_bavail: u64,
        pub f_files: u64,
        pub f_ffree: u64,
        pub f_fsid: u64,
        pub f_namelen: NameLen,
        pub f_frsize: FragmentSize,
        pub f_spare: [SwordType; 5],
    }

    pub const ADFS_SUPER_MAGIC : FsType =      0xadf5;
    pub const AFFS_SUPER_MAGIC : FsType =      0xADFF;
    pub const BEFS_SUPER_MAGIC : FsType =      0x42465331;
    pub const BFS_MAGIC : FsType =             0x1BADFACE;
    pub const CIFS_MAGIC_NUMBER : FsType =     0xFF534D42;
    pub const CODA_SUPER_MAGIC : FsType =      0x73757245;
    pub const COH_SUPER_MAGIC : FsType =       0x012FF7B7;
    pub const CRAMFS_MAGIC : FsType =          0x28cd3d45;
    pub const DEVFS_SUPER_MAGIC : FsType =     0x1373;
    pub const EFS_SUPER_MAGIC : FsType =       0x00414A53;
    pub const EXT_SUPER_MAGIC : FsType =       0x137D;
    pub const EXT2_OLD_SUPER_MAGIC : FsType =  0xEF51;
    pub const EXT2_SUPER_MAGIC : FsType =      0xEF53;
    pub const EXT3_SUPER_MAGIC : FsType =      0xEF53;
    pub const EXT4_SUPER_MAGIC : FsType =      0xEF53;
    pub const HFS_SUPER_MAGIC : FsType =       0x4244;
    pub const HPFS_SUPER_MAGIC : FsType =      0xF995E849;
    pub const HUGETLBFS_MAGIC : FsType =       0x958458f6;
    pub const ISOFS_SUPER_MAGIC : FsType =     0x9660;
    pub const JFFS2_SUPER_MAGIC : FsType =     0x72b6;
    pub const JFS_SUPER_MAGIC : FsType =       0x3153464a;
    pub const MINIX_SUPER_MAGIC : FsType =     0x137F; /* orig. minix */
    pub const MINIX_SUPER_MAGIC2 : FsType =    0x138F; /* 30 char minix */
    pub const MINIX2_SUPER_MAGIC : FsType =    0x2468; /* minix V2 */
    pub const MINIX2_SUPER_MAGIC2 : FsType =   0x2478; /* minix V2, 30 char names */
    pub const MSDOS_SUPER_MAGIC : FsType =     0x4d44;
    pub const NCP_SUPER_MAGIC : FsType =       0x564c;
    pub const NFS_SUPER_MAGIC : FsType =       0x6969;
    pub const NTFS_SB_MAGIC : FsType =         0x5346544e;
    pub const OPENPROM_SUPER_MAGIC : FsType =  0x9fa1;
    pub const PROC_SUPER_MAGIC : FsType =      0x9fa0;
    pub const QNX4_SUPER_MAGIC : FsType =      0x002f;
    pub const REISERFS_SUPER_MAGIC : FsType =  0x52654973;
    pub const ROMFS_MAGIC : FsType =           0x7275;
    pub const SMB_SUPER_MAGIC : FsType =       0x517B;
    pub const SYSV2_SUPER_MAGIC : FsType =     0x012FF7B6;
    pub const SYSV4_SUPER_MAGIC : FsType =     0x012FF7B5;
    pub const TMPFS_MAGIC : FsType =           0x01021994;
    pub const UDF_SUPER_MAGIC : FsType =       0x15013346;
    pub const UFS_MAGIC : FsType =             0x00011954;
    pub const USBDEVICE_SUPER_MAGIC : FsType = 0x9fa2;
    pub const VXFS_SUPER_MAGIC : FsType =      0xa501FCF5;
    pub const XENIX_SUPER_MAGIC : FsType =     0x012FF7B4;
    pub const XFS_SUPER_MAGIC : FsType =       0x58465342;
    pub const _XIAFS_SUPER_MAGIC : FsType =    0x012FD16D;
}

mod ffi {
    use libc::{c_int,c_char};
    use sys::statfs::vfs;

    extern {
        pub fn statfs(path: * const c_char, buf: *mut vfs::Statfs) -> c_int;
        pub fn fstatfs(fd: c_int, buf: *mut vfs::Statfs) -> c_int;
    }
}

pub fn statfs<P: ?Sized + NixPath>(path: &P, stat: &mut vfs::Statfs) -> Result<()> {
    unsafe {
        Errno::clear();
        let res = try!(
            path.with_nix_path(|path| ffi::statfs(path.as_ptr(), stat))
        );
        from_ffi(res)
    }
}

pub fn fstatfs<T: AsRawFd>(fd: &T, stat: &mut vfs::Statfs) -> Result<()> {
    unsafe {
        Errno::clear();
        from_ffi(ffi::fstatfs(fd.as_raw_fd(), stat))
    }
}
<commit_msg>Fix an indent<commit_after>use {Result, NixPath, from_ffi};
use errno::Errno;
use std::os::unix::io::AsRawFd;

pub mod vfs {
    #[cfg(target_pointer_width = "32")]
    pub mod hwdep {
        use libc::{c_uint};
        pub type FsType = c_uint;
        pub type BlockSize = c_uint;
        pub type NameLen = c_uint;
        pub type FragmentSize = c_uint;
        pub type SwordType = c_uint;
    }

    #[cfg(target_pointer_width = "64")]
    pub mod hwdep {
        use libc::{c_long};
        pub type FsType = c_long;
        pub type BlockSize = c_long;
        pub type NameLen = c_long;
        pub type FragmentSize = c_long;
        pub type SwordType = c_long;
    }

    use sys::statfs::vfs::hwdep::*;

    #[repr(C)]
    #[derive(Debug,Copy,Clone)]
    pub struct Statfs {
        pub f_type:  FsType,
        pub f_bsize: BlockSize,
        pub f_blocks: u64,
        pub f_bfree: u64,
        pub f_bavail: u64,
        pub f_files: u64,
        pub f_ffree: u64,
        pub f_fsid: u64,
        pub f_namelen: NameLen,
        pub f_frsize: FragmentSize,
        pub f_spare: [SwordType; 5],
    }

    pub const ADFS_SUPER_MAGIC : FsType =      0xadf5;
    pub const AFFS_SUPER_MAGIC : FsType =      0xADFF;
    pub const BEFS_SUPER_MAGIC : FsType =      0x42465331;
    pub const BFS_MAGIC : FsType =             0x1BADFACE;
    pub const CIFS_MAGIC_NUMBER : FsType =     0xFF534D42;
    pub const CODA_SUPER_MAGIC : FsType =      0x73757245;
    pub const COH_SUPER_MAGIC : FsType =       0x012FF7B7;
    pub const CRAMFS_MAGIC : FsType =          0x28cd3d45;
    pub const DEVFS_SUPER_MAGIC : FsType =     0x1373;
    pub const EFS_SUPER_MAGIC : FsType =       0x00414A53;
    pub const EXT_SUPER_MAGIC : FsType =       0x137D;
    pub const EXT2_OLD_SUPER_MAGIC : FsType =  0xEF51;
    pub const EXT2_SUPER_MAGIC : FsType =      0xEF53;
    pub const EXT3_SUPER_MAGIC : FsType =      0xEF53;
    pub const EXT4_SUPER_MAGIC : FsType =      0xEF53;
    pub const HFS_SUPER_MAGIC : FsType =       0x4244;
    pub const HPFS_SUPER_MAGIC : FsType =      0xF995E849;
    pub const HUGETLBFS_MAGIC : FsType =       0x958458f6;
    pub const ISOFS_SUPER_MAGIC : FsType =     0x9660;
    pub const JFFS2_SUPER_MAGIC : FsType =     0x72b6;
    pub const JFS_SUPER_MAGIC : FsType =       0x3153464a;
    pub const MINIX_SUPER_MAGIC : FsType =     0x137F; /* orig. minix */
    pub const MINIX_SUPER_MAGIC2 : FsType =    0x138F; /* 30 char minix */
    pub const MINIX2_SUPER_MAGIC : FsType =    0x2468; /* minix V2 */
    pub const MINIX2_SUPER_MAGIC2 : FsType =   0x2478; /* minix V2, 30 char names */
    pub const MSDOS_SUPER_MAGIC : FsType =     0x4d44;
    pub const NCP_SUPER_MAGIC : FsType =       0x564c;
    pub const NFS_SUPER_MAGIC : FsType =       0x6969;
    pub const NTFS_SB_MAGIC : FsType =         0x5346544e;
    pub const OPENPROM_SUPER_MAGIC : FsType =  0x9fa1;
    pub const PROC_SUPER_MAGIC : FsType =      0x9fa0;
    pub const QNX4_SUPER_MAGIC : FsType =      0x002f;
    pub const REISERFS_SUPER_MAGIC : FsType =  0x52654973;
    pub const ROMFS_MAGIC : FsType =           0x7275;
    pub const SMB_SUPER_MAGIC : FsType =       0x517B;
    pub const SYSV2_SUPER_MAGIC : FsType =     0x012FF7B6;
    pub const SYSV4_SUPER_MAGIC : FsType =     0x012FF7B5;
    pub const TMPFS_MAGIC : FsType =           0x01021994;
    pub const UDF_SUPER_MAGIC : FsType =       0x15013346;
    pub const UFS_MAGIC : FsType =             0x00011954;
    pub const USBDEVICE_SUPER_MAGIC : FsType = 0x9fa2;
    pub const VXFS_SUPER_MAGIC : FsType =      0xa501FCF5;
    pub const XENIX_SUPER_MAGIC : FsType =     0x012FF7B4;
    pub const XFS_SUPER_MAGIC : FsType =       0x58465342;
    pub const _XIAFS_SUPER_MAGIC : FsType =    0x012FD16D;
}

mod ffi {
    use libc::{c_int,c_char};
    use sys::statfs::vfs;

    extern {
        pub fn statfs(path: * const c_char, buf: *mut vfs::Statfs) -> c_int;
        pub fn fstatfs(fd: c_int, buf: *mut vfs::Statfs) -> c_int;
    }
}

pub fn statfs<P: ?Sized + NixPath>(path: &P, stat: &mut vfs::Statfs) -> Result<()> {
    unsafe {
        Errno::clear();
        let res = try!(
            path.with_nix_path(|path| ffi::statfs(path.as_ptr(), stat))
        );
        from_ffi(res)
    }
}

pub fn fstatfs<T: AsRawFd>(fd: &T, stat: &mut vfs::Statfs) -> Result<()> {
    unsafe {
        Errno::clear();
        from_ffi(ffi::fstatfs(fd.as_raw_fd(), stat))
    }
}
<|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 dom::bindings::codegen::Bindings::EventBinding::EventMethods;
use dom::bindings::inheritance::Castable;
use dom::bindings::str::DOMString;
use dom::element::Element;
use dom::event::{Event, EventBubbles, EventCancelable};
use dom::eventtarget::EventTarget;
use dom::mouseevent::MouseEvent;
use dom::node::window_from_node;
use dom::window::ReflowReason;
use script_layout_interface::message::ReflowQueryType;
use style::context::ReflowGoal;

/// Trait for elements with defined activation behavior
pub trait Activatable {
    fn as_element(&self) -> ∈

    // Is this particular instance of the element activatable?
    fn is_instance_activatable(&self) -> bool;

    // https://html.spec.whatwg.org/multipage/#run-pre-click-activation-steps
    fn pre_click_activation(&self);

    // https://html.spec.whatwg.org/multipage/#run-canceled-activation-steps
    fn canceled_activation(&self);

    // https://html.spec.whatwg.org/multipage/#run-post-click-activation-steps
    fn activation_behavior(&self, event: &Event, target: &EventTarget);

    // https://html.spec.whatwg.org/multipage/#implicit-submission
    fn implicit_submission(&self, ctrlKey: bool, shiftKey: bool, altKey: bool, metaKey: bool);

    // https://html.spec.whatwg.org/multipage/#concept-selector-active
    fn enter_formal_activation_state(&self) {
        self.as_element().set_active_state(true);

        let win = window_from_node(self.as_element());
        win.reflow(ReflowGoal::ForDisplay,
                   ReflowQueryType::NoQuery,
                   ReflowReason::ElementStateChanged);
    }

    fn exit_formal_activation_state(&self) {
        self.as_element().set_active_state(false);

        let win = window_from_node(self.as_element());
        win.reflow(ReflowGoal::ForDisplay,
                   ReflowQueryType::NoQuery,
                   ReflowReason::ElementStateChanged);
    }
}

/// Whether an activation was initiated via the click() method
#[derive(PartialEq)]
pub enum ActivationSource {
    FromClick,
    NotFromClick,
}

// https://html.spec.whatwg.org/multipage/#run-synthetic-click-activation-steps
pub fn synthetic_click_activation(element: &Element,
                                  ctrl_key: bool,
                                  shift_key: bool,
                                  alt_key: bool,
                                  meta_key: bool,
                                  source: ActivationSource) {
    // Step 1
    if element.click_in_progress() {
        return;
    }
    // Step 2
    element.set_click_in_progress(true);
    // Step 3
    let activatable = element.as_maybe_activatable();
    if let Some(a) = activatable {
        a.pre_click_activation();
    }

    // Step 4
    // https://html.spec.whatwg.org/multipage/#fire-a-synthetic-mouse-event
    let win = window_from_node(element);
    let target = element.upcast::<EventTarget>();
    let mouse = MouseEvent::new(win.r(),
                                DOMString::from("click"),
                                EventBubbles::DoesNotBubble,
                                EventCancelable::NotCancelable,
                                Some(win.r()),
                                1,
                                0,
                                0,
                                0,
                                0,
                                ctrl_key,
                                shift_key,
                                alt_key,
                                meta_key,
                                0,
                                None);
    let event = mouse.upcast::<Event>();
    if source == ActivationSource::FromClick {
        event.set_trusted(false);
    }
    target.dispatch_event(event);

    // Step 5
    if let Some(a) = activatable {
        if event.DefaultPrevented() {
            a.canceled_activation();
        } else {
            // post click activation
            a.activation_behavior(event, target);
        }
    }

    // Step 6
    element.set_click_in_progress(false);
}
<commit_msg>One last refactoring before fixing<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 dom::bindings::codegen::Bindings::EventBinding::EventMethods;
use dom::bindings::inheritance::Castable;
use dom::bindings::str::DOMString;
use dom::element::Element;
use dom::event::{Event, EventBubbles, EventCancelable};
use dom::eventtarget::EventTarget;
use dom::mouseevent::MouseEvent;
use dom::node::window_from_node;
use dom::window::ReflowReason;
use script_layout_interface::message::ReflowQueryType;
use style::context::ReflowGoal;

/// Trait for elements with defined activation behavior
pub trait Activatable {
    fn as_element(&self) -> ∈

    // Is this particular instance of the element activatable?
    fn is_instance_activatable(&self) -> bool;

    // https://html.spec.whatwg.org/multipage/#run-pre-click-activation-steps
    fn pre_click_activation(&self);

    // https://html.spec.whatwg.org/multipage/#run-canceled-activation-steps
    fn canceled_activation(&self);

    // https://html.spec.whatwg.org/multipage/#run-post-click-activation-steps
    fn activation_behavior(&self, event: &Event, target: &EventTarget);

    // https://html.spec.whatwg.org/multipage/#implicit-submission
    fn implicit_submission(&self, ctrl_key: bool, shift_key: bool, alt_key: bool, meta_key: bool);

    // https://html.spec.whatwg.org/multipage/#concept-selector-active
    fn enter_formal_activation_state(&self) {
        self.as_element().set_active_state(true);

        let win = window_from_node(self.as_element());
        win.reflow(ReflowGoal::ForDisplay,
                   ReflowQueryType::NoQuery,
                   ReflowReason::ElementStateChanged);
    }

    fn exit_formal_activation_state(&self) {
        self.as_element().set_active_state(false);

        let win = window_from_node(self.as_element());
        win.reflow(ReflowGoal::ForDisplay,
                   ReflowQueryType::NoQuery,
                   ReflowReason::ElementStateChanged);
    }
}

/// Whether an activation was initiated via the click() method
#[derive(PartialEq)]
pub enum ActivationSource {
    FromClick,
    NotFromClick,
}

// https://html.spec.whatwg.org/multipage/#run-synthetic-click-activation-steps
pub fn synthetic_click_activation(element: &Element,
                                  ctrl_key: bool,
                                  shift_key: bool,
                                  alt_key: bool,
                                  meta_key: bool,
                                  source: ActivationSource) {
    // Step 1
    if element.click_in_progress() {
        return;
    }
    // Step 2
    element.set_click_in_progress(true);
    // Step 3
    let activatable = element.as_maybe_activatable();
    if let Some(a) = activatable {
        a.pre_click_activation();
    }

    // Step 4
    // https://html.spec.whatwg.org/multipage/#fire-a-synthetic-mouse-event
    let win = window_from_node(element);
    let target = element.upcast::<EventTarget>();
    let mouse = MouseEvent::new(win.r(),
                                DOMString::from("click"),
                                EventBubbles::DoesNotBubble,
                                EventCancelable::NotCancelable,
                                Some(win.r()),
                                1,
                                0,
                                0,
                                0,
                                0,
                                ctrl_key,
                                shift_key,
                                alt_key,
                                meta_key,
                                0,
                                None);
    let event = mouse.upcast::<Event>();
    if source == ActivationSource::FromClick {
        event.set_trusted(false);
    }
    target.dispatch_event(event);

    // Step 5
    if let Some(a) = activatable {
        if event.DefaultPrevented() {
            a.canceled_activation();
        } else {
            // post click activation
            a.activation_behavior(event, target);
        }
    }

    // Step 6
    element.set_click_in_progress(false);
}
<|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/. */

//! Types used to report parsing errors.

#![deny(missing_docs)]

use cssparser::{BasicParseError, Token, SourceLocation};
use cssparser::ParseError as CssParseError;
use log;
use style_traits::ParseError;
use stylesheets::UrlExtraData;

/// Errors that can be encountered while parsing CSS.
pub enum ContextualParseError<'a> {
    /// A property declaration was not recognized.
    UnsupportedPropertyDeclaration(&'a str, ParseError<'a>),
    /// A font face descriptor was not recognized.
    UnsupportedFontFaceDescriptor(&'a str, ParseError<'a>),
    /// A font feature values descroptor was not recognized.
    UnsupportedFontFeatureValuesDescriptor(&'a str, ParseError<'a>),
    /// A keyframe rule was not valid.
    InvalidKeyframeRule(&'a str, ParseError<'a>),
    /// A font feature values rule was not valid.
    InvalidFontFeatureValuesRule(&'a str, ParseError<'a>),
    /// A keyframe property declaration was not recognized.
    UnsupportedKeyframePropertyDeclaration(&'a str, ParseError<'a>),
    /// A rule was invalid for some reason.
    InvalidRule(&'a str, ParseError<'a>),
    /// A rule was not recognized.
    UnsupportedRule(&'a str, ParseError<'a>),
    /// A viewport descriptor declaration was not recognized.
    UnsupportedViewportDescriptorDeclaration(&'a str, ParseError<'a>),
    /// A counter style descriptor declaration was not recognized.
    UnsupportedCounterStyleDescriptorDeclaration(&'a str, ParseError<'a>),
    /// A counter style rule had no symbols.
    InvalidCounterStyleWithoutSymbols(String),
    /// A counter style rule had less than two symbols.
    InvalidCounterStyleNotEnoughSymbols(String),
    /// A counter style rule did not have additive-symbols.
    InvalidCounterStyleWithoutAdditiveSymbols,
    /// A counter style rule had extends with symbols.
    InvalidCounterStyleExtendsWithSymbols,
    /// A counter style rule had extends with additive-symbols.
    InvalidCounterStyleExtendsWithAdditiveSymbols
}

impl<'a> ContextualParseError<'a> {
    /// Turn a parse error into a string representation.
    pub fn to_string(&self) -> String {
        fn token_to_str(t: &Token) -> String {
            match *t {
                Token::Ident(ref i) => format!("identifier {}", i),
                Token::AtKeyword(ref kw) => format!("keyword @{}", kw),
                Token::Hash(ref h) => format!("hash #{}", h),
                Token::IDHash(ref h) => format!("id selector #{}", h),
                Token::QuotedString(ref s) => format!("quoted string \"{}\"", s),
                Token::UnquotedUrl(ref u) => format!("url {}", u),
                Token::Delim(ref d) => format!("delimiter {}", d),
                Token::Number { int_value: Some(i), .. } => format!("number {}", i),
                Token::Number { value, .. } => format!("number {}", value),
                Token::Percentage { int_value: Some(i), .. } => format!("percentage {}", i),
                Token::Percentage { unit_value, .. } => format!("percentage {}", unit_value * 100.),
                Token::Dimension { value, ref unit, .. } => format!("dimension {}{}", value, unit),
                Token::WhiteSpace(_) => format!("whitespace"),
                Token::Comment(_) => format!("comment"),
                Token::Colon => format!("colon (:)"),
                Token::Semicolon => format!("semicolon (;)"),
                Token::Comma => format!("comma (,)"),
                Token::IncludeMatch => format!("include match (~=)"),
                Token::DashMatch => format!("dash match (|=)"),
                Token::PrefixMatch => format!("prefix match (^=)"),
                Token::SuffixMatch => format!("suffix match ($=)"),
                Token::SubstringMatch => format!("substring match (*=)"),
                Token::Column => format!("column (||)"),
                Token::CDO => format!("CDO (<!--)"),
                Token::CDC => format!("CDC (-->)"),
                Token::Function(ref f) => format!("function {}", f),
                Token::ParenthesisBlock => format!("parenthesis ("),
                Token::SquareBracketBlock => format!("square bracket ["),
                Token::CurlyBracketBlock => format!("curly bracket {{"),
                Token::BadUrl(ref _u) => format!("bad url parse error"),
                Token::BadString(ref _s) => format!("bad string parse error"),
                Token::CloseParenthesis => format!("unmatched close parenthesis"),
                Token::CloseSquareBracket => format!("unmatched close square bracket"),
                Token::CloseCurlyBracket => format!("unmatched close curly bracket"),
            }
        }

        fn parse_error_to_str(err: &ParseError) -> String {
            match *err {
                CssParseError::Basic(BasicParseError::UnexpectedToken(ref t)) =>
                    format!("found unexpected {}", token_to_str(t)),
                CssParseError::Basic(BasicParseError::EndOfInput) =>
                    format!("unexpected end of input"),
                CssParseError::Basic(BasicParseError::AtRuleInvalid(ref i)) =>
                    format!("@ rule invalid: {}", i),
                CssParseError::Basic(BasicParseError::AtRuleBodyInvalid) =>
                    format!("@ rule invalid"),
                CssParseError::Basic(BasicParseError::QualifiedRuleInvalid) =>
                    format!("qualified rule invalid"),
                CssParseError::Custom(ref err) =>
                    format!("{:?}", err)
            }
        }

        match *self {
            ContextualParseError::UnsupportedPropertyDeclaration(decl, ref err) =>
                format!("Unsupported property declaration: '{}', {}", decl,
                        parse_error_to_str(err)),
            ContextualParseError::UnsupportedFontFaceDescriptor(decl, ref err) =>
                format!("Unsupported @font-face descriptor declaration: '{}', {}", decl,
                        parse_error_to_str(err)),
            ContextualParseError::UnsupportedFontFeatureValuesDescriptor(decl, ref err) =>
            format!("Unsupported @font-feature-values descriptor declaration: '{}', {}", decl,
                    parse_error_to_str(err)),
            ContextualParseError::InvalidKeyframeRule(rule, ref err) =>
                format!("Invalid keyframe rule: '{}', {}", rule,
                        parse_error_to_str(err)),
            ContextualParseError::InvalidFontFeatureValuesRule(rule, ref err) =>
            format!("Invalid font feature value rule: '{}', {}", rule,
                    parse_error_to_str(err)),
            ContextualParseError::UnsupportedKeyframePropertyDeclaration(decl, ref err) =>
                format!("Unsupported keyframe property declaration: '{}', {}", decl,
                        parse_error_to_str(err)),
            ContextualParseError::InvalidRule(rule, ref err) =>
                format!("Invalid rule: '{}', {}", rule, parse_error_to_str(err)),
            ContextualParseError::UnsupportedRule(rule, ref err) =>
                format!("Unsupported rule: '{}', {}", rule, parse_error_to_str(err)),
            ContextualParseError::UnsupportedViewportDescriptorDeclaration(decl, ref err) =>
                format!("Unsupported @viewport descriptor declaration: '{}', {}", decl,
                        parse_error_to_str(err)),
            ContextualParseError::UnsupportedCounterStyleDescriptorDeclaration(decl, ref err) =>
                format!("Unsupported @counter-style descriptor declaration: '{}', {}", decl,
                        parse_error_to_str(err)),
            ContextualParseError::InvalidCounterStyleWithoutSymbols(ref system) =>
                format!("Invalid @counter-style rule: 'system: {}' without 'symbols'", system),
            ContextualParseError::InvalidCounterStyleNotEnoughSymbols(ref system) =>
                format!("Invalid @counter-style rule: 'system: {}' less than two 'symbols'", system),
            ContextualParseError::InvalidCounterStyleWithoutAdditiveSymbols =>
                "Invalid @counter-style rule: 'system: additive' without 'additive-symbols'".into(),
            ContextualParseError::InvalidCounterStyleExtendsWithSymbols =>
                "Invalid @counter-style rule: 'system: extends …' with 'symbols'".into(),
            ContextualParseError::InvalidCounterStyleExtendsWithAdditiveSymbols =>
                "Invalid @counter-style rule: 'system: extends …' with 'additive-symbols'".into(),
        }
    }
}

/// A generic trait for an error reporter.
pub trait ParseErrorReporter {
    /// Called when the style engine detects an error.
    ///
    /// Returns the current input being parsed, the source location it was
    /// reported from, and a message.
    fn report_error(&self,
                    url: &UrlExtraData,
                    location: SourceLocation,
                    error: ContextualParseError);
}

/// An error reporter that uses [the `log` crate](https://github.com/rust-lang-nursery/log)
/// at `info` level.
///
/// This logging is silent by default, and can be enabled with a `RUST_LOG=style=info`
/// environment variable.
/// (See [`env_logger`](https://rust-lang-nursery.github.io/log/env_logger/).)
pub struct RustLogReporter;

impl ParseErrorReporter for RustLogReporter {
    fn report_error(&self,
                    url: &UrlExtraData,
                    location: SourceLocation,
                    error: ContextualParseError) {
        if log_enabled!(log::LogLevel::Info) {
            info!("Url:\t{}\n{}:{} {}", url.as_str(), location.line, location.column, error.to_string())
        }
    }
}

/// Error reporter which silently forgets errors
pub struct NullReporter;

impl ParseErrorReporter for NullReporter {
    fn report_error(&self,
                    _url: &UrlExtraData,
                    _location: SourceLocation,
                    _error: ContextualParseError) {
        // do nothing
    }
}
<commit_msg>Reformat a couple match expressions<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/. */

//! Types used to report parsing errors.

#![deny(missing_docs)]

use cssparser::{BasicParseError, Token, SourceLocation};
use cssparser::ParseError as CssParseError;
use log;
use style_traits::ParseError;
use stylesheets::UrlExtraData;

/// Errors that can be encountered while parsing CSS.
pub enum ContextualParseError<'a> {
    /// A property declaration was not recognized.
    UnsupportedPropertyDeclaration(&'a str, ParseError<'a>),
    /// A font face descriptor was not recognized.
    UnsupportedFontFaceDescriptor(&'a str, ParseError<'a>),
    /// A font feature values descroptor was not recognized.
    UnsupportedFontFeatureValuesDescriptor(&'a str, ParseError<'a>),
    /// A keyframe rule was not valid.
    InvalidKeyframeRule(&'a str, ParseError<'a>),
    /// A font feature values rule was not valid.
    InvalidFontFeatureValuesRule(&'a str, ParseError<'a>),
    /// A keyframe property declaration was not recognized.
    UnsupportedKeyframePropertyDeclaration(&'a str, ParseError<'a>),
    /// A rule was invalid for some reason.
    InvalidRule(&'a str, ParseError<'a>),
    /// A rule was not recognized.
    UnsupportedRule(&'a str, ParseError<'a>),
    /// A viewport descriptor declaration was not recognized.
    UnsupportedViewportDescriptorDeclaration(&'a str, ParseError<'a>),
    /// A counter style descriptor declaration was not recognized.
    UnsupportedCounterStyleDescriptorDeclaration(&'a str, ParseError<'a>),
    /// A counter style rule had no symbols.
    InvalidCounterStyleWithoutSymbols(String),
    /// A counter style rule had less than two symbols.
    InvalidCounterStyleNotEnoughSymbols(String),
    /// A counter style rule did not have additive-symbols.
    InvalidCounterStyleWithoutAdditiveSymbols,
    /// A counter style rule had extends with symbols.
    InvalidCounterStyleExtendsWithSymbols,
    /// A counter style rule had extends with additive-symbols.
    InvalidCounterStyleExtendsWithAdditiveSymbols
}

impl<'a> ContextualParseError<'a> {
    /// Turn a parse error into a string representation.
    pub fn to_string(&self) -> String {
        fn token_to_str(t: &Token) -> String {
            match *t {
                Token::Ident(ref i) => format!("identifier {}", i),
                Token::AtKeyword(ref kw) => format!("keyword @{}", kw),
                Token::Hash(ref h) => format!("hash #{}", h),
                Token::IDHash(ref h) => format!("id selector #{}", h),
                Token::QuotedString(ref s) => format!("quoted string \"{}\"", s),
                Token::UnquotedUrl(ref u) => format!("url {}", u),
                Token::Delim(ref d) => format!("delimiter {}", d),
                Token::Number { int_value: Some(i), .. } => format!("number {}", i),
                Token::Number { value, .. } => format!("number {}", value),
                Token::Percentage { int_value: Some(i), .. } => format!("percentage {}", i),
                Token::Percentage { unit_value, .. } => format!("percentage {}", unit_value * 100.),
                Token::Dimension { value, ref unit, .. } => format!("dimension {}{}", value, unit),
                Token::WhiteSpace(_) => format!("whitespace"),
                Token::Comment(_) => format!("comment"),
                Token::Colon => format!("colon (:)"),
                Token::Semicolon => format!("semicolon (;)"),
                Token::Comma => format!("comma (,)"),
                Token::IncludeMatch => format!("include match (~=)"),
                Token::DashMatch => format!("dash match (|=)"),
                Token::PrefixMatch => format!("prefix match (^=)"),
                Token::SuffixMatch => format!("suffix match ($=)"),
                Token::SubstringMatch => format!("substring match (*=)"),
                Token::Column => format!("column (||)"),
                Token::CDO => format!("CDO (<!--)"),
                Token::CDC => format!("CDC (-->)"),
                Token::Function(ref f) => format!("function {}", f),
                Token::ParenthesisBlock => format!("parenthesis ("),
                Token::SquareBracketBlock => format!("square bracket ["),
                Token::CurlyBracketBlock => format!("curly bracket {{"),
                Token::BadUrl(ref _u) => format!("bad url parse error"),
                Token::BadString(ref _s) => format!("bad string parse error"),
                Token::CloseParenthesis => format!("unmatched close parenthesis"),
                Token::CloseSquareBracket => format!("unmatched close square bracket"),
                Token::CloseCurlyBracket => format!("unmatched close curly bracket"),
            }
        }

        fn parse_error_to_str(err: &ParseError) -> String {
            match *err {
                CssParseError::Basic(BasicParseError::UnexpectedToken(ref t)) => {
                    format!("found unexpected {}", token_to_str(t))
                }
                CssParseError::Basic(BasicParseError::EndOfInput) => {
                    format!("unexpected end of input")
                }
                CssParseError::Basic(BasicParseError::AtRuleInvalid(ref i)) => {
                    format!("@ rule invalid: {}", i)
                }
                CssParseError::Basic(BasicParseError::AtRuleBodyInvalid) => {
                    format!("@ rule invalid")
                }
                CssParseError::Basic(BasicParseError::QualifiedRuleInvalid) => {
                    format!("qualified rule invalid")
                }
                CssParseError::Custom(ref err) => {
                    format!("{:?}", err)
                }
            }
        }

        match *self {
            ContextualParseError::UnsupportedPropertyDeclaration(decl, ref err) => {
                format!("Unsupported property declaration: '{}', {}", decl,
                        parse_error_to_str(err))
            }
            ContextualParseError::UnsupportedFontFaceDescriptor(decl, ref err) => {
                format!("Unsupported @font-face descriptor declaration: '{}', {}", decl,
                        parse_error_to_str(err))
            }
            ContextualParseError::UnsupportedFontFeatureValuesDescriptor(decl, ref err) => {
                format!("Unsupported @font-feature-values descriptor declaration: '{}', {}", decl,
                        parse_error_to_str(err))
            }
            ContextualParseError::InvalidKeyframeRule(rule, ref err) => {
                format!("Invalid keyframe rule: '{}', {}", rule,
                        parse_error_to_str(err))
            }
            ContextualParseError::InvalidFontFeatureValuesRule(rule, ref err) => {
                format!("Invalid font feature value rule: '{}', {}", rule,
                        parse_error_to_str(err))
            }
            ContextualParseError::UnsupportedKeyframePropertyDeclaration(decl, ref err) => {
                format!("Unsupported keyframe property declaration: '{}', {}", decl,
                        parse_error_to_str(err))
            }
            ContextualParseError::InvalidRule(rule, ref err) => {
                format!("Invalid rule: '{}', {}", rule, parse_error_to_str(err))
            }
            ContextualParseError::UnsupportedRule(rule, ref err) => {
                format!("Unsupported rule: '{}', {}", rule, parse_error_to_str(err))
            }
            ContextualParseError::UnsupportedViewportDescriptorDeclaration(decl, ref err) => {
                format!("Unsupported @viewport descriptor declaration: '{}', {}", decl,
                        parse_error_to_str(err))
            }
            ContextualParseError::UnsupportedCounterStyleDescriptorDeclaration(decl, ref err) => {
                format!("Unsupported @counter-style descriptor declaration: '{}', {}", decl,
                        parse_error_to_str(err))
            }
            ContextualParseError::InvalidCounterStyleWithoutSymbols(ref system) => {
                format!("Invalid @counter-style rule: 'system: {}' without 'symbols'", system)
            }
            ContextualParseError::InvalidCounterStyleNotEnoughSymbols(ref system) => {
                format!("Invalid @counter-style rule: 'system: {}' less than two 'symbols'", system)
            }
            ContextualParseError::InvalidCounterStyleWithoutAdditiveSymbols => {
                "Invalid @counter-style rule: 'system: additive' without 'additive-symbols'".into()
            }
            ContextualParseError::InvalidCounterStyleExtendsWithSymbols => {
                "Invalid @counter-style rule: 'system: extends …' with 'symbols'".into()
            }
            ContextualParseError::InvalidCounterStyleExtendsWithAdditiveSymbols => {
                "Invalid @counter-style rule: 'system: extends …' with 'additive-symbols'".into()
            }
        }
    }
}

/// A generic trait for an error reporter.
pub trait ParseErrorReporter {
    /// Called when the style engine detects an error.
    ///
    /// Returns the current input being parsed, the source location it was
    /// reported from, and a message.
    fn report_error(&self,
                    url: &UrlExtraData,
                    location: SourceLocation,
                    error: ContextualParseError);
}

/// An error reporter that uses [the `log` crate](https://github.com/rust-lang-nursery/log)
/// at `info` level.
///
/// This logging is silent by default, and can be enabled with a `RUST_LOG=style=info`
/// environment variable.
/// (See [`env_logger`](https://rust-lang-nursery.github.io/log/env_logger/).)
pub struct RustLogReporter;

impl ParseErrorReporter for RustLogReporter {
    fn report_error(&self,
                    url: &UrlExtraData,
                    location: SourceLocation,
                    error: ContextualParseError) {
        if log_enabled!(log::LogLevel::Info) {
            info!("Url:\t{}\n{}:{} {}", url.as_str(), location.line, location.column, error.to_string())
        }
    }
}

/// Error reporter which silently forgets errors
pub struct NullReporter;

impl ParseErrorReporter for NullReporter {
    fn report_error(&self,
                    _url: &UrlExtraData,
                    _location: SourceLocation,
                    _error: ContextualParseError) {
        // do nothing
    }
}
<|endoftext|>


<commit_before><commit_msg>Make tests less intensive on Miri<commit_after><|endoftext|>


<commit_before>//
// Copyright 2019 The Project Oak Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

//! Test utilities to help with unit testing of Oak SDK code.

use anyhow::Context;
use log::{debug, info};
use oak_abi::{
    label::Label,
    proto::oak::application::{
        node_configuration::ConfigType, ApplicationConfiguration, ConfigMap, NodeConfiguration,
        WebAssemblyConfiguration,
    },
};
use prost::Message;
use std::{collections::HashMap, path::PathBuf, process::Command, sync::Arc};
use tonic::{
    metadata::MetadataValue,
    transport::{Certificate, Channel, ClientTlsConfig, Identity},
    Request,
};

pub enum Profile {
    Release,
    Debug,
}

// TODO(#544): re-enable unit tests of SDK functionality

/// Uses cargo to compile a Rust manifest to Wasm bytes.
pub fn compile_rust_wasm(
    cargo_path: &str,
    module_wasm_file_name: &str,
    profile: Profile,
) -> anyhow::Result<Vec<u8>> {
    // Use a separate target dir for Wasm build artifacts. The precise name is not relevant, but it
    // should end with `target` so that it gets automatically ignored by our `.gitignore`.
    let target_dir = PathBuf::from("oak_tests/target");

    let mut args = vec![
        "build".to_string(),
        format!(
            "--target-dir={}",
            target_dir.to_str().expect("invalid target dir")
        ),
        "--target=wasm32-unknown-unknown".to_string(),
        format!("--manifest-path={}", cargo_path),
    ];
    match profile {
        Profile::Release => args.push("--release".to_string()),
        Profile::Debug => (),
    }

    Command::new("cargo")
        .args(args)
        .env_remove("RUSTFLAGS")
        .spawn()
        .context("could not spawn cargo build")?
        .wait()
        .context("could not wait for cargo build to finish")?;

    let mut module_path = target_dir;
    module_path.push("wasm32-unknown-unknown/debug");
    module_path.push(module_wasm_file_name);

    info!("compiled Wasm module path: {:?}", module_path);

    std::fs::read(module_path).context("could not read compiled module")
}

/// Default module name for the module under test.
const DEFAULT_MODULE_NAME: &str = "app";
/// Default entrypoint name for the module under test.
const DEFAULT_ENTRYPOINT_NAME: &str = "oak_main";
/// Default URI that the tests expect to find a live Runtime at.
const RUNTIME_URI: &str = "https://localhost:8080";

const DEFAULT_MODULE_MANIFEST: &str = "Cargo.toml";

// Retry parameters when connecting to a gRPC server.
const RETRY_COUNT: u32 = 600;
const RETRY_INTERVAL: std::time::Duration = std::time::Duration::from_millis(800);

/// Convenience helper to build and run a single-Node Application with the given module name, using
/// the default name "oak_main" for its entrypoint.
pub fn run_single_module_default(
    module_config_name: &str,
) -> Result<Arc<oak_runtime::Runtime>, oak::OakError> {
    run_single_module(module_config_name, DEFAULT_ENTRYPOINT_NAME)
}

/// Convenience helper to build and run a single-Node application with the given Wasm module file
/// name, using the provided entrypoint name.
pub fn run_single_module(
    module_wasm_file_name: &str,
    entrypoint_name: &str,
) -> Result<Arc<oak_runtime::Runtime>, oak::OakError> {
    run_single_module_with_config(module_wasm_file_name, entrypoint_name, ConfigMap::default())
}

/// Convenience helper to build and run a single-Node application with the given Wasm module file
/// name, using the provided entrypoint name, passing in the provided `ConfigMap` at start-of-day.
pub fn run_single_module_with_config(
    module_wasm_file_name: &str,
    entrypoint_name: &str,
    config_map: ConfigMap,
) -> Result<Arc<oak_runtime::Runtime>, oak::OakError> {
    let combined_config = runtime_config(module_wasm_file_name, entrypoint_name, config_map);
    oak_runtime::configure_and_run(combined_config)
}

/// Build the configuration needed to launch a test Runtime instance that runs a single-Node
/// application with the given Wasm module file name and entrypoint.
pub fn runtime_config(
    module_wasm_file_name: &str,
    entrypoint_name: &str,
    config_map: ConfigMap,
) -> oak_runtime::RuntimeConfiguration {
    let wasm: HashMap<String, Vec<u8>> = [(
        DEFAULT_MODULE_NAME.to_string(),
        compile_rust_wasm(
            DEFAULT_MODULE_MANIFEST,
            module_wasm_file_name,
            Profile::Debug,
        )
        .expect("failed to build wasm module"),
    )]
    .iter()
    .cloned()
    .collect();

    runtime_config_wasm(wasm, DEFAULT_MODULE_NAME, entrypoint_name, config_map)
}

/// Build the configuration needed to launch a test Runtime instance that runs the given collection
/// of Wasm modules, starting with the given module name and entrypoint.
pub fn runtime_config_wasm(
    wasm_modules: HashMap<String, Vec<u8>>,
    module_config_name: &str,
    entrypoint_name: &str,
    config_map: ConfigMap,
) -> oak_runtime::RuntimeConfiguration {
    oak_runtime::RuntimeConfiguration {
        metrics_port: Some(9090),
        introspect_port: Some(1909),
        secure_server_configuration: oak_runtime::SecureServerConfiguration {
            grpc_config: Some(oak_runtime::GrpcConfiguration {
                grpc_server_tls_identity: Some(Identity::from_pem(
                    include_str!("../certs/local.pem"),
                    include_str!("../certs/local.key"),
                )),
                grpc_client_root_tls_certificate: Some(
                    oak_runtime::config::load_certificate(&include_str!("../certs/ca.pem"))
                        .unwrap(),
                ),
                oidc_client_info: None,
            }),
            http_config: create_http_config(),
        },
        app_config: ApplicationConfiguration {
            wasm_modules,
            initial_node_configuration: Some(NodeConfiguration {
                name: "test".to_string(),
                config_type: Some(ConfigType::WasmConfig(WebAssemblyConfiguration {
                    wasm_module_name: module_config_name.to_string(),
                    wasm_entrypoint_name: entrypoint_name.to_string(),
                })),
            }),
        },
        config_map,
        sign_table: oak_runtime::SignatureTable::default(),
    }
}

/// Tries to create a [`oak_runtime::HttpConfiguration`]. Returns `None`, if any of the paths does
/// not represent a valid file.
fn create_http_config() -> Option<oak_runtime::HttpConfiguration> {
    let tls_config = oak_runtime::tls::TlsConfig::new(
        "../../../certs/local/local.pem",
        "../../../certs/local/local.key",
    )?;
    Some(oak_runtime::HttpConfiguration { tls_config })
}

/// Build a channel and interceptor suitable for building a client that connects
/// to a Runtime under test.
pub async fn channel_and_interceptor() -> (Channel, impl Into<tonic::Interceptor>) {
    // Build a channel that connects to the Runtime under test.
    let uri = RUNTIME_URI.parse().expect("Error parsing URI");
    let tls_config = ClientTlsConfig::new()
        .ca_certificate(Certificate::from_pem(include_str!("../certs/ca.pem")));
    let builder = Channel::builder(uri)
        .tls_config(tls_config)
        .expect("Couldn't create TLS configuration");

    // The Runtime may have just been started for a test, and may take some time
    // to come fully up, start a gRPC server and accept connections. Allow for
    // this by retrying at intervals until the server responds or we hit a retry
    // limit.
    let mut retries = 0;
    let channel;
    loop {
        match builder.connect().await {
            Ok(c) => {
                debug!("Connected to gRPC server");
                channel = c;
                break;
            }
            Err(err) => {
                if retries < RETRY_COUNT {
                    debug!("Failed to connect, try again momentarily: {:?}", err);
                    retries += 1;
                    std::thread::sleep(RETRY_INTERVAL);
                } else {
                    panic!("Failed to connect, last err: {:?}", err);
                }
            }
        }
    }

    // Build an interceptor that will attach a public-untrusted Oak label to
    // every gRPC request.
    let mut label = Vec::new();
    Label::public_untrusted()
        .encode(&mut label)
        .expect("Error encoding label");
    let interceptor = move |mut request: Request<()>| {
        request.metadata_mut().insert_bin(
            oak_abi::OAK_LABEL_GRPC_METADATA_KEY,
            MetadataValue::from_bytes(label.as_ref()),
        );
        Ok(request)
    };

    (channel, interceptor)
}
<commit_msg>Rename cargo_path to manifest_path (#1571)<commit_after>//
// Copyright 2019 The Project Oak Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

//! Test utilities to help with unit testing of Oak SDK code.

use anyhow::Context;
use log::{debug, info};
use oak_abi::{
    label::Label,
    proto::oak::application::{
        node_configuration::ConfigType, ApplicationConfiguration, ConfigMap, NodeConfiguration,
        WebAssemblyConfiguration,
    },
};
use prost::Message;
use std::{collections::HashMap, path::PathBuf, process::Command, sync::Arc};
use tonic::{
    metadata::MetadataValue,
    transport::{Certificate, Channel, ClientTlsConfig, Identity},
    Request,
};

pub enum Profile {
    Release,
    Debug,
}

// TODO(#544): re-enable unit tests of SDK functionality

/// Uses cargo to compile a Rust manifest to Wasm bytes.
pub fn compile_rust_wasm(
    manifest_path: &str,
    module_wasm_file_name: &str,
    profile: Profile,
) -> anyhow::Result<Vec<u8>> {
    // Use a separate target dir for Wasm build artifacts. The precise name is not relevant, but it
    // should end with `target` so that it gets automatically ignored by our `.gitignore`.
    let target_dir = PathBuf::from("oak_tests/target");

    let mut args = vec![
        "build".to_string(),
        format!(
            "--target-dir={}",
            target_dir.to_str().expect("invalid target dir")
        ),
        "--target=wasm32-unknown-unknown".to_string(),
        format!("--manifest-path={}", manifest_path),
    ];
    match profile {
        Profile::Release => args.push("--release".to_string()),
        Profile::Debug => (),
    }

    Command::new("cargo")
        .args(args)
        .env_remove("RUSTFLAGS")
        .spawn()
        .context("could not spawn cargo build")?
        .wait()
        .context("could not wait for cargo build to finish")?;

    let mut module_path = target_dir;
    module_path.push("wasm32-unknown-unknown/debug");
    module_path.push(module_wasm_file_name);

    info!("compiled Wasm module path: {:?}", module_path);

    std::fs::read(module_path).context("could not read compiled module")
}

/// Default module name for the module under test.
const DEFAULT_MODULE_NAME: &str = "app";
/// Default entrypoint name for the module under test.
const DEFAULT_ENTRYPOINT_NAME: &str = "oak_main";
/// Default URI that the tests expect to find a live Runtime at.
const RUNTIME_URI: &str = "https://localhost:8080";

const DEFAULT_MODULE_MANIFEST: &str = "Cargo.toml";

// Retry parameters when connecting to a gRPC server.
const RETRY_COUNT: u32 = 600;
const RETRY_INTERVAL: std::time::Duration = std::time::Duration::from_millis(800);

/// Convenience helper to build and run a single-Node Application with the given module name, using
/// the default name "oak_main" for its entrypoint.
pub fn run_single_module_default(
    module_config_name: &str,
) -> Result<Arc<oak_runtime::Runtime>, oak::OakError> {
    run_single_module(module_config_name, DEFAULT_ENTRYPOINT_NAME)
}

/// Convenience helper to build and run a single-Node application with the given Wasm module file
/// name, using the provided entrypoint name.
pub fn run_single_module(
    module_wasm_file_name: &str,
    entrypoint_name: &str,
) -> Result<Arc<oak_runtime::Runtime>, oak::OakError> {
    run_single_module_with_config(module_wasm_file_name, entrypoint_name, ConfigMap::default())
}

/// Convenience helper to build and run a single-Node application with the given Wasm module file
/// name, using the provided entrypoint name, passing in the provided `ConfigMap` at start-of-day.
pub fn run_single_module_with_config(
    module_wasm_file_name: &str,
    entrypoint_name: &str,
    config_map: ConfigMap,
) -> Result<Arc<oak_runtime::Runtime>, oak::OakError> {
    let combined_config = runtime_config(module_wasm_file_name, entrypoint_name, config_map);
    oak_runtime::configure_and_run(combined_config)
}

/// Build the configuration needed to launch a test Runtime instance that runs a single-Node
/// application with the given Wasm module file name and entrypoint.
pub fn runtime_config(
    module_wasm_file_name: &str,
    entrypoint_name: &str,
    config_map: ConfigMap,
) -> oak_runtime::RuntimeConfiguration {
    let wasm: HashMap<String, Vec<u8>> = [(
        DEFAULT_MODULE_NAME.to_string(),
        compile_rust_wasm(
            DEFAULT_MODULE_MANIFEST,
            module_wasm_file_name,
            Profile::Debug,
        )
        .expect("failed to build wasm module"),
    )]
    .iter()
    .cloned()
    .collect();

    runtime_config_wasm(wasm, DEFAULT_MODULE_NAME, entrypoint_name, config_map)
}

/// Build the configuration needed to launch a test Runtime instance that runs the given collection
/// of Wasm modules, starting with the given module name and entrypoint.
pub fn runtime_config_wasm(
    wasm_modules: HashMap<String, Vec<u8>>,
    module_config_name: &str,
    entrypoint_name: &str,
    config_map: ConfigMap,
) -> oak_runtime::RuntimeConfiguration {
    oak_runtime::RuntimeConfiguration {
        metrics_port: Some(9090),
        introspect_port: Some(1909),
        secure_server_configuration: oak_runtime::SecureServerConfiguration {
            grpc_config: Some(oak_runtime::GrpcConfiguration {
                grpc_server_tls_identity: Some(Identity::from_pem(
                    include_str!("../certs/local.pem"),
                    include_str!("../certs/local.key"),
                )),
                grpc_client_root_tls_certificate: Some(
                    oak_runtime::config::load_certificate(&include_str!("../certs/ca.pem"))
                        .unwrap(),
                ),
                oidc_client_info: None,
            }),
            http_config: create_http_config(),
        },
        app_config: ApplicationConfiguration {
            wasm_modules,
            initial_node_configuration: Some(NodeConfiguration {
                name: "test".to_string(),
                config_type: Some(ConfigType::WasmConfig(WebAssemblyConfiguration {
                    wasm_module_name: module_config_name.to_string(),
                    wasm_entrypoint_name: entrypoint_name.to_string(),
                })),
            }),
        },
        config_map,
        sign_table: oak_runtime::SignatureTable::default(),
    }
}

/// Tries to create a [`oak_runtime::HttpConfiguration`]. Returns `None`, if any of the paths does
/// not represent a valid file.
fn create_http_config() -> Option<oak_runtime::HttpConfiguration> {
    let tls_config = oak_runtime::tls::TlsConfig::new(
        "../../../certs/local/local.pem",
        "../../../certs/local/local.key",
    )?;
    Some(oak_runtime::HttpConfiguration { tls_config })
}

/// Build a channel and interceptor suitable for building a client that connects
/// to a Runtime under test.
pub async fn channel_and_interceptor() -> (Channel, impl Into<tonic::Interceptor>) {
    // Build a channel that connects to the Runtime under test.
    let uri = RUNTIME_URI.parse().expect("Error parsing URI");
    let tls_config = ClientTlsConfig::new()
        .ca_certificate(Certificate::from_pem(include_str!("../certs/ca.pem")));
    let builder = Channel::builder(uri)
        .tls_config(tls_config)
        .expect("Couldn't create TLS configuration");

    // The Runtime may have just been started for a test, and may take some time
    // to come fully up, start a gRPC server and accept connections. Allow for
    // this by retrying at intervals until the server responds or we hit a retry
    // limit.
    let mut retries = 0;
    let channel;
    loop {
        match builder.connect().await {
            Ok(c) => {
                debug!("Connected to gRPC server");
                channel = c;
                break;
            }
            Err(err) => {
                if retries < RETRY_COUNT {
                    debug!("Failed to connect, try again momentarily: {:?}", err);
                    retries += 1;
                    std::thread::sleep(RETRY_INTERVAL);
                } else {
                    panic!("Failed to connect, last err: {:?}", err);
                }
            }
        }
    }

    // Build an interceptor that will attach a public-untrusted Oak label to
    // every gRPC request.
    let mut label = Vec::new();
    Label::public_untrusted()
        .encode(&mut label)
        .expect("Error encoding label");
    let interceptor = move |mut request: Request<()>| {
        request.metadata_mut().insert_bin(
            oak_abi::OAK_LABEL_GRPC_METADATA_KEY,
            MetadataValue::from_bytes(label.as_ref()),
        );
        Ok(request)
    };

    (channel, interceptor)
}
<|endoftext|>


<commit_before>//! A module for the automatic map generation

use noise::{Brownian2, Seed, open_simplex2};

// TODO pick:
// use traits::*;
// use traits::{Map, Tile, TileMap};
use traits::{Tile, TileMap};

// Probably really buggy code...

/// A map
///
/// Note: It's chunked into big chunks and small chunks.
///       Small chunks keeps the noise data. Big chunks
///       determines the overlay layer.
pub struct MapGenerator<'a> {
  seed: &'a Seed,
}

/// Types of big chunks
enum BChunkType {
  /// Reserved for history, empty per default, but gets opened as the game is played. Manually designed.
  History,
  // Automatic map generated chunk
  Auto,
  // Manually random generated chunk
  Manually,
}

// TODO: Find out how to prevent double islands (manually generated islands)

impl<'a> MapGenerator<'a> {
  /// Creates a new map
  pub fn new(seed: &'a Seed) -> MapGenerator<'a> {
     MapGenerator {
       seed: seed,
     }
   }

  // TODO: Add some sort of cache

  /// Get the noise value at a given point
  fn get_noise_value(&self, x: i64, y: i64) -> f64 {
    let noise = Brownian2::new(open_simplex2, 4).wavelength(32.0);
    noise.apply(&self.seed, &[x as f64, y as f64])
  }

  /// Get big chunk coordinates
  fn get_bchunk(x: i64, y: i64) -> (i64, i64) {
    // TODO: Chunk size 64?
    (((x as f64) / 64.0).floor() as i64, ((y as f64) / 64.0).floor() as i64)
  }

  /* TODO: Finish this:
  fn get_bchunk_type(x: i64, y: i64) -> BChunkType {
    let noise = Brownian2::new(open_simplex2, 4).wavelength(32.0);
    noise.apply(&self.seed, &[x as f64, y as f64])
  }
  */

  /// Get overlay value (used for customizing the noise)
  fn get_overlay_value(&self, x: i64, y: i64) -> f64 {
    // TODO
    // Stuff here
    1.0
  }
}

impl<'a> TileMap for MapGenerator<'a> {

  // Add foreground/background
  /// Get the tile at a given point
  fn get_tile(&self, x: i64, y: i64) -> Tile {
    let val = (self.get_noise_value(x, y) + self.get_overlay_value(x, y)) / 2.0;

    if val > 0.9 {
      Tile::Grass
    } else {
      Tile::Water
    }
  }
}
<commit_msg>Fix indentation<commit_after>//! A module for the automatic map generation

use noise::{Brownian2, Seed, open_simplex2};

// TODO pick:
// use traits::*;
// use traits::{Map, Tile, TileMap};
use traits::{Tile, TileMap};

// Probably really buggy code...

/// A map
///
/// Note: It's chunked into big chunks and small chunks.
///       Small chunks keeps the noise data. Big chunks
///       determines the overlay layer.
pub struct MapGenerator<'a> {
  seed: &'a Seed,
}

/// Types of big chunks
enum BChunkType {
  /// Reserved for history, empty per default, but gets opened as the game is played. Manually designed.
  History,
  // Automatic map generated chunk
  Auto,
  // Manually random generated chunk
  Manually,
}

// TODO: Find out how to prevent double islands (manually generated islands)

impl<'a> MapGenerator<'a> {
  /// Creates a new map
  pub fn new(seed: &'a Seed) -> MapGenerator<'a> {
    MapGenerator {
      seed: seed,
    }
  }

  // TODO: Add some sort of cache

  /// Get the noise value at a given point
  fn get_noise_value(&self, x: i64, y: i64) -> f64 {
    let noise = Brownian2::new(open_simplex2, 4).wavelength(32.0);
    noise.apply(&self.seed, &[x as f64, y as f64])
  }

  /// Get big chunk coordinates
  fn get_bchunk(x: i64, y: i64) -> (i64, i64) {
    // TODO: Chunk size 64?
    (((x as f64) / 64.0).floor() as i64, ((y as f64) / 64.0).floor() as i64)
  }

  /* TODO: Finish this:
  fn get_bchunk_type(x: i64, y: i64) -> BChunkType {
    let noise = Brownian2::new(open_simplex2, 4).wavelength(32.0);
    noise.apply(&self.seed, &[x as f64, y as f64])
  }
  */

  /// Get overlay value (used for customizing the noise)
  fn get_overlay_value(&self, x: i64, y: i64) -> f64 {
    // TODO
    // Stuff here
    1.0
  }
}

impl<'a> TileMap for MapGenerator<'a> {

  // Add foreground/background
  /// Get the tile at a given point
  fn get_tile(&self, x: i64, y: i64) -> Tile {
    let val = (self.get_noise_value(x, y) + self.get_overlay_value(x, y)) / 2.0;

    if val > 0.9 {
      Tile::Grass
    } else {
      Tile::Water
    }
  }
}
<|endoftext|>


<commit_before>// Copyright 2016 Walter Kuppens.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// Memory partition sizes (physical).
// TODO: Calculate based on ranges below.
const RAM_SIZE: usize = 0x800;
const PPU_CTRL_REGISTERS_SIZE: usize = 0x8;
const MISC_CTRL_REGISTERS_SIZE: usize = 0x20;
const EXPANSION_ROM_SIZE: usize = 0x1FE0;
const SRAM_SIZE: usize = 0x2000;
const PRG_ROM_SIZE: usize = 0x4000;

// Virtual memory map bounds.
const RAM_START_ADDR: usize = 0x0;
const RAM_END_ADDR: usize = 0x7FF;
const RAM_MIRROR_START: usize = 0x800;
const RAM_MIRROR_END: usize = 0x1FFF;
const PPU_CTRL_REGISTERS_START: usize = 0x2000;
const PPU_CTRL_REGISTERS_END: usize = 0x2007;
const PPU_CTRL_REGISTERS_MIRROR_START: usize = 0x2008;
const PPU_CTRL_REGISTERS_MIRROR_END: usize = 0x3FFF;
const MISC_CTRL_REGISTERS_START: usize = 0x4000;
const MISC_CTRL_REGISTERS_END: usize = 0x401F;
const EXPANSION_ROM_START: usize = 0x4020;
const EXPANSION_ROM_END: usize = 0x5FFF;
const SRAM_START: usize = 0x6000;
const SRAM_END: usize = 0x7FFF;
const PRG_ROM_1_START: usize = 0x8000;
const PRG_ROM_1_END: usize = 0xBFFF;
const PRG_ROM_2_START: usize = 0xC000;
const PRG_ROM_2_END: usize = 0xFFFF;

/// Partitioned physical memory layout for CPU memory. These fields are not
/// meant to be accessed directly by the CPU implementation and are instead
/// accessed through a read function that handles memory mapping.
pub struct Memory {
    // 2kB of internal RAM for which it's use is entirely up to the programmer.
    ram: [u8; RAM_SIZE],

    // Contains PPU registers that allow the running application to communicate
    // with the PPU.
    ppu_ctrl_registers: [u8; PPU_CTRL_REGISTERS_SIZE],

    // Contains NES APU and I/O registers. Also allows use of APU and I/O
    // functionality that is normally disabled.
    misc_ctrl_registers: [u8; MISC_CTRL_REGISTERS_SIZE],

    expansion_rom: [u8; EXPANSION_ROM_SIZE],

    // 8kB of static RAM.
    sram: [u8; SRAM_SIZE],

    prg_rom_1: [u8; PRG_ROM_SIZE],
    prg_rom_2: [u8; PRG_ROM_SIZE]
}

impl Memory {
    pub fn new() -> Memory {
        Memory {
            ram: [0; RAM_SIZE],
            ppu_ctrl_registers: [0; PPU_CTRL_REGISTERS_SIZE],
            misc_ctrl_registers: [0; MISC_CTRL_REGISTERS_SIZE],
            expansion_rom: [0; EXPANSION_ROM_SIZE],
            sram: [0; SRAM_SIZE],
            prg_rom_1: [0; PRG_ROM_SIZE],
            prg_rom_2: [0; PRG_ROM_SIZE]
        }
    }

    /// Returns true when the provided address is in the provided range
    /// (inclusive).
    ///
    /// NOTE: Inclusive ranges are in unstable rust and this function can be
    /// replaced once it lands in stable (RFC 1192).
    fn addr_in_range(&self, addr: usize, lower: usize, upper: usize) -> bool {
        addr >= lower && addr <= upper
    }

    /// Maps a given virtual address to a physical address internal to the
    /// emulator. Returns a memory buffer and index for physical memory access.
    ///
    /// TODO: Add permissions flag for special addresses?
    pub fn map(&mut self, addr: usize) -> (&mut [u8], usize) {
        // Address translation for accessing system memory. No modifications
        // need to be done to the address as it's at the start of addressable
        // memory.
        if self.addr_in_range(addr, RAM_START_ADDR, RAM_END_ADDR) {
            return (&mut self.ram, addr)
        }

        // Address translation for mirroring of system memory. System memory at
        // $0000-$07FF is mirrored at $0800-$0FFF, $1000-$17FF, and $1800-$1FFF
        // - attempting to access memory at, for example, $0173 is the same as
        // accessing memory at $0973, $1173, or $1973.
        if self.addr_in_range(addr, RAM_MIRROR_START, RAM_MIRROR_END) {
            let new_addr = addr % RAM_SIZE;
            return (&mut self.ram, new_addr)
        }

        // Address translation for accessing the PPU control registers.
        if self.addr_in_range(addr, PPU_CTRL_REGISTERS_START,
                              PPU_CTRL_REGISTERS_END) {
            let new_addr = addr - PPU_CTRL_REGISTERS_START;
            return (&mut self.ppu_ctrl_registers, new_addr)
        }

        // Address translation for mirroring of the PPU control registers. PPU
        // control at $2000-$2007 is mirrored 1023 times at $2008-$3FFF.
        if self.addr_in_range(addr, PPU_CTRL_REGISTERS_MIRROR_START,
                              PPU_CTRL_REGISTERS_MIRROR_END) {
            let new_addr = (addr - PPU_CTRL_REGISTERS_START) %
                PPU_CTRL_REGISTERS_SIZE;
            return (&mut self.ppu_ctrl_registers, new_addr)
        }

        // Address translation for miscellaneous registers (such as APU etc).
        if self.addr_in_range(addr, MISC_CTRL_REGISTERS_START,
                              MISC_CTRL_REGISTERS_END) {
            let new_addr = addr - MISC_CTRL_REGISTERS_START;
            return (&mut self.misc_ctrl_registers, new_addr)
        }

        // Address translation for accessing cartridge expansion ROM.
        if self.addr_in_range(addr, EXPANSION_ROM_START, EXPANSION_ROM_END) {
            let new_addr = addr - EXPANSION_ROM_START;
            return (&mut self.expansion_rom, new_addr)
        }

        // Address translation for accessing SRAM.
        if self.addr_in_range(addr, SRAM_START, SRAM_END) {
            let new_addr = addr - SRAM_START;
            return (&mut self.sram, new_addr)
        }

        // Address translation for accessing the program rom (bank 1).
        if self.addr_in_range(addr, PRG_ROM_1_START, PRG_ROM_1_END) {
            let new_addr = addr - PRG_ROM_1_START;
            return (&mut self.prg_rom_1, new_addr)
        }

        // Address translation for accessing the program rom (bank 2).
        if self.addr_in_range(addr, PRG_ROM_2_START, PRG_ROM_2_END) {
            let new_addr = addr - PRG_ROM_2_START;
            return (&mut self.prg_rom_2, new_addr)
        }

        panic!("Unable to map virtual address {:#X} to any physical address", addr);
    }
}
<commit_msg>Cleaned up constants in memory.rs a bit<commit_after>// Copyright 2016 Walter Kuppens.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// Memory partition sizes (physical).
// TODO: Calculate based on ranges below.
const RAM_SIZE                : usize = 0x800;
const PPU_CTRL_REGISTERS_SIZE : usize = 0x8;
const MISC_CTRL_REGISTERS_SIZE: usize = 0x20;
const EXPANSION_ROM_SIZE      : usize = 0x1FE0;
const SRAM_SIZE               : usize = 0x2000;
const PRG_ROM_SIZE            : usize = 0x4000;

// Virtual memory map bounds.
const RAM_START_ADDR                 : usize = 0x0;
const RAM_END_ADDR                   : usize = 0x7FF;
const RAM_MIRROR_START               : usize = 0x800;
const RAM_MIRROR_END                 : usize = 0x1FFF;
const PPU_CTRL_REGISTERS_START       : usize = 0x2000;
const PPU_CTRL_REGISTERS_END         : usize = 0x2007;
const PPU_CTRL_REGISTERS_MIRROR_START: usize = 0x2008;
const PPU_CTRL_REGISTERS_MIRROR_END  : usize = 0x3FFF;
const MISC_CTRL_REGISTERS_START      : usize = 0x4000;
const MISC_CTRL_REGISTERS_END        : usize = 0x401F;
const EXPANSION_ROM_START            : usize = 0x4020;
const EXPANSION_ROM_END              : usize = 0x5FFF;
const SRAM_START                     : usize = 0x6000;
const SRAM_END                       : usize = 0x7FFF;
const PRG_ROM_1_START                : usize = 0x8000;
const PRG_ROM_1_END                  : usize = 0xBFFF;
const PRG_ROM_2_START                : usize = 0xC000;
const PRG_ROM_2_END                  : usize = 0xFFFF;

/// Partitioned physical memory layout for CPU memory. These fields are not
/// meant to be accessed directly by the CPU implementation and are instead
/// accessed through a read function that handles memory mapping.
pub struct Memory {
    // 2kB of internal RAM for which it's use is entirely up to the programmer.
    ram: [u8; RAM_SIZE],

    // Contains PPU registers that allow the running application to communicate
    // with the PPU.
    ppu_ctrl_registers: [u8; PPU_CTRL_REGISTERS_SIZE],

    // Contains NES APU and I/O registers. Also allows use of APU and I/O
    // functionality that is normally disabled.
    misc_ctrl_registers: [u8; MISC_CTRL_REGISTERS_SIZE],

    expansion_rom: [u8; EXPANSION_ROM_SIZE],

    // 8kB of static RAM.
    sram: [u8; SRAM_SIZE],

    prg_rom_1: [u8; PRG_ROM_SIZE],
    prg_rom_2: [u8; PRG_ROM_SIZE]
}

impl Memory {
    pub fn new() -> Memory {
        Memory {
            ram: [0; RAM_SIZE],
            ppu_ctrl_registers: [0; PPU_CTRL_REGISTERS_SIZE],
            misc_ctrl_registers: [0; MISC_CTRL_REGISTERS_SIZE],
            expansion_rom: [0; EXPANSION_ROM_SIZE],
            sram: [0; SRAM_SIZE],
            prg_rom_1: [0; PRG_ROM_SIZE],
            prg_rom_2: [0; PRG_ROM_SIZE]
        }
    }

    /// Returns true when the provided address is in the provided range
    /// (inclusive).
    ///
    /// NOTE: Inclusive ranges are in unstable rust and this function can be
    /// replaced once it lands in stable (RFC 1192).
    fn addr_in_range(&self, addr: usize, lower: usize, upper: usize) -> bool {
        addr >= lower && addr <= upper
    }

    /// Maps a given virtual address to a physical address internal to the
    /// emulator. Returns a memory buffer and index for physical memory access.
    ///
    /// TODO: Add permissions flag for special addresses?
    pub fn map(&mut self, addr: usize) -> (&mut [u8], usize) {
        // Address translation for accessing system memory. No modifications
        // need to be done to the address as it's at the start of addressable
        // memory.
        if self.addr_in_range(addr, RAM_START_ADDR, RAM_END_ADDR) {
            return (&mut self.ram, addr)
        }

        // Address translation for mirroring of system memory. System memory at
        // $0000-$07FF is mirrored at $0800-$0FFF, $1000-$17FF, and $1800-$1FFF
        // - attempting to access memory at, for example, $0173 is the same as
        // accessing memory at $0973, $1173, or $1973.
        if self.addr_in_range(addr, RAM_MIRROR_START, RAM_MIRROR_END) {
            let new_addr = addr % RAM_SIZE;
            return (&mut self.ram, new_addr)
        }

        // Address translation for accessing the PPU control registers.
        if self.addr_in_range(addr, PPU_CTRL_REGISTERS_START,
                              PPU_CTRL_REGISTERS_END) {
            let new_addr = addr - PPU_CTRL_REGISTERS_START;
            return (&mut self.ppu_ctrl_registers, new_addr)
        }

        // Address translation for mirroring of the PPU control registers. PPU
        // control at $2000-$2007 is mirrored 1023 times at $2008-$3FFF.
        if self.addr_in_range(addr, PPU_CTRL_REGISTERS_MIRROR_START,
                              PPU_CTRL_REGISTERS_MIRROR_END) {
            let new_addr = (addr - PPU_CTRL_REGISTERS_START) %
                PPU_CTRL_REGISTERS_SIZE;
            return (&mut self.ppu_ctrl_registers, new_addr)
        }

        // Address translation for miscellaneous registers (such as APU etc).
        if self.addr_in_range(addr, MISC_CTRL_REGISTERS_START,
                              MISC_CTRL_REGISTERS_END) {
            let new_addr = addr - MISC_CTRL_REGISTERS_START;
            return (&mut self.misc_ctrl_registers, new_addr)
        }

        // Address translation for accessing cartridge expansion ROM.
        if self.addr_in_range(addr, EXPANSION_ROM_START, EXPANSION_ROM_END) {
            let new_addr = addr - EXPANSION_ROM_START;
            return (&mut self.expansion_rom, new_addr)
        }

        // Address translation for accessing SRAM.
        if self.addr_in_range(addr, SRAM_START, SRAM_END) {
            let new_addr = addr - SRAM_START;
            return (&mut self.sram, new_addr)
        }

        // Address translation for accessing the program rom (bank 1).
        if self.addr_in_range(addr, PRG_ROM_1_START, PRG_ROM_1_END) {
            let new_addr = addr - PRG_ROM_1_START;
            return (&mut self.prg_rom_1, new_addr)
        }

        // Address translation for accessing the program rom (bank 2).
        if self.addr_in_range(addr, PRG_ROM_2_START, PRG_ROM_2_END) {
            let new_addr = addr - PRG_ROM_2_START;
            return (&mut self.prg_rom_2, new_addr)
        }

        panic!("Unable to map virtual address {:#X} to any physical address", addr);
    }
}
<|endoftext|>