<commit_before>use ash::vk;

use hal::error::{DeviceCreationError, HostExecutionError};

// Generic error codes from Vulkan
#[derive(Debug)]
pub(crate) enum Error {
    OutOfHostMemory,
    OutOfDeviceMemory,
    InitializationFailed,
    DeviceLost,
    MemoryMapFailed,
    LayerNotPresent,
    ExtensionNotPresent,
    FeatureNotPresent,
    IncompatibleDriver,
    TooManyObjects,
    FormatNotSupported,
    FragmentedPool,
    SurfaceLostKhr,
    NativeWindowInUseKhr,
    OutOfDateKhr,
    IncompatibleDisplayKhr,
    ValidationFailedExt,
    // Not an actual vulkan error, but handle the case where an implementation
    // might return an unkown error.
    Unknown,
}

impl From<vk::Result> for Error {
    fn from(result: vk::Result) -> Self {
        match result {
            ERROR_OUT_OF_HOST_MEMORY => Error::OutOfHostMemory,
            ERROR_OUT_OF_DEVICE_MEMORY => Error::OutOfDeviceMemory,
            ERROR_INITIALIZATION_FAILED => Error::InitializationFailed,
            ERROR_DEVICE_LOST => Error::DeviceLost,
            ERROR_MEMORY_MAP_FAILED => Error::MemoryMapFailed,
            ERROR_LAYER_NOT_PRESENT => Error::LayerNotPresent,
            ERROR_EXTENSION_NOT_PRESENT => Error::ExtensionNotPresent,
            ERROR_FEATURE_NOT_PRESENT => Error::FeatureNotPresent,
            ERROR_INCOMPATIBLE_DRIVER => Error::IncompatibleDriver,
            ERROR_TOO_MANY_OBJECTS => Error::TooManyObjects,
            ERROR_FORMAT_NOT_SUPPORTED => Error::FormatNotSupported,
            ERROR_FRAGMENTED_POOL => Error::FragmentedPool,
            ERROR_SURFACE_LOST_KHR => Error::SurfaceLostKhr,
            ERROR_NATIVE_WINDOW_IN_USE_KHR => Error::NativeWindowInUseKhr,
            ERROR_OUT_OF_DATE_KHR => Error::OutOfDateKhr,
            ERROR_INCOMPATIBLE_DISPLAY_KHR => Error::IncompatibleDisplayKhr,
            ERROR_VALIDATION_FAILED_EXT => Error::ValidationFailedExt,
            _ => Error::Unknown,
        }
    }
}

// Impl `From<Error>` for various HAL error types.
//
// Syntax:
//    #HalError {
//       #VulkanError => #HalErrorVariant,
//    }
macro_rules! from_error {
    { $($name:ident { $($base_error:ident => $err:ident,)* },)* } => {
        $(
            impl From<Error> for $name {
                fn from(err: Error) -> Self {
                    match err {
                        $(
                            Error::$base_error => $name::$err,
                        )*
                        _ => unreachable!("Unexpected error code ({:?}). Non specification conformant driver.", err),
                    }
                }
            }
        )*
    }
}

from_error! {
    DeviceCreationError {
        OutOfHostMemory => OutOfHostMemory,
        OutOfDeviceMemory => OutOfDeviceMemory,
        InitializationFailed => InitializationFailed,
        ExtensionNotPresent => MissingExtension,
        FeatureNotPresent => MissingFeature,
        TooManyObjects => TooManyObjects,
        DeviceLost => DeviceLost,
    },
}

from_error! {
    HostExecutionError {
        OutOfHostMemory => OutOfHostMemory,
        OutOfDeviceMemory => OutOfDeviceMemory,
        DeviceLost => DeviceLost,
    },
}
<commit_msg>Fix result matching for vulkan backend<commit_after>use ash::vk;

use hal::error::{DeviceCreationError, HostExecutionError};

// Generic error codes from Vulkan
#[derive(Debug)]
pub(crate) enum Error {
    OutOfHostMemory,
    OutOfDeviceMemory,
    InitializationFailed,
    DeviceLost,
    MemoryMapFailed,
    LayerNotPresent,
    ExtensionNotPresent,
    FeatureNotPresent,
    IncompatibleDriver,
    TooManyObjects,
    FormatNotSupported,
    FragmentedPool,
    SurfaceLostKhr,
    NativeWindowInUseKhr,
    OutOfDateKhr,
    IncompatibleDisplayKhr,
    ValidationFailedExt,
    // Not an actual vulkan error, but handle the case where an implementation
    // might return an unkown error.
    Unknown,
}

impl From<vk::Result> for Error {
    fn from(result: vk::Result) -> Self {
        match result {
            vk::Result::ERROR_OUT_OF_HOST_MEMORY => Error::OutOfHostMemory,
            vk::Result::ERROR_OUT_OF_DEVICE_MEMORY => Error::OutOfDeviceMemory,
            vk::Result::ERROR_INITIALIZATION_FAILED => Error::InitializationFailed,
            vk::Result::ERROR_DEVICE_LOST => Error::DeviceLost,
            vk::Result::ERROR_MEMORY_MAP_FAILED => Error::MemoryMapFailed,
            vk::Result::ERROR_LAYER_NOT_PRESENT => Error::LayerNotPresent,
            vk::Result::ERROR_EXTENSION_NOT_PRESENT => Error::ExtensionNotPresent,
            vk::Result::ERROR_FEATURE_NOT_PRESENT => Error::FeatureNotPresent,
            vk::Result::ERROR_INCOMPATIBLE_DRIVER => Error::IncompatibleDriver,
            vk::Result::ERROR_TOO_MANY_OBJECTS => Error::TooManyObjects,
            vk::Result::ERROR_FORMAT_NOT_SUPPORTED => Error::FormatNotSupported,
            vk::Result::ERROR_FRAGMENTED_POOL => Error::FragmentedPool,
            vk::Result::ERROR_SURFACE_LOST_KHR => Error::SurfaceLostKhr,
            vk::Result::ERROR_NATIVE_WINDOW_IN_USE_KHR => Error::NativeWindowInUseKhr,
            vk::Result::ERROR_OUT_OF_DATE_KHR => Error::OutOfDateKhr,
            vk::Result::ERROR_INCOMPATIBLE_DISPLAY_KHR => Error::IncompatibleDisplayKhr,
            vk::Result::ERROR_VALIDATION_FAILED_EXT => Error::ValidationFailedExt,
            _ => Error::Unknown,
        }
    }
}

// Impl `From<Error>` for various HAL error types.
//
// Syntax:
//    #HalError {
//       #VulkanError => #HalErrorVariant,
//    }
macro_rules! from_error {
    { $($name:ident { $($base_error:ident => $err:ident,)* },)* } => {
        $(
            impl From<Error> for $name {
                fn from(err: Error) -> Self {
                    match err {
                        $(
                            Error::$base_error => $name::$err,
                        )*
                        _ => unreachable!("Unexpected error code ({:?}). Non specification conformant driver.", err),
                    }
                }
            }
        )*
    }
}

from_error! {
    DeviceCreationError {
        OutOfHostMemory => OutOfHostMemory,
        OutOfDeviceMemory => OutOfDeviceMemory,
        InitializationFailed => InitializationFailed,
        ExtensionNotPresent => MissingExtension,
        FeatureNotPresent => MissingFeature,
        TooManyObjects => TooManyObjects,
        DeviceLost => DeviceLost,
    },
}

from_error! {
    HostExecutionError {
        OutOfHostMemory => OutOfHostMemory,
        OutOfDeviceMemory => OutOfDeviceMemory,
        DeviceLost => DeviceLost,
    },
}
<|endoftext|>


<commit_before>use std::collections::BTreeSet;
use std::ffi::OsString;
use std::fs;
use std::path::{Path, PathBuf};

pub fn walk_dir<P: AsRef<Path>>(path: P) -> BTreeSet<String> {
    fn walk_dir(path: PathBuf) -> Vec<OsString> {
        let paths = match fs::read_dir(path) {
            Ok(rd)   => rd,
            Err(why) => panic!("{:?}", why),
        };
        paths
            .filter(|de| de.is_ok())
            .flat_map(|de| {
                let path = de.unwrap().path();
                if is_hidden(&path) {
                    Vec::new()
                } else if path.is_file() {
                    vec![path.into_os_string()]
                } else {
                    walk_dir(path)
                }
            })
            .collect::<Vec<OsString>>()
    }

    walk_dir(path.as_ref().to_path_buf()).iter()
        .map(|f| f.clone().into_string())
        .filter(|f| f.is_ok())
        .map(|f| f.unwrap())
        .collect::<BTreeSet<String>>()
}

fn is_hidden(path: &PathBuf) -> bool {
    let file_name = path.file_name().and_then(|f| f.to_str());
    file_name.map_or(false, |f| f.starts_with(".") && f.len() > 1 && f != "..")
}
<commit_msg>[Refactor] Use filter_map()<commit_after>use std::collections::BTreeSet;
use std::ffi::OsString;
use std::fs;
use std::path::{Path, PathBuf};
use std::result::Result;

pub fn walk_dir<P: AsRef<Path>>(path: P) -> BTreeSet<String> {
    fn walk_dir(path: PathBuf) -> Vec<OsString> {
        let paths = match fs::read_dir(path) {
            Ok(rd)   => rd,
            Err(why) => panic!("{:?}", why),
        };
        paths
            .filter_map(Result::ok)
            .flat_map(|de| {
                let path = de.path();
                if is_hidden(&path) {
                    Vec::new()
                } else if path.is_file() {
                    vec![path.into_os_string()]
                } else {
                    walk_dir(path)
                }
            })
            .collect::<Vec<OsString>>()
    }

    walk_dir(path.as_ref().to_path_buf()).iter()
        .map(|f| f.clone().into_string())
        .filter_map(Result::ok)
        .collect::<BTreeSet<String>>()
}

fn is_hidden(path: &PathBuf) -> bool {
    let file_name = path.file_name().and_then(|f| f.to_str());
    file_name.map_or(false, |f| f.starts_with(".") && f.len() > 1 && f != "..")
}
<|endoftext|>


<commit_before>extern crate syscall;

use std::{io, mem, slice};
use std::env;
use std::os::unix::ffi::OsStrExt;
use std::os::unix::io::RawFd;
use std::path::PathBuf;
use std::process::{exit, ExitStatus};
use std::os::unix::process::ExitStatusExt;
use syscall::{EINTR, SigAction, waitpid};

pub(crate) const PATH_SEPARATOR: &str = ";";
pub(crate) const NULL_PATH: &str = "null:";

pub(crate) const O_CLOEXEC: usize = syscall::O_CLOEXEC;
pub(crate) const SIGHUP: i32 = syscall::SIGHUP as i32;
pub(crate) const SIGINT: i32 = syscall::SIGINT as i32;
pub(crate) const SIGTERM: i32 = syscall::SIGTERM as i32;
pub(crate) const SIGCONT: i32 = syscall::SIGCONT as i32;
pub(crate) const SIGSTOP: i32 = syscall::SIGSTOP as i32;
pub(crate) const SIGTSTP: i32 = syscall::SIGTSTP as i32;
pub(crate) const SIGPIPE: i32 = syscall::SIGPIPE as i32;

pub(crate) const STDIN_FILENO: RawFd = 0;
pub(crate) const STDOUT_FILENO: RawFd = 1;
pub(crate) const STDERR_FILENO: RawFd = 2;

pub(crate) fn geteuid() -> io::Result<u32> { cvt(syscall::geteuid()).map(|pid| pid as u32) }

pub(crate) fn getuid() -> io::Result<u32> { cvt(syscall::getuid()).map(|pid| pid as u32) }

pub(crate) fn is_root() -> bool { syscall::geteuid().map(|id| id == 0).unwrap_or(false) }

pub unsafe fn fork() -> io::Result<u32> { cvt(syscall::clone(0)).map(|pid| pid as u32) }

pub fn fork_exit(status: i32) -> ! { exit(status) }

pub fn wait_for_interrupt(pid: u32) -> io::Result<()> {
    let mut status = 0;

    loop {
        match waitpid(pid as usize, &mut status, 0) {
            Err(ref error) if error.errno == EINTR => continue,
            Err(ref error) => break Err(io::Error::from_raw_os_error(error.errno)),
            Ok(_) => break Ok(()),
        }
    }
}

pub fn wait_for_child(pid: u32) -> io::Result<u8> {
    let mut status;
    use syscall::{waitpid, ECHILD};

    loop {
        status = 0;
        match waitpid(pid as usize, &mut status, 0) {
            Err(ref error) if error.errno == ECHILD => break,
            Err(error) => return Err(io::Error::from_raw_os_error(error.errno)),
            _ => ()
        }
    }

    let status = ExitStatus::from_raw(status as i32);
    Ok(status.code().unwrap_or(0) as u8)
}

pub(crate) fn getpid() -> io::Result<u32> { cvt(syscall::getpid()).map(|pid| pid as u32) }

pub(crate) fn kill(pid: u32, signal: i32) -> io::Result<()> {
    cvt(syscall::kill(pid as usize, signal as usize)).and(Ok(()))
}

pub(crate) fn killpg(pgid: u32, signal: i32) -> io::Result<()> {
    cvt(syscall::kill(-(pgid as isize) as usize, signal as usize)).and(Ok(()))
}

pub(crate) fn pipe2(flags: usize) -> io::Result<(RawFd, RawFd)> {
    let mut fds = [0; 2];
    cvt(syscall::pipe2(&mut fds, flags))?;
    Ok((fds[0], fds[1]))
}

pub(crate) fn setpgid(pid: u32, pgid: u32) -> io::Result<()> {
    cvt(syscall::setpgid(pid as usize, pgid as usize)).and(Ok(()))
}

pub(crate) fn fork_and_exec<F: Fn()>(
    prog: &str,
    args: &[&str],
    stdin: Option<RawFd>,
    stdout: Option<RawFd>,
    stderr: Option<RawFd>,
    clear_env: bool,
    before_exec: F
) -> io::Result<u32> {
    // Construct a valid set of arguments to pass to execve. Ensure
    // that the program is the first argument.
    let mut cvt_args: Vec<[usize; 2]> = Vec::new();
    cvt_args.push([prog.as_ptr() as usize, prog.len()]);
    for arg in args {
        cvt_args.push([arg.as_ptr() as usize, arg.len()]);
    }

    // Get the PathBuf of the program if it exists.
    let prog = if prog.contains(':') || prog.contains('/') {
        // This is a fully specified scheme or path to an
        // executable.
        Some(PathBuf::from(prog))
    } else if let Ok(paths) = env::var("PATH") {
        // This is not a fully specified scheme or path.
        // Iterate through the possible paths in the
        // env var PATH that this executable may be found
        // in and return the first one found.
        env::split_paths(&paths)
            .filter_map(|mut path| {
                path.push(prog);
                if path.exists() {
                    Some(path)
                } else {
                    None
                }
            })
            .next()
    } else {
        None
    };

    // If clear_env set, clear the env.
    if clear_env {
        for (key, _) in env::vars() {
            env::remove_var(key);
        }
    }

    if let Some(prog) = prog {
        unsafe {
            match fork()? {
                0 => {
                    if let Some(stdin) = stdin {
                        let _ = dup2(stdin, STDIN_FILENO);
                        let _ = close(stdin);
                    }

                    if let Some(stdout) = stdout {
                        let _ = dup2(stdout, STDOUT_FILENO);
                        let _ = close(stdout);
                    }

                    if let Some(stderr) = stderr {
                        let _ = dup2(stderr, STDERR_FILENO);
                        let _ = close(stderr);
                    }

                    before_exec();

                    let error = syscall::execve(prog.as_os_str().as_bytes(), &cvt_args);
                    let error = io::Error::from_raw_os_error(error.err().unwrap().errno);
                    eprintln!("ion: command exec: {}", error);
                    fork_exit(1);
                }
                pid => {
                    if let Some(stdin) = stdin {
                        let _ = close(stdin);
                    }

                    if let Some(stdout) = stdout {
                        let _ = close(stdout);
                    }

                    if let Some(stderr) = stderr {
                        let _ = close(stderr);
                    }

                    Ok(pid)
                }
            }
        }
    } else {
        // The binary was not found.
        Err(io::Error::from_raw_os_error(syscall::ENOENT))
    }
}

pub(crate) fn execve(prog: &str, args: &[&str], clear_env: bool) -> io::Error {
    // Construct a valid set of arguments to pass to execve. Ensure
    // that the program is the first argument.
    let mut cvt_args: Vec<[usize; 2]> = Vec::new();
    cvt_args.push([prog.as_ptr() as usize, prog.len()]);
    for arg in args {
        cvt_args.push([arg.as_ptr() as usize, arg.len()]);
    }

    // Get the PathBuf of the program if it exists.
    let prog = if prog.contains(':') || prog.contains('/') {
        // This is a fully specified scheme or path to an
        // executable.
        Some(PathBuf::from(prog))
    } else if let Ok(paths) = env::var("PATH") {
        // This is not a fully specified scheme or path.
        // Iterate through the possible paths in the
        // env var PATH that this executable may be found
        // in and return the first one found.
        env::split_paths(&paths)
            .filter_map(|mut path| {
                path.push(prog);
                if path.exists() {
                    Some(path)
                } else {
                    None
                }
            })
            .next()
    } else {
        None
    };

    // If clear_env set, clear the env.
    if clear_env {
        for (key, _) in env::vars() {
            env::remove_var(key);
        }
    }

    if let Some(prog) = prog {
        // If we found the program. Run it!
        let error = syscall::execve(prog.as_os_str().as_bytes(), &cvt_args);
        io::Error::from_raw_os_error(error.err().unwrap().errno)
    } else {
        // The binary was not found.
        io::Error::from_raw_os_error(syscall::ENOENT)
    }
}

#[allow(dead_code)]
pub(crate) fn signal(signal: i32, handler: extern "C" fn(i32)) -> io::Result<()> {
    let new = SigAction {
        sa_handler: unsafe { mem::transmute(handler) },
        sa_mask:    [0; 2],
        sa_flags:   0,
    };
    cvt(syscall::sigaction(signal as usize, Some(&new), None)).and(Ok(()))
}

pub(crate) fn reset_signal(signal: i32) -> io::Result<()> {
    let new = SigAction {
        sa_handler: unsafe { mem::transmute(syscall::flag::SIG_DFL) },
        sa_mask:    [0; 2],
        sa_flags:   0,
    };
    cvt(syscall::sigaction(signal as usize, Some(&new), None)).and(Ok(()))
}

pub(crate) fn tcsetpgrp(tty_fd: RawFd, pgid: u32) -> io::Result<()> {
    let fd = cvt(syscall::dup(tty_fd, b"pgrp"))?;

    let pgid_usize = pgid as usize;
    let res = syscall::write(fd, unsafe {
        slice::from_raw_parts(
            &pgid_usize as *const usize as *const u8,
            mem::size_of::<usize>(),
        )
    });

    let _ = syscall::close(fd);

    cvt(res).and(Ok(()))
}

pub(crate) fn dup(fd: RawFd) -> io::Result<RawFd> { cvt(syscall::dup(fd, &[])) }

pub(crate) fn dup2(old: RawFd, new: RawFd) -> io::Result<RawFd> {
    cvt(syscall::dup2(old, new, &[]))
}

pub(crate) fn close(fd: RawFd) -> io::Result<()> { cvt(syscall::close(fd)).and(Ok(())) }

pub(crate) fn isatty(fd: RawFd) -> bool {
    if let Ok(tfd) = syscall::dup(fd, b"termios") {
        let _ = syscall::close(tfd);
        true
    } else {
        false
    }
}

// Support function for converting syscall error to io error
fn cvt(result: Result<usize, syscall::Error>) -> io::Result<usize> {
    result.map_err(|err| io::Error::from_raw_os_error(err.errno))
}

// TODO
pub mod signals {
    pub(crate) fn block() {}

    /// Unblocks the SIGTSTP/SIGTTOU/SIGTTIN/SIGCHLD signals so children processes can be
    /// controlled
    /// by the shell.
    pub(crate) fn unblock() {}
}

pub mod job_control {
    use shell::job_control::*;

    use shell::Shell;
    use shell::foreground::ForegroundSignals;
    use shell::status::FAILURE;
    use std::os::unix::process::ExitStatusExt;
    use std::process::ExitStatus;
    use std::sync::{Arc, Mutex};
    use syscall::{self, ECHILD, waitpid};
    use super::{SIGINT, SIGPIPE};

    pub(crate) fn watch_background(
        _fg: Arc<ForegroundSignals>,
        _processes: Arc<Mutex<Vec<BackgroundProcess>>>,
        _pid: u32,
        _njob: usize,
    ) {
        // TODO: Implement this using syscall::call::waitpid
    }

    pub(crate) fn watch_foreground(shell: &mut Shell, pid: i32, command: &str ) -> i32 {
        let mut signaled = 0;
        let mut exit_status = 0;
        let mut status;

        fn get_pid_value(pid: i32) -> usize {
            if pid < 0 {
                !(pid.abs() as usize)
            } else {
                pid as usize
            }
        }

        let pgid = get_pid_value(pid);

        loop {
            status = 0;
            let result = waitpid(pgid, &mut status, 0);
            match result {
                Err(error) => {
                    match error.errno {
                        ECHILD if signaled == 0 => break exit_status,
                        ECHILD => break signaled,
                        _ => {
                            eprintln!("ion: waitpid error: {}", error);
                            break FAILURE;
                        }
                    }
                }
                Ok(0) => (),
                Ok(pid) => {
                    let es = ExitStatus::from_raw(status as i32);
                    match es.signal() {
                        Some(SIGPIPE) => continue,
                        Some(signal) => {
                            eprintln!("ion: process ended by signal {}", signal);
                            match signal {
                                SIGINT => {
                                    let _ = syscall::kill(pgid, signal as usize);
                                    shell.break_flow = true;
                                }
                                _ => {
                                    shell.handle_signal(signal);
                                }
                            }
                            signaled = 128 + signal as i32;
                        }
                        None => {
                            exit_status = es.code().unwrap();
                        }
                    }
                }
                // TODO: Background job control for Redox
                // _pid if WIFSTOPPED(status) => {
                //     shell.send_to_background(pid as u32, ProcessState::Stopped, command.into());
                //     shell.break_flow = true;
                //     break 128 + signal as i32;
                // }
            }
        }
    }
}

pub mod variables {
    pub(crate) fn get_user_home(_username: &str) -> Option<String> {
        // TODO
        None
    }
}
<commit_msg>Call execve from fork_and_exec in sys/redox.rs so they can share code<commit_after>extern crate syscall;

use std::{io, mem, slice};
use std::env;
use std::os::unix::ffi::OsStrExt;
use std::os::unix::io::RawFd;
use std::path::PathBuf;
use std::process::{exit, ExitStatus};
use std::os::unix::process::ExitStatusExt;
use syscall::{EINTR, SigAction, waitpid};

pub(crate) const PATH_SEPARATOR: &str = ";";
pub(crate) const NULL_PATH: &str = "null:";

pub(crate) const O_CLOEXEC: usize = syscall::O_CLOEXEC;
pub(crate) const SIGHUP: i32 = syscall::SIGHUP as i32;
pub(crate) const SIGINT: i32 = syscall::SIGINT as i32;
pub(crate) const SIGTERM: i32 = syscall::SIGTERM as i32;
pub(crate) const SIGCONT: i32 = syscall::SIGCONT as i32;
pub(crate) const SIGSTOP: i32 = syscall::SIGSTOP as i32;
pub(crate) const SIGTSTP: i32 = syscall::SIGTSTP as i32;
pub(crate) const SIGPIPE: i32 = syscall::SIGPIPE as i32;

pub(crate) const STDIN_FILENO: RawFd = 0;
pub(crate) const STDOUT_FILENO: RawFd = 1;
pub(crate) const STDERR_FILENO: RawFd = 2;

pub(crate) fn geteuid() -> io::Result<u32> { cvt(syscall::geteuid()).map(|pid| pid as u32) }

pub(crate) fn getuid() -> io::Result<u32> { cvt(syscall::getuid()).map(|pid| pid as u32) }

pub(crate) fn is_root() -> bool { syscall::geteuid().map(|id| id == 0).unwrap_or(false) }

pub unsafe fn fork() -> io::Result<u32> { cvt(syscall::clone(0)).map(|pid| pid as u32) }

pub fn fork_exit(status: i32) -> ! { exit(status) }

pub fn wait_for_interrupt(pid: u32) -> io::Result<()> {
    let mut status = 0;

    loop {
        match waitpid(pid as usize, &mut status, 0) {
            Err(ref error) if error.errno == EINTR => continue,
            Err(ref error) => break Err(io::Error::from_raw_os_error(error.errno)),
            Ok(_) => break Ok(()),
        }
    }
}

pub fn wait_for_child(pid: u32) -> io::Result<u8> {
    let mut status;
    use syscall::{waitpid, ECHILD};

    loop {
        status = 0;
        match waitpid(pid as usize, &mut status, 0) {
            Err(ref error) if error.errno == ECHILD => break,
            Err(error) => return Err(io::Error::from_raw_os_error(error.errno)),
            _ => ()
        }
    }

    let status = ExitStatus::from_raw(status as i32);
    Ok(status.code().unwrap_or(0) as u8)
}

pub(crate) fn getpid() -> io::Result<u32> { cvt(syscall::getpid()).map(|pid| pid as u32) }

pub(crate) fn kill(pid: u32, signal: i32) -> io::Result<()> {
    cvt(syscall::kill(pid as usize, signal as usize)).and(Ok(()))
}

pub(crate) fn killpg(pgid: u32, signal: i32) -> io::Result<()> {
    cvt(syscall::kill(-(pgid as isize) as usize, signal as usize)).and(Ok(()))
}

pub(crate) fn pipe2(flags: usize) -> io::Result<(RawFd, RawFd)> {
    let mut fds = [0; 2];
    cvt(syscall::pipe2(&mut fds, flags))?;
    Ok((fds[0], fds[1]))
}

pub(crate) fn setpgid(pid: u32, pgid: u32) -> io::Result<()> {
    cvt(syscall::setpgid(pid as usize, pgid as usize)).and(Ok(()))
}

pub(crate) fn fork_and_exec<F: Fn()>(
    prog: &str,
    args: &[&str],
    stdin: Option<RawFd>,
    stdout: Option<RawFd>,
    stderr: Option<RawFd>,
    clear_env: bool,
    before_exec: F
) -> io::Result<u32> {
    unsafe {
        match fork()? {
            0 => {
                if let Some(stdin) = stdin {
                    let _ = dup2(stdin, STDIN_FILENO);
                    let _ = close(stdin);
                }

                if let Some(stdout) = stdout {
                    let _ = dup2(stdout, STDOUT_FILENO);
                    let _ = close(stdout);
                }

                if let Some(stderr) = stderr {
                    let _ = dup2(stderr, STDERR_FILENO);
                    let _ = close(stderr);
                }

                before_exec();

                let error = execve(prog, args, clear_env);
                eprintln!("ion: command exec: {}", error);
                fork_exit(1);
            }
            pid => {
                if let Some(stdin) = stdin {
                    let _ = close(stdin);
                }

                if let Some(stdout) = stdout {
                    let _ = close(stdout);
                }

                if let Some(stderr) = stderr {
                    let _ = close(stderr);
                }

                Ok(pid)
            }
        }
    }
}

pub(crate) fn execve(prog: &str, args: &[&str], clear_env: bool) -> io::Error {
    // Construct a valid set of arguments to pass to execve. Ensure
    // that the program is the first argument.
    let mut cvt_args: Vec<[usize; 2]> = Vec::new();
    cvt_args.push([prog.as_ptr() as usize, prog.len()]);
    for arg in args {
        cvt_args.push([arg.as_ptr() as usize, arg.len()]);
    }

    // Get the PathBuf of the program if it exists.
    let prog = if prog.contains(':') || prog.contains('/') {
        // This is a fully specified scheme or path to an
        // executable.
        Some(PathBuf::from(prog))
    } else if let Ok(paths) = env::var("PATH") {
        // This is not a fully specified scheme or path.
        // Iterate through the possible paths in the
        // env var PATH that this executable may be found
        // in and return the first one found.
        env::split_paths(&paths)
            .filter_map(|mut path| {
                path.push(prog);
                if path.exists() {
                    Some(path)
                } else {
                    None
                }
            })
            .next()
    } else {
        None
    };

    // If clear_env set, clear the env.
    if clear_env {
        for (key, _) in env::vars() {
            env::remove_var(key);
        }
    }

    if let Some(prog) = prog {
        // If we found the program. Run it!
        let error = syscall::execve(prog.as_os_str().as_bytes(), &cvt_args);
        io::Error::from_raw_os_error(error.err().unwrap().errno)
    } else {
        // The binary was not found.
        io::Error::from_raw_os_error(syscall::ENOENT)
    }
}

#[allow(dead_code)]
pub(crate) fn signal(signal: i32, handler: extern "C" fn(i32)) -> io::Result<()> {
    let new = SigAction {
        sa_handler: unsafe { mem::transmute(handler) },
        sa_mask:    [0; 2],
        sa_flags:   0,
    };
    cvt(syscall::sigaction(signal as usize, Some(&new), None)).and(Ok(()))
}

pub(crate) fn reset_signal(signal: i32) -> io::Result<()> {
    let new = SigAction {
        sa_handler: unsafe { mem::transmute(syscall::flag::SIG_DFL) },
        sa_mask:    [0; 2],
        sa_flags:   0,
    };
    cvt(syscall::sigaction(signal as usize, Some(&new), None)).and(Ok(()))
}

pub(crate) fn tcsetpgrp(tty_fd: RawFd, pgid: u32) -> io::Result<()> {
    let fd = cvt(syscall::dup(tty_fd, b"pgrp"))?;

    let pgid_usize = pgid as usize;
    let res = syscall::write(fd, unsafe {
        slice::from_raw_parts(
            &pgid_usize as *const usize as *const u8,
            mem::size_of::<usize>(),
        )
    });

    let _ = syscall::close(fd);

    cvt(res).and(Ok(()))
}

pub(crate) fn dup(fd: RawFd) -> io::Result<RawFd> { cvt(syscall::dup(fd, &[])) }

pub(crate) fn dup2(old: RawFd, new: RawFd) -> io::Result<RawFd> {
    cvt(syscall::dup2(old, new, &[]))
}

pub(crate) fn close(fd: RawFd) -> io::Result<()> { cvt(syscall::close(fd)).and(Ok(())) }

pub(crate) fn isatty(fd: RawFd) -> bool {
    if let Ok(tfd) = syscall::dup(fd, b"termios") {
        let _ = syscall::close(tfd);
        true
    } else {
        false
    }
}

// Support function for converting syscall error to io error
fn cvt(result: Result<usize, syscall::Error>) -> io::Result<usize> {
    result.map_err(|err| io::Error::from_raw_os_error(err.errno))
}

// TODO
pub mod signals {
    pub(crate) fn block() {}

    /// Unblocks the SIGTSTP/SIGTTOU/SIGTTIN/SIGCHLD signals so children processes can be
    /// controlled
    /// by the shell.
    pub(crate) fn unblock() {}
}

pub mod job_control {
    use shell::job_control::*;

    use shell::Shell;
    use shell::foreground::ForegroundSignals;
    use shell::status::FAILURE;
    use std::os::unix::process::ExitStatusExt;
    use std::process::ExitStatus;
    use std::sync::{Arc, Mutex};
    use syscall::{self, ECHILD, waitpid};
    use super::{SIGINT, SIGPIPE};

    pub(crate) fn watch_background(
        _fg: Arc<ForegroundSignals>,
        _processes: Arc<Mutex<Vec<BackgroundProcess>>>,
        _pid: u32,
        _njob: usize,
    ) {
        // TODO: Implement this using syscall::call::waitpid
    }

    pub(crate) fn watch_foreground(shell: &mut Shell, pid: i32, command: &str ) -> i32 {
        let mut signaled = 0;
        let mut exit_status = 0;
        let mut status;

        fn get_pid_value(pid: i32) -> usize {
            if pid < 0 {
                !(pid.abs() as usize)
            } else {
                pid as usize
            }
        }

        let pgid = get_pid_value(pid);

        loop {
            status = 0;
            let result = waitpid(pgid, &mut status, 0);
            match result {
                Err(error) => {
                    match error.errno {
                        ECHILD if signaled == 0 => break exit_status,
                        ECHILD => break signaled,
                        _ => {
                            eprintln!("ion: waitpid error: {}", error);
                            break FAILURE;
                        }
                    }
                }
                Ok(0) => (),
                Ok(pid) => {
                    let es = ExitStatus::from_raw(status as i32);
                    match es.signal() {
                        Some(SIGPIPE) => continue,
                        Some(signal) => {
                            eprintln!("ion: process ended by signal {}", signal);
                            match signal {
                                SIGINT => {
                                    let _ = syscall::kill(pgid, signal as usize);
                                    shell.break_flow = true;
                                }
                                _ => {
                                    shell.handle_signal(signal);
                                }
                            }
                            signaled = 128 + signal as i32;
                        }
                        None => {
                            exit_status = es.code().unwrap();
                        }
                    }
                }
                // TODO: Background job control for Redox
                // _pid if WIFSTOPPED(status) => {
                //     shell.send_to_background(pid as u32, ProcessState::Stopped, command.into());
                //     shell.break_flow = true;
                //     break 128 + signal as i32;
                // }
            }
        }
    }
}

pub mod variables {
    pub(crate) fn get_user_home(_username: &str) -> Option<String> {
        // TODO
        None
    }
}
<|endoftext|>


<commit_before>use syntax::ast::expr::*;
use syntax::ast::constant::*;
use syntax::ast::op::*;
use syntax::ast::types::*;
use syntax::ast::typer::resolve_type;
use JSType = syntax::ast::types::Type;
use stdlib::value::{Value, VNull, ResultValue, to_value};
use stdlib::*;
use run::exec::Executor;
use std::gc::Gc;
use std::c_str::CString;
use std::mem::size_of;
use jit::{Context, Function, Type, Types, Compilable, CDECL};
use jit::{UByte, SysChar, SysBool, Void, Int, UInt, Pointer, Float64, Signature};
use jit;

fn compile_type(js_type:&JSType) -> Box<Type> {
	match *js_type {
		UndefinedType | NullType | NativeObjectType | ObjectType | AnyType => Types::get_void_ptr(),
		FunctionType => Types::get_void_ptr(),
		StringType => Type::create_pointer(Types::get_char()),
		BooleanType => jit_compile!(bool),
		NumberType => Types::get_float64(),
		IntegerType => jit_compile!(i32),
		AnyOfType(ref types) => {
			fail!("Unknown types: {}", types)
		}
	}
}
/// A Javascript JIT compiler
pub struct JITCompiler {
	/// The JIT Context
	context: Box<Context>,
	/// An object representing the global object
	pub global: Value
}
impl JITCompiler {
	fn with_builder<R>(&self, cb: || -> R) -> R {
		self.context.build_start();
		let rv = cb();
		self.context.build_end();
		rv
	}
}
impl Executor<Function> for JITCompiler {
	fn new() -> JITCompiler {
		let global = Value::new_obj(None);
		object::init(global);
		console::init(global);
		math::init(global);
		array::init(global);
		function::init(global);
		json::init(global);
		number::init(global);
		error::init(global);
		string::init(global);
		uri::init(global);
		JITCompiler {
			context: Context::new(),
			global: global
		}
	}
	#[inline(always)]
	fn set_global(&mut self, name:String, val:Value) -> Value {
		self.global.set_field(name, val)
	}
	#[inline(always)]
	fn get_global(&self, name:String) -> Value {
		self.global.get_field(name)
	}
	fn compile(&self, expr: &Expr) -> Box<Function> {
		self.with_builder(|| {
			fn compile_value(func:&Function, expr: &Expr) -> Box<jit::Value> {
				let valuedata_t = jit_compile!(int);
				let valuedata_ptr_t = jit_compile!(*$valuedata_t);
				let value_t = valuedata_ptr_t;
				let cstring_t = jit_compile!(*char);
				let create_value_sig = jit_compile!(() -> $value_t);
				let undefined = || {
					let ptr = func.create_value(Types::get_void_ptr());
					let val = 0u8.compile(func);
					func.insn_store(ptr, val);
					ptr
				};
				let global = func.get_param(0);
				let scope = func.get_param(1);
				let this = func.get_param(2);
				match expr.def {
					ConstExpr(CNull) => {
						let ptr = func.create_value(jit_compile!(*void));
						let val = 1u8.compile(func);
						func.insn_store(ptr, val);
						ptr
					},
					ConstExpr(CUndefined) => {
						undefined()
					},
					ConstExpr(CBool(v)) => {
						v.compile(func)
					},
					ConstExpr(CNum(n)) => {
						n.compile(func)
					},
					ConstExpr(CString(ref s)) => {
						s.compile(func)
					},
					BinOpExpr(BinNum(OpAdd), ref a, ref b) => {
						let i_a = compile_value(func, *a);
						let i_b = compile_value(func, *b);
						func.insn_add(i_a, i_b)
					},
					BinOpExpr(BinNum(OpSub), ref a, ref b) => {
						let i_a = compile_value(func, *a);
						let i_b = compile_value(func, *b);
						func.insn_sub(i_a, i_b)
					},
					BinOpExpr(BinNum(OpMul), ref a, ref b) => {
						let i_a = compile_value(func, *a);
						let i_b = compile_value(func, *b);
						func.insn_mul(i_a, i_b)
					},
					BinOpExpr(BinNum(OpDiv), ref a, ref b) => {
						let i_a = compile_value(func, *a);
						let i_b = compile_value(func, *b);
						func.insn_div(i_a, i_b)
					},
					BinOpExpr(BinNum(OpMod), ref a, ref b) => {
						let i_a = compile_value(func, *a);
						let i_b = compile_value(func, *b);
						func.insn_rem(i_a, i_b)
					},
					BinOpExpr(BinBit(BitAnd), ref a, ref b) => {
						let i_a = compile_value(func, *a);
						let i_b = compile_value(func, *b);
						func.insn_convert(func.insn_and(i_a, i_b), jit_compile!(i32), false)
					},
					BinOpExpr(BinBit(BitOr), ref a, ref b) => {
						let i_a = compile_value(func, *a);
						let i_b = compile_value(func, *b);
						func.insn_convert(func.insn_or(i_a, i_b), jit_compile!(i32), false)
					},
					BinOpExpr(BinBit(BitXor), ref a, ref b) => {
						let i_a = compile_value(func, *a);
						let i_b = compile_value(func, *b);
						func.insn_convert(func.insn_xor(i_a, i_b), jit_compile!(i32), false)
					},
					BinOpExpr(BinBit(BitShl), ref a, ref b) => {
						let i_a = compile_value(func, *a);
						let i_b = compile_value(func, *b);
						func.insn_convert(func.insn_shl(i_a, i_b), jit_compile!(i32), false)
					},
					BinOpExpr(BinBit(BitShr), ref a, ref b) => {
						let i_a = compile_value(func, *a);
						let i_b = compile_value(func, *b);
						func.insn_convert(func.insn_shr(i_a, i_b), jit_compile!(i32), false)
					},
					BinOpExpr(BinComp(CompEqual), ref a, ref b) | BinOpExpr(BinComp(CompStrictEqual), ref a, ref b) => {
						let i_a = compile_value(func, *a);
						let i_b = compile_value(func, *b);
						func.insn_convert(func.insn_eq(i_a, i_b), jit_compile!(bool), false)
					},
					BinOpExpr(BinComp(CompNotEqual), ref a, ref b) | BinOpExpr(BinComp(CompStrictNotEqual), ref a, ref b) => {
						let i_a = compile_value(func, *a);
						let i_b = compile_value(func, *b);
						func.insn_convert(func.insn_neq(i_a, i_b), jit_compile!(bool), false)
					},
					BinOpExpr(BinComp(CompLessThan), ref a, ref b) => {
						let i_a = compile_value(func, *a);
						let i_b = compile_value(func, *b);
						func.insn_convert(func.insn_lt(i_a, i_b), jit_compile!(bool), false)
					},
					BinOpExpr(BinComp(CompLessThanOrEqual), ref a, ref b) => {
						let i_a = compile_value(func, *a);
						let i_b = compile_value(func, *b);
						func.insn_convert(func.insn_leq(i_a, i_b), jit_compile!(bool), false)
					},
					BinOpExpr(BinComp(CompGreaterThan), ref a, ref b) => {
						let i_a = compile_value(func, *a);
						let i_b = compile_value(func, *b);
						func.insn_convert(func.insn_gt(i_a, i_b), jit_compile!(bool), false)
					},
					BinOpExpr(BinComp(CompGreaterThanOrEqual), ref a, ref b) => {
						let i_a = compile_value(func, *a);
						let i_b = compile_value(func, *b);
						func.insn_convert(func.insn_geq(i_a, i_b), jit_compile!(bool), false)
					},
					UnaryOpExpr(UnaryMinus, ref a) => {
						func.insn_neg(compile_value(func, *a))
					},
					UnaryOpExpr(UnaryNot, ref a) => {
						let mut val = compile_value(func, *a);
						val = func.insn_convert(val, jit_compile!(bool), false);
						val = func.insn_neg(val);
						func.insn_convert(val, jit_compile!(bool), false)
					},
					UnaryOpExpr(UnaryPlus, ref a) => {
						compile_value(func, *a)
					},
					BlockExpr(ref exprs) => {
						let mut result = undefined();
						let last = exprs.last();
						for expr in exprs.iter() {
							let res = compile_value(func, expr);
							if expr == last.unwrap() {
								result = res;
							}
						}
						result
					},
					ReturnExpr(Some(ref ex)) => {
						let ret = compile_value(func, *ex);
						func.insn_return(convert_to_value(func, ret));
						ret
					}
					_ => fail!("Unimplemented {}", expr)
				}
			};
			let value_t = jit_compile!(*int);
			let default_sig_t = Type::create_signature(CDECL, value_t, &mut [&*value_t, &*value_t, &*value_t]);
			let func = self.context.create_function(default_sig_t);
			let value = compile_value(func, expr);
			func.insn_return(convert_to_value(func, value));
			func.set_optimization_level(5);
			func.set_recompilable();
			func.compile();
			func
		})
	}
	fn run(&mut self, comp:Box<Function>) -> ResultValue {
		// global fn(global, scope, this)
		let func: fn(Value, Value, Value) -> Value = comp.closure();
		return Ok(func(self.global, self.global, self.global));
	}
}

fn convert_to_value(func:&Function, val:&jit::Value) -> Box<jit::Value> {
	let valuedata_t = jit_compile!(i32);
	let valuedata_ptr_t = Type::create_pointer(&*valuedata_t);
	let value_t = Type::create_struct(&mut [&*valuedata_ptr_t]);
	let undef_value = Value::undefined;
	let val_type = val.get_type();
	let val_kind = val_type.get_kind();
	if val_kind.contains(SysBool) || val_kind.contains(UByte) {
		let bool_value = to_value::<bool>;
		let sig = Type::create_signature(CDECL, value_t, &mut [&*jit_compile!(bool)]);
		func.insn_call_native1("bool_value", bool_value, sig, &mut [val])
	} else if val_kind.contains(Pointer) {
		let ref_t = val_type.get_ref();
		if ref_t.get_kind().contains(SysChar) {
			fn string_value(val: *i8) -> Value {
				unsafe {
					let text = CString::new(val, false);
					to_value(text.as_str().unwrap().into_string())
				}
			}
			let sig = Type::create_signature(CDECL, value_t, &mut [&*val_type]);
			func.insn_call_native1("string_value", string_value, sig, &mut [val])
		} else {
			fn ptr_value(ptr: *i8) -> Value {
				match ptr.to_uint() {
					0u => Value::undefined(),
					1u => Value {
						ptr: Gc::new(VNull)
					},
					ptr => fail!("Invalid pointer: {}", ptr)
				}
			}
			let sig = Type::create_signature(CDECL, value_t, &mut [&*Types::get_void_ptr()]);
			func.insn_call_native1("ptr_value", ptr_value, sig, &mut [val])
		}
	} else if val_kind.contains(Int) || val_kind.contains(UInt) {
		let int_value = to_value::<i32>;
		let sig = Type::create_signature(CDECL, value_t, &mut [&*jit_compile!(i32)]);
		func.insn_call_native1("int_value", int_value, sig, &mut [val])
	} else if val_kind.contains(Float64) {
		let float_value = to_value::<f64>;
		let sig = Type::create_signature(CDECL, value_t, &mut [&*Types::get_float64()]);
		func.insn_call_native1("float_value", float_value, sig, &mut [val])
	} else {
		fail!("Invalid kind {}", val_kind.bits())
	}
}<commit_msg>Shorten value_t definition<commit_after>use syntax::ast::expr::*;
use syntax::ast::constant::*;
use syntax::ast::op::*;
use syntax::ast::types::*;
use syntax::ast::typer::resolve_type;
use JSType = syntax::ast::types::Type;
use stdlib::value::{Value, VNull, ResultValue, to_value};
use stdlib::*;
use run::exec::Executor;
use std::gc::Gc;
use std::c_str::CString;
use std::mem::size_of;
use jit::{Context, Function, Type, Types, Compilable, CDECL};
use jit::{UByte, SysChar, SysBool, Void, Int, UInt, Pointer, Float64, Signature};
use jit;

fn compile_type(js_type:&JSType) -> Box<Type> {
	match *js_type {
		UndefinedType | NullType | NativeObjectType | ObjectType | AnyType => Types::get_void_ptr(),
		FunctionType => Types::get_void_ptr(),
		StringType => Type::create_pointer(Types::get_char()),
		BooleanType => jit_compile!(bool),
		NumberType => Types::get_float64(),
		IntegerType => jit_compile!(i32),
		AnyOfType(ref types) => {
			fail!("Unknown types: {}", types)
		}
	}
}
/// A Javascript JIT compiler
pub struct JITCompiler {
	/// The JIT Context
	context: Box<Context>,
	/// An object representing the global object
	pub global: Value
}
impl JITCompiler {
	fn with_builder<R>(&self, cb: || -> R) -> R {
		self.context.build_start();
		let rv = cb();
		self.context.build_end();
		rv
	}
}
impl Executor<Function> for JITCompiler {
	fn new() -> JITCompiler {
		let global = Value::new_obj(None);
		object::init(global);
		console::init(global);
		math::init(global);
		array::init(global);
		function::init(global);
		json::init(global);
		number::init(global);
		error::init(global);
		string::init(global);
		uri::init(global);
		JITCompiler {
			context: Context::new(),
			global: global
		}
	}
	#[inline(always)]
	fn set_global(&mut self, name:String, val:Value) -> Value {
		self.global.set_field(name, val)
	}
	#[inline(always)]
	fn get_global(&self, name:String) -> Value {
		self.global.get_field(name)
	}
	fn compile(&self, expr: &Expr) -> Box<Function> {
		self.with_builder(|| {
			fn compile_value(func:&Function, expr: &Expr) -> Box<jit::Value> {
				let valuedata_t = jit_compile!(int);
				let valuedata_ptr_t = jit_compile!(*$valuedata_t);
				let value_t = valuedata_ptr_t;
				let cstring_t = jit_compile!(*char);
				let create_value_sig = jit_compile!(() -> $value_t);
				let undefined = || {
					let ptr = func.create_value(Types::get_void_ptr());
					let val = 0u8.compile(func);
					func.insn_store(ptr, val);
					ptr
				};
				let global = func.get_param(0);
				let scope = func.get_param(1);
				let this = func.get_param(2);
				match expr.def {
					ConstExpr(CNull) => {
						let ptr = func.create_value(jit_compile!(*void));
						let val = 1u8.compile(func);
						func.insn_store(ptr, val);
						ptr
					},
					ConstExpr(CUndefined) => {
						undefined()
					},
					ConstExpr(CBool(v)) => {
						v.compile(func)
					},
					ConstExpr(CNum(n)) => {
						n.compile(func)
					},
					ConstExpr(CString(ref s)) => {
						s.compile(func)
					},
					BinOpExpr(BinNum(OpAdd), ref a, ref b) => {
						let i_a = compile_value(func, *a);
						let i_b = compile_value(func, *b);
						func.insn_add(i_a, i_b)
					},
					BinOpExpr(BinNum(OpSub), ref a, ref b) => {
						let i_a = compile_value(func, *a);
						let i_b = compile_value(func, *b);
						func.insn_sub(i_a, i_b)
					},
					BinOpExpr(BinNum(OpMul), ref a, ref b) => {
						let i_a = compile_value(func, *a);
						let i_b = compile_value(func, *b);
						func.insn_mul(i_a, i_b)
					},
					BinOpExpr(BinNum(OpDiv), ref a, ref b) => {
						let i_a = compile_value(func, *a);
						let i_b = compile_value(func, *b);
						func.insn_div(i_a, i_b)
					},
					BinOpExpr(BinNum(OpMod), ref a, ref b) => {
						let i_a = compile_value(func, *a);
						let i_b = compile_value(func, *b);
						func.insn_rem(i_a, i_b)
					},
					BinOpExpr(BinBit(BitAnd), ref a, ref b) => {
						let i_a = compile_value(func, *a);
						let i_b = compile_value(func, *b);
						func.insn_convert(func.insn_and(i_a, i_b), jit_compile!(i32), false)
					},
					BinOpExpr(BinBit(BitOr), ref a, ref b) => {
						let i_a = compile_value(func, *a);
						let i_b = compile_value(func, *b);
						func.insn_convert(func.insn_or(i_a, i_b), jit_compile!(i32), false)
					},
					BinOpExpr(BinBit(BitXor), ref a, ref b) => {
						let i_a = compile_value(func, *a);
						let i_b = compile_value(func, *b);
						func.insn_convert(func.insn_xor(i_a, i_b), jit_compile!(i32), false)
					},
					BinOpExpr(BinBit(BitShl), ref a, ref b) => {
						let i_a = compile_value(func, *a);
						let i_b = compile_value(func, *b);
						func.insn_convert(func.insn_shl(i_a, i_b), jit_compile!(i32), false)
					},
					BinOpExpr(BinBit(BitShr), ref a, ref b) => {
						let i_a = compile_value(func, *a);
						let i_b = compile_value(func, *b);
						func.insn_convert(func.insn_shr(i_a, i_b), jit_compile!(i32), false)
					},
					BinOpExpr(BinComp(CompEqual), ref a, ref b) | BinOpExpr(BinComp(CompStrictEqual), ref a, ref b) => {
						let i_a = compile_value(func, *a);
						let i_b = compile_value(func, *b);
						func.insn_convert(func.insn_eq(i_a, i_b), jit_compile!(bool), false)
					},
					BinOpExpr(BinComp(CompNotEqual), ref a, ref b) | BinOpExpr(BinComp(CompStrictNotEqual), ref a, ref b) => {
						let i_a = compile_value(func, *a);
						let i_b = compile_value(func, *b);
						func.insn_convert(func.insn_neq(i_a, i_b), jit_compile!(bool), false)
					},
					BinOpExpr(BinComp(CompLessThan), ref a, ref b) => {
						let i_a = compile_value(func, *a);
						let i_b = compile_value(func, *b);
						func.insn_convert(func.insn_lt(i_a, i_b), jit_compile!(bool), false)
					},
					BinOpExpr(BinComp(CompLessThanOrEqual), ref a, ref b) => {
						let i_a = compile_value(func, *a);
						let i_b = compile_value(func, *b);
						func.insn_convert(func.insn_leq(i_a, i_b), jit_compile!(bool), false)
					},
					BinOpExpr(BinComp(CompGreaterThan), ref a, ref b) => {
						let i_a = compile_value(func, *a);
						let i_b = compile_value(func, *b);
						func.insn_convert(func.insn_gt(i_a, i_b), jit_compile!(bool), false)
					},
					BinOpExpr(BinComp(CompGreaterThanOrEqual), ref a, ref b) => {
						let i_a = compile_value(func, *a);
						let i_b = compile_value(func, *b);
						func.insn_convert(func.insn_geq(i_a, i_b), jit_compile!(bool), false)
					},
					UnaryOpExpr(UnaryMinus, ref a) => {
						func.insn_neg(compile_value(func, *a))
					},
					UnaryOpExpr(UnaryNot, ref a) => {
						let mut val = compile_value(func, *a);
						val = func.insn_convert(val, jit_compile!(bool), false);
						val = func.insn_neg(val);
						func.insn_convert(val, jit_compile!(bool), false)
					},
					UnaryOpExpr(UnaryPlus, ref a) => {
						compile_value(func, *a)
					},
					BlockExpr(ref exprs) => {
						let mut result = undefined();
						let last = exprs.last();
						for expr in exprs.iter() {
							let res = compile_value(func, expr);
							if expr == last.unwrap() {
								result = res;
							}
						}
						result
					},
					ReturnExpr(Some(ref ex)) => {
						let ret = compile_value(func, *ex);
						func.insn_return(convert_to_value(func, ret));
						ret
					}
					_ => fail!("Unimplemented {}", expr)
				}
			};
			let value_t = jit_compile!(*int);
			let default_sig_t = Type::create_signature(CDECL, value_t, &mut [&*value_t, &*value_t, &*value_t]);
			let func = self.context.create_function(default_sig_t);
			let value = compile_value(func, expr);
			func.insn_return(convert_to_value(func, value));
			func.set_optimization_level(5);
			func.set_recompilable();
			func.compile();
			func
		})
	}
	fn run(&mut self, comp:Box<Function>) -> ResultValue {
		// global fn(global, scope, this)
		let func: fn(Value, Value, Value) -> Value = comp.closure();
		return Ok(func(self.global, self.global, self.global));
	}
}

fn convert_to_value(func:&Function, val:&jit::Value) -> Box<jit::Value> {
	let value_t = jit_compile!(*int);
	let undef_value = Value::undefined;
	let val_type = val.get_type();
	let val_kind = val_type.get_kind();
	if val_kind.contains(SysBool) || val_kind.contains(UByte) {
		let bool_value = to_value::<bool>;
		let sig = Type::create_signature(CDECL, value_t, &mut [&*jit_compile!(bool)]);
		func.insn_call_native1("bool_value", bool_value, sig, &mut [val])
	} else if val_kind.contains(Pointer) {
		let ref_t = val_type.get_ref();
		if ref_t.get_kind().contains(SysChar) {
			fn string_value(val: *i8) -> Value {
				unsafe {
					let text = CString::new(val, false);
					to_value(text.as_str().unwrap().into_string())
				}
			}
			let sig = Type::create_signature(CDECL, value_t, &mut [&*val_type]);
			func.insn_call_native1("string_value", string_value, sig, &mut [val])
		} else {
			fn ptr_value(ptr: *i8) -> Value {
				match ptr.to_uint() {
					0u => Value::undefined(),
					1u => Value {
						ptr: Gc::new(VNull)
					},
					ptr => fail!("Invalid pointer: {}", ptr)
				}
			}
			let sig = Type::create_signature(CDECL, value_t, &mut [&*Types::get_void_ptr()]);
			func.insn_call_native1("ptr_value", ptr_value, sig, &mut [val])
		}
	} else if val_kind.contains(Int) || val_kind.contains(UInt) {
		let int_value = to_value::<i32>;
		let sig = Type::create_signature(CDECL, value_t, &mut [&*jit_compile!(i32)]);
		func.insn_call_native1("int_value", int_value, sig, &mut [val])
	} else if val_kind.contains(Float64) {
		let float_value = to_value::<f64>;
		let sig = Type::create_signature(CDECL, value_t, &mut [&*Types::get_float64()]);
		func.insn_call_native1("float_value", float_value, sig, &mut [val])
	} else {
		fail!("Invalid kind {}", val_kind.bits())
	}
}<|endoftext|>


<commit_before>fn main() {
    // Prevent building SPIRV-Cross on wasm32 target
    let target_arch = std::env::var("CARGO_CFG_TARGET_ARCH");
    if let Ok(arch) = target_arch {
        if "wasm32" == arch {
            return;
        }
    }

    let target_os = std::env::var("CARGO_CFG_TARGET_OS");
    let is_macos = target_os.is_ok() && target_os.unwrap() == "macos";

    let mut build = cc::Build::new();
    build.cpp(true);

    let compiler = build.try_get_compiler();
    let is_clang = compiler.is_ok() && compiler.unwrap().is_like_clang();

    if is_macos && is_clang {
        build.flag("-std=c++14").cpp_set_stdlib("c++");
    } else {
        build.flag_if_supported("-std=c++14");
    }

    build
        .file("src/wrapper.cpp")
        .file("src/vendor/SPIRV-Cross/spirv_cfg.cpp")
        .file("src/vendor/SPIRV-Cross/spirv_cross.cpp")
        .file("src/vendor/SPIRV-Cross/spirv_cross_parsed_ir.cpp")
        .file("src/vendor/SPIRV-Cross/spirv_parser.cpp")
        .file("src/vendor/SPIRV-Cross/spirv_cross_util.cpp");

    #[cfg(feature = "glsl")]
    build
        .file("src/vendor/SPIRV-Cross/spirv_glsl.cpp")
        .flag("-DSPIRV_CROSS_WRAPPER_GLSL");

    #[cfg(feature = "hlsl")]
    build
        .file("src/vendor/SPIRV-Cross/spirv_hlsl.cpp")
        .flag("-DSPIRV_CROSS_WRAPPER_HLSL");

    #[cfg(feature = "msl")]
    build
        .file("src/vendor/SPIRV-Cross/spirv_msl.cpp")
        .flag("-DSPIRV_CROSS_WRAPPER_MSL");

    build.compile("spirv-cross-rust-wrapper");
}
<commit_msg>Unconditionally include SPIRV-Cross GLSL compiler<commit_after>fn main() {
    // Prevent building SPIRV-Cross on wasm32 target
    let target_arch = std::env::var("CARGO_CFG_TARGET_ARCH");
    if let Ok(arch) = target_arch {
        if "wasm32" == arch {
            return;
        }
    }

    let target_os = std::env::var("CARGO_CFG_TARGET_OS");
    let is_macos = target_os.is_ok() && target_os.unwrap() == "macos";

    let mut build = cc::Build::new();
    build.cpp(true);

    let compiler = build.try_get_compiler();
    let is_clang = compiler.is_ok() && compiler.unwrap().is_like_clang();

    if is_macos && is_clang {
        build.flag("-std=c++14").cpp_set_stdlib("c++");
    } else {
        build.flag_if_supported("-std=c++14");
    }

    build
        .file("src/wrapper.cpp")
        .file("src/vendor/SPIRV-Cross/spirv_cfg.cpp")
        .file("src/vendor/SPIRV-Cross/spirv_cross.cpp")
        .file("src/vendor/SPIRV-Cross/spirv_cross_parsed_ir.cpp")
        .file("src/vendor/SPIRV-Cross/spirv_parser.cpp")
        .file("src/vendor/SPIRV-Cross/spirv_cross_util.cpp");

    // Ideally the GLSL compiler would be omitted here, but the HLSL and MSL compiler
    // currently inherit from it. So it's necessary to unconditionally include it here.
    build
        .file("src/vendor/SPIRV-Cross/spirv_glsl.cpp")
        .flag("-DSPIRV_CROSS_WRAPPER_GLSL");

    #[cfg(feature = "hlsl")]
    build
        .file("src/vendor/SPIRV-Cross/spirv_hlsl.cpp")
        .flag("-DSPIRV_CROSS_WRAPPER_HLSL");

    #[cfg(feature = "msl")]
    build
        .file("src/vendor/SPIRV-Cross/spirv_msl.cpp")
        .flag("-DSPIRV_CROSS_WRAPPER_MSL");

    build.compile("spirv-cross-rust-wrapper");
}
<|endoftext|>


<commit_before>use std::ops::{Mul, Add, Div, Sub, Index};
use libnum::{One, Zero, Float};
use std::cmp::PartialEq;
use math::linalg::Metric;
use math::linalg::vector::Vector;
use math::utils::{dot, argmax};

pub struct Matrix<T> {
	pub cols: usize,
	pub rows: usize,
	pub data: Vec<T>
}

impl<T: Zero + One + Copy> Matrix<T> {
    pub fn new(rows: usize, cols: usize, data: Vec<T>) -> Matrix<T> {

        assert_eq!(cols*rows, data.len());
        Matrix {
            cols: cols,
            rows: rows,
            data: data
        }
    }

    pub fn zeros(rows: usize, cols: usize) -> Matrix<T> {
    	Matrix {
            cols: cols,
            rows: rows,
            data: vec![T::zero(); cols*rows]
        }
    }

    pub fn ones(rows: usize, cols: usize) -> Matrix<T> {
        Matrix {
            cols: cols,
            rows: rows,
            data: vec![T::one(); cols*rows]
        }
    }

    pub fn identity(size: usize) -> Matrix<T> {
    	let mut data = vec![T::zero(); size * size];

    	for i in 0..size
    	{
    		data[(i*(size+1)) as usize] = T::one();
    	}

    	Matrix {
            cols: size,
            rows: size,
            data: data
        }
    }

    pub fn from_diag(diag: &[T]) -> Matrix<T> {
    	let size = diag.len();
    	let mut data = vec![T::zero(); size * size];

    	for i in 0..size
    	{
    		data[(i*(size+1)) as usize] = diag[i];
    	}

    	Matrix {
            cols: size,
            rows: size,
            data: data
        }
    }

    pub fn transpose(&self) -> Matrix<T> {
        let mut new_data = vec![T::zero(); self.cols * self.rows];
        for i in 0..self.cols
        {
            for j in 0..self.rows
            {
                new_data[i*self.rows+j] = self.data[j*self.cols + i];
            }
        }

        Matrix {
            cols: self.rows,
            rows: self.cols,
            data: new_data
        }
    }
}

impl<T: Copy + Zero + PartialEq> Matrix<T> {
    pub fn is_diag(&self) -> bool {

        for i in 0..self.rows {
            for j in 0..self.cols {
                if (i != j) && (self[[i,j]] != T::zero()) {
                    return false;
                }
            }
        }

        return true;
    }
}

impl<T: Copy + One + Zero + Add<T, Output=T>
        + Mul<T, Output=T> + Sub<T, Output=T>
        + Div<T, Output=T> + PartialOrd> Matrix<T> {

    pub fn inverse(&self) -> Matrix<T> {
        let (l,u,p) = self.lup_decomp();

        unimplemented!();
    }

    pub fn det(&self) -> T {
        assert_eq!(self.rows, self.cols);

        let n = self.cols;

        if self.is_diag() {
            let mut d = T::one();

            for i in 0..n {
                d = d * self[[i,i]];
            }

            return d;
        }

        if n == 2 {
            return (self[[0,0]] * self[[1,1]]) - (self[[0,1]] * self[[1,0]]);
        }

        if n == 3 {
            return (self[[0,0]] * self[[1,1]] * self[[2,2]]) + (self[[0,1]] * self[[1,2]] * self[[2,0]])
                    + (self[[0,2]] * self[[1,0]] * self[[2,1]]) - (self[[0,0]] * self[[1,2]] * self[[2,1]])
                    - (self[[0,1]] * self[[1,0]] * self[[2,2]]) - (self[[0,2]] * self[[1,1]] * self[[2,0]]);
        }

        let (l,u,p) = self.lup_decomp();

        let mut d = T::one();

        for i in 0..n {
            d = d * l[[i,i]];
            d = d * u[[i,i]];
        }

        return d;
    }

    pub fn lup_decomp(&self) -> (Matrix<T>, Matrix<T>, Matrix<T>) {
        assert!(self.rows == self.cols);

        let n = self.cols;

        let mut l = Matrix::<T>::zeros(n, n);
        let mut u = Matrix::<T>::zeros(n, n);

        let mt = self.transpose();

        let mut p = Matrix::<T>::identity(n);

        // Compute the permutation matrix
        for i in 0..n {
            let row = argmax(&mt.data[i*(n+1)..(i+1)*n]) + i;

            if row != i {
                for j in 0..n {
                    p.data.swap(i*n + j, row*n+j)
                }
            }
        }

        let a_2 = &p * self;

        for i in 0..n {
            l.data[i*(n+1)] = T::one();

            for j in 0..i+1 {
                let mut s1 = T::zero();

                for k in 0..j {
                    s1 = s1 + l.data[j*n + k] * u.data[k*n + i];
                }

                u.data[j*n + i] = a_2[[j,i]] - s1;
            }

            for j in i..n {
                let mut s2 = T::zero();

                for k in 0..i {
                    s2 = s2 + l.data[j*n + k] * u.data[k*n + i];
                }

                l.data[j*n + i] = (a_2[[j,i]] - s2) / u[[i,i]];
            }

        }

        (l,u,p)
    }
}

impl <T: Copy + One + Zero + Mul<T, Output=T>> Mul<T> for Matrix<T> {
    type Output = Matrix<T>;

    fn mul(self, f: T) -> Matrix<T> {
        (&self) * (&f)
    }
}

impl <'a, T: Copy + One + Zero + Mul<T, Output=T>> Mul<&'a T> for Matrix<T> {
    type Output = Matrix<T>;

    fn mul(self, f: &T) -> Matrix<T> {
        (&self) * f
    }
}

impl <'a, T: Copy + One + Zero + Mul<T, Output=T>> Mul<T> for &'a Matrix<T> {
    type Output = Matrix<T>;

    fn mul(self, f: T) -> Matrix<T> {
        self * (&f)
    }
}

impl<'a, 'b, T: Copy + One + Zero + Mul<T, Output=T>> Mul<&'b T> for &'a Matrix<T> {
    type Output = Matrix<T>;

    fn mul(self, f: &T) -> Matrix<T> {
        let new_data : Vec<T> = self.data.iter().map(|v| (*v) * (*f)).collect();

        Matrix {
            cols: self.cols,
            rows: self.rows,
            data: new_data
        }
    }
}

impl <T: Copy + Zero + One + Mul<T, Output=T> + Add<T, Output=T>> Mul<Matrix<T>> for Matrix<T> {
    type Output = Matrix<T>;

    fn mul(self, m: Matrix<T>) -> Matrix<T> {
        (&self) * (&m)
    }
}

impl <'a, T: Copy + Zero + One + Mul<T, Output=T> + Add<T, Output=T>> Mul<Matrix<T>> for &'a Matrix<T> {
    type Output = Matrix<T>;

    fn mul(self, m: Matrix<T>) -> Matrix<T> {
        self * (&m)
    }
}

impl <'a, T: Copy + Zero + One + Mul<T, Output=T> + Add<T, Output=T>> Mul<&'a Matrix<T>> for Matrix<T> {
    type Output = Matrix<T>;

    fn mul(self, m: &Matrix<T>) -> Matrix<T> {
        (&self) * m
    }
}

impl<'a, 'b, T: Copy + Zero + One + Mul<T, Output=T> + Add<T, Output=T>> Mul<&'b Matrix<T>> for &'a Matrix<T> {
	type Output = Matrix<T>;

	fn mul(self, m: &Matrix<T>) -> Matrix<T> {
		// Will use Strassen algorithm if large, traditional otherwise
		assert!(self.cols == m.rows);

        let mut new_data = vec![T::zero(); self.rows * m.cols];

        let mt = m.transpose();

        for i in 0..self.rows
        {
            for j in 0..m.cols
            {
                new_data[i * m.cols + j] = dot( &self.data[(i * self.cols)..((i+1)*self.cols)], &mt.data[(j*m.rows)..((j+1)*m.rows)] );
            }
        }

        Matrix {
            rows: self.rows,
            cols: m.cols,
            data: new_data
        }
	}
}

impl<T: Copy + One + Zero + Mul<T, Output=T> + Add<T, Output=T>> Mul<Vector<T>> for Matrix<T> {
    type Output = Vector<T>;

    fn mul(self, v: Vector<T>) -> Vector<T> {
        assert!(v.size == self.cols);

        let mut new_data = vec![T::zero(); self.rows];

        for i in 0..self.rows
        {
            new_data[i] = dot(&self.data[i*self.cols..(i+1)*self.cols], &v.data);
        }

        return Vector {
            size: self.rows,
            data: new_data
        }
    }
}

impl<T: Copy + One + Zero + Add<T, Output=T>> Add<T> for Matrix<T> {
	type Output = Matrix<T>;

	fn add(self, f: T) -> Matrix<T> {
		let new_data = self.data.into_iter().map(|v| v + f).collect();

        Matrix {
            cols: self.cols,
            rows: self.rows,
            data: new_data
        }
    }
}

impl<T: Copy + One + Zero + Add<T, Output=T>> Add<Matrix<T>> for Matrix<T> {
	type Output = Matrix<T>;

	fn add(self, m: Matrix<T>) -> Matrix<T> {
		assert!(self.cols == m.cols);
		assert!(self.rows == m.rows);

		let new_data = self.data.into_iter().enumerate().map(|(i,v)| v + m.data[i]).collect();

        Matrix {
            cols: self.cols,
            rows: self.rows,
            data: new_data
        }
	}
}

impl<T: Copy + One + Zero + Sub<T, Output=T>> Sub<T> for Matrix<T> {
    type Output = Matrix<T>;

    fn sub(self, f: T) -> Matrix<T> {
        let new_data = self.data.into_iter().map(|v| v - f).collect();

        Matrix {
            cols: self.cols,
            rows: self.rows,
            data: new_data
        }
    }
}

impl<T: Copy + One + Zero + Sub<T, Output=T>> Sub<Matrix<T>> for Matrix<T> {
	type Output = Matrix<T>;

	fn sub(self, m: Matrix<T>) -> Matrix<T> {
		assert!(self.cols == m.cols);
		assert!(self.rows == m.rows);

		let new_data = self.data.into_iter().enumerate().map(|(i,v)| v - m.data[i]).collect();

        Matrix {
            cols: self.cols,
            rows: self.rows,
            data: new_data
        }
	}
}

impl<T: Copy + One + Zero + PartialEq + Div<T, Output=T>> Div<T> for Matrix<T> {
	type Output = Matrix<T>;

	fn div(self, f: T) -> Matrix<T> {
		assert!(f != T::zero());

		let new_data = self.data.into_iter().map(|v| v / f).collect();

        Matrix {
            cols: self.cols,
            rows: self.rows,
            data: new_data
        }
	}
}

impl<T> Index<[usize; 2]> for Matrix<T> {
	type Output = T;

	fn index(&self, idx : [usize; 2]) -> &T {
		assert!(idx[0] < self.rows);
		assert!(idx[1] < self.cols);

		&self.data[idx[0] * self.cols + idx[1]]
	}
}

impl<T: Float> Metric<T> for Matrix<T> {
    fn norm(&self) -> T {
        let mut s = T::zero();

        for u in &self.data {
            s = s + (*u) * (*u);
        }

        s.sqrt()
    }
}<commit_msg>Implementing generalized borrowing for matrix arithmetic.<commit_after>use std::ops::{Mul, Add, Div, Sub, Index};
use libnum::{One, Zero, Float};
use std::cmp::PartialEq;
use math::linalg::Metric;
use math::linalg::vector::Vector;
use math::utils::{dot, argmax};

pub struct Matrix<T> {
	pub cols: usize,
	pub rows: usize,
	pub data: Vec<T>
}

impl<T: Zero + One + Copy> Matrix<T> {
    pub fn new(rows: usize, cols: usize, data: Vec<T>) -> Matrix<T> {

        assert_eq!(cols*rows, data.len());
        Matrix {
            cols: cols,
            rows: rows,
            data: data
        }
    }

    pub fn zeros(rows: usize, cols: usize) -> Matrix<T> {
    	Matrix {
            cols: cols,
            rows: rows,
            data: vec![T::zero(); cols*rows]
        }
    }

    pub fn ones(rows: usize, cols: usize) -> Matrix<T> {
        Matrix {
            cols: cols,
            rows: rows,
            data: vec![T::one(); cols*rows]
        }
    }

    pub fn identity(size: usize) -> Matrix<T> {
    	let mut data = vec![T::zero(); size * size];

    	for i in 0..size
    	{
    		data[(i*(size+1)) as usize] = T::one();
    	}

    	Matrix {
            cols: size,
            rows: size,
            data: data
        }
    }

    pub fn from_diag(diag: &[T]) -> Matrix<T> {
    	let size = diag.len();
    	let mut data = vec![T::zero(); size * size];

    	for i in 0..size
    	{
    		data[(i*(size+1)) as usize] = diag[i];
    	}

    	Matrix {
            cols: size,
            rows: size,
            data: data
        }
    }

    pub fn transpose(&self) -> Matrix<T> {
        let mut new_data = vec![T::zero(); self.cols * self.rows];
        for i in 0..self.cols
        {
            for j in 0..self.rows
            {
                new_data[i*self.rows+j] = self.data[j*self.cols + i];
            }
        }

        Matrix {
            cols: self.rows,
            rows: self.cols,
            data: new_data
        }
    }
}

impl<T: Copy + Zero + PartialEq> Matrix<T> {
    pub fn is_diag(&self) -> bool {

        for i in 0..self.rows {
            for j in 0..self.cols {
                if (i != j) && (self[[i,j]] != T::zero()) {
                    return false;
                }
            }
        }

        return true;
    }
}

impl<T: Copy + One + Zero + Add<T, Output=T>
        + Mul<T, Output=T> + Sub<T, Output=T>
        + Div<T, Output=T> + PartialOrd> Matrix<T> {

    pub fn inverse(&self) -> Matrix<T> {
        let (l,u,p) = self.lup_decomp();

        unimplemented!();
    }

    pub fn det(&self) -> T {
        assert_eq!(self.rows, self.cols);

        let n = self.cols;

        if self.is_diag() {
            let mut d = T::one();

            for i in 0..n {
                d = d * self[[i,i]];
            }

            return d;
        }

        if n == 2 {
            return (self[[0,0]] * self[[1,1]]) - (self[[0,1]] * self[[1,0]]);
        }

        if n == 3 {
            return (self[[0,0]] * self[[1,1]] * self[[2,2]]) + (self[[0,1]] * self[[1,2]] * self[[2,0]])
                    + (self[[0,2]] * self[[1,0]] * self[[2,1]]) - (self[[0,0]] * self[[1,2]] * self[[2,1]])
                    - (self[[0,1]] * self[[1,0]] * self[[2,2]]) - (self[[0,2]] * self[[1,1]] * self[[2,0]]);
        }

        let (l,u,p) = self.lup_decomp();

        let mut d = T::one();

        for i in 0..n {
            d = d * l[[i,i]];
            d = d * u[[i,i]];
        }

        return d;
    }

    pub fn lup_decomp(&self) -> (Matrix<T>, Matrix<T>, Matrix<T>) {
        assert!(self.rows == self.cols);

        let n = self.cols;

        let mut l = Matrix::<T>::zeros(n, n);
        let mut u = Matrix::<T>::zeros(n, n);

        let mt = self.transpose();

        let mut p = Matrix::<T>::identity(n);

        // Compute the permutation matrix
        for i in 0..n {
            let row = argmax(&mt.data[i*(n+1)..(i+1)*n]) + i;

            if row != i {
                for j in 0..n {
                    p.data.swap(i*n + j, row*n+j)
                }
            }
        }

        let a_2 = &p * self;

        for i in 0..n {
            l.data[i*(n+1)] = T::one();

            for j in 0..i+1 {
                let mut s1 = T::zero();

                for k in 0..j {
                    s1 = s1 + l.data[j*n + k] * u.data[k*n + i];
                }

                u.data[j*n + i] = a_2[[j,i]] - s1;
            }

            for j in i..n {
                let mut s2 = T::zero();

                for k in 0..i {
                    s2 = s2 + l.data[j*n + k] * u.data[k*n + i];
                }

                l.data[j*n + i] = (a_2[[j,i]] - s2) / u[[i,i]];
            }

        }

        (l,u,p)
    }
}

impl <T: Copy + One + Zero + Mul<T, Output=T>> Mul<T> for Matrix<T> {
    type Output = Matrix<T>;

    fn mul(self, f: T) -> Matrix<T> {
        (&self) * (&f)
    }
}

impl <'a, T: Copy + One + Zero + Mul<T, Output=T>> Mul<&'a T> for Matrix<T> {
    type Output = Matrix<T>;

    fn mul(self, f: &T) -> Matrix<T> {
        (&self) * f
    }
}

impl <'a, T: Copy + One + Zero + Mul<T, Output=T>> Mul<T> for &'a Matrix<T> {
    type Output = Matrix<T>;

    fn mul(self, f: T) -> Matrix<T> {
        self * (&f)
    }
}

impl<'a, 'b, T: Copy + One + Zero + Mul<T, Output=T>> Mul<&'b T> for &'a Matrix<T> {
    type Output = Matrix<T>;

    fn mul(self, f: &T) -> Matrix<T> {
        let new_data : Vec<T> = self.data.iter().map(|v| (*v) * (*f)).collect();

        Matrix {
            cols: self.cols,
            rows: self.rows,
            data: new_data
        }
    }
}

impl <T: Copy + Zero + One + Mul<T, Output=T> + Add<T, Output=T>> Mul<Matrix<T>> for Matrix<T> {
    type Output = Matrix<T>;

    fn mul(self, m: Matrix<T>) -> Matrix<T> {
        (&self) * (&m)
    }
}

impl <'a, T: Copy + Zero + One + Mul<T, Output=T> + Add<T, Output=T>> Mul<Matrix<T>> for &'a Matrix<T> {
    type Output = Matrix<T>;

    fn mul(self, m: Matrix<T>) -> Matrix<T> {
        self * (&m)
    }
}

impl <'a, T: Copy + Zero + One + Mul<T, Output=T> + Add<T, Output=T>> Mul<&'a Matrix<T>> for Matrix<T> {
    type Output = Matrix<T>;

    fn mul(self, m: &Matrix<T>) -> Matrix<T> {
        (&self) * m
    }
}

impl<'a, 'b, T: Copy + Zero + One + Mul<T, Output=T> + Add<T, Output=T>> Mul<&'b Matrix<T>> for &'a Matrix<T> {
	type Output = Matrix<T>;

	fn mul(self, m: &Matrix<T>) -> Matrix<T> {
		// Will use Strassen algorithm if large, traditional otherwise
		assert!(self.cols == m.rows);

        let mut new_data = vec![T::zero(); self.rows * m.cols];

        let mt = m.transpose();

        for i in 0..self.rows
        {
            for j in 0..m.cols
            {
                new_data[i * m.cols + j] = dot( &self.data[(i * self.cols)..((i+1)*self.cols)], &mt.data[(j*m.rows)..((j+1)*m.rows)] );
            }
        }

        Matrix {
            rows: self.rows,
            cols: m.cols,
            data: new_data
        }
	}
}

impl <T: Copy + Zero + One + Mul<T, Output=T> + Add<T, Output=T>> Mul<Vector<T>> for Matrix<T> {
    type Output = Vector<T>;

    fn mul(self, m: Vector<T>) -> Vector<T> {
        (&self) * (&m)
    }
}

impl <'a, T: Copy + Zero + One + Mul<T, Output=T> + Add<T, Output=T>> Mul<Vector<T>> for &'a Matrix<T> {
    type Output = Vector<T>;

    fn mul(self, m: Vector<T>) -> Vector<T> {
        self * (&m)
    }
}

impl <'a, T: Copy + Zero + One + Mul<T, Output=T> + Add<T, Output=T>> Mul<&'a Vector<T>> for Matrix<T> {
    type Output = Vector<T>;

    fn mul(self, m: &Vector<T>) -> Vector<T> {
        (&self) * m
    }
}

impl<'a, 'b, T: Copy + One + Zero + Mul<T, Output=T> + Add<T, Output=T>> Mul<&'b Vector<T>> for &'a Matrix<T> {
    type Output = Vector<T>;

    fn mul(self, v: &Vector<T>) -> Vector<T> {
        assert!(v.size == self.cols);

        let mut new_data = vec![T::zero(); self.rows];

        for i in 0..self.rows
        {
            new_data[i] = dot(&self.data[i*self.cols..(i+1)*self.cols], &v.data);
        }

        return Vector {
            size: self.rows,
            data: new_data
        }
    }
}

impl<T: Copy + One + Zero + Add<T, Output=T>> Add<T> for Matrix<T> {
    type Output = Matrix<T>;

    fn add(self, f: T) -> Matrix<T> {
        (&self) + (&f)
    }
}

impl<'a, T: Copy + One + Zero + Add<T, Output=T>> Add<T> for &'a Matrix<T> {
    type Output = Matrix<T>;

    fn add(self, f: T) -> Matrix<T> {
        self + (&f)
    }
}

impl<'a, T: Copy + One + Zero + Add<T, Output=T>> Add<&'a T> for Matrix<T> {
    type Output = Matrix<T>;

    fn add(self, f: &T) -> Matrix<T> {
        (&self) + f
    }
}

impl<'a, 'b, T: Copy + One + Zero + Add<T, Output=T>> Add<&'b T> for &'a Matrix<T> {
	type Output = Matrix<T>;

	fn add(self, f: &T) -> Matrix<T> {
		let new_data : Vec<T> = self.data.iter().map(|v| (*v) + (*f)).collect();

        Matrix {
            cols: self.cols,
            rows: self.rows,
            data: new_data
        }
    }
}

impl<T: Copy + One + Zero + Add<T, Output=T>> Add<Matrix<T>> for Matrix<T> {
    type Output = Matrix<T>;

    fn add(self, f: Matrix<T>) -> Matrix<T> {
        (&self) + (&f)
    }
}

impl<'a, T: Copy + One + Zero + Add<T, Output=T>> Add<Matrix<T>> for &'a Matrix<T> {
    type Output = Matrix<T>;

    fn add(self, f: Matrix<T>) -> Matrix<T> {
        self + (&f)
    }
}

impl<'a, T: Copy + One + Zero + Add<T, Output=T>> Add<&'a Matrix<T>> for Matrix<T> {
    type Output = Matrix<T>;

    fn add(self, f: &Matrix<T>) -> Matrix<T> {
        (&self) + f
    }
}

impl<'a, 'b, T: Copy + One + Zero + Add<T, Output=T>> Add<&'b Matrix<T>> for &'a Matrix<T> {
	type Output = Matrix<T>;

	fn add(self, m: &Matrix<T>) -> Matrix<T> {
		assert!(self.cols == m.cols);
		assert!(self.rows == m.rows);

		let new_data = self.data.iter().enumerate().map(|(i,v)| *v + m.data[i]).collect();

        Matrix {
            cols: self.cols,
            rows: self.rows,
            data: new_data
        }
	}
}

impl<T: Copy + One + Zero + Sub<T, Output=T>> Sub<T> for Matrix<T> {
    type Output = Matrix<T>;

    fn sub(self, f: T) -> Matrix<T> {
        (&self) - (&f)
    }
}

impl<'a, T: Copy + One + Zero + Sub<T, Output=T>> Sub<&'a T> for Matrix<T> {
    type Output = Matrix<T>;

    fn sub(self, f: &T) -> Matrix<T> {
        (&self) - f
    }
}

impl<'a, T: Copy + One + Zero + Sub<T, Output=T>> Sub<T> for &'a Matrix<T> {
    type Output = Matrix<T>;

    fn sub(self, f: T) -> Matrix<T> {
        self - (&f)
    }
}

impl<'a, 'b, T: Copy + One + Zero + Sub<T, Output=T>> Sub<&'b T> for &'a Matrix<T> {
    type Output = Matrix<T>;

    fn sub(self, f: &T) -> Matrix<T> {
        let new_data = self.data.iter().map(|v| *v - *f).collect();

        Matrix {
            cols: self.cols,
            rows: self.rows,
            data: new_data
        }
    }
}

impl<T: Copy + One + Zero + Sub<T, Output=T>> Sub<Matrix<T>> for Matrix<T> {
    type Output = Matrix<T>;

    fn sub(self, f: Matrix<T>) -> Matrix<T> {
        (&self) - (&f)
    }
}

impl<'a, T: Copy + One + Zero + Sub<T, Output=T>> Sub<Matrix<T>> for &'a Matrix<T> {
    type Output = Matrix<T>;

    fn sub(self, f: Matrix<T>) -> Matrix<T> {
        self - (&f)
    }
}

impl<'a, T: Copy + One + Zero + Sub<T, Output=T>> Sub<&'a Matrix<T>> for Matrix<T> {
    type Output = Matrix<T>;

    fn sub(self, f: &Matrix<T>) -> Matrix<T> {
        (&self) - f
    }
}

impl<'a, 'b, T: Copy + One + Zero + Sub<T, Output=T>> Sub<&'b Matrix<T>> for &'a Matrix<T> {
	type Output = Matrix<T>;

	fn sub(self, m: &Matrix<T>) -> Matrix<T> {
		assert!(self.cols == m.cols);
		assert!(self.rows == m.rows);

		let new_data = self.data.iter().enumerate().map(|(i,v)| *v - m.data[i]).collect();

        Matrix {
            cols: self.cols,
            rows: self.rows,
            data: new_data
        }
	}
}

impl<T: Copy + One + Zero + PartialEq + Div<T, Output=T>> Div<T> for Matrix<T> {
    type Output = Matrix<T>;

    fn div(self, f: T) -> Matrix<T> {
        (&self) / (&f)
    }
}

impl<'a, T: Copy + One + Zero + PartialEq + Div<T, Output=T>> Div<T> for &'a Matrix<T> {
    type Output = Matrix<T>;

    fn div(self, f: T) -> Matrix<T> {
        self / (&f)
    }
}

impl<'a, T: Copy + One + Zero + PartialEq + Div<T, Output=T>> Div<&'a T> for Matrix<T> {
    type Output = Matrix<T>;

    fn div(self, f: &T) -> Matrix<T> {
        (&self) / f
    }
}

impl<'a, 'b, T: Copy + One + Zero + PartialEq + Div<T, Output=T>> Div<&'b T> for &'a Matrix<T> {
	type Output = Matrix<T>;

	fn div(self, f: &T) -> Matrix<T> {
		assert!(*f != T::zero());

		let new_data = self.data.iter().map(|v| *v / *f).collect();

        Matrix {
            cols: self.cols,
            rows: self.rows,
            data: new_data
        }
	}
}

impl<T> Index<[usize; 2]> for Matrix<T> {
	type Output = T;

	fn index(&self, idx : [usize; 2]) -> &T {
		assert!(idx[0] < self.rows);
		assert!(idx[1] < self.cols);

		&self.data[idx[0] * self.cols + idx[1]]
	}
}

impl<T: Float> Metric<T> for Matrix<T> {
    fn norm(&self) -> T {
        let mut s = T::zero();

        for u in &self.data {
            s = s + (*u) * (*u);
        }

        s.sqrt()
    }
}<|endoftext|>